質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.08%

Pytorchで大きいepochで学習するとlossとaccが急激に変化する

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 486

Doggo

score 12

前提・実現したいこと

Python 3.7.4
Pytorch 1.4.0

発生している問題・エラーメッセージ

Pytorchで重み学習済みVGG16モデルのfine-tuningを行っているのですが、200epoch学習させたら以下の画像ように
80epochあたりで急激にlossが増加し、accが低下しました。どのような原因が考えられるでしょうか?
model loss
model acc

該当のソースコード

 # VGG-16モデルのインスタンスを生成
use_pretrained = True  # 学習済みのパラメータを使用
net = models.vgg16(pretrained=use_pretrained)
# 1000クラス → 10クラスに変更
net.classifier[6] = nn.Linear(in_features=4096, out_features=10, bias=True)


def do_train(net, dataloader_dict, criterion, optimizer, num_epochs):

    # 初期設定
    #学習中の指標を保存するリストを作成
    #1epochのtrainに一応値を入れておく
    train_acc_list = [0.]
    train_loss_list = [0.]
    val_acc_list = []
    val_loss_list = []

    # GPUが使えるかを確認
    device = "cuda" if torch.cuda.is_available() else "cpu"
    print("使用デバイス:", device)

    # ネットワークをGPUへ
    net = net.to(device)
    if device == 'cuda':
        net = torch.nn.DataParallel(net) # make parallel

        # ネットワークがある程度固定であれば、高速化させる
        torch.backends.cudnn.benchmark = True

    # epochのループ
    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch+1, num_epochs))
        print('-------------')

        # epochごとの訓練と検証のループ
        for phase in ['train', 'val']:
            if phase == 'train':
                net.train()  # モデルを訓練モードに
            else:
                net.eval()   # モデルを検証モードに

            epoch_loss = 0.0  # epochの損失和
            epoch_corrects = 0  # epochの正解数

            # 未学習時の検証性能を確かめるため、epoch=0の訓練は省略
            if (epoch == 0) and (phase == 'train'):
                continue

            # データローダーからミニバッチを取り出すループ
            for inputs, labels in tqdm(dataloader_dict[phase]):

                # GPUが使えるならGPUにデータを送る
                inputs = inputs.to(device)
                labels = labels.to(device)

                # optimizerを初期化
                optimizer.zero_grad()


                # 順伝搬(forward)計算
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = net(inputs)
                    loss = criterion(outputs, labels)  # 損失を計算
                    _, preds = torch.max(outputs, 1)  # ラベルを予測

                    # 訓練時はバックプロパゲーション
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                    # 結果の計算
                    epoch_loss += loss.item() * inputs.size(0)  # lossの合計を更新
                    # 正解数の合計を更新
                    epoch_corrects += torch.sum(preds == labels.data)

            # epochごとのlossと正解率を表示
            epoch_loss = epoch_loss / len(dataloader_dict[phase].dataset)
            epoch_acc = epoch_corrects.double(
            ) / len(dataloader_dict[phase].dataset)

            #listにlossとaccを保存
            if phase == "train":
                train_acc_list.append(epoch_acc)
                train_loss_list.append(epoch_loss)
            else:
                val_acc_list.append(epoch_acc)
                val_loss_list.append(epoch_loss)

            print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))

    # PyTorchのネットワークパラメータの保存
    save_path = os.path.join(os.getcwd(), "final_weight.pth")
    torch.save(net, save_path)

    #dictで返す
    history = {'acc': train_acc_list,
               'loss': train_loss_list,
               'val_acc': val_acc_list,
               'val_loss': val_loss_list}
    return history

optimizer = optim.Adam(net.parameters())
criterion = nn.CrossEntropyLoss()

num_epochs = 200
hist = do_train(net, dataloader_dict, criterion, optimizer, num_epochs)

試したこと

環境によって起きたエラーかと思ったのでGoogle Colaboratory上でも実行してみましたが同様の結果が得られたので、コードに問題があると思っています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

原因は、optimizersにAdamを使用しているためです。長期間で訓練すると、損失が劇的に増えることが知られています。

これは、Adamのパラメータのデフォルト値などが引き起こしている原因です。詳しくはこちらを参考にしてください。対策としてはAdamのepsilonの値を変更するか、より安定したAMSGradを使用することだと思います。

参考資料)

https://stackoverflow.com/questions/52220242/why-does-the-loss-of-a-cnn-decrease-for-a-long-time-and-then-suddenly-increase

https://discuss.pytorch.org/t/loss-suddenly-increases-using-adam-optimizer/11338/3

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.08%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る