PyTorch ガイド: ディープラーニング モデルのトレーニングを高速化する 17 のヒント!

PyTorch ガイド: ディープラーニング モデルのトレーニングを高速化する 17 のヒント!

PyTorch でディープラーニング モデルをトレーニングする場合、モデルのトレーニングを高速化するにはどうすればよいでしょうか?

この記事では、最小限の変更で最大限の効果を発揮しながら、PyTorch のディープラーニング モデルを高速化する方法をいくつか紹介します。それぞれのアプローチについて、その背後にある考え方を簡単に説明し、改善率を推定し、その限界について説明します。重要だと思う部分を重点的に取り上げ、それぞれの部分でいくつか例を挙げてみます。次に、モデルのトレーニングに GPU を使用していると仮定します。これらの方法では、基本的に他のライブラリをインポートする必要はなく、pytorch の変更のみが必要です。

[[378697]]

推定される高速化に基づいて、さまざまな方法をランク付けすると次のようになります。

  1. 異なる学習率スケジュールの使用を検討する
  2. DataLoader で複数のワーカープロセスとページロックメモリを使用する
  3. バッチサイズの最大化
  4. 自動混合精度AMPの使用
  5. さまざまな最適化を検討する
  6. オープンcudNNベンチマーク
  7. CPUとGPU間のデータ転送には注意してください
  8. 勾配/活性化チェックポイントの使用
  9. 勾配累積の使用
  10. マルチGPU分散トレーニング
  11. グラデーションを0ではなくNoneに設定する
  12. .tensor() の代わりに .as_tensor() を使用する
  13. 必要なときのみデバッグモードを有効にする
  14. グラデーションクリッピングの使用
  15. BatchNorm の前にバイアスを無視する
  16. 検証中に勾配計算を無効にする
  17. 入力とバッチ処理の正規化

1. 異なる学習率スケジュールの使用を検討する

トレーニング中に使用される学習率スケジュールは、収束率とモデルの一般化能力に大きな影響を与える可能性があります。

Leslie N. Smith は巡回学習率法と 1 サイクル学習率法を提案し、その後 fast.ai の Jeremy Howard と Sylvain Gugger によって普及しました。一般的に、1Cycle 学習率法は次の図に示されます。

最良の場合、この戦略は従来の学習率スケジュールと比較して大幅な高速化を達成できます。スミス氏はこれを「スーパーコンバージェンス」と呼んでいます。たとえば、1Cycle 戦略を使用すると、ImageNet での ResNet-56 トレーニングの反復回数を 10 倍減らして、元の論文のパフォーマンスに一致させることができます。この戦略は、一般的なアーキテクチャとオプティマイザー全体でうまく機能するようです。

PyTorch は、こ​​の操作を実装するために torch.optim.lr_scheduler.CyclicLR と torch.optim.lr_scheduler.OneCycleLR の 2 つのメソッドを提供します。関連ドキュメントを参照してください。

どちらの方法にも欠点は、多くの追加のハイパーパラメータが導入されることです。この記事とリポジトリでは、適切なハイパーパラメータ(上記の学習率を含む)を見つける方法の詳細な概要と実装について説明します。

なぜこれが行われるのでしょうか? 現時点では完全には明らかではありませんが、考えられる説明の 1 つは、学習率を定期的に増加させることで、損失の鞍点をより早く通過できるようになるということです。

2. DataLoaderで複数のワーカープロセスとページロックメモリを使用する

torch.utils.data.DataLoader を使用する場合は、デフォルト値の 0 ではなく num_workers > 0 を設定し、デフォルト値の False ではなく pin_memory=True を設定します。なぜそうするのかについては、この記事で答えがわかります。

上記のアプローチに従って、Szymon Micacz は 4 つのワーカーとページロックされたメモリを使用して、1 つのエポックで 2 倍の高速化を達成しました。

経験則として、プロセス数は利用可能な GPU の数の 4 倍に設定します。この値より大きくまたは小さくすると、トレーニングが遅くなります。ただし、num_workers を増やすと CPU とメモリの消費量が増加することに注意してください。

3. バッチサイズを最大化する

バッチサイズを増やすかどうかについては、常に意見が分かれています。一般的に、バッチ サイズを大きくすると、GPU メモリが許せばトレーニング速度が向上しますが、学習率などの他のハイパーパラメータも調整する必要があります。経験則として、バッチ サイズが 2 倍になると、学習率もそれに応じて 2 倍になります。

