自分の PC(Mac) に入れるならどっち?oMLX と TensorFold の違いを見る

メディア統括本部 サービスリライアビリティグループ(SRG)の長谷川(@rarirureluis)です。
#SRG(Service Reliability Group)は、主に弊社メディアサービスのインフラを横断的にサポートし、既存サービスの改善や新規サービスの立ち上げ、OSS への貢献などを行うグループです。
Mac でLLM への同時リクエストを処理する推論サーバーとして、oMLX とTensorFold を比較しました。
TensorFold 0.6.2 を紹介する第三者レビューでは、oMLX が同時リクエストを1 件ずつ処理したのに対し、TensorFold は8 件すべての初回トークンを1.6 秒以内に返して高速だったと報告されていました。
今回は TensorFold の対応モデルである NVIDIA-Nemotron-3.5-Lightning-30B-A3B-MLX-4bit を用い、Mac(M4 Max・64 GiB メモリ)で両サーバーに同じ MTP 重みを読み込ませる構成へ全面的に差し替えて測定しました。
測定の結果、短い入力 8 件同時ではTensorFold が約1.16 倍(+16.4%)高速でしたが、oMLX も全リクエストの生成を並行して進めており、「oMLX が直列で TensorFold が並列だから速い」という単純な構図ではありませんでした。また、複数件で動作したMTP の下書き採用数は全体のごく一部にとどまり、MTP 単独でこの速度差を説明することも困難でした。
本記事では、測定結果を整理した上で、推論生成コストの構造と、短い入力・長い入力それぞれでコストを減らす実装設計をコードから確認します。

測定結果の全体像


同一の Nemotron 3.5 Lightning(MLX 4-bit)モデルおよび MTP 重みを用い、サーバーを単独で順次起動して各条件を 3 回測定した中央値の結果です。全体の処理速度は で計算しています。初回トークン時間の範囲は、各試行の最小値と最大値をそれぞれ中央値にしたものです。
同時処理数・入力長項目oMLX 0.7.0TensorFold 0.6.4
短い入力 1 件初回トークン時間(TTFT)0.48 秒0.30 秒
短い入力 1 件完了時間2.56 秒2.51 秒
短い入力 1 件全体の処理速度100.1 tok/s101.8 tok/s
短い入力 3 件初回トークン時間(TTFT)0.94〜1.62 秒0.36〜1.33 秒
短い入力 3 件全件の完了時間5.64 秒4.93 秒
短い入力 3 件全体の処理速度136.2 tok/s155.7 tok/s
短い入力 8 件初回トークン時間(TTFT)0.90〜4.56 秒0.34〜3.40 秒
短い入力 8 件全件の完了時間13.00 秒11.16 秒
短い入力 8 件全体の処理速度157.6 tok/s183.4 tok/s
長い入力 1 件初回トークン時間(TTFT)5.57 秒4.72 秒
長い入力 1 件完了時間7.48 秒6.56 秒
長い入力 1 件全体の処理速度34.2 tok/s39.0 tok/s
長い入力 3 件初回トークン時間(TTFT)6.23〜19.96 秒4.85〜18.45 秒
長い入力 3 件全件の完了時間23.32 秒20.61 秒
長い入力 3 件全体の処理速度32.9 tok/s37.3 tok/s
※入力長:短い入力は270〜276 トークン、長い入力は5,337〜5,340 トークン。各リクエスト256 トークン生成。

同時バッチ処理のタイムライン


