PyTorchでモデルを学習させ、いざ評価フェーズに入ると、たまに精度が不安定になったり、期待した結果が出なかったりすることがある。特に、ドロップアウトやバッチ正規化を使っているモデルでは、この現象が顕著だ。本番環境へのデプロイを控えていると、この挙動の違いは非常に厄介な問題になる。
何が起きたか(課題)
モデルがトレーニングモードのまま推論に使われていると、以下のような問題が発生する。
- 推論結果がバッチごとに変動し、再現性がなくなる。
- BatchNorm層がミニバッチの統計情報を使ってしまい、学習済みの正規化状態が維持されない。
- ドロップアウト層が意図せずニューロンをランダムに無効化し、予測精度が低下する。
どう解決したか(概要)
この不安定性を解消するため、推論時には以下の2つの操作をセットで実行するのが鉄則だった。
-
model.eval(): モデルを評価モードに切り替える。これにより、ドロップアウトが無効になり、BatchNorm層の統計情報が固定される。 -
with torch.no_grad(): 勾配計算を停止する。これによりメモリ消費が抑えられ、推論速度が向上する。
具体的な実行コードは、この2つを組み合わせた以下の形式になる。
model.eval()
with torch.no_grad():
outputs = model(inputs)
model.eval() が特に重要なのは、Dropout 層と BatchNorm 層の動作を制御するためだ。トレーニング中はオーバーフィッティングを防ぐためにランダムな要素が導入されるが、評価時にはこれが安定性を損なう。model.eval() を呼ぶことで、ドロップアウトは完全に無効化され、BatchNorm層は学習中に蓄積された移動平均と分散を固定値として使用するようになる。この切り替えがないと、バッチ間の統計情報が変動し、出力が一貫しなくなる。
また、torch.no_grad() の併用は、推論フェーズでは不要な勾配計算をスキップさせることで、メモリ効率を劇的に改善し、計算速度を向上させる効果がある。
効果(Before/After)
この定型コードを導入した結果、評価フェーズでの出力の安定性が完全に保証された。特にBatchNorm層の影響が大きいデータセットでは、精度のばらつきがほぼゼロになった。メモリ使用量も大幅に削減できたため、大規模なテストデータセットの処理も高速化できた。
🚀 詳細な設定とコードはこちら
具体的なWAFのルール設定や、より詳細なログ解析データは元のブログで公開しています。