エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

NVFP4: 4ビットの浮動小数点でLLMを学習する仕組み

こんにちは、AI・機械学習チームの髙橋です。

この記事はエムスリー Advent Calendar 2025 22日目の記事です。前日は同じAI・機械学習チームの鴨田さんによる LLMによって非定形の会話ログを価値あるFAQデータにする話 - エムスリーテックブログでした。

迎賓館赤坂離宮の噴水: 並列処理で射出された水が中央で集約される様子はまるでGPU上の行列演算のよう?

ChatGPTが発表された2022年11月30日から3年が経過し、それからというものLLMの話を聞かない日はない世界になりました。 今日ではCoding Agent無しでは生きていけない、という読者も多いのではないでしょうか。私もそのうちのひとりです。

さて、ベンチマークや実用上のパフォーマンスといった面では、日進月歩凄まじい進展を見せているLLMですが、その能力のコアにあたる部分は3年経っても驚くほど変わっていません。

すなわち、

膨大なパラメータのTransformerモデルを膨大なトークンで事前学習させる

ことです。

「膨大」という言葉が重複しましたが、この事前学習にはまさに途方もない演算を処理する必要があります。 例えば1T級のモデルを学習するにはおおまかに10の25~26乗 FLOPs 程度の演算量が必要になります。

B200のカタログスペック (1枚あたり2.5PFLOPs、10の15乗)であっても、100日(8.64×10の6乗秒)で学習をするにはざっくり500~5000枚程度が必要になる計算です。

この途方もない演算を行うべく、数十兆円とも言われるデータセンター投資が行われているわけですが、もし同じGPUの計算量を4倍にできたとしたら数十兆円のコストを1/4にできるわけですから、とんでもないROIになります。

今回はそんな可能性を秘めた4ビット浮動小数点、NVFP4について解説していこうと思います。

数値精度と演算処理速度

先の導入は少し盛り気味でしたが、今回はLLMを低精度の浮動小数点を利用して学習するときにどのように量子化が行われているかをみていきます。

前置きとして、まずGPUの演算性能が入力の数値精度によってどのように変化していくかみていきましょう。

V100~B200までのGPU1枚あたりの性能(TFLOPs単位、Dense)をまとめたものが以下になります。*1

世代 GPU名 最大消費電力 FP16性能 FP8性能 FP4性能
Volta V100 300W 125 N/A N/A
Ampere A100 400W 312 N/A N/A
Hopper H100 700W 989 1,979 N/A
Blackwell B200 1,200W 2,500 5,000 10,000

下二行のH100とB200の性能を見れば分かる通り、数値精度が半分になれば計算処理速度が倍になる逆比例の関係があります。

つまり、学習で使用する浮動小数点の精度を下げることができれば、 具体的にはFP16で行っていたものをFP4で同じようにできれば、 同じGPUを使って計算量を4倍に増やすことが出来ます。

一般にニューラルネットワークの学習において数値精度はそれほど高くなくてよい、FP16/BF16であればFP32とほとんどの場合で学習時に差がないことが知られています。

とはいえFP4ともなると表せる値は16通りしかなく、ナイーブに適用すればよいという話ではなくなります。

ではどのような工夫が施され、NVIDIA GPUの現行最新アーキテクチャBlackwellで導入されたNVFP4にまで至ったのかステップバイステップでみていきます。

Step 1: FP4 with Scaling

まずは実際にFP4 (E2M1, 指数部2 仮数部1)で表現できる数値を全通り書き下してみましょう。

10進数 2進数 (S E M) 10進数 2進数 (S E M)
0.0 0 00 0 -0.0 1 00 0
0.5 0 00 1 -0.5 1 00 1
1.0 0 01 0 -1.0 1 01 0
1.5 0 01 1 -1.5 1 01 1
2.0 0 10 0 -2.0 1 10 0
3.0 0 10 1 -3.0 1 10 1
4.0 0 11 0 -4.0 1 11 0
6.0 0 11 1 -6.0 1 11 1

通常の32ビット浮動小数点で表現されている行列をそのままFP4に変換して行列演算をすると、想像に難くないですが、誤差が大きすぎて使いものになりません。特に、ニューラルネットワークのパラメータは多くの場合0を中心に分布するため、+0.1や-0.23といった値はすべて0にキャストされてしまいます。

そこで、一歩目の工夫として、量子化したい数値をFP4の最大値(:=6)にスケールしてから量子化を適用し、実際の値を利用したいときは逆スケールするという方法が考えられます。

実際に[0.1, 0.3, 1.0]という3つの実数は次の手順によってFP4で表現できます。

ステップ 値 (ベクトル) データ型 解説
入力 [0.1,0.3,1.0] FP32 元の数値列
スケール [0.6,1.8,6.0] FP32 FP4の最大値に合わせて拡大 (×6)
量子化 [0.5,2.0,6.0] FP4 一番近いFP4の値に丸める
復元 [0.08,0.33, 1.0] FP32 スケールの逆数を掛ける

すなわち 6 × [0.5, 2.0, 6.0] のように、スケーリング定数 × FP4の数値列として情報を持っておくことで狭い表現幅を最大限に活用できる、というわけです。