各サーバーで全件完了時間が中央値となった試行について、全件で最初の送信を原点とした各リクエストのタイムライン(初回トークン返答時刻と完了時刻)を比較します。
順番oMLX 初回oMLX 完了TensorFold 初回TensorFold 完了
10.92 秒11.63 秒0.34 秒10.39 秒
20.93 秒11.63 秒0.82 秒10.67 秒
31.54 秒12.11 秒1.29 秒10.93 秒
42.14 秒12.48 秒1.75 秒10.97 秒
52.74 秒12.67 秒2.15 秒11.01 秒
63.33 秒12.84 秒3.31 秒11.16 秒
73.94 秒12.94 秒3.33 秒11.12 秒
84.56 秒13.00 秒3.40 秒11.13 秒
oMLX でも8 件すべての初回トークン(最長4.56 秒)は、1 件目のリクエストが完了する時刻(11.63 秒)より前に返答を開始しています。したがって、oMLX も複数リクエストをまとめるバッチ処理を行っており、生成トークンは並行して出力されています。
ただし、各リクエストがバッチに合流するまでの時間は TensorFold の最長 3.40 秒に対し、oMLX は4.56 秒(1.16 秒差)でした。TensorFold の方が先に合流を完了しており、最後の合流時点で各リクエストに残された生成トークン数も異なるため、初回トークン以降の時間をそのまま純粋な decode 速度として比較することはできません。

測定環境と測定方法


測定の再現性を確保するため、ハードウェア、モデル、運用条件を整理しました。

ハードウェアおよびソフトウェア構成

測定日は2026 年10 月5 日、検証機は MacBook Pro, Apple M4 Max, 40 コアGPU, 64 GiB 統合メモリ, macOS 26.7 です。
同一マシン・同一OS ですが、ランタイム構成は異なります。oMLX はバージョン 0.7.0(Python 3.11.17, MLX 0.32.2, mlx-lm 0.31.4.dev132+g94cdcae13, mlx-vlm 0.7.1, commit )を使用しました。
TensorFold はバージョン0.6.4(Python 3.12.12, MLX 0.32.3, mlx-lm 0.32.0, commit )を用いています。

使用モデルとアーキテクチャ

使用したモデルは、Hugging Face で配布されている(revision )です。
総パラメータ数 30B のうちトークンごとに約 3B が動作する MoE 構造を持ち、Mamba-2、Attention、MoE(専門の小ネットワークExpert 128 個中6 個を選択)を組み合わせた52 層のハイブリッド構成()を採用しています。重みは 4-bit affine(group size 64)で量子化されており、本体重みは 17.78 GB、MTP 重みは0.75 GB という構成です。

oMLX 向けMTP 重みの準備

配布状態のMTP 重みは という別ファイルに格納され、キー名にはプレフィックスがありません。TensorFold はこの配置をそのまま読み込みますが、oMLX のNemotron MTP 実装はのようなプレフィックス付きのキーを要求します。
そこで、oMLX 用のディレクトリに を生成し、全34 個のMTP キーにプレフィックスを付与してindex ファイルへ登録しました。
変換前後でテンソル本体のペイロードSHA-256 は完全に一致しており()、量子化やテンソルの形状(shape)は変更していません。oMLX 側でもMTP モジュールへの strict load に成功し、生成時の MTP 利用を確認した上で測定しています。両エンジンともソースコードの独自変更は行っていません。

確定1トークンあたりの概念的コスト


推論処理におけるコスト構造を整理します。

Prefill とDecode の二段階

LLM へのリクエスト処理は大きく2 つの段階に分かれます。
第一の段階である Prefill(プロンプト処理フェーズ)は、入力されたプロンプト全体のトークン列を並列に計算し、KV キャッシュ(Attention 層)および過去を保持する内部状態である SSM 状態(Mamba 層)を構築して最初の1 トークンを出力する処理です。Self-Attention の計算量を含むため、計算量は入力長に対して非線形に増加します。
第二の段階である Decode(トークン生成フェーズ)では、直前のトークンを入力として次の1 トークンを逐次生成する処理を繰り返します。直前トークンに依存する逐次性を持ち、モデルの重み(MoE では選択された Expert と共有 Expert、Attention、Mamba パラメータ)や状態(KV キャッシュ・SSM 状態)の読み書き、およびホストCPU からのディスパッチオーバーヘッド(launch overhead)が1 ステップごとに発生します。

投機的デコードにおけるコスト式

