info@formless.jp

【前編】ローカルLLMを使い比べていたら、自分で量子化したくなった

ローカルLLMを触っていると、モデルの名前だけでは分からないことが次々に出てくる。

会話は自然なのに、指定した形式では返してくれない。小さいモデルが意外に使える場面もあれば、大きなモデルに替えても期待したほど改善しない場面もある。同じモデルでも、プロンプトや推論エンジンを変えると、速度も出力も違ってくる。

これまで、GPUサーバー上でいくつものモデルを動かし、比較し、追加学習も試してきた。その過程で、関心が「どのモデルを選ぶか」から、「モデルをどういう形で動かすか」へ広がっていった。

その先に出てきたのが、自分で量子化を試すという選択肢だった。

まずは、モデルを動かして使ってみる

ここでいうローカルLLMは、ノートPCの中だけで動くモデルという意味ではない。外部の推論APIに任せるのではなく、利用できるGPUサーバー上で、自分でモデルを起動し、設定して使う形も含めている。

初期に動かしていたモデルの一つがQwen3-32Bだった。A100 80GBを2枚使い、vLLMでAPIとして呼び出せる環境を用意した。

応答が返ってくるところまで動くと、ひとまず安心する。ただ、実際に処理へ組み込むと、それだけでは足りない。

例えば、プログラムが受け取るためにJSONで返してほしい場合、文章として親切な前置きでも余計な出力になる。必要な項目が抜けたり、数値が範囲から外れたりすれば、そのままでは使えない。

人が読んで「よく答えている」と感じることと、システムの部品として扱いやすいことは、別だった。

一問の印象ではなく、条件をそろえて比較する

そこで、何度か会話してモデルの印象を決めるのではなく、入力や生成条件をそろえて比較するようになった。

Qwen、GLM、DeepSeek系、Phi、Gemma、gpt-ossなど、複数のモデルを対象に、文章評価と構造化出力を組み合わせたタスクを実行した。

見ていたのは、モデルが文章に付ける点数の高さだけではない。

指定した形式で返せるか。内容を変えた入力に対して、判断がどう変わるか。同じ入力を繰り返したときに、どの程度ぶれるか。そして、一つの応答にどれくらい時間がかかるか。

この比較を通じて、「モデルの性能」を一つの数字で済ませるのは難しいと感じるようになった。

JSONを正しく返せても、内容の判断まで正しいとは限らない。反対に、内容は使えそうでも、形式の失敗が多ければ後処理が必要になる。何を重視するかで、選ぶモデルも変わってくる。

なお、これはLLMの動作を確かめるための技術検証であり、教育効果や、人間の評価者を代替できるかを検証したものではない。

Qwen3.5-9Bは、出力形式が比較的安定していた

その比較に入れた一つが、Qwen3.5-9Bでした。

確認したかったのは、自然に会話できるかだけでなく、決められた形式で繰り返し応答を返せるかという点です。

初期の実験では、14テーマ・5段階の合成入力をそれぞれ40回、合計2,800回実行しました。temperatureは0、思考モードはOFFに固定しています。2,800種類の独立した問題ではなく、同じ入力を繰り返して安定性を見た実験です。

結果は、2,800応答のうち2,738応答、約97.8%をJSONとして解析できました。

完全に失敗がなくなったわけではありません。それでも、今回の条件では、機械的に読み取れる形式で返すという点で比較的安定していました。

これは内容の正しさとは別の評価です。ただ、LLMをプログラムから呼び出して使うなら、出力の形がある程度そろうことには意味があります。Qwen3.5-9Bについては、そうした形式面の挙動を具体的な件数で確認できました。

プロンプトと生成条件を変えて、19,600回実行した

モデルの比較に加えて、指示の出し方も調べました。

Qwen3-14Bでは、98件の合成入力に対し、4種類のプロンプト候補、5段階のtemperature、seedを含む反復条件を組み合わせ、計19,600回の推論を実行しました。

プロンプトを選ぶデータと、選んだ後に確認するデータは分けています。確認用の結果を見てから、都合のよい候補へ選び直すことはしていません。

