「Pytorch:LearningRate」の版間の差分

提供:classwiki
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の3版が非表示)
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_classimbalance.pyをそのまま実行してください.おそらく,テストデータに対する精度は80%くらいになったと思います.
ダウンロードしたら,exersise_learningrate.pyをそのまま実行してください.おそらく,テストデータに対する精度は80%くらいになったと思います.


= 学習途中での学習率の変更 =
= 学習途中での学習率の変更 =
18行目: 18行目:
現在の学習率は
現在の学習率は
  learning_rate = 1e-1
  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

解答例

解答例