モデル別実行レシピ

MLX-LMで3Bモデルを実行して速度を読む:初回ロード、プリフィル、デコード、KVキャッシュ

初回のダウンロードとモデル読み込み、長い入力の処理、回答生成はそれぞれ別の待ち時間です。同じ条件で分けて記録しましょう。

MLX-LM1公式リポジトリがデフォルトとして指定するmlx-community/Llama-3.2-3B-Instruct-4bitを、Apple Silicon Macの仮想Python環境で実行します。3B・4ビットはドキュメントにある開始モデルであり、すべてのMacで収まる保証ではありません。初回ダウンロードとモデル読み込み、長いプロンプトを処理するプリフィル2、トークン3を生成するデコード4、会話が続くにつれて増えるKVキャッシュ5を分けて確認します。モデル、プロンプト、出力上限を固定し、コールドスタートとウォームセッションを分けて記録してください。

実行条件と要点
  • mlx-community/Llama-3.2-3B-Instruct-4bitは、MLX-LMリポジトリがデフォルトに指定する実在のモデルIDです。3B・4ビットという表記は、すべてのメモリー構成で動くことを意味しません。
  • プロンプトを読むプリフィルと回答を生成するデコード、初回実行と同じセッション内の後続質問を分けて記録します。
  • KVキャッシュや開いているアプリも統合メモリを使います。長いコンテキストやキャッシュ上限は、回答品質とメモリー使用量の両方に影響します。

初回実行が遅ければ、モデル自体が遅いのでしょうか?

Apple Silicon Macでモデルを初めて実行すると、ファイルのダウンロード、重みの読み込み、入力処理、回答生成が続けて行われます。この全過程がひとつの待ち時間に見えると、どこに時間がかかったのか分かりません。モデルを起動したまま次の質問をすれば、ダウンロード済みのファイルと実行中のプロセスを再利用できます。そのため、初回の待ち時間と会話中の次の回答速度は分けて考えます。

この記事では、MLX-LM公式リポジトリがデフォルトとして案内するmlx-community/Llama-3.2-3B-Instruct-4bitを使います。モデルカードと設定ファイルでは、Llama 3.2 3B Instruct構造と4ビット量子化6設定を確認できます。このモデルIDは、公式ドキュメントに掲載された実行例を再現する際に使えます。この例で得られる動作結果は他のモデル全体の性能を示すものではなく、大きなモデルや別アーキテクチャには個別の確認が必要です。

コマンド内の英語プロンプトは、インストールと基本的な生成が動くか確認するためのものです。韓国語の回答品質を評価する試験ではないため、実際に使う言語と資料で別途確認してください。

まず互換性のある独立した実行環境を作ります

MLX-LMはPythonパッケージです。プロジェクトごとの仮想環境7にインストールすると、他のPython作業と分けて管理できます。次のコマンドは環境を作成し、公式パッケージをインストールして、短い入力で基本的な生成を確認する手順です。導入に失敗したら、最新の公式案内と使用環境を確認してください。

MLX8の現行公式インストールガイドは、Apple Silicon、ARMネイティブのPython 3.10以降、macOS 14.0以降を要件としています。Rosetta経由でIntel用プロセスとして動くPythonはネイティブ環境ではないため、パッケージが見つからない場合はPythonのアーキテクチャも確認してください。

コマンドの--max-tokens 128は、生成する回答トークンの上限です。プロンプトを含むコンテキスト上限を128にする意味ではありません。この値を変えると許可する回答の長さと生成時間も変わるため、最初の比較では固定します。コマンド終了後に同じコマンドを再実行すると、新しいプロセスが始まります。モデルを読み込んだままのセッションで追加質問を観察するには、mlx_lm.chatを起動し、同じプロセス内で質問してください。

仮想環境にMLX-LMを導入して最初の回答を生成
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install mlx-lm
mlx_lm.generate --model mlx-community/Llama-3.2-3B-Instruct-4bit --prompt "Explain why prompt length affects generation time in two sentences." --max-tokens 128
公式のデフォルトモデルIDを使い、まず短い回答を確認します。

3B・4ビットは開始用の規模であり、メモリー保証ではありません

モデル名の3Bはおおよそのパラメーター規模、4bitは重みを表す精度設定を示します。量子化は重みに必要なメモリーを減らせますが、実行時にはモデルのメタデータや一時的な計算領域も必要です。回答を生成するとKVキャッシュが加わり、入力が長いほどプリフィル中にも余裕が必要になる場合があります。ファイルをダウンロードするディスク容量と、実行中に使う統合メモリは別の資源です。