OpenAI の論文では、バッチ サイズが異なると収束期間も異なることが示されています。 Daniel Huynh 氏は、さまざまなバッチ サイズ (上記の 1Cycle 戦略を使用) でいくつかの実験を行い、バッチ サイズを 64 から 512 に増やして 4 倍の高速化を達成しました。

ただし、バッチ サイズが大きくなるとモデルの一般化能力が低下し、その逆も同様であることに注意してください。

4. 自動混合精度AMPを使用する

PyTorch 1.6 はネイティブの自動混合精度トレーニングをサポートします。一部の操作では、精度を損なわずに、単精度 (FP32) よりも半精度 (FP16) を使用した方が高速になります。 AMP は、どの操作をどの精度で実行するかを自動的に決定できるため、トレーニングを高速化し、メモリ使用量を削減できます。

AMP の使用方法は次のとおりです。

  1. import torch# trainingscaler = torch.cuda.amp.GradScaler()始め一度作成します。for data, label in data_iter:
  2. オプティマイザ.zero_grad()
  3. # 演算を混合精度キャストする 
  4. torch.cuda.amp.autocast()を使用する場合:
  5. 損失 = モデル(データ)
  6. # 損失をスケールし backward() を呼び出します
  7.  スケールグラデーションを作成する
  8. スケーラー.スケール(損失).後方()
  9. # 勾配をスケール解除し呼び出します
  10. #またはoptimizer.step() をスキップします
  11. スケーラー.ステップ(オプティマイザー)
  12. # スケール更新します 次の反復
  13. スケーラー.更新()

Huang 氏とその同僚は、NVIDIA V100 GPU 上でいくつかの一般的な言語モデルとビジョン モデルのベンチマークを実施し、FP32 トレーニングで AMP を使用するとトレーニング速度が約 2 倍、最大 5.5 倍向上することを発見しました。

現在、上記の方法をサポートしているのは CUDA のみです。詳細については、このドキュメントを参照してください。

5. さまざまな最適化を検討する

AdamW は fast.ai によって提案された重み減衰 (L2 正則化ではない) を備えた Adam であり、torch.optim.AdamW を通じて PyTorch に実装されています。 AdamW はエラーとトレーニング時間の両方で Adam を上回ります。体重減少がアダムの働きを良くする理由については、この記事をご覧ください。

Adam と AdamW はどちらも、上記の 1Cycle 戦略に適しています。

さらに、LARS や LAMB などの他の最適化ツールも広く注目を集めています。

NVIDA の APEX は、Adam などの一般的なオプティマイザーを最適化して統合します。PyTorch のオリジナルの Adam と比較すると、GPU メモリ間の複数の転送が回避されるため、トレーニング速度が約 5% 向上します。

6. cudNNベンチマークを開く

モデル アーキテクチャが固定されており、入力サイズが一定である場合は、torch.backends.cudnn.benchmark = True に設定すると、モデルの速度が向上する可能性があります (ヘルプ ドキュメント)。 cudNN オートチューナーを有効にすると、cudNN で畳み込みを計算する複数の方法をベンチマークし、最も高速なものを選択できます。

高速化効果に関しては、Szymon Migacz は、前方畳み込みで速度を 70% 向上させ、前方および後方同時畳み込みで速度を 27% 向上させました。

上記の方法に従ってバッチ サイズを最大化する場合、この自動調整には非常に時間がかかる可能性があることに注意してください。

7. CPUとGPU間のデータ転送に注意してください

テンソルは、tensor.cpu() を介して GPU から CPU に転送でき、その逆の場合は tensor.cuda() を使用しますが、このようなデータ変換のコストは高くなります。 .item() と .numpy() の使用についても同様です。.detach() を使用することをお勧めします。

新しいテンソルを作成する場合は、キーワード引数 device=torch.device('cuda:0') を使用して、それを GPU に直接割り当てます。

データを転送するには .to(non_blocking=True) を使用するのが最適ですが、転送後に同期ポイントがないことを確認してください。

Santosh Gupta の SpeedTorch も試してみる価値がありますが、速度が上がるかどうかは完全には明らかではありません。

8. 勾配/活性化チェックポイントを使用する

チェックポイントは計算をメモリに保存することによって機能します。チェックポイントは、バックプロパゲーション アルゴリズムの実行中に計算グラフの中間アクティベーションを保存しませんが、バックプロパゲーション中に再計算され、モデルの任意の部分に使用できます。

