stars長いコンテキストでの gpt-oss トレーニング

OpenAI gpt-oss トレーニング向けの Unsloth Flex Attention サポートを紹介できることを嬉しく思います。これにより 8倍以上の文脈長, VRAM 使用量を50%以上削減 および >1.5× 高速なトレーニング(精度低下なし) Flash Attention 3(FA3)を使用するものを含むすべての実装と比較して。Unsloth Flex Attention により、次が可能になります: 60K のコンテキスト長 BF16 LoRA の場合、80GB VRAM の H100 GPU 上で動作します。さらに:

  • あなたは 今すぐエクスポート/保存 あなたの QLoRA でファインチューニングした gpt-oss モデルを llama.cpp、vLLM、Ollama、または Hugging Face に

  • 我々は gpt-oss トレーニングの 損失が無限大に発散する問題を修正しました float16 GPU(T4 Colab のような)で

  • 我々は gpt-oss 実装の Unsloth には無関係な問題、最も顕著なのは swiglu_limit = 7.0 が transformers の MXFP4 推論中に適切に適用されることです

🦥Unsloth Flex Attention サポートのご紹介

Unsloth の Flex Attention サポートにより、単一の 80GB VRAM H100 で QLoRA なら最大 81K コンテキスト長、BF16 LoRA なら 60K コンテキストを扱うことができます!これらの利点は次に適用されます: 両方 gpt-oss-20b と gpt-oss-120b! 使用するコンテキスト長が長いほど、Unsloth Flex Attention から得られる利得は大きくなります:

比較すると、Unsloth 以外のすべての実装は 80GB GPU 上で最大 9K コンテキスト長に制限され、FA3 を使っても 15K コンテキストにしか到達できません。しかし、 FA3 は attention sinks の逆伝播をサポートしていないため gpt-oss トレーニングには不適切です。したがって、以前に gpt-oss トレーニングで FA3 を使用していた場合、私たちは 今は使用しないことを お勧めします。したがって、Unsloth を使わない場合に 80GB VRAM で得られる最大コンテキスト長は約 9K です。

Unsloth Flex Attention を使ったトレーニングは少なくとも 1.3× の高速化をもたらし、コンテキスト長が増えるほど利得は大きくなり、最大で 2× の高速化に達します。Flex Attention はコンテキストにスケールするため、シーケンスが長いほど VRAM とトレーニング時間の節約が大きくなります。詳しくは こちらに記載.

Rohan Pandey に深く感謝します(彼の) Flex Attention 実装arrow-up-rightは、Unsloth の Flex Attention 実装の開発に直接インスピレーションを与えました。

🕶️ Attention Sinks(アテンションシンク)

OpenAI の GPT OSS モデルは、 スライディングウィンドウアテンションとフルアテンションの交互パターンを使用します、スライディングウィンドウアテンション、という具合に(SWA、FA、SWA、FA、等)。各スライディングウィンドウは 128 トークン (現在のトークンを含む)だけに注目するため、計算量は大幅に削減されます。しかし、これによりスライディングウィンドウが小さいために長いコンテキストの検索や推論が無意味になるという問題も生じます。多くの研究所はこれを、スライディングウィンドウを 2048 または 4096 トークンに拡張することで解決しています。

OpenAI は次を活用しました: Attention Sinks(アテンションシンク) Efficient Streaming Language Models with Attention Sinks からの知見 🔓 Tiled MLP:500K+の解放arrow-up-right この論文は、小さなスライディングウィンドウを使うことができるが、最初のトークンにグローバルアテンションを追加する必要があることを示しています!論文は以下のような良い図を提供しています:

論文は次のことを発見しました: アテンション機構は最初の数トークン(1〜4)に多くの重みを割り当てるように見える、そしてスライディングウィンドウ操作中にそれらを削除してしまうと、これらの「重要な」最初の数トークンが消え、長いコンテキストの検索が悪化します。

もし対数パープレキシティ(値が高いほど悪い)をプロットし、事前学習モデルの設定されたコンテキスト長を超えて長いコンテキスト推論を行うと、パープレキシティが急上昇する(良くない)ことが分かります。しかし赤い線(Attention Sinks を使用)は低いままで、これは非常に良いことです!

論文はまた、 Attention Is Off By One メソッドarrow-up-right が部分的に機能することを示しています。ただし、より低いパープレキシティを得るにはいくつかの追加のシンクトークンを加える必要があります。 論文は、学習可能な単一のシンクトークンを追加することが非常にうまくいくことを示しています! そしてそれが OpenAI が GPT-OSS に対して行ったことです!

📐Unsloth の Flex Attention 実装は

Flex Attention https://pytorch.org/blog/flexattention/arrow-up-right 非常に強力で、実践者にアテンション機構をカスタマイズするための 2 つのルートを提供します: スコア修飾子(f)マスキング関数(M).