MTP をはじめとする投機的デコードでは、追加ヘッドが先々の候補トークン列を下書き(draft)し、本体モデルがそれらの候補を1 回のforward パスでまとめて検証(verify)します。greedy サンプリング()の条件下では、下書き候補列の先頭から本体モデルのargmax 予測と一致するプレフィックスのみが採用され、不一致となった地点以降は破棄されて本体の予測トークンで訂正されます。
1 確定トークンあたりに消費される概念的な時間コストは、次のように整理できます。
  • : 本体モデル(ターゲットモデル)による計算・検証時間
  • : MTP ヘッドによる下書き生成時間
  • : キャッシュや状態の更新・巻き戻し時間
  • : ホストCPU からのディスパッチや制御オーバーヘッド
  • : そのステップで本体モデルにより確定したトークンの総数(下書き採用トークン、訂正トークン、ボーナストークンを含む)
※ GPU とCPU は非同期に並行して動作するため、分子の単純な加算は厳密な実測式ではなく、概念的な内訳の整理です。または投機的採用数()そのものとは区別されます。
複数リクエストを束ねるバッチ処理において、デコード中の1 回の計算単位における処理レートは次の通りです。
このラウンドレートはデコード中の処理速度であり、Prefill 時間や合流待ち時間を含むエンドツーエンドの全体処理速度とは異なります。
ここで留意すべき点として、MTP 重みを読み込んでいても同時処理で機能するとは限らない点(oMLX は今回の Nemotron 経路において2 件以上の同時リクエストで停止)、そして下書き採用率が高くても下書きや検証のオーバーヘッド()が節約時間を上回ればスループットは向上しない点が挙げられます。

短い入力で何が起きていたか


短い入力(270〜276 トークン)の 8 件同時処理において、TensorFold は 183.4 tok/s を記録し、oMLX(157.6 tok/s)に対して約1.16 倍高速でした。この差をもたらした実装要因を検証します。

下書きを無効にした結果

oMLX 0.7.0 のログを確認したところ、単独リクエストの本測定3 回では1 サイクルあたり1.77〜1.80 トークン、下書き採用率75.2〜78.9%でMTP が動作していました(※ウォームアップ試行で記録された1.75 や1.78 とは区別して本測定のみを集計)。しかし、Nemotron で 2 件以上の同時リクエストを受け付けると、次のログを出力してMTP を直ちに停止し、通常のバッチ生成へ切り替えていました。
一方の TensorFold は、8 件同時処理時でもMTP による下書き処理を継続していました。この効果を確認するため、TensorFold に同一の48 リクエストを(投機的デコード無効)で送信する対照測定を実施しました。
入力長・同時処理数下書き有効の全件完了時間下書き無効(no-drafts)の全件完了時間下書き有効化の倍率
短い入力 1 件2.51 秒2.49 秒0.99 倍(差なし)
短い入力 3 件4.93 秒5.58 秒約1.13 倍
短い入力 8 件11.16 秒12.48 秒約1.12 倍
長い入力 1 件6.56 秒7.11 秒約1.08 倍
長い入力 3 件20.61 秒22.24 秒約1.08 倍
対照測定の結果、短い入力8 件同時において下書きを無効にしたTensorFold の完了時間は12.48 秒でした。これはoMLX の13.00 秒と比較しても約1.04 倍高速です。
測定ログに残された実際の下書き採用数を見ると、短い入力8 件同時の3 試行(計24 リクエスト、生成総数6,144 トークン)において、TensorFold が採用した下書きトークン数は合計で66 トークンでした。
提示された下書き182 トークンに対する採用率は36.3%(66/182)ですが、生成トークン全体(6,144 トークン)に占める下書き採用分はわずか1.07%にとどまります(tokens per round は1.004〜1.045)。各リクエストの採用数は0〜10 個の範囲でした。
短い入力 3 件同時でも生成全体に占める採用分は 32 / 2,304 トークン(1.39%)でした。
単独処理時の TensorFold では256 トークン中70〜72 トークンの下書きが採用され(合計213 / 768 トークン、tokens per round は1.384〜1.399)、1 ラウンドあたり約1.4 トークン進んでいたのに対し、8 件同時処理では採用数が大幅に減少しています。 なお、oMLX の単独時における 1.77〜1.80 tok/cycle は MTP 動作区間のみを対象としたサイクルあたりの値であり、TensorFold の tokens per round は通常生成ラウンドを含むリクエスト全体を分母としているため、両者の数値をそのまま直接比較することはできません。
また、測定順序は非交互であり、TensorFold の はMTP ヘッドによる下書きだけでなく文脈コピー(context copies)による下書きも同時に無効化します。したがって、「1.12倍がMTPの効果で、1.04倍がカーネルの効果」のように機械的に掛け算して内訳を配分することはできません。
生成全体に占める採用分が 1.07%という少なさから見て MTP 単独で16.4%差の主因を説明することは困難ですが、下書きに伴う本体ステップ数や検証時間の重なりは複雑であり、各要因の寄与率を完全に切り分ける測定までは行っていないため、厳密な内訳は未測定です。

