- WASTE は、2.78兆パラメータの完全な Kimi K3 オープンウェイトモデルを縮小せずに 982GiB のコンテナへ変換し、一般向けノートPCで実行するための C ベース推論エンジン
- モデルの常駐トランクだけをメモリに置き、トークンごとに有効化される約 4% のエキスパート重み を NVMe から読み込み、残りの RAM はサイズ制限付きのエキスパートキャッシュとして使う
- Kimi K3 は 4K コンテキストで最小 29.05GB RAM で開けるが、実用的な構成は 64GB MacBook Pro の 46GB 予算で、ここで 0.45〜0.62 tok/s を記録
- エキスパート読み込みと計算を重ねて約 1.6 倍改善し、次レイヤーのルーターを 1 residual 先行して実行することでキャッシュヒット率を 14% から 38% に高めつつ、総読み込み量とロジットは変えない
- インターネット接続・トークン単位課金・外部データ送信なしで超大型モデルをローカル実行できるが、内蔵 NVMe と約 1TB の保存領域が必要で、RAM 予算が 52GB を超えると OS のページングでむしろ急激に遅くなる可能性がある
WASTE の目標と実装形態
- WASTE(Weight-Aware Streaming Tensor Engine) は、ランタイムの外部依存がない埋め込み可能な C 推論エンジン
libwaste.aとwaste実行ファイルだけを使い、libc と pthreads 以外に BLAS、CUDA、ONNX、Python は不要- Python はモデル変換と PyTorch 基準検証にだけ使われ、推論経路には入らない
- 公開 API は 26 個の関数で構成され、モデルオープン、RAM 上限設定、生成、セッション保存、終了をサポート
- 現在の検証対象は Kimi K3 2.78T 全体モデル
- 公開された元データは 1.42TB、変換後コンテナは 982GiB
- 蒸留・枝刈り・縮小版ではない
- Kimi-Linear 48B も同じエンジンとフォーマットで、19GiB コンテナ、最小 1.87GB RAM、10.7 tok/s を記録
- プロジェクト名は、デスク上のハードウェアで動かせるモデルをクラウドデータセンターで回し、トークン課金と電力を同時に消費する状況を減らすという目標に由来する
ディスクストリーミング構造
- MoE 構造の K3 はトークンごとにモデルの約 4% だけが有効化 されるため、非活性の重みを RAM に常駐させず、必要な時点でアクセスできるよう配置する
.wasteコンテナは JSON マニフェスト、常駐トランク、レイヤー別エキスパートバンクで構成される- 各エキスパートレコードは 4KiB アラインメント
- gate・up・down 行列を隣接配置し、1 つのエキスパートをちょうど 1 回の
preadで読む - ページキャッシュは macOS の
F_NOCACHE、Linux のO_DIRECT、Windows のFILE_FLAG_NO_BUFFERINGで回避する
- ページキャッシュを回避しないと、RAM より小さいテスト用コンテナが OS キャッシュに入り、982GiB モデルでは再現されないヒット率を作ってしまう
- レコード読み込み時には magic、エキスパート ID、オフセット範囲を常に確認し、切り詰められたバンクや誤って結合されたバンクが誤った重みで応答しないようにする
- payload の
crc32検査は--verifyで有効化 - 検証コストは Kimi-Linear で約 5%、K3 で約 1% で、デフォルトは無効
- コピー・ダウンロードしたコンテナや信頼できないディスク上のコンテナは、一度検証することを推奨
- トランクとコードブックにはチェックサムがない
- payload の
先読みとルーター予測
- あるレイヤーのルーターが 16 個のエキスパート ID を決めると、各読み込みを別スレッドで要求し、計算は到着したデータから消費する
- 読み込みと計算の重なりで K3 は約 1.6 倍 改善
- 実行する処理とキャッシュ統計は機能有効化の前後で同じ
- 次レイヤーの実際の hidden state が作られる前に、常駐している次ルーターを現在の hidden state で実行し、エキスパート 6 個を先読みする
- 1 residual 先行の予測は rank 1 で 92%、上位 6 個で 81% の精度
- 実際のルーターが最終エキスパートを決定するため、出力は正確に維持される
- demand hit rate は 14% から 38% に上がり、総読み込みバイト数は変わらない
WASTE_LOOKAHEAD=0で無効化できる
- prefill に同じ手法を適用した実装は削除された
- decode レイヤーはキャッシュスロット 16 個を占有するが、chunk レイヤーは約 550 個を占有する
- 先読みしたレコードが使用前に追い出され、読み込み量は 6.9% 増え、時間は短縮しなかった
量子化と精度
- エキスパート重みは、8 次元ベクトルに対する 256 項目コードブック 3 段階の 残差ベクトル量子化 で保存され、重みあたり 3.00 ビットを使う
- 行列全体を復元せず、部分内積テーブルを作ったうえで、各行をテーブル参照 3 回と加算 2 回で処理する
- トランクは 4 ビットと 8 ビットを維持する
- モデルはエキスパートに対してだけ量子化認識学習されているため、3 ビットトランクでは出力が崩壊する
- キャッシュ予測は当たっていたがスループットも改善しなかったため削除された
- すべてのレイヤーは PyTorch 基準実装と比較される
- 最終ロジット差は
3.6e-06 - ビジョンタワーは独自基準と
2.3e-06 - latent KV キャッシュ変換は
1.2e-05レベルで同一のロジットを維持する
- 最終ロジット差は
RAM 予算と狭い性能帯
- K3 は 92 レイヤーでそれぞれ 16 個のエキスパートを使い、トークンあたり 17.0GB のワーキングセット を作る
- キャッシュがこのサイズより小さいと、あるトークンで保存したエキスパートが次トークン前に追い出され、ヒット率が 0% になる
- 64GB システムでの測定では、RAM を多く割り当てても常に速くなるわけではない
- 32GB 予算・3.32GB キャッシュ: ヒット率 0%、0.50 tok/s
- 46GB 予算・17.32GB キャッシュ: 既存ヒット率 17%、0.53〜0.55 tok/s
- 52GB 予算・23.32GB キャッシュ: 0.04〜0.15 tok/s で再現性なし
- 58GB 予算・29.32GB キャッシュ: 0.02〜0.03 tok/s
- ルーター lookahead は 46GB でヒット率を約 14% から 38% に上げるが、52GB 以上での崩壊はキャッシュミスではなく OS のページング が原因
- 58GB ではヒット率がさらに高くても 46GB より約 20 倍遅い
- 大きな予算でシステムをページング状態に陥らせると、その後 46GB 測定も 0.02 tok/s まで落ちることがある
- デフォルト予算は、物理 RAM の 7/8 未満で、トークンワーキングセット単位まで下げて選ぶ
- 64GB MacBook Pro では 46.24GB を使い、17.56GB をエキスパートキャッシュに割り当てる
- 明示した予算が最小値より小さい場合、スワップで続行せず起動を拒否する
- 128GB システムでは、トランクとワーキングセット 3 倍に相当する全推奨予算を使える
K3 の性能とハードウェア要件
- 測定システムは 64GB MacBook Pro M5 Pro と内蔵 SSD
- 4K コンテキスト最小 RAM: 29.05GB
- 32K: 30.54GB、128K: 35.63GB、1M: 83.21GB
- 常駐トランク: 27.28GB
- モデルロード: 20 秒
- decode: デフォルト予算で 0.45〜0.62 tok/s
- prefill: chunked 0.47 tok/s、逐次 0.29 tok/s
- 最小 29.05GB でモデルは開けるが、32GB システムは激しくページングする可能性があり、実際の推奨仕様は 64GB
- コールド状態ではトークンごとにエキスパート 17.0GB を読み込み、lookahead の 38% ヒット率では 10.5GB を読む
- 内蔵 SSD は 12.78GB/s、外付け USB エンクロージャは 0.94GB/s と測定された
- 1 トークンがエキスパート 17GB を読むため、外部ストレージでは同じ処理に約 13 秒かかる
- 元データのダウンロードは外付けディスクに置けるが、変換後コンテナは内蔵 NVMe に置く必要がある
- 変換コンテナ用に 982GiB、元 shard の staging 用に 1.42TB が必要で、staging 領域は変換後に解放できる
Attention とマルチモーダル処理
- K3 の attention は Kimi Delta Attention と gated multi-head latent attention を 3:1 で組み合わせる
- KDA は増加する KV キャッシュの代わりに固定サイズの recurrent state を保持する
- MLA は head ごとの key/value を展開せず、幅 512 の latent をキャッシュする
kv_b_projを query と output に吸収し、4K コンテキストキャッシュを 11.25GB から 0.21GB に削減- 従来比 53 倍削減
- 128K では展開レイアウトが 360GB、latent レイアウトが 7.2GB を要求する
- マルチモーダル経路は 4.01 億パラメータ、27 レイヤー、patch 14 の ViT をサポート
- 1024 patch 画像エンコードは 15.7 秒
- 896×896 画像はデフォルト設定で 256 個のシーケンス位置を占める
- 画像埋め込みも 92 個の MoE レイヤーを通るため、コストの大半はビジョンタワーより text prefill と同じ
vision.jsonのmax_patchesを半分にすると、プロンプト位置数も半分になる
- PNG、JPEG、GIF、BMP、TGA、PSD をサポートし、
run、chat、evalで画像を使える- 会話中にエンコード済み画像の位置は attention state に残り、次ターンで再エンコードしない
- ビジョンタワーは画像があるときだけロードされ、重み 434MB と全体予約メモリ 1.12GB を使う
変換、実行、サーバー
- ビルドには C11 コンパイラと
makeだけが必要make checkは実モデルなしで合成コンテナにより 23 件の検査に通過し、11 件をスキップする- 実コンテナ 2 つがあれば全検査は 36 件
- K3 変換では公開されている moonshotai/Kimi-K3 の safetensors shard 96 個をそのまま使う
- 3 プロセス基準で M5 Pro では約 4.7 時間かかる
- 純粋な PyTorch encoder は 23.7 時間かかる
- レイヤー単位で再開できるため、中断時は進行中だったレイヤーだけを再処理する
- downloader は部分ファイル再開、指数バックオフと jitter、
Content-Length確認、完了 shard 状態記録をサポートする
- CLI は
run、chat、eval、planなどを提供し、--jsonでeval、tokenize、plan、info、benchの結果を機械可読に出力する serve/は公開 C API を ctypes で呼び出す OpenAI 互換 HTTP サーバー/v1/chat/completions、/v1/completions、/v1/models、/healthを提供- ストリーミング、ツール定義・結果、typed call arguments、JSON 応答スキーマ、
tool_choice、think channel、thinking_effort、画像を処理する - プロンプトレンダラーは K3 リリースの
encoding_k3.pyを移植しており、重みディレクトリがあれば 38 個の会話を segment 単位で比較する
プラットフォームと現在の制約
- macOS arm64、Linux arm64、Linux x86_64 は同じモデル非依存テストで 23 pass・11 skip を記録し、sanitizer と fuzz 400 件にも通過した
- Windows x86_64 は MinGW-w64 でクロスコンパイルして合成コンテナ、CLI、forward pass を検証したが、実モデルコンテナでは実行していない
- MSVC と Windows ARM64 はサポートしない
- Windows のページキャッシュ回避は CI ファイルシステムでのみ確認され、RAM より大きい実コンテナ負荷では検証されていない
- x86 SIMD は CPUID に応じて AVX-512 または AVX2 を選ぶが、AVX-512 経路は実サポート CPU でまだ実行されていない
- Metal backend は正確だが、小さな依存 matvec が数百回発生するワークロード形状のため CPU より 22% 遅く、デフォルト無効
- API はまだ固定されておらず、chat format の自動変換は現状 K3 のみ対応
- Kimi-Linear はテンプレートを推測せず raw モードで実行する
- エキスパート別の不均一ビット割り当ては導入予定がない
- 3 ビット目の価値はレイヤー内エキスパート間で最大 1.15 倍、レイヤー間で 1.01 倍しか違わず、最適割り当ての利得がなかった
- routing frequency ベースの割り当ても保存容量は減らせるが、ボトルネックである I/O はほとんど減らせなかった
- ライセンスは Apache 2.0
1件のコメント
Hacker Newsのコメント
本当に素晴らしい。今すぐクラウド事業者より実用的になろうというプロジェクトではなく、可能性の境界を示すプロジェクトだと思う。
モデル効率の改善とローカル機器の性能向上がかみ合えば、いつか高品質なローカルモデルも経済的に運用できるようになるかもしれない。
毎秒0.5トークンは、長い作業には役に立たないと思う。むしろお金をかけて16GBの4060 Tiを2枚用意し、テンソル並列化を適用する。
20年後なら、太陽光で動き、芝刈りや歩道清掃の合間に働くサイバーパンク風の低速ロボット、あるいは庭で盆栽の成長速度に辛うじて追いつきながら剪定するロボットに向いていそうだ。
トークン料金を支払い、推論事業者が電気代を負担するのが無駄だというが、キュウリを買えば農家が水や肥料の費用を負担しているのと何が違うのか分からない。LLMが後付けした理屈であってほしい。
アイデア自体は興味深く、より小さいモデルで試してみたい。毎秒0.5トークンを生成しながらSSDから毎秒数GBを読むなら、一般消費者向けノートPCには依然として大きすぎるが、250〜500GiBモデルを対象にする場合にはむしろ実用的かもしれない。
42Wを継続的に使い、電気料金がkWhあたり20セントだと仮定すると、100万トークンあたり約5ドルで、ハードウェアを含むその他の費用は除いた値になる。
標準のllama.cppでもGGUFを
mmapできるので、メモリに入らない部分はディスクに残り、カーネルのページキャッシュが頻繁に使う部分である常駐トランクを維持してくれる。あえて独自実装する利点が何なのか気になる。mmapを試したうえで直接実装し、10倍速くなったと言っていた。データベースエンジンが独自キャッシュを実装する理由と同じだ。カーネルのページングは汎用・要求ベースだが、実際のアクセスパターンが分かれば必要なデータを先読みしてパイプライン化できる。
すべてRAMに収まるモデルなら、llama-serverは
--no-mmapで実行するほうがよかった。もちろんKimi K3全体と100万トークンのコンテキストを載せるには2TBサーバーが必要だ。READMEがLLMの書いたものだという印象を強く受けるが、コードベースもLLMが書いたのか気になる。
今ではLLMとエージェントを調整するのに自分のスキルを活用し、より良いコードをはるかに速く書いている。開発者は新しい技術に適応するか、取り残されるかのどちらかを選ばなければならない。
ユーザーには重要だが完成品を見る読者には関係のない内部判断や、Claude特有の分かりにくい用語がそのまま入っている。LLMを頻繁に使っており、複雑なコードを書くのに非常に有用だという点は認めるが、文章の初稿品質はひどい。
claudeがいるので、推測する必要もない。Claudeにコミットまで任せるほどなら、コードを自分でレビューした可能性も低そうだ。作業に合ったモデルを正確に選べるほど技術が進歩すれば、価値は大きくなり得る。自動探索の過程で1日30分ほどだけ大きなモデルを動かし、残りの時間は小型モデルを使う未来を想像できる。