ホームページ  >  記事  >  テクノロジー周辺機器  >  限られた GPU リソースで非常に大規模なモデルを微調整する方法

限られた GPU リソースで非常に大規模なモデルを微調整する方法

WBOY
WBOY転載
2023-04-13 08:10:071503ブラウズ

限られた GPU リソースで非常に大規模なモデルを微調整する方法

質問: モデルのサイズが GPU の容量を超えた場合はどうすればよいですか?

#この記事は、Yandex Data Analysis Institute が教えている「効率的なディープ ラーニング システム」コースからインスピレーションを得ています。

予備知識: 読者は前方パスと後方パスの動作原理をすでに理解していることを前提としています。これは、この記事の内容を理解する上で非常に重要です。この記事では、フレームワークとして PyTorch を使用します。 ###############はじめましょう!

5 億を超えるパラメーターを持つ大規模なモデル (別名 gpt-2-xl) を使用しようとして、GPU リソースが制限されているため変換できない場合、どうすればよいですか? GPU 上で実行するためにインストールされている場合、またはモデルのトレーニング中に論文で定義されているバッチ サイズを達成できない場合は?おそらく、諦めてモデルの軽量バージョンを使用するか、トレーニング バッチ サイズを減らして、論文に記載されているトレーニング結果が得られないようにすることができます。

#ただし、上記の問題の解決に役立つテクニックがいくつかあります。

# 15 億のパラメーターを使用して GPT-2-XL モデルを微調整する方法についていくつかの方法を説明します。

問題の核心

まず、モデルをロードするために必要な GPU メモリの問題を理解しましょう。 GPUの実体。

モデルに FP32 (32 ビット浮動小数点) パラメーターがあると仮定すると、このモデルは、Adam オプティマイザーを実行するなど、GPU でトレーニングする必要があります。 。

#計算してみると、衝撃的な結果が得られました。

すでに 12 GB の容量を備えた NVIDIA コンピュータがあると仮定します。メモリはGeForce RTX 3060。まず、1e9 FP32 パラメータは約 4 GB の GPU メモリを占有します。 限られた GPU リソースで非常に大規模なモデルを微調整する方法

#同様に、同じ量のメモリがグラデーション用に予約されます。したがって、合計 8 GB のメモリが確保されていますが、まだトレーニングが開始されておらず、オプティマイザがロードされていないため、オプティマイザのロードにもある程度のメモリが必要です。 Adam オプティマイザーはパラメータごとに 1 回目と 2 回目のバックアップを保存する必要があり、これには 8 GB の追加メモリが必要です。これを計算すると、モデルを GPU に正しくロードするには、約 16 GB の GPU メモリが必要になります。この例では、GPU の空きメモリは 12 GB のみです。見た目が悪いですよね?

# ただし、この問題を解決するにはいくつかの方法があります。関連するものは次のとおりです。