全体では19,358回、約98.8%が厳密な出力形式の検査を通りました。こちらはJSONとして読めるかだけでなく、必要な項目や型なども検査しています。

棄却された242回の内訳は、JSON不正が78回、スキーマ違反が164回でした。ある候補では、temperature 1.0の980回中61回が棄却されており、失敗の出方にも条件による差がありました。

一方、形式が安定しても、内容の細かな違いを十分に区別できるとは限りませんでした。

例えば、隣り合う品質段階を正しい順に区別できた割合は、同じtemperature 0の確認データでも、候補によって約71.0〜77.4%と、約6.4ポイント違っていました。ただし、これは合成データ上の指標であり、一般的な正答率ではありません。

また、この指標で高かった候補が、別の指標や応答時間でも最良とは限りませんでした。

プロンプトの調整には意味があります。ただ、「工夫すればすべて解決する」というものでもありませんでした。

LoRAで文体は変わった。能力の評価は別に必要だった

追加学習も、初期の段階で試していました。

Qwen3-32Bに対し、LoRAを使って88件規模の小さなデータで学習させたところ、出力の文体に変化が見られました。前置きを含む文章から、教師データに近い簡潔な書き方へ変わったのです。

一方、損失の推移を見ると、学習を続ければよいわけではありませんでした。

訓練データへの損失は下がり続けるのに、検証データへの損失は約1エポック付近を境に悪化しました。過学習を疑う挙動です。ただし、小さなデータによる実験なので、この結果を大規模な学習へそのまま一般化することはできません。

確認できたのは、出力の文体が変わったことです。この初期のLoRA実験では、一般的な推論能力が向上したかを確かめるベンチマーク評価までは行っていません。

文体が好みに近づいたことと、モデルが賢くなったことは、分けて考える必要がありました。

既製の軽量モデルを使うだけでは分からないこと

出力の品質と並行して、気になっていたのがメモリ容量と速度です。

16GB、24GB、32GB、64GBといったVRAM容量を想定し、モデルや配布形式を比較する計画も組みました。実行にはA100を使っているため、それぞれの容量の市販GPUを直接比較したものではありません。

GGUFやFP8など、すでに量子化された配布モデルも使いました。この段階では、配布されている量子化モデルを選んで使うことが中心でした。

ただ、比較を進めると、ファイルサイズだけでは実際の使い勝手を判断できません。

GGUFにはllama.cpp、公式FP8モデルにはvLLMを使うなど、モデルと一緒に実行方式も変わっています。そのため、測定した速度差を、そのままモデルや量子化方式だけの差とは言えませんでした。

コンテキスト長や同時リクエスト数、出力するトークン数も、必要なメモリや待ち時間に関わります。

比較表の数字を眺めるだけでなく、その数字がどんな条件で出たのかまで確認する必要がありました。

「選ぶ」から「自分で圧縮する」へ

ここまで試してきたのは、主に三つの方向です。

  1. モデルを替える
  2. プロンプトや生成条件を調整する
  3. 追加学習をする

いずれもモデルの挙動を変える方法ですが、モデル本体の保存容量を直接小さくするものではありません。

そこで、自分で量子化することが次の検証対象として浮かんできました。

量子化は、モデルの重みなどを少ないビット数の数値で表し、データ量を減らす方法です。ただし、数値を丸める以上、出力品質を損なう可能性もあります。

ここまでモデルや実行条件を比較してきたからこそ、配布モデルを選ぶだけでなく、圧縮の仕方そのものを確かめてみたくなりました。

どこまで数値を粗くしても、出力品質は保てるのか。モデル全体を同じ精度にするのではなく、重要な部分だけ元の精度で残せないか。そして、軽くしたモデルは実際の推論でも速くなるのか。

小さく保存できること、実行できること、能力が残っていることは、それぞれ別に確かめなければなりません。

Qwen3.5-9Bを含むモデル比較で続けてきた「動かして、記録して、確認する」という作業を、今度はモデルの圧縮にも向けてみる。

次回は、そこから実際に量子化へ踏み込んだ過程を書いていきます。

すべての記事へ

視点を、もうひとつ。