具体的には、フォワードパスでは、関数は torch.no_grad() で実行され、中間アクティベーションは保存されません。代わりに、フォワード パスは入力タプルと関数の引数を保存します。バックプロパゲーション中、保存された入力と関数が取得され、関数を介して再度順方向に伝播され、中間アクティベーションが記録され、これらのアクティベーション値を使用して勾配が計算されます。

したがって、特定のバッチ サイズの場合、実行時間はわずかに長くなる可能性がありますが、メモリ消費量は大幅に削減されます。その結果、バッチ サイズをさらに増やすことができ、GPU をより有効に活用できるようになります。

チェックポイントは torch.utils.checkpoint を通じて簡単に実装できますが、そのアイデアと本質は依然として必要です。 Priya Goyal のチュートリアルでは、チェックポイントの重要な考え方のいくつかが明確に説明されており、一読することをお勧めします。

9. 勾配累積を使用する

バッチ サイズを増やす別の方法は、Optimizer.step() を呼び出す前に、複数の .backward() パスにわたって勾配を蓄積することです。

Hugging Face の Thomas Wolf が公開した記事によると、勾配累積は次のように実装できます。

  1. model.zero_grad() # 勾配テンソルをリセットしますfor i, (inputs, labels) in enumerate(training_set):
  2. predictions = model(inputs) #フォワードパス
  3. loss = loss_function(predictions, labels) # 損失関数を計算する     
  4. loss = loss / acceleration_steps # 損失を正規化します(平均化されている場合)
  5. loss.backward() # 後方パス
  6. if (i+1) % acceleration_steps == 0: #数ステップ後進するのを待つ
  7. optimizer.step() # これでオプティマイザのステップを実行できます
  8. model.zero_grad() # 勾配テンソルをリセットする
  9. if (i+1) % evaluation_steps == 0: # 次の場合にモデルを評価します...
  10. assess_model() # ...勾配は蓄積されていない

このアプローチは主に GPU メモリの制限を回避するためのものですが、他の .backward() ループとのトレードオフについてはよくわかりません。 fastai フォーラムでの議論では、実際にトレーニングがスピードアップする可能性があることが示されているため、試してみる価値があるかもしれません。詳細については、GitHub の rawgradient_accumulation.py を参照してください。

10. マルチGPU分散トレーニング

分散トレーニングでモデルを高速化する簡単な方法は、torch.nn.DataParallel の代わりに torch.nn.DistributedDataParallel を使用することです。この方法では、各 GPU は専用の CPU コアによって駆動されるため、DataParallel の GIL の問題を回避できます。

詳細については、分散トレーニング関連のドキュメントを読むことを強くお勧めします。

  1. PyTorch 分散概要 — PyTorch チュートリアル 1.7.0 ドキュメント

11. グラデーションを0ではなくNoneに設定する

.zero_grad() の代わりに .zero_grad(set_to_none=True) を設定します。

この方法では、メモリ アロケータは、勾配を積極的に 0 に設定するのではなく、勾配を処理します。これにより、ドキュメントに示されているように、適度な速度向上が得られるはずですが、あまり期待しないでください。

これには副作用がないことに注意してください。詳細についてはドキュメントをお読みください。

12. .tensor() の代わりに .as_tensor() を使用する

torch.tensor() は基本的にデータをコピーするので、numpy 配列を変換する場合は、データのコピーを避けるために torch.as_tensor() または torch.from_numpy() を使用します。

13. 必要なときだけデバッグモードを有効にする

Pytorch には、autograd.profiler、autograd.grad_check、autograd.anomaly_detection など、多くのデバッグ ツールが用意されています。これらのデバッグ ツールを使用するときは注意してください。これらは明らかにトレーニング速度に影響するため、必要がない場合はオフにしてください。

14. グラデーションクリッピングを使用する

RNN における勾配爆発を回避するために、勾配クリッピング gradient = min(gradient, threshold) を使用すると収束を加速することができ、これは理論と実験によって裏付けられています。

Hugging Face の Transformer は、グラデーション クリッピングを AMP などの他の方法と効果的に組み合わせる明確な例を示しています。

PyTorch では、torch.nn.utils.clip_grad_norm_ を使用してこれを行うこともできます (ドキュメントを参照)。

