← Python and ROCm 教室へ戻る

第8章

学習してみたい

ここでは、答えを出すだけでなく「少し直す」までを 1 回だけ体験します。

今日は何をしたい?

学習では、まず答えを出し、そのずれを測り、そのずれを小さくする向きへ重みを少し動かします。この 1 回分を短いコードで見て、lossbackward()step() の役目をつかみます。

学習 1 回の流れは、この 4 ステップです。

pred = model(x) loss = loss_fn(pred, y_true) loss.backward() optimizer.step()
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 の変化と重みの変化を両方見ています。

実行すると、たとえばこう表示されます。数値はランダムな重みで初期化されるため、毎回変わります。

重み(学習前): 0.3127 loss(1回目): 2.8452 重み(学習後): 0.6502 loss(2回目): 1.8228

数値は毎回少し変わりますが、loss が小さくなっていれば学習が進んでいます。

1 回の学習で loss がほとんど変わらないこともあります。それは普通のことです。学習は「少しずつ直す」ものなので、1 回で完璧になることは期待しなくて大丈夫です。

どこがROCm?

学習では、推論の forward に加えて、backward()(逆向きの計算)と step()(重み更新)も GPU 側で動きます。モデルとデータを .to(device) で GPU に置いておけば、この3段階がすべて GPU 上で行われます。推論より仕事が多い分、GPU を使う恩恵が大きくなる場面です。

ここで出てきたPython

zero_grad / backward / step の順番(クリックで開く)

学習の 1 サイクルは「zero_grad → backward → step」のセットです。zero_grad() を忘れると前の勾配が残り、backward() を 2 回呼ぶとエラーになります。最初はこの順番を 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())