下書き深さと共有行配分の決定

なぜ TensorFold の8 件同時処理では、下書きの提示自体が182 トークンと少なかったのでしょうか。
この挙動の背景には、TensorFold のスケジューラー()における単独実行時の深さ決定と、共有ラウンドでの行配分処理の違いがあります。
単独ストリームの深さ決定処理()では、過去の受容率履歴と単独ラウンドコストに基づき、単位コストあたりの期待トークン数()を最大化する深さ(1 以上)を求めます。
一方、複数ストリームが同時に稼働する共有ラウンドでは、行配分処理()が全体の共有行コストと各ストリームの採択確率を評価して配分を決めます。このとき、本体の通常生成に必要な1 行は残したまま、追加の下書きに割り当てる行数が0()になると、その下書き候補を切り落とす()仕組みになっています。
提示された下書き自体が 182 トークンと少なく採用が 66 トークンにとどまったことについては、起動時に測定された共有行幅ごとの所要時間比を使うコスト評価や、この による候補の切り落としが関係する有力な候補と考えられます。ただし、各ラウンドで実際に選択された深さや配分の推移はログに未記録のため、下書き候補の切り落としが頻繁に発生したと実測から断定することはできません。
なお、複数ストリームの進行制御処理()では、各ストリームの進行を同期させながら、複数リクエストをまとめる を呼び出して一括計算を行っています。

TensorFold: 1 ラウンドのコストを減らす設計

MTP による寄与が限定的であるとすれば、何が速度差を生んだのでしょうか。
TensorFold のソースコードから確認できる設計上の特徴を整理します。
残差加算と正規化の融合カーネル( / )では、残差加算とレイヤー正規化(RMSNorm)を単一のMetal カーネル内でまとめて実行します。カーネル内部の実装を確認すると、残差加算結果()と正規化出力()は両方ともメモリへ書き込まれます。しかし、加算結果をカーネル内のレジスタに保持して正規化計算にもそのまま使うため、別個のカーネルとして実行した場合に発生する「残差をメモリから再読み出しする工程」とカーネル起動を省くことができます。保存そのものは残るものの、中間テンソルの不要な再読み出しを抑制する設計です。
また、Apple Silicon 向けに行単位の演算を行う4-bit row カーネル()を備えています
💡
Apple M4 には M5 で導入された Tensor Unit は搭載されていません。そのためM1〜M4 環境ではテンソルユニット依存の処理を避け、スレッドグループ単位で行の独立性を保つrow カーネルが選択されます。
MoE ブロックでは、ルーティング集約処理()とグループ化実行()において、バッチ内の複数ストリームから同一の Expert を選択したトークンを行単位で集約します( はグループ化カーネルのタイリング条件)。
複数ストリームのトークンで同一 Expert が選ばれた場合、重みを再利用してメモリ帯域消費を抑える余地を作る設計です。ただし、各行のペア読み出しはモデル固有の厳密なビット列を維持するものの、単一の共有ラウンド(8 ストリーム)内で実際にどれだけの割合で重みが再利用されたかという実効再利用度自体は今回のベンチマークでは計測していません。
Mamba-2 層においては、走査処理()とストリーム単位の管理()により、各ストリームの SSM 状態を個別に保持します。下書きトークンが棄却された場合でも、状態復元処理()によって採用されたプレフィックス長までの状態を安全に保持し、他リクエストと混ざることなくロールバックできる設計です。
バックボーンの decode 用キャッシュと MTP ヘッド用キャッシュを分離して管理し、本体とヘッドの状態を区別して保持する設計となっています。
なお、全 52 層が単一カーネルで動くわけでも、CPU オーバーヘッドがゼロなわけでもなく、カーネル呼び出し回数や中間テンソルの不要な再読み出しを抑えることを意図した設計です。

