第8章
学習してみたい
ここでは、答えを出すだけでなく「少し直す」までを 1 回だけ体験します。
今日は何をしたい?
学習では、まず答えを出し、そのずれを測り、そのずれを小さくする向きへ重みを少し動かします。この 1 回分を短いコードで見て、loss と backward() と step() の役目をつかみます。
学習 1 回の流れは、この 4 ステップです。
- pred
- モデルが出した予測値。まだ正解とは離れている。
- loss
- 予測と正解のずれを 1 個の数にしたもの。小さいほどよい。
- MSELoss
- ずれの測り方のひとつ(Mean Squared Error:平均二乗誤差)。予測と正解の差を2乗して平均する。差が大きいほど値が大きくなる。
- SGD(optimizer)
- 重みの動かし方のひとつ(Stochastic Gradient Descent)。lr=0.1 は「一度に動かす量」で、小さいほど慎重に動かす。
- backward()
- ずれを「どの重みをどっちに直せばいいか」に変換する。
- step()
- 重みを実際に少し動かす。ここで学習が進む。
確認コード
import torch
import torch.nn as nn
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = nn.Linear(1, 1).to(device)
x = torch.tensor([[1.0]], device=device)
y_true = torch.tensor([[2.0]], device=device)
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
# -- 重みの変化を見る --
print("重み(学習前):", model.weight.item())
pred = model(x)
loss = loss_fn(pred, y_true)
print("loss(1回目):", loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("重み(学習後):", model.weight.item())
# -- もう1回やると loss が変わる --
pred2 = model(x)
loss2 = loss_fn(pred2, y_true)
print("loss(2回目):", loss2.item())このコードを chapter08.py として保存して、python chapter08.py で実行します。
学習の流れは、ざっくり言うと「答えを出す → ずれを数にする → 直す」です。上のコードでは 1 回やった後にもう 1 回繰り返して、loss の変化と重みの変化を両方見ています。
実行すると、たとえばこう表示されます。数値はランダムな重みで初期化されるため、毎回変わります。
数値は毎回少し変わりますが、loss が小さくなっていれば学習が進んでいます。
どこがROCm?
学習では、推論の forward に加えて、backward()(逆向きの計算)と step()(重み更新)も GPU 側で動きます。モデルとデータを .to(device) で GPU に置いておけば、この3段階がすべて GPU 上で行われます。推論より仕事が多い分、GPU を使う恩恵が大きくなる場面です。
ここで出てきたPython
- 変数へ段階ごとの結果を順に入れていく
- loss.item() — 1 個の数として取り出す
zero_grad / backward / step の順番(クリックで開く)
学習の 1 サイクルは「zero_grad → backward → step」のセットです。zero_grad() を忘れると前の勾配が残り、backward() を 2 回呼ぶとエラーになります。最初はこの順番を 1 セットずつ繰り返す形で覚えるのが安全です。
よくあるつまずき
- optimizer.zero_grad() を忘れると、前の勾配が残って見え方が分かりにくくなります。
- 1 回の学習で全部よくなるとは限りません。ここでは流れをつかむのが目的です。
- loss は「ずれの大きさ」です。小さいほどよい、とまず考えれば大丈夫です。
- backward() を 2 回呼ぶとエラーになります。zero_grad → backward → step のセットを 1 回ずつ繰り返すのが基本です。
1分演習
上のコードで、学習の繰り返しを 5 回に増やしてみましょう。for i in range(5): で囲んで、毎回の loss を print します。回を重ねるごとに loss が下がっていくのを見届けてみてください。
ヒント: for i in range(5): は「5 回繰り返す」という意味です。繰り返したいコードは、その下にインデント(スペース 4 つ分の字下げ)して書きます。インデントがズレると Python はエラーになります。
for i in range(5):
optimizer.zero_grad()
pred = model(x)
loss = loss_fn(pred, y_true)
loss.backward()
optimizer.step()
print(f"ステップ {i+1} — loss:", loss.item())