このモデルを「3Bだから8GBのMacで動く」といった規則にしないでください。統合メモリの容量やmacOSが使う量はMacごとに異なり、ブラウザー、開発ツール、ビデオ会議アプリなどもメモリを使います。実行前にアクティビティモニタでメモリー圧力と起動中のアプリを確認し、必要なデータを保存してから短いプロンプトで始めましょう。メモリー圧力が高いままになったりアプリが止まったりしたら、コンテキストを短くし、他のアプリを閉じて再確認します。クラッシュした場合は同じ条件で繰り返さず、先に空きメモリーを増やすか、より小さく互換性のあるモデルに切り替えてください。

木のブロックの山、厚くなるノート、電話が一つの木製トレーの周りに置かれています。
重みに加えて、コンテキストや他のアプリも統合メモリを使います。

入力を読む時間と回答を生成する時間は別です

モデルはまずプロンプトをトークン単位で読み、内部表現を計算します。この入力処理の段階をプリフィルと呼びます。短い質問より長い文書の要約でプリフィルに時間がかかることがあるのはこのためです。その後、モデルが出力トークンを一つずつ生成するデコード段階に進みます。文書が長いと最初のトークンまで待つことがあり、長い回答を求めると生成が長く続きます。どちらも「応答が遅い」と感じますが、原因と調整する設定は異なります。

繰り返し試すときは、モデル、プロンプト、出力上限を同じにします。最初の実行はファイルのダウンロードとモデル読み込みを含むコールドスタートとして別に記録します。続いて、モデルが起動したままの同じmlx_lm.chatセッションで最初の質問と追加の質問を観察すると、プロセス再起動の待ち時間とセッション中の処理を分けられます。ただし追加の質問には前の会話コンテキストが含まれる場合があり、入力長が異なれば同じプリフィル試験ではありません。新しいセッションと継続中のセッションの値を同じ欄に混ぜないでください。

生成中にプロンプト処理速度と生成速度が表示される場合は、それぞれ入力トークンと出力トークンの単位で記録します。速度の数値だけでなく、モデルを新たに読み込んだか、入力の長さ、出力上限、開いていたアプリも記録してください。後で同じ条件を再現できるよう、MLX-LMの版、macOS、Macのチップとメモリー構成も残します。公開ベンチマークと比べる前に、モデルID、量子化、入力長、測定区間が同じか確認してください。

ノートパソコンと紙の配置が三つの机の場面で続き、最初は閉じていて後の場面では開いています。
モデルの読み込み、入力処理、トークン生成を分けて考えます。

コンテキストとKVキャッシュでメモリーの選択が変わります

同じモデルでも、会話が長くなると過去のトークンのキーとバリュー情報を保存するKVキャッシュが増えることがあります。短い質問で成功したからといって、長い文書をいくつも入れても同じメモリー余裕が残るとは限りません。出力の長さも重要です。長い回答を許すと生成トークンが増え続け、キャッシュと処理時間も増えます。まず短い入力と短い出力で始め、必要に応じて条件を一つずつ増やし、どの段階で圧力が高まるか確認してください。

MLX-LMの--prefill-step-sizeは長いプロンプトを処理するまとまりの大きさを、--max-kv-sizeは対応するキャッシュ構成の上限を調整します。公式ドキュメントによると、プリフィルのまとまりを小さくすると入力処理中のピークメモリーを抑えられる一方、処理速度が落ちることがあります。回転型KVキャッシュの上限を小さくするとRAM9使用量を減らせますが、古いコンテキストを保持できず回答品質に影響する場合があります。次の値はオプションの使い方を示す例であり、すべてのMacやモデルへの一律の推奨値ではありません。

設定を比べるときは、二つの値を同時に変えないでください。まず--prefill-step-sizeだけを調整し、プリフィル時間とメモリー圧力を確認します。元の設定に戻してから--max-kv-sizeを個別に変更し、同じ質問でコンテキスト保持と回答品質を比べます。これらは自動的に有効にする速度ボタンではなく、メモリー、処理時間、コンテキスト保持のトレードオフです。

