前のブログではLoRAを見ました。低ランク近似を利用して、W=BAという追加のパラメータを実装してました。 今回はその手法をちょっと拡張したモデルのようです。
QLoRA: Efficient Finetuning of Quantized LLMs
Tim Dettmers, Artidoro Pagnoni, Ari Holtzman, Luke Zettlemoyer
https://arxiv.org/abs/2305.14314
実装
https://github.com/artidoro/qlora
結構解説記事もありました。どれも同じような感じでしたので、大体あってそうです。
GPUメモリが小さくてもパラメーター数が大きい言語モデルをトレーニング可能になる手法「QLoRA」が登場、一体どんな手法なのか?
https://gigazine.net/news/20230603-qlora-finetuning-llm/
みてみます。
65Bパラメータモデルを単一の48GB GPUでファインチューニングできる
と書いてあります。この場合のファインチューニングはLoRAを含むパラメータ最適化のことだと思います。LoRAについての記事は、
https://blueqat.com/yuichiro_minato2/d2a03601-2f3e-4535-980d-33c79add516c
に書きましたが、通常の事前学習モデルと並行して、低ランク近似した重み行列を導入し、そちらを追加学習します。
今回のQLoRAではそれに加えて3つの工夫があると書いてあります。
論文より引用:
左側は追加の層であるアダプターを用いないフルのファインチューニング。16bitのTransformerを使って32bitの最適化機構を使うようです。新参者すぎてOptimizer stateというのがわかってないですが。真ん中のLoRAは追加層(?)をAdapterと呼んでいて追加学習します。右のQLoRAでは、16bitトランスフォーマーが4bitに量子化されていて、CPUメモリ領域が追加されています。
3つの工夫は、
(1) 4-bit NormalFloat, an information theoretically optimal quantization data type for normally distributed data that yields better empirical results than 4-bit Integers and 4-bit Floats. (2) Double Quantization, a method that quantizes the quantization constants, saving an average of about 0.37 bits per parameter (approximately 3 GB for a 65B model). (3) Paged Optimizers, using NVIDIA unified memory to avoid the gradient checkpointing memory spikes that occur when processing a mini-batch with a long sequence length. We combine these contributions into a better tuned LoRA approach that includes adapters at every network layer and thereby avoids almost all of the accuracy tradeoffs seen in prior work.
ChatGPTを使って日本語翻訳してみると、
(1) 4-bit NormalFloatは、正規分布データに対して情報理論的に最適な量子化データタイプであり、4ビット整数や4ビット浮動小数点よりも優れた実証結果をもたらします。
(2) ダブル量子化は、量子化定数を量子化する方法であり、パラメータあたり平均約0.37ビット(65Bモデルの場合、約3GB)を節約します。
(3) ページドオプティマイザーは、NVIDIAの統合メモリを使用して、長いシーケンス長のミニバッチを処理する際に発生する勾配チェックポイントのメモリスパイクを避けます。
これらの貢献を組み合わせることで、すべてのネットワーク層にアダプターを含む、より洗練されたLoRAアプローチに仕上げ、以前の作業で見られたほとんどすべての精度のトレードオフを避けます。
となりました。最初は4bitの量子化ですが、NormalFloatと呼ばれるものを利用していて、整数や浮動小数点よりも性能がいいみたいです。仕組みがわかってないので、余裕あれば見てみます。二つ目はダブル量子化で、量子化定数というのが式の中にあり、その量子化定数自体も量子化するという仕組みらしいです。パッとみた感じ量子化定数の求め方が書いてありましたので解説もしてみたいです。三つ目はメモリの問題で、学習時の最適化に微分ベースの最適化ソルバーを使うと思いますが、その勾配チェックポイントの保存をGPUのVRAMだけでなく、CPUメモリに逃して効率化するということみたいです。VRAMは基本的には足りないので、多少速度を犠牲にしてVRAMを使わないように工夫をしてVRAMの利用量を減らしたという感じだと思います。
今回は最初の2つについて確認します。正直量子化がポイントになってきますが、なにしろ機械学習分野に入り込んできたばかりで量子化の知識が不足しています。
今回はBlock-wise k-bit Quantizationということで、パラメータの量子化だけでなく、さらにそれをブロックに分割する手法のようです。そもそもの量子化について簡単な説明がありわかりやすいです。fp32をint8に量子化する際には、int8では8bitを利用して整数を作るので、2^8 =256なので、-127から127までの整数を表現できる。fp32をint8に量子化するには、単純に四捨五入を使って、
Xint8 = round(127/absmax(Xfp32) * Xfp32)
となり、式変形して、127/absmax(Xfp32)の部分を量子化定数Cfp32として扱うようです。結局量子化定数に元の値をかけて、四捨五入します。この式を見るとちょっと問題点があるように見えますというか、あるようです。
absmaxでは、全体の値の絶対値の最大値で127を割りますので、外れ値がある場合には、この定数が極端な値を取ることになり、全体の値が正しく量子化されないということが起こりうることが想像できます。そのため、Xの値をブロックごとに分割して平坦化を行う工夫がされているようです。そして、それぞれのブロックごとに独立した量子化定数cを持たせれば外れ値の影響を小さくできます。Xを連続するブロックのサイズBに分割するようです。
上記のk-bit量子化の説明の後にLoRAの簡単な説明もありましたが、基本的にはLoRAの論文そのままでしたので、割愛します。
そして、4bitの量子化についてNormalFloatと呼ばれるものの利用ですが、ただ量子化するだけでなく、Quantile Quantizationという手法を使うようです。こちらは、
8-bit Optimizers via Block-wise Quantization
Tim Dettmers, Mike Lewis, Sam Shleifer, Luke Zettlemoyer
https://arxiv.org/abs/2110.02861
こちらの論文に詳しく書いてあるみたいですが、ちょっと時間の関係で次回に回します。。。
どうやら量子化した時の情報損失を減らすため(多分ハズレ値に対して?)に、経験的累積分布関数(eCDF)を使用して、データの量子を推定し、これらの量子を基にデータをビンに均等にデータを割り当て、離散化するようです。入力データの分布が決まっている場合、例えば正規化されていたりするとこのような高度な量子化に対して高コストなアルゴリズムの適用を避けることができるようです。
興味はありますが、これはまた別の機会にみたいと思います。続いてDouble Quantization(二重量子化?)ですが、こちらは先ほどできてた量子化定数について、そのオーバーヘッドを減らすための工夫のようです。
パラメータの評価には下記の論文が使われていましたが、こちらも読めていません。。。
The case for 4-bit precision: k-bit Inference Scaling Laws
Tim Dettmers, Luke Zettlemoyer
https://arxiv.org/abs/2212.09720
どうやら量子化定数がfp32のようなので、さらにそれを量子化してfp8にするようで、
from 32/64 = 0.5 bits, to 8/64 + 32/(64 · 256) = 0.127 bits
とパラメータあたり0.373 bitsの削減となり結構削減できますね。
3つ目のCPUメモリへの割り当ては割愛しますが、結構いろんな手法を組み合わせてかなりパフォーマンスを維持したまま軽量化されていますね。知らない知識も多かったので根性で勉強します。以上です。