その スコア修飾子(f) これにより、ソフトマックス操作の前にアテンションのロジットを編集でき、 マスキング関数(M) (後者)は不要な操作をスキップすることを可能にします(例:スライディングウィンドウアテンションは最後の 128 トークンのみを見る)。

ポイントは、Flex Attention が任意のスコア修飾子とマスキング関数で高速な自動生成 Triton カーネルを提供することです!

σ(s×f(QKT+M))\sigma\bigg(s\times\bold{f}(QK^T+\bold{M})\bigg)

これは Flex Attention を使ってアテンションシンクを実装できることを意味します!単一のアテンションシンクの実装は、 OpenAI の元の GPT-OSS リポジトリ と HuggingFace の transformers 実装の両方で提供されています。

上記はシンクを Q @ K.T の末尾に連結し、ソフトマックスを行い、最後の列(シンクトークン)を取り除くことを示しています。

Flex Attention の Github リポジトリからのいくつかの可視化ユーティリティを使うことで、これを可視化できます。シーケンス長が 16、スライディングウィンドウが 5 と仮定します。左は最後のシンク列(デフォルト実装)、右はシンク位置をインデックス 0 に移動した場合(我々の実装)です。 Flex Attention の Github リポジトリarrow-up-rightを使うと可視化できます。

末尾にあるシンク位置(デフォルト)

シンク位置をインデックス 0 に移動

興味深い発見:公式の Flex Attention スライディングウィンドウ実装はウィンドウサイズを「最後のトークン数として」考慮します プラスワン (現在のトークンを含むため)。HuggingFace と GPT OSS の実装は厳密に最後の N トークンのみを見ます。つまり下記は https://pytorch.org/blog/flexattention/arrow-up-right および https://github.com/meta-pytorch/attention-gymarrow-up-right:

デフォルトの Flex Attention(3+1 トークン)

HuggingFace、GPT-OSS(3+0 トークン)

我々はまた、最後の N トークンに注目するのか N+1 トークンに注目するのかを確認するために OpenAI の公式 GPT-OSS 実装を通じて確認しました: https://github.com/openai/gpt-oss/blob/main/gpt_oss/torch/model.pyarrow-up-right

そして我々は、最後の 3 トークン(3+1 ではなく)が注目されていることを確認しました!これは次のように等号ではなく不等号を使うべきであることを意味します: <= SLIDING_WINDOWの場合は、を使用してください < SLIDING_WINDOW (つまり等号ではなく「より小さい」を使う)。

また、シンクトークンのインデックスを最初に移動したため、正しくインデックス付けするには q_idx に 1 を足す必要があります:

インデックス 0 の実装を確認するために、標準の Hugging Face の実行(Unsloth Flex Attention を使用しない)とトレーニング損失が一致することを我々のグラフで検証しました:

📜 アテンションシンクの数学的導出

K と V をパディングせずにアテンションシンクを計算する別の方法があります。まずソフトマックス操作が行うことに注意し、ここではスカラーとしてシンク付きの 2 番目のバージョンを求めます:\

A(x)=exp(xi)exp(xi)Asink(x)=exp(xi)exp(s)+exp(xi)A(x) = \frac{\exp(x_i)}{\sum{\exp{(x_i)}}} \\ A_{sink}(x) = \frac{\exp(x_i)}{\exp{(s)}+ \sum{\exp{(x_i)}}}

Flex Attention から logsumexp を取得できます: return_lse = True 、そして我々は次のようにします:

A(x)=exp(xi)exp(xi)exp(xi)exp(s)+exp(xi)=exp(xi)exp(xi)exp(xi)exp(s)+exp(xi)LSE(x)=logsumexp(x)=logexp(xi)exp(LSE(x))=exp(logexp(xi))=exp(xi)A(x) = \frac{\exp(x_i)}{\sum{\exp{(x_i)}}} \\ \frac{\exp(x_i)}{\exp{(s)}+ \sum{\exp{(x_i)}}} = \frac{\exp(x_i)}{\sum{\exp{(x_i)}}} \frac{\sum{\exp{(x_i)}}}{\exp{(s)}+ \sum{\exp{(x_i)}}} \\ \text{LSE}(x) = \text{logsumexp}(x) = \log{\sum\exp(x_i)} \\ \exp{(\text{LSE}(x))} = \exp{\big(\log{\sum\exp(x_i)}\big)} = \sum\exp(x_i)

これでアテンションのシンク版を容易に導出できます。ただしこの方法はゼロパディング方式よりも多少誤差が大きいため、我々は依然として元のバージョンをデフォルトとしています。

Unslothは現在gpt-ossのRLをサポートしています!我々は2つのノートブックを作成しました。詳細はgpt-oss RL用の特定のブログをご覧ください:💾

