第1章 本書の対象読者とゴール
この章では、本書がどんな読者に向けて書かれているのか、そして読み終えたときに何ができるようになっていてほしいのかを整理します。 具体的な技術の話はまだ出てきません。 まずは「自分はこの本の対象だろうか」「この本を読むと何が手に入るのか」を確認します。
1.1 llama-cli でモデルは動かせるが、内部の流れは曖昧な人へ
本書の読者は、おそらく llama.cpp を一度は触ったことがあるはずです。
GGUF 形式のモデルファイルをダウンロードし、llama-cli -m model.gguf -p "..." と打てば、ターミナルに文章が流れていく。
あるいは llama-server を立ち上げて、ブラウザやアプリから API 経由で応答を受け取る。
ここまでは、ドキュメントやブログ記事のとおりに進めれば、たしかに「動く」状態にたどり着けます。
しかし、こんな問いを投げかけられたらどうでしょうか。
「あなたが入力したプロンプトの文字列が、次の 1 トークンになって返ってくるまでに、llama.cpp の中では何が起きていますか?」
この問いに、順を追って答えられる人は意外と多くありません。
入力された文字列がトークンの列に変換され、そのトークンが埋め込みベクトルになり、計算グラフが組み立てられ、CPU や GPU のバックエンドで行列計算が実行され、最後の層から出てきた数値の並びから次のトークンが選ばれる。
この一連の流れは、llama-cli という一本のコマンドの内側にまとめられているため、普段は意識せずに済んでいます。
図 1-1 プロンプトから次の1トークンまでの隠れた処理経路
本書が対象とするのは、まさにこの「隠された部分」に漠然とした不安や好奇心を感じている人です。 具体的には、次のような方を想定しています。
llama.cppでモデルは動かせるが、内部で何が起きているかは説明できない量子化や GGUF、KV キャッシュといった言葉は知っているが、自分の言葉では語れない
C++ のコードは読めるので、ドキュメントではなくソースそのものから理解したい
トラブルや性能の問題が起きたとき、当て推量ではなく仕組みから原因を切り分けたい
いずれかに心当たりがあれば、本書はあなたのために書かれています。
注釈
本書は C++ のコードを引用しながら進めます。 関数、構造体、ポインター、テンプレートといった基本的な文法は読める前提です。 一方で、LLM や Transformer の知識は前提としません。 トークンや埋め込み、Attention、KV キャッシュといった概念は、ソースを読むのに必要な範囲で第 2 章から順に積み上げます。
1.2 なぜ内部を理解するのか
「コマンドを打てば動くのだから、内部を知らなくてもいいのでは?」
これは自然な疑問です。
実際、多くの場面では内部を意識しなくても llama.cpp を使えます。
では、なぜ本書はわざわざ「ソースを読もう」と勧めるのでしょうか。
理由は単純です。 うまくいっている間は内部を知らなくても困りません。 困るのは、うまくいかなくなったときや、もう一歩踏み込みたくなったときです。
たとえば、次のような場面を考えてみてください。
同じモデルなのに、量子化の種類を変えたら速度も品質も変わった。なぜなのかを説明したい。
手元の Mac では速いのに、別の環境では極端に遅い。どのレイヤーがボトルネックなのかを切り分けたい。
コンテキスト長を伸ばしたらメモリーが急に膨らんだ。KV キャッシュが何をどれだけ確保しているのかを知りたい。
新しいモデルアーキテクチャに対応させたい。計算グラフがどこでどう構築されているのかを追いたい。
こうした場面では、「なんとなく動く」では立ち止まってしまいます。 内部の仕組みを知っていれば、「この現象はこの段階で起きているはずだ」と仮説を立てられます。 仮説が立てば、次に確認すべき場所が見えます。
内部を理解するとは、ソースコードをすべて暗記することではありません。 入力がどこを通って、どう処理されて、出力になるのか、その流れを自分の頭の中に地図として持つことです。 この地図があれば、未知の問題に出会っても、闇雲に設定をいじるのではなく、筋道を立てて調べられるようになります。
本書のゴールは、「llama.cpp を使えるようになること」ではなく、「llama.cpp の中で何が起きているかを語れるようになること」にあります。
1.3 本書のゴール:推論パイプラインの地図
本書を読み終えたとき、読者は次のことができるようになっているはずです。
プロンプトの文字列がトークンに変換され、最終的に次のトークンが選ばれるまでの流れを、自分の言葉で順を追って説明できる。
ggmlというテンソル計算ライブラリと、その上に乗るllama.cpp本体の役割分担を区別できる。モデルの読み込み、計算グラフの構築、バックエンドでの実行、サンプリングといった各段階が、どのソースファイルのどのあたりに対応するのかを指させる。
量子化、KV キャッシュ、バックエンドの選択といった要素が、速度やメモリーにどう効いてくるのかを仕組みから理解している。
これらは一度身につければ、llama.cpp のバージョンが上がっても、別の推論エンジンに触れても応用がききます。
表面的な API は変わっても、「トークン化 → 埋め込み → 計算グラフ → 実行 → サンプリング」という推論の骨格は大きくは変わらないからです。
図 1-2 推論パイプラインの地図(5段階とソースの対応)
本書は、この骨格をまず全体像として示し、そこから各部位を段階的に詳細化していきます。 全体像は次の第 3 章で、ブロックダイアグラムとデータフロー図を使って俯瞰します。 その前に第 2 章で、地図を読むために最低限必要な LLM の概念を準備します。
1.4 本書で扱うものと扱わないもの
深く潜るためには、潜る場所を絞る必要があります。 あれもこれもと手を広げると、どの話題も中途半端な理解に終わってしまいます。 ここでは、本書が何を深く扱い、何に軽く触れ、何を意図的に扱わないのかを先に示しておきます。 読み始める前にスコープを把握しておくと、「この話はこの本の範囲外なのだな」と迷わずに進めます。
区分 |
内容 |
|---|---|
深く扱う |
|
軽く触れる |
多数あるモデルアーキテクチャの個別実装(代表例のみ精読)、周辺バックエンド(SYCL、HIP、OpenCL ほかは位置づけのみ)、Python の GGUF 変換スクリプト |
扱わない |
LLM の学習(トレーニング)、Transformer の数学的導出、ファインチューニング、各モデルの設計思想の比較、量子化アルゴリズムの最適性の証明 |
表 1-1 本書が扱う範囲
本書の主眼は、「学習済みモデルを読み込んで推論する」という一本の道筋 にあります。
モデルをどう訓練するか、Transformer がなぜそう設計されているのかといった話題は、それぞれ一冊の本になる広さを持っています。
本書はそこには踏み込まず、llama.cpp が推論時に実際に何をしているのかに集中します。
扱わない領域について学びたくなったときは、その領域に特化した資料を参照してください。 本書で得た「推論パイプラインの地図」は、そうした学習においても確かな足場になります。
1.5 学び方の方針
最後に、本書が採用している学び方の方針を共有しておきます。 この方針を頭の片隅に置いておくと、各章の意図がつかみやすくなります。
全体像から入り、段階的に詳細化する。 本書はいきなり個別のソースファイルには飛び込みません。 まず推論全体の流れを図で俯瞰し、登場人物と役割を把握してから、各ブロックを一段ずつ掘り下げます。 急がば回れで、地図を持ってから歩き出す順序を大切にします。
図 1-3 本書の進め方(全体像から段階的詳細化へ)
ソースコードと対応づけて説明する。
概念を説明したら、それが llama.cpp のどこに、どう実装されているのかを必ず突き合わせます。
コードの引用は、注目してほしい箇所を絞って抜粋し、その直後に解説を添える形を基本とします。
図と表で理解を支える。 構造の説明には図を、型や関数の一覧と比較には表を使います。 注意点や落とし穴、補足は、本文から少し浮かせたコラムとして添えます。
対象バージョンを固定する。
ソースは日々更新されるため、本書は llama.cpp のコミット 006640408(build b9503 付近)を基準とします。
行番号はバージョンによってずれるため、コードの場所は主にファイルパスと関数や構造体の名前で示します。
Tip
本書を読むときは、ぜひ手元に llama.cpp のソースを用意してください。
本文で引用する関数や構造体を、実際のファイルの中で探してみると、地図と現地の風景が結びつき、理解が一段深まります。
この章では、本書の対象読者、内部を理解する意義、ゴール、スコープ、学び方の方針を確認しました。 本書のゴールは、「推論パイプラインの地図を自分の頭の中に持つこと」 です。
次の第 2 章では、その地図を読むために必要な LLM の最小限の概念(トークン、埋め込み、Attention、KV キャッシュ、自己回帰生成)を、llama.cpp のソースを読む準備として順に整理していきます。