LLM量子化のビジュアルガイド
(newsletter.maartengrootendorst.com)- 大規模言語モデル(LLM)は通常のハードウェアで実行するには大きすぎ、一般に数十億個のパラメータを持つため、大量のVRAMを備えたGPUが必要
- そのため、改良された学習手法やアダプタなどを通じてこれらのモデルをより小さくする研究にますます注目が集まっており、この分野の主要技術の1つが量子化(Quantization)
Part 1: 大規模言語モデルの「問題」
- LLM(Large Language Model)は、含まれるパラメータ数に応じて名付けられている
- このようなモデルには通常、数十億個のパラメータ(主に重み)が含まれ、保存コストもかなり大きくなりうる
- 推論中、活性化は入力と重みの積によって生成され、同様にかなり大きくなりうる
- そのため、与えられた値を保存するのに必要な空間を最小化しながら、数十億個の値をできるだけ効率よく表現しようとする
数値を表現する方法
- 与えられた値は浮動小数点数(実数)として表現されることが多い
- これらの値は「ビット」で表現され、IEEE-754標準は、各ビットが値を表すために符号、指数、仮数(fraction)のいずれの役割を持つかを説明している
- 値の表現に使われるビット数が多いほど、一般に精度は高くなる
- 利用できるビット数が多いほど、表現できる値の範囲も広がる
メモリ制約
- 700億個のパラメータを持つモデルを想定すると、FP32(full-precision)を使う場合、モデルをロードするだけで280GBのメモリが必要
- そのため、モデルのパラメータを表すビット数を最小化することが非常に重要だが、精度が下がるとモデルの正確性も一般に低下する
- 正確性を維持しつつ値を表すビット数を減らすことが目標であり、ここで量子化(quantization)が登場する
Part 2: 量子化の紹介
- 量子化は、モデルパラメータの精度を高いビット幅(例: 32ビット浮動小数点)から低いビット幅(例: 8ビット整数)へ下げることを目的とする
- ビット数を減らすたびに、元のパラメータを低ビット表現へ「圧縮」するためのマッピングが行われる
一般的なデータ型
FP16
- FP32からFP16(half precision)に移ると、FP16が取りうる値の範囲はFP32よりかなり小さくなる
BF16
- FP32と似た値の範囲を得るため、「切り詰められたFP32」の一種である bfloat16 が導入された
- BF16はFP16と同じ数のビットを使いながら、より広い値域を持つことができ、ディープラーニングの用途でよく使われる
INT8
- さらにビット数を減らすと、浮動小数点表現ではなく整数ベースの表現に近づく
対称量子化
- 元の浮動小数点値の範囲が、量子化空間で0を中心とする対称な範囲にマッピングされる
- 浮動小数点空間における0の量子化値は、量子化空間でも正確に0である
非対称量子化
- 対称量子化とは異なり、0を中心とした対称ではない
- 最小値(β)と最大値(α)を、浮動小数点範囲から量子化範囲の最小値と最大値へマッピングする
- ゼロポイント(zero-point)量子化と呼ばれる手法の1つ
範囲マッピングとクリッピング
- ベクトル全体の範囲をマッピングすると、外れ値のせいで小さな値がすべて同じ低ビット表現にマッピングされ、区別する情報を失ってしまう
- その代わりに、特定の値でクリッピング(clipping)することを選べる
- クリッピングとは、すべての外れ値が同じ値を持つようにして、元の値に対する別の動的範囲を設定すること
- 外れ値でない値の量子化誤差は大きく減る一方、外れ値の量子化誤差は増加する
キャリブレーション(Calibration)
重み(およびバイアス)
- 重みとバイアスは、モデルを実行する前に既知の静的な値と見なせる
- バイアスは重みよりはるかに少ないため、より高精度(例: INT16)で保持され、量子化の主な対象は重みに向けられる
- 静的で既知の重みに対するキャリブレーション手法には、入力範囲のパーセンタイルを手動で選ぶ方法、元の重みと量子化後の重みの平均二乗誤差(MSE)を最適化する方法、元の値と量子化値の間のエントロピー(KLダイバージェンス)を最小化する方法などがある
活性化
- 入力はLLM全体で継続的に更新され、一般に「活性化」と呼ばれる
- これらの値は、各入力データが推論中にモデルへ与えられるたびに変わるため、正確に量子化するのが難しい
- これらの値は各隠れ層の後で更新されるため、入力データがモデルを通過するときにしか、推論中にどのような値になるか分からない
Part 3: 学習後量子化(PTQ - Post-Training Quantization)
動的量子化
- データが隠れ層を通過した後に活性化が収集される
- この活性化分布は、出力を量子化するために必要なゼロポイント(z)とスケールファクタ(s)の値を計算するのに使われる
- データが新しい層を通過するたびにこのプロセスが繰り返される。そのため各層は固有の z と s の値を持ち、それぞれ異なる量子化スキームを持つ
静的量子化
- 推論時ではなく事前にゼロポイント(z)とスケールファクタ(s)を計算する
- これらの値を見つけるために、キャリブレーション用データセットをモデルに与えて潜在的な分布を収集する
- 実際の推論を行う際には s と z の値は再計算されず、すべての活性化に対してグローバルに使われて量子化される
- 一般に、動的量子化は各隠れ層ごとに s と z を計算しようとするため、やや高精度だが計算時間が増える可能性がある
- 一方、静的量子化は精度はやや低いが、すでに s と z の値が分かっているため高速である
4ビット量子化の領域
- 8ビット未満へ下げることは、ビットを失うたびに量子化誤差が増えるため、難しい作業であることが分かっている
- HuggingFace で一般的に共有されている2つの方法、GPTQ と GGUF を見ていく
GPTQ
- 4ビットへ量子化する方法として、実際に最もよく知られた手法の1つ
- 非対称量子化を使い、各層を独立して処理してから次へ進む層単位の方式で行う
- 層ごとの量子化プロセスでは、まずその層の重みを逆ヘッセ行列に変換する。これはモデル損失関数の2階微分であり、各重みの変化に対してモデル出力がどれほど敏感かを示す
- 簡単に言えば、その層における各重みの(逆)重要度を示している
- ヘッセ行列で値が小さい重みは、わずかな変化でもモデル性能に大きな影響を与えうるため、より重要である
GGUF
- GPTQ は LLM 全体を GPU 上で実行するには優れた量子化手法だが、常にそのような容量があるとは限らない
- その代わりに、LLM のすべての層を CPU にオフロードするために GGUF を使うことができる
- 十分な VRAM がない場合でも、CPU と GPU の両方を使えるようにしてくれる
Part 4: 量子化認識学習(QAT - Quantization Aware Training)
- 第3部では学習後にモデルを量子化する方法を見てきたが、この量子化には実際の学習プロセスを考慮しないという欠点がある
- そこで量子化認識学習(QAT)が登場する。PTQ と異なり、QAT は学習中に量子化手順そのものを学習することを目指す
- QAT は学習中に量子化がすでに考慮されているため、PTQ より高精度になる傾向がある
1ビットLLMの時代: BitNet
- BitNet はモデルの重みを単一の1ビット、つまり -1 または 1 で表現する
- トランスフォーマーアーキテクチャに量子化プロセスを直接組み込むことでこれを実現する
- トランスフォーマーアーキテクチャは大半の LLM の基盤として使われており、線形層を含む計算で構成される
- BitNet はこれらの線形層を BitLlinear と呼ばれるものに置き換える
重みの量子化
- 学習中、重みは INT8 に保存され、その後、基本戦略である符号関数を使って 1 ビットに量子化される
- 本質的には、重み分布を 0 を中心に移動させたうえで、0 の左側にあるものをすべて -1 に、右側にあるものをすべて 1 に割り当てる
活性化の量子化
- 活性化を量子化するため、BitLinear は、行列積(×)にはより高い精度が必要であることから、活性化を FP16 から INT8 に変換するために absmax 量子化を使う
逆量子化
- α(活性化の絶対値の最大値)と β(重みの平均絶対値)を追跡しており、これらの値は後で活性化を FP16 に逆量子化するのに役立つ
- 出力活性化は {α, γ} によって再スケーリングされ、元の精度へ逆量子化される
すべての大規模言語モデルは 1.58 ビットである
- BitNet 1.58b は、先に述べたスケーリングの問題を改善するために導入された
- この新しい方法では、モデルの各重みは -1 または 1 だけでなく、0 も値として取れるようになり、三値(ternary)になる
- 興味深いことに、0 を追加するだけでも BitNet は大きく改善し、計算速度も大幅に向上する
0の力
- 0 を追加することがなぜそれほど大きな改善なのか? これは行列積と大きく関係している
- 1.58 ビットに量子化された重みがあれば、乗算だけを行えばよいため計算速度を大きく高められるだけでなく、特徴のフィルタリングも可能になる
量子化
- 重みの量子化を行うために、BitNet 1.58b は、以前に見た absmax 量子化の変種である absmean 量子化を使う
- 単純に重み分布を圧縮し、絶対平均(α)を使って値を量子化し、それらを -1、0、または 1 に丸める
- BitNet と比べて活性化の量子化は1点を除いて同じである。活性化を [0, 2ᵇ⁻¹] の範囲に調整する代わりに、今度は absmax 量子化を使って [-2ᵇ⁻¹, 2ᵇ⁻¹] に調整する
- 1.58 ビット量子化には、(主に)2つの工夫が必要だった:
- 三値表現 [-1, 0, 1] を作るために 0 を追加
- 重みに対する absmean 量子化
-
「13B BitNet b1.58 は、レイテンシ、メモリ使用量、エネルギー消費の面で、3B FP16 LLM より効率的である」
- したがって、計算効率の高い 1.58 ビット化によって軽量モデルを得られる
まだコメントはありません。