長い入力で何が起きていたか


入力が約 5,340 トークンに達する長い入力の測定結果です。
  • 長い入力 1 件:oMLX 7.48 秒 vs TensorFold 6.56 秒(約1.14 倍)
  • 長い入力 3 件:oMLX 23.32 秒(32.9 tok/s) vs TensorFold 20.61 秒(37.3 tok/s、約1.13 倍)
3 件同時処理において TensorFold はoMLX より約2.7 秒早く完了していますが、この理由は3 件のリクエストを同時に並列生成したからではありません。

単一リクエスト内の Prefill Chunk バッチ処理

第一に、長いプロンプトに対する単一リクエスト内での Prefill 効率が挙げられます。
TensorFold では、M1〜M4 プロセッサ向けに プロパティが有効化されます。長いプロンプトをチャンク単位で読み込む際、チャンク投入処理()により、連続する複数チャンクを1 回のforward パスにまとめて投入します。
この際、Linear、Mamba、Attention 層は各チャンクの境界を独立して保持しますが、MoE 層の計算では を用い、同一リクエスト内の複数チャンクにまたがる Expert 計算を一括実行します。
実測時のランタイム記録でも、TensorFold の長い入力における全試行(native/no-drafts、単独/3 件同時問わず)で、が記録されていました。
ただし各チャンクの具体的なトークン数はログからは特定できず、また が処理する3 チャンクは単一リクエスト内の連続チャンクであって、3 件のクライアントリクエストを並列処理したものではありません。この単一リクエスト内でのチャンクバッチ化による Prefill 効率化が、長い入力1 件におけるTTFT(4.72 秒 vs 5.57 秒)および完了時間の差を生んだ有力な候補と考えられます。

観測された出力区間は重ならなかった

第二の特徴は、TensorFold におけるメモリ受付制御(admission control)と、それに伴う直列的な完了挙動です。
長い入力 3 件同時処理における各リクエストのタイムラインを確認すると、出力の進行状況が分かります。
初回の順番oMLX 初回 / 完了TensorFold 初回 / 完了
16.41 秒 / 17.03 秒4.57 秒 / 6.51 秒
219.39 秒 / 22.96 秒11.40 秒 / 13.50 秒
319.99 秒 / 23.32 秒18.31 秒 / 20.61 秒
TensorFold では、1 件目のリクエストが 6.51 秒で完了した後に 2 件目の初回トークンが 11.40 秒に返り、2 件目が 13.50 秒で完了した後に 3 件目が返答を開始しています。つまり、観測された出力区間は重なっていませんでした。
なぜこのような挙動になったのでしょうか。TensorFold の起動ログには次の記録がありました。
TensorFold のコード上、 や、あるいは / によるプロンプト待機ロジックが存在します。指定されたメモリ上限 51.8 GiB からプロセス予約用の 3 GiB を引いた 48.8 GiB を MLX バッファ上限とする一方、他プロセスの使用量(24.1 GiB)を差し引いた を受付予算として管理しています。
8 ストリーム共有ラウンドのワークスペースが最大7.22 GiB を占有し、5,300 トークン級のキャッシュを保持するリクエストが複数重なると予算を超過するリスクがあるため待機させる設計です。
ただし、個別の待機理由はログに未記録のため、具体的な分岐を特定することはできません。
これに対し、oMLX は1 件目の生成を行っている最中に後続プロンプトの Prefill を並行開始しました。prefill と decode が同じ GPU を使うため、decode の合間に新しいプロンプトの読み込みが入れば生成へ割り当てられる時間が減ります。実測でも1 件目の完了が単独時の7.48 秒から17.03 秒へと遅れました。
なお、出力が直列に完了したことは Prefill 計算が完全に直列だったことの直接の証明ではありません。しかし、TensorFold が長い入力においてoMLX よりも早く全件を完了できた要因が「3件の並列 decode」によるものではないことは実測タイムラインから分かります。

