YouTubeの数時間とLLM推論に関する85ページの手書きノート – ここから始めよう
Hours of YouTube and 85 handtyped pages of notes on LLM Inference – Start here (github.com)
要約
この記事は、C++とCUDAで小規模なLLM推論エンジンを構築することを通じて、プロンプトからトークン生成までのプロセスを第一原理から解説しています。80ページ以上にわたる手書きノートと図解が含まれており、AIの助けなしに執筆された詳細な解説が提供されています。
全文翻訳
YouTubeの数時間とLLM推論に関する85ページの手書きノート – ここから始めよう
C++とCUDAで小規模なエンジンを構築することにより、LLM推論を第一原理から教える。
このシリーズは、モデルの重みをロードしてからトランスフォーマーの各部分をGPUで実行するまで、プロンプトと生成されたトークンの間で行われることを追っています。
私の推論ノート
私の手書きノートと図解が80ページ以上にわたる推論をゼロから(PDF)をお読みください。このPDFの執筆はすべて私自身が開発したもので、AIによる執筆ではありません。
ビルドシリーズ | 6時間以上の映像
各ビデオの補足ノートはstudy-notes indexにあり、個別のMarkdownおよびPDFフォルダがあります。また、完全なPDFコレクションを読むこともできます。
これまでの進捗
- C++17 / CUDAプロジェクトで、CMakeでビルドされ、Unicode対応トークン化のためにICUとリンクされています。
- 直接
model.safetensorsのロード:メタデータを解析し、テンソルオフセットを検証し、生のBF16ウェイトをGPUメモリにコピーします。CPU側での追加コピーを避けるためのメモリマップドローダー実装もあります。 - 16層すべてにわたる埋め込み、正規化、アテンション、MLPテンソルへの直接ポインタを持つ、固定されたLlama 3.2 1B Instructウェイトレイアウト。
- Unicode、特殊トークン、エンコード/デコード、Instructチャットプロンプト形式をサポートするローカルBPEトークナイザー。その期待される出力は、専用のテスト実行可能ファイルでカバーされています。
- CUDA埋め込みギャザーカーネルとプリフィルパス。GPUにプロンプトトークンIDをコピーし、アクティベーションを割り当てます。
- 2,048幅の隠れ状態用のCUDA RMSNormカーネル。FP32で削減し、フォワードパス全体で学習済みのBF16ウェイトを適用します。
- Dense causal prefillは現在、すべての16層を実行します:Q/K/Vプロジェクション、RoPE、grouped-query attention、出力プロジェクション、アテンション残差、アテンション後RMSNorm、SwiGLU MLP、およびMLP残差。
- 最終的なRMSNormとタイされた埋め込み/LMヘッドプロジェクションはFP32ロジットを生成します。GPUのargmaxが各次のトークンを選択します。
- 各シーケンスと層ごとにブロックテーブルを持つ共有BF16 KVページプール。各物理ページにはKとVが16トークンずつ格納されます。プリフィルはプロンプトページを埋め、デコードは絶対RoPE位置に1つの新しいトークンを追加します。
- Instructチャットフォーマット、EOS/EOT停止、および2,048トークンコンテキスト内の設定可能な出力長を持つ、貪欲な応答生成。
- 持続的なスクラッチバッファと、プリフィルとデコードで共有される1つのcuBLASハンドル。Qストレージは出力/MLPプロジェクションのために再利用され、正規化ストレージはアテンション出力のために再利用されます。
- ランタイムサイズのバッファ、パックされたプロジェクション、およびシーケンスごとの別々のKVページマッピングとアテンション長を持つバッチデコード。リクエスト数はKVプールを拡大しません。
- 静的バッチ処理と連続スケジューラ。これらは利用可能なページ予算に従ってキューに入れられたプロンプトを受け入れ、完了時にページと予算を返します。
- FP32オンラインソフトマックスによる直接ページ化デコードアテンション。各クエリヘッドはシーケンスのキャッシュされたページをストリームし、連続したプレフィックスを収集したりアテンションスコアを格納したりすることなく、重み付けされた値を累積します。
Part 8ではPrefill, Decode, and the KV Cacheを解説しています。Part 9ではStatic and Continuous Batchingを、現在のページ化キャッシュとオンラインソフトマックスデコードアテンションを含めて解説します。
現在のスコープ
Llama 3.2 1B推論パスには、dense causal prefill、paged decode attention、および静的または連続バッチ処理が含まれます。この学習エンジンのモデル寸法と2,048トークンコンテキストは固定されています。KVプールはデフォルトで128 MiBで、--kv-cache-mib Nで設定できます。アクティブリクエスト容量は、固定の2リクエスト制限ではなく、ワークロードのページ予算に従います。
アドミッションは、各リクエストの最大処理プレフィックスのスペースを保証します: prompt_tokens + allowed_new_tokens - 1、これは16トークンページに切り上げられ、16層すべてに適用されます。許可される出力予算はコンテキスト制限にクランプされ、最終的に予測されたトークンは再度処理されることなく返されます。これらのアドミッションクレジットは物理ページとは別であり、後者には遅延して割り当てられます。早期完了は、割り当てられたページと残りのクレジットの両方を解放します。
リクエストは、予算がアクティブリクエストと一致しない場合、FIFO順で待機します。アクティブリクエストには完了するためのスペースがあるため、将来のページ境界の成長がプールを枯渇させたり、デッドロックを引き起こしたりすることはありません。プール全体を超える予算を持つリクエストは、明確なエラーとともに拒否されます。この保守的なポリシーは、プリエンプションと再計算を回避します。要求された大きな出力予算は、モデルが最終的に早期に停止しても、同時実行性を制限する可能性があります。
--statsは、プールサイズ、ピークアクティブリクエスト数、最大のデコードバッチ、ピーク割り当てページ数、アドミッション待機時間、および最終的な空きページ数を報告します。プリフィルはデコードイテレーション間で1度に1つのプロンプトを処理します。
BF16計算は、バッチサイズが異なると異なる丸め方をする場合があります。語彙ロジットがほぼ同点の場合、貪欲な出力トークンは、個別の実行とバッチ実行で異なる場合があります。バッチサイズ間でのビット単位の出力等価性は保証されません。
ビルド
要件
- CUDA対応NVIDIA GPUおよびCUDA Toolkit
- CMake 3.24以上
- C++17コンパイラ
- ICU開発ライブラリ
nlohmann/jsonヘッダー- モデルウェイト
models/llama-3.2-1b-instruct/model.safetensors - 対応するトークナイザー
models/llama-3.2-1b-instruct/tokenizer.model(models/Llama-3.2-1B-Instruct/original/tokenizer.modelからコピーしてください)
mkdir -p models/llama-3.2-1b-instruct
cp models/Llama-3.2-1B-Instruct/original/tokenizer.model models/llama-3.2-1b-instruct/
cmake -S . -B build
cmake --build build -j
./build/samir-vllm "Explain the KV cache in two sentences." 128
# Continuous batching (default): admit requests whose page budgets fit.
./build/samir-vllm "Say hello." 64 "Explain the KV cache." "What is RoPE?"
# Static batching: wait for the current group before admitting more.
./build/samir-vllm --static "Say hello." 64 "Explain the KV cache." "What is RoPE?"
# More than two requests share the same default 128 MiB pool.
./build/samir-vllm --stats "Explain paging." 64 "Explain GQA." "Explain RoPE." "Explain softmax."
# A smaller pool queues requests when their declared budgets cannot fit together.
./build/samir-vllm --kv-cache-mib 8 --stats "Explain paging." 64 "Explain GQA." "Explain RoPE."
./build/tokenizer-test models/llama-3.2-1b-instruct/tokenizer.model
オプションの--static、--continuous、--kv-cache-mib N、および--statsフラグの後、最初の引数はプロンプトで、2番目の引数はmax_new_tokens(デフォルト:128)です。残りの引数は追加のプロンプトで、トークン予算は各リクエストに適用されます。すべてのプロンプトはInstructユーザーメッセージとしてフォーマットされます。生成はEOS、EOT、またはEOM、あるいは出力/コンテキスト制限で独立して停止し、完了した各応答はトークンIDとリクエスト番号とともに印刷されます。
プロンプトはデコードを一時停止して、一度に1つずつプリフィルされます。各デコードステップは、共有バッファにアクティブな各シーケンスから1つのトークンをパックします。アテンションは、そのシーケンスのキャッシュのみを読み取ります。リクエストは、異なるプロンプト長と出力長を持つことができます。Continuous batchingは、ページクレジットが利用可能になったときに待機中のリクエストを受け入れ、static batchingは現在のグループが終了した後に次のグループを受け入れます。
プロジェクトレイアウト
src/ Engineのエントリーポイント、CUDAカーネル、トークナイザー実装
include/ 公開カーネルとトークナイザーヘッダー
tests/ トークナイザーテスト
python/ トークナイザー参照スクリプト
proper_notes/ 学習ノートインデックス、markdown/ソース、pdf/閲覧版
scripts/ 学習ノートPDFの再構築
notes.md ビルドからの作業ノート
ライセンス
src/、include/、tests/、およびpython/のエンジンソースコードは、CMakeLists.txt、.gitignore、およびこのREADMEとともに、MITライセンスの下でライセンスされています。
proper_notes/、notes.md、およびpodLibraryInstall.mdのノート、ならびにこのプロジェクトで提供される手書きノート、スキャン、イラスト、ノートの写真、およびPDFは、すべての権利を留保されており、MITライセンスから除外されています。個人的な閲覧および学習は許可されています。再配布、再公開、再ホスティング、再販、または改変版の配布には、無料か有料かを問わず、事前の書面による許可が必要です。LICENSE-NOTESで完全な条件と例外を確認してください。
公開リポジトリは、GitHubの利用規約の下でGitHub内で表示およびフォークできます。
モデルアセットと依存関係
Llamaでビルド。バンドルされているLlama 3.2トークナイザーおよび別途ダウンロードされたLlama 3.2ウェイトは、MetaのLlama 3.2コミュニティライセンスおよび利用許諾ポリシーを保持します。これらはMITライセンスから除外されています。Llama資料を再配布する場合は、契約、ポリシー、および帰属表示を保持してください。
CUDA、cuBLAS、ICU、およびnlohmann/jsonを含むサードパーティの依存関係は、それぞれのライセンスを保持します。