「Pytorch:LearningRate」の版間の差分
(→準備) |
(→解答例) |
||
| (同じ利用者による、間の4版が非表示) | |||
| 10行目: | 10行目: | ||
wget -P ./data -r https://vrl.sys.wakayama-u.ac.jp/class/pytorch_tutorial/datasets/cifar-10-batches-py/ | wget -P ./data -r https://vrl.sys.wakayama-u.ac.jp/class/pytorch_tutorial/datasets/cifar-10-batches-py/ | ||
ダウンロードしたら,exersise_learningrate.pyをそのまま実行してください.おそらく,テストデータに対する精度は80%くらいになったと思います. | |||
= 学習途中での学習率の変更 = | = 学習途中での学習率の変更 = | ||
DNNの学習においては,学習率が小さすぎると学習がなかなか進まず,一方で学習率を大きくすると,重みの更新も大雑把になり,なかなか収束してくれません.そこで,初期学習率を高く設定し,学習が進むにつれて徐々に落としていくのが一般的です.なお,具体的に学習率どの値にすればよいのかは,タスク,データセット,モデルアーキテクチャ,オプティマイザ,その他多くの要因が絡むので,一概には言えません. | DNNの学習においては,学習率が小さすぎると学習がなかなか進まず,一方で学習率を大きくすると,重みの更新も大雑把になり,なかなか収束してくれません.そこで,初期学習率を高く設定し,学習が進むにつれて徐々に落としていくのが一般的です.なお,具体的に学習率どの値にすればよいのかは,タスク,データセット,モデルアーキテクチャ,オプティマイザ,その他多くの要因が絡むので,一概には言えません. | ||
現在の学習率は | |||
learning_rate = 1e-1 | |||
となっており,学習中は完全に固定されています. | |||
Pytorchでは,オプティマイザ(SGDなど,学習対象の重みをアップデートする役割を持つ)を生成する際に,学習率(learning_rate)を指定します. | |||
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum, weight_decay=weight_decay) | |||
学習途中で学習率を変更する場合は,オプティマイザを再生成しても構いませんが(かつてはそのようにしていた),コードが煩雑になります.最近は,torch.optim に lr_scheduler なるものが実装されているので,これを用いて簡単に学習率のスケジューリングができます. | |||
では,実装してみましょう.以下のように書いてください.(細字は初めから書いてあるコード,太字は書き足すコード.) | |||
# モデル、損失関数、オプティマイザの設定 | |||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |||
model = models.resnet18() | |||
model.fc.__init__(512,10) | |||
model = model.to(device) | |||
criterion = nn.CrossEntropyLoss() | |||
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum, weight_decay=weight_decay) | |||
'''scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[num_epochs//2], gamma=0.1)''' | |||
ここで,optim.lr_scheduler.MultiStepLR はある決められたエポック数に達すると学習率を gamma 倍してくれる機能を実装したもので,引数の milestones は,何エポックで学習率を落とすか,をリストで指定するためのものです. | |||
この時点ではまだスケジューラを定義しただけであり,プログラムを実行しても結果は変わりません.スケジューラに仕事をさせるには,以下のように書いてください. | |||
# 学習ループ | |||
def train_model(): | |||
model.train() | |||
for epoch in range(num_epochs): | |||
total_loss = 0 | |||
for images, labels in train_loader: | |||
images, labels = images.to(device), labels.to(device) | |||
optimizer.zero_grad() | |||
outputs = model(images) | |||
loss = criterion(outputs, labels) | |||
loss.backward() | |||
optimizer.step() | |||
total_loss += loss.item() | |||
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss/len(train_loader):.4f}") | |||
'''scheduler.step()''' | |||
これで実装完了です.エポック数が予定の1/2を過ぎたあたりで loss の値がガクッと落ちていることが確認できると思います. | |||
=これも調べてみましょう= | |||
warmup | |||
= 解答例 = | |||
[//vrl.sys.wakayama-u.ac.jp/class/pytorch_tutorial/exersise_learningrate/exersise_learningrate_answer.py 解答例] | |||
2025年3月27日 (木) 04:39時点における最新版
学習率をスケジューリングする機能を扱う練習をします.
準備
まず,作業用ディレクトリに移動した後に,以下のコマンドを実行して,プログラムをダウンロードしてください.
wget https://vrl.sys.wakayama-u.ac.jp/class/pytorch_tutorial/exersise_learningrate/exersise_learningrate.py
データセットはCIFAR-10を用います.(他の演習でダウンロード済みの場合は,以下を実行しなくても構いません.ただし,データセットへのパスを適宜修正してください.)
wget -P ./data -r https://vrl.sys.wakayama-u.ac.jp/class/pytorch_tutorial/datasets/cifar-10-batches-py/
ダウンロードしたら,exersise_learningrate.pyをそのまま実行してください.おそらく,テストデータに対する精度は80%くらいになったと思います.
学習途中での学習率の変更
DNNの学習においては,学習率が小さすぎると学習がなかなか進まず,一方で学習率を大きくすると,重みの更新も大雑把になり,なかなか収束してくれません.そこで,初期学習率を高く設定し,学習が進むにつれて徐々に落としていくのが一般的です.なお,具体的に学習率どの値にすればよいのかは,タスク,データセット,モデルアーキテクチャ,オプティマイザ,その他多くの要因が絡むので,一概には言えません.
現在の学習率は
learning_rate = 1e-1
となっており,学習中は完全に固定されています.
Pytorchでは,オプティマイザ(SGDなど,学習対象の重みをアップデートする役割を持つ)を生成する際に,学習率(learning_rate)を指定します.
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum, weight_decay=weight_decay)
学習途中で学習率を変更する場合は,オプティマイザを再生成しても構いませんが(かつてはそのようにしていた),コードが煩雑になります.最近は,torch.optim に lr_scheduler なるものが実装されているので,これを用いて簡単に学習率のスケジューリングができます.
では,実装してみましょう.以下のように書いてください.(細字は初めから書いてあるコード,太字は書き足すコード.)
# モデル、損失関数、オプティマイザの設定
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = models.resnet18()
model.fc.__init__(512,10)
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum, weight_decay=weight_decay)
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[num_epochs//2], gamma=0.1)
ここで,optim.lr_scheduler.MultiStepLR はある決められたエポック数に達すると学習率を gamma 倍してくれる機能を実装したもので,引数の milestones は,何エポックで学習率を落とすか,をリストで指定するためのものです.
この時点ではまだスケジューラを定義しただけであり,プログラムを実行しても結果は変わりません.スケジューラに仕事をさせるには,以下のように書いてください.
# 学習ループ
def train_model():
model.train()
for epoch in range(num_epochs):
total_loss = 0
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss/len(train_loader):.4f}")
scheduler.step()
これで実装完了です.エポック数が予定の1/2を過ぎたあたりで loss の値がガクッと落ちていることが確認できると思います.
これも調べてみましょう
warmup