勾配累積/マイクロバッチング;

  • 勾配チェックポイント;
  • ##モデルの並列トレーニング;
  • #パイプライン ジョブ;
  • Tensor の並列化
  • 混合精度トレーニング;
  • #メモリ オフロード;
  • # オプティマイザーの 8 ビット量子化。
  • #次に、これらの技術について詳しく説明します。 ###############始める###############

    質問: モデルが GPU の容量より大きい場合はどうすればよいですか?

    • #シンプル モード: バッチ サイズ 1 を調整できません
    • プロフェッショナル モード: パラメータは調整できません

    概要

    # #モデルがGPUの容量より大きい場合、バッチサイズを1に設定しても不十分ですが、どうすればよいですか?解決策として、勾配チェックポイントを設定するという概念があります。この概念を見てみましょう。 n 層を含む単純なフィードフォワード ニューラル ネットワークの場合、勾配計算図は次のとおりです。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    ##ニューラル ネットワーク層のアクティブ化は f でマークされたノードに対応し、順方向パス中にこれらすべてのノードが順番に計算されます。これらの層の活性化およびパラメータに対応する損失勾配は、b とラベル付けされたノードによって表されます。逆方向パスでは、これらすべてのノードが逆の順序で評価されます。 f ノードの計算結果は b ノードの計算に使用されるため、すべての f ノードはパスフォワード後にメモリに保持されます。バックプロパゲーションがノード f のすべての依存関係を計算できるほど進行した場合にのみ、ノード f をメモリから消去できます。これは、単純なバックプロパゲーションに必要なメモリがニューラル ネットワーク層の数 n に応じて線形に増加することを意味します。

    これらのノードの計算順序は次のとおりです。紫色の影付きの円は、特定の時点でどのノードをメモリに保存する必要があるかを示します。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    グラデーション チェックポイント

    # 上で説明した単純な逆伝播は計算的に最適です。各ノードを 1 回だけ計算します。ただし、ノードを再計算すると、メモリを大量に節約できる可能性があります。たとえば、各ノードは簡単に再計算できます。実行順序と使用メモリは次の図に示すとおりです。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法#この戦略はメモリの観点から最適です。ただし、ノード計算の数は、以前のスケーリング係数 n と比較して n² 倍にスケーリングされることに注意してください。各 n ノードは、順番に n 回再計算されます。計算速度が遅いため、この方法は深層学習には適していません。

    メモリと計算のバランスをとるには、ノードの再計算を頻繁に行わないようにする戦略を提案する必要があります。ここで使用される戦略は、ニューラル ネットワーク活性化のサブセットをチェックポイント ノードとしてマークすることです。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法この例では、sqrt(n) 番目のノードをチェックポイントとしてマークすることを選択します。このように、チェックポイント ノードの数とチェックポイント間のノードの数は sqrt(n) の間にあります。これは、必要なメモリ量も n のオーダーで増加することを意味します。この戦略で必要な追加の計算は、ネットワークを介した 1 回の順方向パスで必要な計算と同等です。

    ルーチン:

    グラデーション チェックポイントの詳細を学習したら、次の方法を参照してください。この概念を PyTorch に適用すると、それほど難しくないようです:

    勾配累積/マイクロバッチ処理

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    ##概要

    # ディープ ラーニング モデルはますます大規模になっており、そのような大規模なニューラル ネットワークを GPU メモリにインストールするのは困難です。したがって、トレーニング中により小さいバッチ サイズを選択する必要があり、これにより収束が遅くなり、精度が低下する可能性があります。

    勾配累積とは何ですか?

    ニューラル ネットワークをトレーニングする場合、通常、データはバッチに分割され、ニューラル ネットワークは実際のターゲットに対する損失を計算するために使用されるバッチ ラベルを予測します。 。次に、逆方向パスを実行して勾配を計算し、モデルの重みを更新します。勾配の累積により、トレーニング プロセスの最後のステップが変更されます。次のミニバッチに進む前に、各ミニバッチのネットワークの重みを更新するのではなく、勾配値を保存し、以前に保存した勾配に新しい勾配を追加します。重みは、モデルがいくつかのミニバッチを処理した後にのみ更新されます。勾配累積は、より大きなバッチ サイズをシミュレートします。小さなバッチで 64 枚の画像を使用する場合、バッチ サイズが 8 を超えると、「CUDA メモリ エラー...」が報告されます。この場合、8 バッチの画像を使用し、モデルが 64/8 = 8 バッチを処理した後に重みを 1 回更新できます。この 8 つのバッチの各勾配を累積すると、結果は (ほぼ) 同じになり、トレーニングが実行できます。

    ルーチン:

    勾配累積を行わない標準トレーニング ループは通常、次のようになります。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    PyTorch では、勾配の累積を簡単に行うことができます。モデルがaccumulation_stepsを使用したミニバッチ処理を完了した後、最適化を実行できます。また、accumulation_steps を使用して、損失関数の性質に従ってランニング損失を分割することもできます。

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    実に美しいですね。 ? loss.backward() が呼び出されたときに勾配が計算され、optimizer.zero_grad() が呼び出されて停止されるまで PyTorch によって累積されます。

    重要なポイント

    一部のネットワーク アーキテクチャでは、BatchNorm などの専用のバッチ操作を使用します。同じバッチサイズを使用すると、結果が若干異なる場合があります。

    混合精度トレーニング

    概要

    混合精度トレーニングとは、一部またはすべての FP32 パラメーターを FP16、TF16 (浮動小数点テンソル)、または BF16 (浮動小数点バイト) などの小さな形式に変換することを指します。

    主な利点

    混合精度トレーニングの主な利点は次のとおりです。

      ##メモリ使用量の削減;
    • パフォーマンスの向上 (演算強度の向上または通信使用量の削減) );
    • #計算を高速化するには、専用のハードウェアを使用します。
    現時点では、最初の利点であるメモリ使用量の削減のみに興味があります。PyTorch モデルを使用してそれを達成する方法を見てみましょう。 ##################ルーティーン: ################# ########### #

    その結果、.half() 操作の完了後、モデルは 2 分の 1 に小さくなりました。モデルを別の形式 (つまり、BF16、TF16) に変換した後のスケーリング損失については、次の記事で説明します。 Softmax など、一部の操作は FP16 では完了できません。 PyTorch は torch.autocast を使用して、これらの特殊なケースを処理できます。

    8 ビット オプティマイザー

    モデル サイズを増やすことは、パフォーマンスを向上させる効果的な方法です。ただし、大規模なモデルをトレーニングするには、モデル、勾配、オプティマイザーの状態 (アダムの指数平滑和や以前の勾配の二乗和など) を保存する必要があり、これらはすべて限られた量の利用可能なメモリに保存されます。

    32 ビット オプティマイザーを 8 ビット オプティマイザーにダウングレードし、値の範囲を 23² から 2⁸=256 のみに減らします。これは、最適化はオプティマイザによって予約されており、メモリの量によって大きな違いが生じます。

    研究者らは新しい 8 ビット Adam オプティマイザーを提案し、論文の著者は記事の中で次のように述べています。記憶の中のオリジナル」。

    8 ビット オプティマイザーには 3 つのコンポーネントがあります: (1) 外れ値を分離し、エラーを各ビットに均等に分散するブロック レベルの量子化、(2) )小さな値と大きな値を高精度で定量化する動的量子化; (3) 単語埋め込み最適化モデルの安定性を向上させる安定した埋め込み層。

    #これらのコンポーネントを使用すると、8 ビット状態を使用して最適化を直接実行できます。 8 ビット オプティマイザーの状態を 32 ビットに量子化し、更新を実行してから、状態を 8 ビットに量子化して保存します。 8 ビットから 32 ビットへの変換は、量子化と逆量子化を実行するために GPU メモリへの低速コピーや追加の一時メモリを必要とせずに、レジスタ内で要素ごとに実行されます。 GPU の場合、これは 8 ビット オプティマイザーが通常の 32 ビット オプティマイザーよりも高速であることを意味します。

    8 ビット Adam を使用した後の感動的な結果を見てみましょう:

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    ご覧のとおり、量子化された Adam を使用すると、約 8.5 GB の GPU メモリが節約されます。これは非常に素晴らしいことです。

    #使いやすさを理解した後、Python で実装する方法を見てみましょう。

    Facebook が提供する Bitsandbytes パッケージは、CUDA カスタム関数の軽量ラッパーであり、8 ビット オプティマイザーと量子化関数をカプセル化し、それを使用します。ビットアダムは実現できます。 ##################ルーティーン: ################# ########### ## ##上で述べたように、量子化オプティマイザーの使用は非常に簡単で、結果は良好です。

    上記のすべての方法に基づいて、GPU 上で GPT-2-XL を微調整します。

    最後に、上記の方法をマスターした後、これらの方法を使用して実際的な問題を解決し、15 億のパラメーターを使用して GPT-2-XL モデルを微調整します。どうやら、12 GB の RAM を搭載した NVIDIA GeForce RTX 3060 GPU にロードする方法はないようです。使用できるすべてのメソッドをリストします: 限られた GPU リソースで非常に大規模なモデルを微調整する方法

    • 勾配チェックポイント;
    • 混合精度トレーニング (トリックを設定しました: 同じモデル サンプルを 2 つ使用します)まず、.half を使用して GPU にロードし、gpu_model という名前を付けます。次に、CPU に cpu_model という名前を付けます。GPU モデルを評価した後、gpu_model の勾配を cpu_model にロードし、オプティマイザを実行します。step()、パラメータを gpu_model に更新);
    • batch_size=64、minibatch_size=4 の勾配累積を使用します。これは、accumulation_steps によってスケールする必要があります。 Loss;
    • 8 ビット Adam オプティマイザー。

    上記のすべての方法を使用して、コードを確認してください:

    限られた GPU リソースで非常に大規模なモデルを微調整する方法

    上記のすべての方法を使用した後、GPU 上で 16GB GPT-2-XL モデルの微調整が実現したことがわかりました。これは驚くべきことです。

    結論

    このブログでは、メモリを効率的に使用するための重要な概念を説明します。上で述べたように、難しい作業です。他の概念については、以降の記事で説明します。この記事をお読みいただき、誠にありがとうございます!

以上が限られた GPU リソースで非常に大規模なモデルを微調整する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。