長い会話を保つ必要があるなら、キャッシュを制限する前に短い入力で基準を作り、同じ質問で回答品質を比べてください。回答が短く途切れたり、以前の指示を忘れたりしても、速度が向上した証拠ではありません。必要なコンテキスト長や品質を満たせなくなったら、キャッシュ上限を元に戻し、より小さなモデルか、メモリーに余裕のある機器を検討してください。

オプションを示すコマンド例
mlx_lm.generate --model mlx-community/Llama-3.2-3B-Instruct-4bit --prompt "Summarize this short note." --max-tokens 128 --prefill-step-size 512 --max-kv-size 4096

自分の作業に合う速度かどう判断すればよいでしょうか?

一回の総実行時間より、実際によく経験する待ち時間を基準に考えましょう。アプリを閉じたりコンピューターを再起動したりしてモデルプロセスを頻繁に起動し直す人は、重みの再読み込みを何度も待ちます。モデルを一つのセッションで起動したまま何度も質問する人は、追加質問のプリフィルとデコードをより頻繁に体感します。長い報告書から一、二文の回答を求める作業と、短い質問から長い草稿を求める作業でも、時間を使う段階は異なります。一つの平均速度ではすべてを説明できません。

可能ならウォームアップ後に同じ条件で3回実行し、中央値を使います。1回だけ極端に速かったり遅かったりした結果の影響を抑えるためです。コールドスタート、ウォームセッション、プリフィル、デコード、ピークメモリーを分け、モデル、入力、出力上限、版、他に開いていたアプリも記録すると、設定を変えた後に同じ条件で比較し直せます。

この例では、MLX-LM公式の3B・4ビットチェックポイント10で短い対話を最後まで実行します。メモリー圧力が安定していれば、実際の文脈長11または出力長を一度に一つずつ増やし、その都度、回答品質とメモリー状態を確認してください。短い試行でもメモリー不足になる場合や必要なモデルが未対応なら、そこで止めて、より小さな対応モデルか別のエンジンを選びます。速度を比べる際は、同じ入力で初回ロード、セッション中の次の応答、メモリーの余裕を分けて記録します。その結果から、自分の作業に耐えられる構成か判断できます。

空欄の罫線があるノートの横に、同じ大きさのカード3枚と複数の小さなトレーが整然と並んでいます。
モデルと入力を固定し、待ち時間を分けて繰り返します。

用語の注釈

  1. MLX-LM — MLXを使い、言語モデルの読み込み・推論・微調整を行うパッケージです。MLXフレームワーク本体や、MLXを使うすべてのアプリを指す言葉ではありません。

    本文に戻る
  2. プリフィル — LLMが入力プロンプトを読み、各トークンの内部表現を計算する段階です。プロンプトが長いほど処理するトークンが増えます。

    本文に戻る
  3. トークン — モデルが入力や出力を分けて処理する単位です。1トークンが1文字や一定の時間に相当するわけではありません。

    本文に戻る
  4. デコード — LLMでは入力処理後に出力トークンを生成する段階です。VAEやオーディオコーデックでは、圧縮表現や符号化データから元の形式を復元する処理を指すことがあります。

    本文に戻る
  5. KVキャッシュ — 過去トークンのAttention用キー・バリューを保存し、後続トークン生成で再利用するメモリです。容量はコンテキスト長やバッチサイズで変わります。

    本文に戻る
  6. 量子化 — モデルの数値を少ないビット数で表す方法です。メモリ使用量のほか、精度や実行速度も変わることがあり、影響は形式と実装によります。

    本文に戻る
  7. Python仮想環境 — プロジェクトごとにPythonパッケージを分けて導入する環境です。版の衝突を減らすもので、仮想マシンとは異なります。

    本文に戻る
  8. MLX — Appleが開発する機械学習フレームワークです。Apple siliconでは統合メモリとMetalを活用し、別途Linux向けの実行経路も提供します。対応モデルや機能はMLXを使うツールごとに異なります。

    本文に戻る
  9. システムRAM — プログラムの実行中にデータを一時保存するシステムメモリです。ストレージや独立GPUのVRAMとは異なります。

    本文に戻る
  10. チェックポイント — 学習済みモデルの重みなどを保存したファイルです。同じモデル系列でも、版や用途によって異なるチェックポイントを使うことがあります。

    本文に戻る
  11. コンテキスト長 — 1回のリクエストでモデルが扱える入力と生成内容のトークン範囲です。上限や実際のメモリ使用量はモデルと実行設定によります。

    本文に戻る