こんにちは
今回は「pytorchによる回帰直線の推定」を行っていきたいと思います。
「誤差逆伝播」という機械学習の基本的な手法で回帰直線を推定します。
本当に基礎中の基礎なので、しっかり押さえておきましょう。
pytorchによる回帰直線の推定
回帰直線の推定は
- データを取得(設定)する
- 損失関数を決める
- ハイパーパラメータを決める
- 繰り返し処理で学習する
- 結果を確かめる
という順番でやっていきます。それでは順番に見ていきましょう。
データを取得(設定)する
ではまず、データを設定します。
今回は簡単のため、完全に直線に乗ったデータを用意します。つまり、
X = torch.tensor([1,2,3,4], dtype=torch.float32) Y = torch.tensor([2,4,6,8], dtype=torch.float32) w = torch.tensor(5.0, requires_grad = True, dtype=torch.float32)

という\(Y = 2X\)という直線に乗っているデータです。
今回は直線の傾き\(w\)である\(2\)という値を機械学習で推定していきます。
なお、\(w\)は初期値として\(5\)を設定しています。(この値は何でもいいです。)
さらに、\(X\)の値から予想される\(Y\)の推定値\(y_p\)を
def forward(x): y_p = w*x return y_p
という直線モデルで表現することを考えます。
損失関数を決める
次に損失関数\(loss\)を決めます。
損失関数とは、推定精度の指針になるものです。この値は小さいほど推定精度が良いことを示します。
なので損失関数が小さくなるように、学習を行っていきます。
今回は平均二乗誤差という損失関数を使います。
def loss(y, y_p): return ((y_p - y)**2).mean()
\(y_p\)は\(y\)の推定値, \(y\)はデータの値です。
つまり、データとデータの推定値の差を二乗し、平均(mean)を取ったものになります。
データとデータの推定値の差は小さい方がいいので、これが最小になるような傾き\(w\)を求めていきます。
ハイパーパラメータを決める
ハイパーパラメータとは、人の手で決めるパラメータのことです。
今回は「学習ループの回数」と「学習率」をハイパーパラメータとして決めます。
ite = 1000 lr = 0.01
繰り返し処理で学習をする
ではいよいよ学習を行っていきます。
学習は大きく分けて2ステップで
- 損失関数を微分
- 傾き\(w\)を更新
となります。これを上で決めたite回繰り返します。
for i in range(ite): y_p = forward(X) #2回目から更新されたwが入る→Loss関数が小さくなる l = loss(Y, y_p) l.backward() with torch.no_grad(): w -= lr*w.grad w.grad.zero_() if i % 50 == 0: print(f'epoch : {i}, w : {w:.3f}, Loss : {l:.8f}')
4行目が損失関数の微分, 5-6行目が傾きの更新を表しています。
with torch.no_grad()は「演算を行ったときに、その誤差逆伝播を記録しない」という意味です。pytorchは自動で誤差逆伝播を計算しますが、傾き(重み)を更新するための演算に対しては、その必要がないのです。
また、w.gradつまり\(\frac{dLoss}{dw}\)は呼び出されるたびに、値がどんどん足されていくため、ループの最後でw.grad.zero_()として\(\frac{dLoss}{dw}\)をリセットします。
結果を確かめる
学習ループが終わったら、思い通りの結果が出ているか確かめてみましょう。
print(f' w = {w:.3f}') # w=2.000
となれば、予想通り\(w = 2.0\)が得られていることが分かります!!
よって、機械学習を使って
$$
X = (1,2,3,4) Y = (2,4,6,8)
$$
というデータから、\(Y = 2X\)という回帰直線を推定することができました!!
まとめ
以下のようなコードで回帰直線を推定しました。
import torch X = torch.tensor([1,2,3,4], dtype=torch.float32) Y = torch.tensor([2,4,6,8], dtype=torch.float32) w = torch.tensor(5.0, requires_grad = True, dtype=torch.float32) def loss(y, y_p): return ((y_p - y)**2).mean() def forward(x): y_p = w*x return y_p ite = 1000 lr = 0.01 for i in range(ite): y_p = forward(X) l = loss(Y, y_p) l.backward() with torch.no_grad(): w -= lr*w.grad w.grad.zero_() if i % 50 == 0: print(f'epoch : {i}, w : {w:.3f}, Loss : {l:.8f}') print(f' w = {w:.3f}')
手順としては
- データを取得(設定)する
- 損失関数を決める
- ハイパーパラメータを決める
- 繰り返し処理で学習する
- 結果を確かめる
といったものになります。