量子化ではQ4_K_MとかQ4_K_Sとか種類があります。じゃあその違いって具体的になに?ということで見てみました。
※ この記事からの抜粋
コンパイルエラーを元気に説明するLLMをファインチューンでつくる - ローカルファインチューン完全ガイド - - きしだのHatena
たとえばLlama-3.2-1B-InstructのUnslothさんによるGGUFを見るとこんな感じで色々あります。
https://huggingface.co/unsloth/Llama-3.2-1B-Instruct-GGUF/tree/main.

Q4は4bitで量子化、つまり値を4bitで表しますよということなのでそのままですね。Q3なら3bit、Q5なら5bit。
問題はK_Mの部分。
ここで、KはK meansという手法を使って量子化することを表します。
そしてMとかSはサイズです。Medium, Smallの略です。Lもあります。
でもここでじゃあMediumとかSmallとか何よってなるので、実際の量子化を見てみます。
https://huggingface.co/unsloth/Llama-3.2-1B-Instruct-GGUF/blob/main/Llama-3.2-1B-Instruct-Q4_K_M.gguf
https://huggingface.co/unsloth/Llama-3.2-1B-Instruct-GGUF/blob/main/Llama-3.2-1B-Instruct-Q4_K_S.gguf
まずQ4_K_S。Q4_Kの中にQ5_Kがまじってますね。

これがQ4_K_MだとQ6_Kになります。

Transformerの計算の中でQuery、Key、Valueという要素があるのですけど、Valueだけ精度が高くなってます。
ついでに、じゃあなんでValueの値だけ精度が高いかというのも見ておきましょう。
ここに、Javaで書いたLLMの実装があります。というか、Cで書かれたものをあたたかみのある手作業でJavaに変換したものです。
https://gist.github.com/kishida/05656bfcbe840f269784f7dbbee5928e#file-llama-java-L300
qとkey_cacheを掛けたものを合計してattにいれてsoftmaxということをやってます。

softmaxは指数関数をかけたものをその合計で割るというものです。
そういった操作をするので掛け算の結果がそのまま残るわけではなく、精度が落ちてもかまわないわけですね。
一方でvalueに関しては、そうやって求めた値に掛けるだけ。

qkで計算した結果にsoftmaxをかけてvを掛けたものをそのまま使うので精度が重要ってことで高めの精度が使われてます。
F32もありますが、ここはShapeを見ると次元が低いです。行列を使って値を求めたあとに掛けるバイアス値なので精度重要だし、数も少なく量子化するメリットもでにくいのでそのままF32が使われてます。
ところでこれは、Qwen-Image-Layeredという、画像をレイヤーに分解するモデルのQuantStackでのQ4_K_Mの2ブロック目。
Q4_K主体でv_proj.weightだけQ6_K。
https://huggingface.co/QuantStack/Qwen-Image-Layered-GGUF/blob/main/Qwen_Image_Layered-Q4_K_M.gguf
同じQwen-Image-LayeredのQ4_K_Mでもunslothさんのところでは2ブロック目もQ5_K主体になっていて、Q4_Kになるのは3ブロック目からでした。
https://huggingface.co/unsloth/Qwen-Image-Layered-GGUF/blob/main/qwen-image-layered-Q4_K_M.gguf

同じ量子化でも微妙に違ったりするのですね。

ここで気づいた。
画像や動画の生成モデルは量子化の影響を受けやすくVRAMはみ出ていいのでなるべく大きいサイズを選ぶ - きしだのHatena
Q4_K_Mがそこまで性能劣化しない割にサイズも小さくCPUにもやさしいということでよく使われます。
もっと詳しい説明はここに
https://g-pc.info/archives/43789/