出力の一致性の検証


推論サーバーの再現性を確認するため、greedy サンプリング()の条件下で、同じ入力に対して同一のトークン列が出力されるかを検証しました。
英文 4 文ずつ 8 種類(max_tokens=128)を用い、単独実行時と同時処理時で出力の一致を比較した結果です。
比較対象oMLX 0.7.0TensorFold 0.6.4
単独で2 回送った返答同士8/8 一致8/8 一致
3 件同時と単独の比較(5 試行×3 入力=15 回)8/15 一致(7 回不一致)15/15 一致
8 件同時と単独の比較(3 試行×8 入力=24 回)9/24 一致(15 回不一致)24/24 一致
同時処理の合計一致率17/39 一致(22 回不一致)39/39 一致
oMLX はAPI レスポンスに token ID 列を含まないため、出力文字列と生成トークン数を比較しました。
TensorFold は文字列とトークン数に加え、token ID 列のハッシュ値も比較しています。
oMLX では同時処理39 回中22 回で出力に不一致が発生しました(単独時では「宽大窗户」だった出力が同時処理時では「宽敞窗户」に変わるなど)。同時処理によってバッチ形状が変わり、さらに Nemotron では MTP の有効・無効状態が切り替わるため、これらの変化が出力の揺らぎを引き起こしたと考えられます。
対照的に、TensorFold は同時処理を行った39 回すべてのリクエストにおいて、文字列、生成トークン数、token ID 列ハッシュが単独実行時と一致しました。
また、TensorFold リポジトリ付属の検証スクリプト()を用いた追加自己テストにおいても、コード生成とチャット文脈のそれぞれで greedy 1 入力、sampled 8 入力、計 18 入力を含む 96 回の試行(うち同時実行88 回)すべてで単独実行時とのtoken ID hash 完全一致が確認されています。下書き無効時()との比較でも、18 入力すべてで出力が一致しました。

出力が一致する仕組み

GPU で複数リクエストをバッチ処理すると、スレッド割り当てやリダクション(総和計算)の順序が微細に変化することがあります。浮動小数点演算は結合法則が成り立たないため、加算順序の違いが丸め誤差を生み、選択されるトークンが反転する場合があります。
TensorFold では、row カーネル内部においてリダクション演算の順序を固定しています(row invariant)。バッチ内に他のリクエストの行が追加されても、各行が実行する浮動小数点演算の手順とビット表現は単独処理時と同一に保たれます。さらに起動時の自己チェックにおいて、単独処理時の結果をビット単位で再現できることが確認された行幅(検証幅16、共有幅128)のみを用いて推論を実行します。

共通点と違い、どちらを選ぶか


測定結果および実装の調査を通じて明らかになった両推論サーバーの特徴を整理します。

共通点

両推論サーバーは Apple Silicon(MLX)環境に特化した OpenAI 互換の推論サーバーであり、Apache-2.0 ライセンスで公開されています。短い入力の単独リクエスト(MTP 読み込み済)では、完了時間がoMLX 2.56 秒、TensorFold 2.51 秒と測定範囲が重なり、ほぼ同等の結果でした。
今回の検証範囲(8 入力×2 回)において単独実行では両サーバーとも 8/8 一致しました。また両者ともKV キャッシュを再利用するキャッシュ機構(prefix cache / prompt cache)を備えています。

違いのまとめ