ニューラルネットワークでの問題

しかし、ニューラルネットワークの学習・推論時ではこの愚直な手法では実用的ではないことが分かっています。 というのも、ニューラルネットワークのパラメータやアクティベーションは非常に大きな値を取ることがあり、モデルが大規模化すればするほどその傾向が強くなるためです。*2

さきほどの例で最大の値を1.0から100.0にして同様に適用すると以下のようになります。

ステップ 値 (ベクトル) データ型 解説
入力 [0.1,0.3,100.0] FP32 元の数値列
スケール [0.006,0.018,6.0] FP32 スケーリング定数は6/100
量子化 [0.0,0.0,6.0] FP4 一番近いFP4の値に丸める
復元 [0.0,0.0,100.0] FP32 0.1と0.3が0になってしまう

0.1と0.3が0.0になってしまい適切に量子化できないことがわかります。

Step 2: Block-wise Scaling

この問題を解消するために出てきたのが、Block-wise Scalingという手法です。*3

アイデアはシンプルで、対象とする数値列をブロックに分割しそれぞれのブロックごとにスケーリング定数を計算します。 こうすることで、例え極めて大きい値が1つあったとしても、それによって適切に表現できない要素はそのブロック内だけですむようになります。

なぜBlock-wiseであればうまくいくか

ブロック内のゼロに近い数値が量子化によって「0」になってしまっても、なぜ大きな問題にはならないのでしょうか。

このメカニズムはDettmersら LLM.int8()で議論されています。 Dettmersらによれば、LLMの演算結果においては絶対値の大きな値(外れ値)が支配的な役割を果たしているといいます。つまり、計算結果への寄与度が大きい「大きな値」さえ正確に表現できていれば、最終的なモデルの性能は大きく変わらないのです。

そのため、Block-wise Scalingによって大きな値のダイナミックレンジを確保することはニューラルネットワークへの応用を想定したときには理にかなっており、その副作用として微小な値が0に丸められたとしても、全体の結果に対する影響は極めて限定的だと言えます。

Step 3: NVFP4

Step 2のブロック単位スケーリングをさらに推し進め、Blackwellアーキテクチャで採用されたのがNVFP4です。

NVFP4の最大の特徴は2段階のスケーリングを採用していることです。

具体的には、テンソル全体に対する基準となるTensor-level scaling (FP32)に加え、16要素のブロックごとに微調整を行うBlock-level scaling (FP8)を組み合わせる構成になっています。 ブロックごとのスケールをFP32ではなくFP8に量子化して持つことで、メタデータのメモリオーバーヘッドを極限まで削減しているのが特徴です。

実数値への復元は、以下の3つの積によって行われます。

tensor-level定数(FP32) × block-level定数(FP8) × 数値(FP4)

シミュレーションしてみる

NVFP4のアイデア自体で本当にうまくいくのか、簡単なシミュレーションコードをclaude codeと一緒に用意しました。

github.com

今回は次の3つの手法で行列積を手元のMacBookでシミュレーション(行列サイズ (128, 128), 正規分布の平均0 標準偏差0.1)で行いました。*4

  1. 直接FP4に変換した場合
  2. 1つのスケーリング定数を利用して量子化した場合
  3. NVFP4の手法で量子化した場合
手法 平均誤差 (Mean Error) 相対誤差 (Rel Error) 改善率 (vs Naive)
直接FP4に変換 0.0903 100.00% 1.00x
1つのスケーリング定数 0.0173 19.20% 5.21x
NVFP4 0.0147 16.21% 6.17x

たしかに、NVFP4のようにブロックごとにスケーリング定数を用意してあげることで、より正確な行列演算ができることが確認できました。

終わりに

NVFP4で実際に事前学習を試みた事例が2025年下半期に入ってから報告され始めています。

現時点では1T級のモデルの学習でFP4を採用したという報告は無いですが、そう遠くないうちに4ビットネイティブな事前学習が実現され、モデルの更なる大規模化が達成されるかもしれません。

最後に宣伝になりますが、過去にもLLMの演算効率や言語モデルの歴史的経緯について書いているので、ぜひ読んでみていただけると嬉しいです。

www.m3tech.blog

www.m3tech.blog

We are hiring!

AI チームでは、LLMや機械学習に造詣が深いエンジニアを募集しています。 ご気軽にカジュアル面談からでも応募をお待ちしております!

エンジニア採用ページはこちら

jobs.m3.com

カジュアル面談もお気軽にどうぞ

jobs.m3.com

インターンも常時募集しています

open.talentio.com

*1:それぞれの性能は公式ページを参照した。v100, a100, h100, b200

*2:例えばLLM.int8()のFigure1が分かりやすい。

*3:例えばTraining DNNs with Hybrid Block Floating Point8-bit Optimizers via Block-wise QuantizationLLM.int8()で提案されている。

*4:手元のMacBook Proでの実験なので行列サイズを大きくできない&ニューラルネットワークに出てくるより現実的な数値分布は用意できなかったため、Block-wise scalingとNVFP4の正確な比較は残念ながらできていないです。