機械学習3章
勾配降下法
予測関数
損失関数
勾配計算
パラメーター修正
https://gyazo.com/4997bca55cc6f32c71458369cd400e65
1予測計算
予測関数 Yp = W*X + B
Yp = 予測値
(weight)W = 係数
(bias)B = 定数
2 損失関数
学習データが入力と正解値の両方を含んでいるとき正解値の列を分離して正解テンソルYとする
YpとYの差が小さくなる関数を求める
3 勾配計算
予測関数を構成するWとBを少しずつ値を変えた時の損失の変化の度合い(勾配)を調べる
損失関数の最低値をとるためにWとBのずらすべき方向が勾配に当たる
4 パラメーター修正
勾配計算の結果(勾配値)に小さな定数(学習率)をかけ、その値だけWとBを同時に減らす
勾配降下法実装
身長から体重を予測する。一次関数→最適な直線を求める
1 データの前処理
2 座標系の変換
平均値が0になるように座標を並行移動する
機械学習モデルでは、データは0に近い値を持つことが望ましい。
3 予測計算
xとyをテンソルに変換する
重みWとBの変数を定義
勾配計算するためrequires_grad=Trueとする
変数には初期値として1.0の値を設定
code:python
W = torch.tensor(1.0,requires_grad=True).float()
B = torch.tensor(1.0,requires_grad=True).float()
予測値=Yp
Yp = W*X+B
→予測関数predを経由したコードは
code:python
def pred(X):
return W * X + B
Yp = pred(X)
4 損失関数
損失関数は平均二乗誤差で計算する
code:python
def mse(Yp, Y):
loss = ((Yp - Y) ** 2).mean()
return loss
#損失計算
loss = mse(Yp, Y)
5 勾配計算
code:python
#勾配計算
loss.backward()
#勾配値確認
print(W.grad)
print(B.grad)
6 パラメータ修正
勾配計算した値に学習率(0.01, 0.001が基本)lrをかけた結果を元のパラメータ値からひく
code:python
#エラーが発生する
lr = 0.001
w -= lr * W.grad
B -= lr * B.grad
このパラメーター修正を少しづつ繰り返し行うことでWとBを正しい位置に近づけることが勾配降下法
繰り返し処理の回数と学習率はケースバイケース
7 繰り返し計算
初期化のセル
code:pythoh
W = torch.tensor(1.0, requires_grad=True).float()
B = torch.tensor(1.0, requires_grad=True).float()
#繰り返し計算
num_epochs = 500
#学習率
lr = 0.001
#記録用配列初期化
history = np.zeros((0,2))
ループ処理の実行
code:python
for epoch in range(num_epochs):
Yp = pred(x)
loss = mse(Yp, Y)
loss.backward()
with torch.no_grad():
W -= lr * W.grad
B -= lr * B.grad
W.grad.zero_()
B.grad.zero_()
# 損失の記録(繰り返し回数とその時の損失の記録)
if (epoch %10 == 0):
item = np.array(epoch, loss.item())
history = np.vstack((history, item))
print(f'epoch = {epoch} loss = {loss:.4f}')
評価結果
code:python
#パラメーターの最終値
print('W = ', W.data.numpy())
print('B = ', B.data.numpy())
#損失の確認
print(f'初期状態 : 損失 : {history0,1:.4f}')
print(f'最終状態 : 損失 : {history-1,1:.4f}')
学習がうまく行ったことを表す
最適化関数の利用
code:python
# 初期化
# WとBを変数として扱う
W = torch.tensor(1.0, requires_grad=True).float()
B = torch.tensor(1.0, requires_grad=True).float()
# 繰り返し回数
num_epochs = 500
# 学習率
lr = 0.001
# optimizerとしてSGD(確率的勾配降下法)を指定する(変更点)
import torch.optim as optim
optimizer = optim.SGD(W, B, lr=lr)
# 記録用配列初期化
history = np.zeros((0, 2))
※最適化関数には数多くのアルゴリズムがある。その中でSGDというクラスのアルゴリズムは最もシンプルなもの
code:python
#SGDを使用した場合の繰り返し処理はどうなるのか
for epoch in range(num_epochs):
Yp = pred(x)
loss = mse(Yp, Y)
loss = loss.backward()
#変更点
#parameter修正
optimizer.step()
#勾配値初期化
optimizer.zero_grad()
if (epoch %10 == 0):
item = np.array(epoch, loss.item())
history = np.vstach((history, item))
print(f'epoch = {epoch} loss = {loss:.4f}')
step関数でパラメータ値を間接的に変更する
先ほどの手組みの結果と全く同じ値になる。
SGD の内部ロジック
code:python
with torch.no_grad():
W -= lr * W.grad
B -= lr * B.grad
最適化関数を取り入れたことで様々なチューニングを簡単にできるようになる
code:python
#最適化関数をチューニングした場合の初期化処理
W = torch.tensor(1.0, requires_grad=True).float()
B = torch.tensor(1.0, requires_grad=True).float()
num_epochs = 500
lr = 0.001
#optimizerとしてSGD(確率的勾配降下法)を指定する
import torch.optim as optim
optimizer = optim.SGD(W, B, lr=lr, momentum=0.9)
history = np.zeros((0,2))
チューニングした方が学習の速度が速い
momentumというアルゴリズムによって学習が早くなる