どのモデルが勾配クリッピングの恩恵を受けることができるかは完全にはわかりませんが、RNN、Transformer ベースのモデル、および ResNet のさまざまなオプティマイザーでは確実に機能するようです。

15. BatchNorm の前にバイアスを無視する

シンプルで効果的なアプローチは、BatchNormalization レイヤーの前のレイヤーのバイアスをオフにすることです。 2D 畳み込み層の場合、bias キーワードを False に設定することでこれを実現できます (つまり、torch.nn.Conv2d(...,bias=False,...))。これがどのように機能するかを理解するには、ドキュメントをお読みください。

他の方法と比較して、この方法は速度が向上します。

16. 検証中に勾配計算を無効にする

モデルの検証中にtorch.no_grad()を使用する

17. 入力とバッチ処理の正規化

すでに実行しているかもしれませんが、もう一度確認してください。

  • 入力は正規化されていますか?
  • バッチ処理を正規化しますか?

その他のヒント: ポイントごとの融合に JIT を使用する

隣接するポイント単位の操作を実行する場合は、PyTorch JIT を使用してそれらを FusionGroup に結合し、デフォルトの複数のコアではなく単一のコアで起動しながら、読み取りと書き込み用のメモリを節約できます。

Szymon Migacz は、次のように @torch.jit.script デコレータを使用して GELU 操作を融合する方法を示しています。

  1. @torch.jit.scriptdef fused_gelu(x): x * 0.5 * (1.0 + torch.erf(x / 1.41421))を返します

これらの操作を融合すると、fused_gelu は融合されていないバージョンよりも 5 倍高速に実行されます。

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式サイトにアクセスして許可を申請してください。

<<:  AIopsにおける人工知能

>>:  AIと機械学習でデータセンターを強化

ブログ    
ブログ    

推薦する

AI開発者の皆さん、こちらをお読みください: 主流のモバイルディープラーニングフレームワークの包括的なレビュー

PCと比較すると、モバイルデバイスは携帯性に優れており、普及率も高くなっています。近年、モバイルデバ...

美容業界に参入しよう! AIはフェイスリフト手術も可能

この記事は公開アカウント「Reading Core Technique」(ID: AI_Discov...

ビッグデータの本当の問題と、なぜ機械学習だけがそれを解決できるのか

多くの企業が、データの取得から洞察の獲得まで、スムーズに実行されるパイプラインの構築に依然として苦労...

機械学習を使用して画像キャプションを生成する

最近のディープ ニューラル ネットワークの開発以前は、業界で最も優秀な人材でもこの問題を解決できませ...

MOEA Framework 1.9は、MOEAアルゴリズムを開発するためのJavaクラスライブラリをリリースしました。

MOEA フレームワークは、多目的進化アルゴリズム (MOEA) を開発するための Java ライ...

...

世界をリセットし、すべてをつなげる5Gは人工知能にどんな機会と課題をもたらすのか

[[274397]] 5G時代は人工知能にどのような新たな機会をもたらすのでしょうか?人工知能と5G...

DeepMindが乳がん診断AIをリリース:市場に投入するにはまだ多くの課題がある

GoogleのDeepMindチームは最近、「乳がんスクリーニングAIシステムの国際評価」と題した論...

ガートナー、2024年以降のIT組織とユーザーに関する重要な予測を発表

ガートナーは、2024 年以降のトップ 10 の戦略予測を発表しました。ガートナーは、生成型人工知能...

Lingzhi Unuo CTO Xu Ke: AI技術が従来の保険販売モデルのジレンマを打破

[51CTO.comより] 徐克氏は百度で検索とスマートレコメンデーションの分野で長年勤務。2015...

ソフトウェア定義車の基礎 - FOTA および SOTA ソリューション

OTAとは何ですか? OTA(Over-the-Air Technology)は中国語でエアダウンロ...

4つの基本的なソートアルゴリズムのPHPコード実装

アルゴリズムはプログラムの核であり、アルゴリズムの品質がプログラムの品質を決定すると多くの人が言いま...

AI アバターが CES に登場! Samsung の Neon チャットボットは学習、進化、記憶が可能です!

サムスンの待望のスマートヒューマンプロジェクト「Neon」が、ついにCES 2020でデビューしまし...

18のAIリーディングカンパニー、大学、研究機関が共同で初のAIフレームワークエコシステムイニシアチブを発表

本日、上海で人工知能フレームワークエコシステムサミットが開催されました。サミットでは、MindSpo...

...