新機能:gpt-ossトレーニング後のGGUF、vLLMへの保存 llama.cpp, vLLM、または QLoRAでgpt-ossをファインチューニングした後、直接モデルを保存、エクスポート、またはマージして HF

以前は、QLoRA でファインチューニングした gpt-oss モデルは Unsloth 内でしか実行できませんでした。我々は次をマージする機能を導入することでその制限を取り除きました: を使用して ネイティブフォーマット を使用して で保存するか、ネイティブの および ファインチューニング済みモデルを保存するには、bf16 形式でエクスポートすることもできます、 (gpt-oss のような)ベースモデルをマージすることで、 次のコマンドを使って bf16 フォーマットでファインチューニング済みモデルをエクスポートできるようになりました: オンデマンドの MXFP4 の逆量子化 .

その を使用して MXFP4 Safetensors 形式でsave_method="mxfp4" GGUF を使って保存できます。

形式への変換をはるかに高速にします。 を使用して 新機能:QLoRA でファインチューニングしたモデルを GGUF に保存またはマージして他のフレームワーク(例:Hugging Face、llama.cpp の GGUF)で使用できるようになりました。

モデルをマージして Hugging Face Hub にプッシュしたい場合は、次を使用してください:

マージされたモデルで推論を実行するには、vLLM や Llama.cpp などを使用できます。OpenAI は次の 推論設定 を両モデルに対して推奨しています: temperature=1.0, top_p=1.0, top_k=0

モデルをマージして直接 Hugging Face ハブへプッシュすることを好む場合:

  1. 最新の llama.cppGitHub で入手arrow-up-rightできます。下のビルド手順に従うこともできます。変更してください -DGGML_CUDA=ON から -DGGML_CUDA=OFF GPU がない場合や CPU 推論のみを行いたい場合は。

  2. Llama.cpp への保存 を使用して cp llama.cpp/build/bin/llama-* llama.cp

  3. python3 llama.cpp/convert_hf_to_gguf.py gpt-oss-finetuned-merged/ --outfile gpt-oss-finetuned-mxfp4.gguf

chevron-right SGLang への保存hashtag
  1. ソースから SGLang をビルド:\

  2. SGLang サーバーを起動:\

  3. 推論を実行:\

♦️gpt-oss を直接ファインチューニングする

我々はまた、ネイティブな MXFP4 量子化フォーマットをロードできるようにするパッチを実装することで、gpt-oss モデルの直接ファインチューニングのサポートを追加しました。これにより 'openai/gpt-oss' モデルを 24GB 未満の VRAM でロードし、QLoRA でファインチューニングすることが可能になります。単に次を使ってモデルをロードしてください:

Peft レイヤーを追加するには次を使用します FastLanguageModel.get_peft_model そして Peft モデル上で SFT ファインチューニングを実行します。

🐛 gpt-oss のバグ修正

我々は 最近 Hugging Face と協力してarrow-up-right OpenAI のカーネルを使用し、MXFP4 推論中に次が正しく適用されるようにすることで推論問題を解決しました。 swiglu_limit = 7.0 が正しく適用されること。

ユーザーからのフィードバックに基づき、長時間の QLoRA トレーニング(60 ステップを超える)を行うと 損失が発散して最終的にエラーになることがあると判明しました。これは BF16 をサポートせず代わりに F16 にフォールバックするデバイス(例:T4 GPU)でのみ発生しました。重要なことに、これは A100 や H100 GPU 上の QLoRA トレーニングや f16 GPU 上の LoRA トレーニングには影響しませんでした。

徹底的な調査の後、我々は F16 に限定された GPU を含むすべての GPU 構成でトレーニング損失の挙動を揃えました。もし以前このために問題を経験していたなら、新しい更新された gpt-oss ノートブックの利用をお勧めします!

float16 のトレーニング損失曲線を bfloat16 マシン(青線)と同等にするために多くの実験を行いました。その結果、次のことが分かりました:

  1. 純粋な float16 は 50 ステップで無限大に発散する

  2. 我々は MoE のダウンプロジェクションに非常に大きな外れ値があることを発見しました

  3. アクティベーションは bfloat16 または float32 で保存する必要がある

下図は GPT OSS 20B の絶対値のアクティベーションを示しており、いくつかが大きくスパイクしています—float16 の最大範囲は 65504 なので float16 マシンではオーバーフローします。

我々はこれを Unsloth で修正したため、すべての float16 トレーニングはそのまま動作します!

🔢 Sink Attention(シンクアテンション)の実装

OpenAI のシンクトークン実装は ここで提供されていますarrow-up-right。以下に提供します:

HuggingFace transformers の実装は ここで提供されていますarrow-up-rightです。以下にも提供します:

最終更新

役に立ちましたか?