観点oMLX 0.7.0TensorFold 0.6.4
短い入力8 件の全体速度157.6 tok/s(完了13.00 秒)183.4 tok/s(完了11.16 秒、約1.16 倍)
短い入力1 件の完了時間2.56 秒2.51 秒(測定範囲が重複し、ほぼ同等)
同時処理時と単独時の出力一致39 回中17 回一致(22 回不一致)39 回中39 回一致
Nemotron の複数件MTP2 件以上の同時リクエストで自動停止複数ストリームでも下書きを継続(生成全体に占める下書き採用分1.07%)
長い入力3 件の挙動Prefill が生成に割り込み全体23.32 秒観測された出力区間は重ならず全体20.61 秒
対応モデルの広さmlx-lm / mlx-vlm 対応の多様なモデル専用カーネルが実装された特定ファミリーに限定
操作・管理インターフェースメニューバー常駐、Web 管理画面、モデル動的切替CLI、launchd サービス登録、TUI、CUDA 対応
待ち行列の制御キュー上限32 件を超過すると503 エラーメモリ予算に基づく受付制御と待機

どちらを選ぶべきか

TensorFold は、Nemotron 3.5 Lightning など最適化対応が明記されているモデルを運用し、複数クライアントからの同時リクエストが発生する環境でデコードスループットを引き出したい場合や、バッチ処理の同時実行数にかかわらず単独実行時と一致する出力を重視する場合に適しています。launchd サービスやCLI スクリプト、TUI を通じてバックエンド推論基盤として運用する構成に向いています。
oMLX は、Hugging Face 上の多種多様なモデルを試したい場合や、メニューバー常駐アプリ・Web 管理画面を通じて手軽にモデルのダウンロード、固定、入れ替えを管理したい場合に向いています。1 リクエストずつの対話利用が中心でGUI の利便性を優先したい構成に適しています。
両者に同一のMTP 重みを読み込ませた今回の測定では、短い入力の単独では測定範囲が重なり、ほぼ同等の結果でした。

再現情報とコード参照


本記事で示した検証結果は、以下のリポジトリ、コミット、および測定ログに基づいています。

参照したソースコードと実装箇所

ソフトウェア対象コード役割・実装上のポイント
TensorFold v0.6.4<br>(commit: )メモリ受付予算の算出()と起動時見積もりログ
TensorFold v0.6.4下書き深さと共有行配分の決定(, , )
TensorFold v0.6.4, 残差加算と正規化の融合カーネル(, )
TensorFold v0.6.4 クラス、Mamba 走査()、複数ストリーム実行()
TensorFold v0.6.4MoE ルーティングと行集約()
TensorFold v0.6.4M4 向け4-bit row カーネル()
TensorFold v0.6.4SwitchMLP のグループ化実行(、)
TensorFold v0.6.4M1〜M4 向けPrefill 判定()、チャンク投入()、下書き生成()
TensorFold v0.6.4Prefill 時のMoE Expert 集約(, )、MoE ブロック()
oMLX v0.7.0Nemotron 複数行バッチにおけるMTP 停止判定処理
oMLX v0.7.0外部Prefill およびDecode Fairness スケジューリングロジック

終わりに


同一の MacBook Pro(M4 Max)と NVIDIA Nemotron 3.5 Lightning を用い、oMLX 0.7.0 とTensorFold 0.6.4 の性能差と挙動の違いを比較しました。
短い入力の単独処理では完了時間がほぼ同等で、複数リクエストの同時処理では TensorFold が高速でした。
実装で削減するコストの着眼点は異なっており、「MTPによる下書き採用だけ」あるいは「直列か並列かという違いだけ」という単一の要因で速度差を説明することはできませんでした。
今回対象にはしていませんが MLX 環境であれば
も比較対象となります。
Splash では qwen35, qwen35moe, qwen4_exp モデルであれば、Splash はかなり高速に動作します。
各最適化の寄与分離は未測定ですが、ハードウェアの特性とフレームワークの実装ロジックが自身のユースケースにどう適合しているかを見極めることが重要です。
SRGにご興味ありましたらぜひこちらからご連絡ください。