「ローカルLLM」の投稿

haruki256

ローカルLLMは、重みファイル1個だけでは動かない

結論

ローカルLLMを動かすには、重みだけでなく、その構造を解釈する設定、対応するトークナイザーと入力形式、それらを実行できる推論エンジンが必要です。重みファイルが手元にあることと、モデルを正しく実行できることは同じではありません。

重みは、学習で得た大量の数値です。ただし、その数値をどの層のどの場所へ配置するかは、モデルのアーキテクチャや設定が決めます。さらに、入力文字列をモデルが使うID列へ変えるトークナイザーも、モデルに対応していなければなりません。

チャット用モデルでは、会話を学習時に想定された制御トークンと並びへ変換するチャットテンプレートも確認します。同じ「userとassistantの会話」でも、モデルごとに期待する入力形式が異なるためです。

推論に必要なものは、大きく次の役割へ分けられます。

  • モデル設定:層数や次元など、重みの構造を解釈する
  • 重み:学習で得たテンソルを保持する
  • トークナイザーと入力形式:文字列や会話をモデル用のID列へ変える
  • 推論エンジン:対応形式を読み、CPUやGPUで計算を実行する
  • 生成設定:logitから次のトークンをどう選ぶかを調整する

Safetensorsは、テンソルを保存する形式です。Hugging Faceのモデルでは、重みのほかに config.json やトークナイザー関連ファイルも使います。

GGUFはテンソルと推論用メタデータを一つのファイルへまとめますが、対応する推論エンジンが必要です。

参考:Using Transformers at Hugging Face、Chat templates、Safetensors、GGUF specification、llama.cpp

互換な一式を読み込めても、次は「重みファイルがメモリに収まるから実行できる」とは限りません。推論中には、重み以外のメモリも使います。

スレッドを開く スレッドを閉じる 2

量子化して重みを小さくしても、ローカルLLMの必要メモリが重みファイルの大きさだけで決まるわけではありません。

自己回帰型Transformerの推論では、少なくとも次の領域を分けて考えます。

  • 読み込んだ重み
  • 処理済みトークンの情報を再利用するKVキャッシュ
  • 推論エンジンが計算に使う一時領域やバッファ

量子化は、主に重みを低いビット数で表して、保存容量や重みのメモリ使用量を減らす方法です。しかし、KVキャッシュや実行時の一時領域まで同じ割合で小さくなるとは限りません。

KVキャッシュは、過去のトークンについてAttentionで使うKeyとValueを保持します。一般的な動的キャッシュでは、処理する文脈が長いほど保持量が増えます。

上限や増え方は、参照範囲を制限するSliding Window Attentionなどの方式とキャッシュ実装で変わります。

また、重みやキャッシュをRAMとVRAMのどちらへ置くかは、推論エンジンの設定で変わります。GPUに載らない部分をCPUへ置けばVRAM使用量は抑えられますが、RAM使用量や転送速度への影響を確認します。

そのため、必要メモリを見るときは、モデルファイルの容量に加えて、コンテキスト長、同時に処理する入力の数(バッチサイズ)、キャッシュ方式、CPUとGPUへの配置を一緒に確認します。

参考:KV cache strategies(Hugging Face Transformers)、Loading models(Hugging Face Transformers)、llama.cpp

では、メモリに収まって文章が生成されたら「正しく動いた」と言えるのでしょうか。確認を一つにまとめると、構成の不一致と実行環境の問題、出力品質の問題を切り分けにくくなります。

ローカルLLMの「動いた」は、少なくとも次の4段階へ分けて確認します。

  1. 読み込み:形式とアーキテクチャが推論エンジンに認識された
  2. 生成:対応するトークナイザーと入力形式で、停止条件まで文章を生成できた
  3. 計算環境:意図したCPU・GPU・オフロード設定で実行された
  4. 品質:用途を代表する固定入力に対し、必要な形式と内容を満たした

サーバーが起動しても、モデルの読み込みに失敗していれば1段階目を通っていません。

文字列が返っても、チャットテンプレートが合わず制御トークンが崩れていれば、2段階目の確認が必要です。GPUを使うつもりでも実際はCPUだけで計算しているなら、3段階目の問題です。

最後の品質確認も、「自然な文章が一度出た」だけでは足りません。要約なら出力形式と重要点、コード生成なら実行結果というように、用途ごとの固定入力と確認項目を用意すると、モデルや設定を変えたときに比較できます。

ここでは、モデル、推論エンジン、API、エージェントも分けて扱います。モデルは重みと構造を扱い、推論エンジンは計算を実行します。

APIは外部から呼ぶ窓口です。エージェントは入力やツール呼び出しの流れを組み立てます。APIやエージェントが動くことは、その下のモデル品質まで保証しません。

ローカルLLMの導入時は、必要な構成をそろえ、重み以外のメモリを見積もります。そのうえで、読み込み・生成・計算環境・品質の順に確認します。

こう分けると、「動かない」「遅い」「回答が合わない」を、重みファイル一つの問題として扱わずに調べられます。

参考:Chat templates、llama.cpp