Laya MLX の性能調査
調査日:2026-09-19。対象:Apple M3 Max、GPU コア 40、統合メモリ 128 GiB、MLX/MLX Metal 0.32.2。これはネイティブランタイム、インストール済み MLX 実装、公式ドキュメント、既存のベンチマーク JSON の静的レビューです。この調査のために GPU ベンチマークやモデル推論は実行していません。以下で提案する最適化のうち、このレポートで計測済みの高速化を持つものはありません。
最初の実験は、モデル全体のコンパイルと代表的なバッチスケジューリング、続いて選択的な量子化行列積であるべきです。これらは支配的な反復作業に対処します。特化したローカル注意カーネルは、長い入力に対する信頼できる長期プロジェクトです。最終 decision-head 層の厳密な枝刈りは実現可能ですが、モデル全体の演算削減は数パーセントにすぎません。チェックポイントを変えずに大きな改善を得るには、密なバックボーンの改善、真に冗長なリクエストの排除、計測された実装ボトルネックの発見が必要です。活性化を差し替えたり、別の注意フラグを有効にしたりするだけでは足りそうにありません。
既存の計測が確立していること
以下は既存の エンドツーエンドの中央値レイテンシ で、プロンプト準備と結果の整形を含み、同期された GPU 完了、5 回のウォームアップ、50 回の計測反復を使っています。モデルのロードとダウンロードは除きます。ベンチマークは 64 問のバッチを許しますが、公開ランタイムの既定は 16 なので、50 問の結果は既定の API 構成ではありません。
| チェックポイント / 精度 | 短 1 問 | 短 10 問 | 短 50 問 | 長 1 問 | 長 10 問 |
|---|---|---|---|---|---|
| Laya MLX FP16 | 13.421 ms | 71.068 ms | 336.030 ms | 44.927 ms | 420.987 ms |
| Laya MLX FP32 | 15.954 ms | 98.820 ms | 450.712 ms | 61.331 ms | 534.242 ms |
| Laya 標準 Torch MPS FP32 | 24.918 ms | 95.265 ms | 497.856 ms | 65.581 ms | 586.594 ms |
| 多言語 MLX FP16 | 7.390 ms | 27.386 ms | 127.565 ms | 37.635 ms | 389.487 ms |
| 多言語 MLX FP32 | 7.988 ms | 32.337 ms | 151.387 ms | 47.208 ms | 451.331 ms |
| 多言語 標準 Torch MPS FP32 | 19.349 ms | 43.158 ms | 194.171 ms | 52.939 ms | 534.492 ms |
出典:Laya FP16、Laya FP32、Laya MPS、多言語 FP16、多言語 FP32、多言語 MPS。長い入力は Laya で 512 トークン、多言語で 1024 トークンを含むため、それらの長入力レイテンシを比べることは同じ系列長での比較ではありません。短い側のパディング後の長さはそれぞれ 93 と 91 です。Torch の比較は FP32 というラベルを保たねばなりません。MLX FP16 と比べるとき、それらはバックエンドの変更と精度の変更を組み合わせているからです。
実行ごとの変動は無視できません。たとえば多言語 FP16 の長 10 問の実行は p50 389.487 ms、p95 462.319 ms、最大 619.663 ms です。その短い単一質問のフォワード中央値は 8.023 ms である一方、独立に計測したエンドツーエンド中央値は 7.390 ms です。それらの中央値を差し引くと、無意味な負の前処理時間になります。現在のファイルは、トークナイザ、Python ディスパッチ、個々の GPU カーネル、同期コストを 分離していません。それらは有用なベースラインを確立するものであり、カーネルレベルのボトルネック診断ではありません。
検証レポートは、3 つのチェックポイントそれぞれについて FP32 と FP16 で 63/63 の argmax 一致を記録し、変種ごとに 100 回の有限で決定的な反復呼び出しを行っています:合計 378/378 の回答一致と 600 回の反復呼び出しです。これらは、繰り返しの質問を含む小さなフィクスチャコーパスに対する回帰チェックです。将来の量子化やアーキテクチャ変更が一般的なタスク精度を保つ証拠ではありません。
なぜ密な行列積を優先すべきか
モデル実装は、パディングされたすべてのトークンに、QKV と出力の射影、ゲート付きエンコーダ MLP、2 つの従来型 transformer decision-head 層を適用します。隠れ幅を D、エンコーダの中間サイズを I、エンコーダの層数を N、decision-head の層数を H とします。これらのブロックでトークンごとに使われる行列重みの数は:
A = N * (4 * D^2 + 3 * D * I) + H * 12 * D^2
dense FLOPs per batch ~= 2 * B * L * A
dense attention FLOPs ~= 4 * B * (N + H) * L^2 * D
これらの推定は、乗算と加算を別々に数え、正規化、活性化、埋め込み、スコアリング、マスキング、メモリ移動、カーネルのオーバーヘッドを除外します。これは算術モデルであり、ランタイムプロファイルではありません。
| チェックポイント系列 | D / I / エンコーダ層 | トークン埋め込みの重み | トークン単位の主要行列重み A | エンコーダのグローバル / ローカル層 |
|---|---|---|---|---|
| Laya / 型付き意思決定 | 1024 / 2624 / 28 | 51,576,832 | 368,312,320 | 10 / 18 |
| 多言語 | 768 / 1152 / 22 | 196,608,000 | 124,452,864 | 8 / 14 |
多言語チェックポイントの合計約 3 億 2200 万パラメータには、1 億 9660 万の埋め込みパラメータが含まれます。推論では選択された埋め込みの行だけが集められ、これは完全な語彙への射影ではありません。そのトークン単位の主要行列の作業量は、英語モデルのおよそ 3 分の 1 で、合計パラメータ数はもっと近く見えるにもかかわらずです。これは計測された短バッチのレイテンシ差と整合しますが、特定のハードウェアボトルネックを証明するものではありません。埋め込みだけの量子化は、とくに多言語で、常駐する重みのサイズを主に減らします。推論レイテンシを改善するとは限りません。
現在の密な注意経路では、注意の積はモデル化した FLOPs のうち、Laya で L=93 のとき約 1.5%、L=512 のとき 7.9%、多言語で L=1024 のとき 23.3% を占めます。実時間に占める割合は大きく異なりえます。プロファイラは、カスタム Metal の作業に着手する前に、行列カーネル、注意カーネル、要素単位カーネル、CPU のグラフ構築、アイドルの隙間を区別すべきです。
優先順位づけした実験
| 優先度 | 実験 | 最良の対象 | 主なトレードオフ / 受け入れ条件 |
|---|---|---|---|
| P0 | 短い形状と長い形状を 1 つずつプロファイルし、モデルまたはエンコーダブロックをコンパイルする | 単一リクエストのレイテンシと Python ディスパッチ | 既存の精度許容範囲内で出力を同一に保つ。初回利用のコンパイルを別に計測する |
| P0 | 実際のトークン予算と長さ分布でバッチングを調整する | 多数の異なる質問と長さが混在するトラフィック | p95 レイテンシとメモリ予算の制約下でスループットを最適化する。待ち行列を考慮する |
| P1 | 選択したバックボーンの線形層を、まず 8 ビット、次に 4 ビットで量子化する | 重みのトラフィックと、場合によっては密な推論 | 品質と較正のゲート。実際の M3 Max の速度は後退しうる |
| P1 | 共有 state のトークナイズと安定した質問テンプレートをキャッシュする | state を共有する多数の質問や反復するルーブリック | トークンの正確な同一性。上限付きキャッシュ。キャッシュありとなしの結果を分ける |
| P1 | 最終ヘッド層の必要な出力のみを計算する | すべてのワークロード、とくに長い系列 | 依存関係の厳密な枝刈り。控えめなモデル全体の演算削減 |
| P2 | タイル境界を使った真のローカルウィンドウ注意 | 512/1024 トークンのワークロード | 新しいカーネルの複雑さ。双方向ウィンドウとパディングの意味を保つ |
| P2 | プロファイルが正当化する箇所だけ residual/norm や GELU/gate を融合する | 小カーネルのオーバーヘッドや活性化のトラフィック | 既存の高速カーネルがすでに多くをカバーしている。厳密な GELU の意味を保つ |
| 別個の製品機能 | 同一のフォワード入力を重複排除する | 実際に質問を繰り返すワークロード | 一意な推論数とキャッシュヒットを報告する。一般的なカーネル高速化として提示しない |
評価済みの完全な推論経路をコンパイルする
Agent.forward() は現在、配列を構築し、self.model を呼び出し、結果を評価します。モデルやブロックのレベルで囲む mx.compile はありません。固定形状のコンパイルは Python のグラフ構築を減らし、対応する操作を融合できます。MLX は形状の特殊化と明示的な状態のキャプチャを文書化しており、shapeless コンパイルが任意の形状依存の Python 操作を安全に保てないことも警告しています。公式コンパイルガイドを参照してください。
まず、重みをロード、キャスト、評価した後に作るコンパイル済み呼び出し可能オブジェクトから始め、通常の形状特殊化を使います。同等性の比較と CPU 互換性のために、既存の非コンパイルの呼び出し可能オブジェクトも保ってください。凍結した推論モデルでは、重みはそのモデルインスタンスに対してキャプチャしたままで構いません。重みやモジュール構造を変えたら、呼び出し可能オブジェクトを再構築するか、該当する状態を明示的にキャプチャしてください。コンパイル済みクロージャをチェックポイントの差し替えをまたいで再利用しないでください。
モデル全体のラッパーを試し、トレースの制約やコンパイルコストがそれを魅力的でなくするなら、エンコーダブロックとヘッドを別々にコンパイルしてください。現在のコードは x.shape を Python の整数に読み込み、明示的なバッチ/長さの値で reshape し、arange(length) のマスクを作り、形状由来の行範囲でマーカーを索引します。この完全なグラフに再設計なしで shapeless=True を適用するのは安全ではありません。動的なマスク構築をコンパイル済みブロックの外へ移し、形状非依存の flatten/unflatten 操作を使えば、後の shapeless 変種が可能になるかもしれません。変化する B、L、マーカー数で検証してください。
形状バケットは再トレースを制限できますが、パディングには計算コストがあります。L=93 を 96 にパディングするとトークン単位の作業が約 3.2% 増え、128 にパディングすると約 37.6% 増えます。厳密形状のコンパイルと、小さな長さ倍数やワークロードに基づく上限付きバケット集合を比べてください。キャッシュポリシーの判断には (batch size, padded length, marker slots, dtype, device/model instance) を含め、形状の変動下でのコールドコンパイルのレイテンシと保持メモリを計測してください。
worker.py の単体の forward ベンチマークは agent.model を直接呼び出します。Agent.forward にだけコンパイルを加えると、現在の forward ベンチマークはそれを迂回し、エンドツーエンドのベンチマークはそれを使うことになります。意味のある比較のためには、両方の経路が同じ候補実装を明示的に選ばねばなりません。mx.eval と GPU 同期は計測手順に残してください。グラフ構築だけを計測しても推論は測れません。
有用なトークンでバッチし、行列スケジューリングを調べる
collate_items は各チャンクをその最長の系列に右パディングし、ランタイムは挿入順に質問をまとめます。異種のトラフィックでは、準備済みの長さでソートまたはバケット化し、質問数の上限に加えてトークン予算を使い、元の質問 ID と出力順を復元してください。バッチ 1、2、4、8、16、32、64 は、サービスを代表する場合にのみ比較します。オンラインのリクエストではバッチを待つ時間も含めてください。オフラインの毎秒質問数だけでは受け入れがたいレイテンシを隠しえます。
現在の短 50 問のワークロードは、パディングされたトークンの約 8.9%(Laya)と 5.8%(多言語)を無駄にします。長いベンチマークの行にはパディングの無駄がありません。したがって、パディング除去やソートだけでは これらの フィクスチャで得られる演算上の利得は限られます。長い 1 問が多数の短い質問に混ざるような、長さが混在する分布こそが、本番での利点を明らかにするのに必要です。パディング除去は、例ごとの RoPE 位置、マーカー位置、注意境界を保たねばなりません。分離マスクなしで例を 1 つの系列に連結するとモデルが変わります。
密なカーネルでは、実際の形状とストライドを調べてください。QKV はすでに単一の射影で、エンコーダ MLP の 2 つの入力分岐はすでに射影を共有しています。それらを無差別に分割すると起動が増えます。連続した [B,L,D] 入力を [B*L,D] へ明示的にフラット化するのは、プロファイラや MLX のディスパッチトレースが好ましくないバッチ GEMM を示した場合にだけ比べてください。フレームワークがすでに効率的にフラット化しているかもしれません。ソースを読んだだけでは、見逃した GEMM 最適化を主張する根拠になりません。
本番実装で層ごとに同期を挿入しないでください。現在のランタイムはチャンクごとに 1 回評価します。余分な待ちは CPU/GPU の重なりをなくし、スケジューリングの改善を覆い隠すことがあります。層レベルのプロファイリングは別の診断実行にすべきです。
量子化:バックボーンを対象にし、そのストレージ契約を実装する
インストール済みの MLX 0.32.2 の量子化層実装は、nn.quantize(..., class_predicate=...) と QuantizedLinear を提供し、mx.quantized_matmul を通じた重みのみの行列積を行います。グループ化されたアフィン量子化は 8 ビットと 4 ビットの実験を支えます。まずエンコーダの線形層をグループサイズ 64 で始め、活性化、norm、型埋め込み、scorer、action head は FP16 のままにします。その後、decision-head の線形層を独立に加え、任意で埋め込みの量子化も加えます。各変種を計測してください。重みのみのカーネルは、トークン数が多いと FP16 の GEMM に負けることがあります。
現在のローダーとモデルには、具体的な統合上の危険があります:
Agent.__init__は格納された すべての 重みを浮動小数点 dtype にキャストし、厳格なロードの前に密なモジュールだけをインスタンス化します。量子化チェックポイントは、選択したモジュール、グループサイズ、ビット幅、モードを記述するメタデータを必要とします。ロードの前に対応する量子化モジュールをインスタンス化し、パックされた整数重みを保ってください。パックされた重みを浮動小数点にキャストするのは有効なロードではありません。- 最初の action-head の線形層は入力幅が
D+4、つまり 1028 か 772 で、アフィン群サイズ 32、64、128 のいずれでも割り切れません。したがって一律の量子化呼び出しは不適切です。変換前に選択したすべての層の入力幅を確認してください。 DecisionModel.__call__は action-head の入力 dtype をself.act_head.layers[0].weight.dtypeから選びます。量子化層ではその重みはパックされた整数ストレージであり、望む活性化の dtype ではありません。action head を除外すれば最初はこの経路を避けられます。後で対応するには、明示的な活性化 dtype の契約が必要です。- 量子化はロジットと較正済み確率を変えます。既存の小さな FP16 フィクスチャの一致は、4 ビット品質の証拠としては不十分です。ホールドアウトのラベル付き choice、score、noul タスク、多言語入力、僅差の判断、異なる選択肢数、エスカレーションの例を使ってください。argmax 一致、タスク精度、スコア誤差、確率のドリフト、較正、action 確率を追跡してください。飽和した action 出力は大きな action ロジットの変化を隠しえます。
FP16 のアフィンのスケールとオフセット、グループサイズ 64 の場合、おおよその行列ストレージはパラメータあたり bits/8 + 4/64 バイトです:8 ビットで 1.0625 バイト、4 ビットで 0.5625 バイトで、FP16 の 2 バイトと比べられます。これらは量子化行列のストレージ推定で、他のテンソルやパッケージングのオーバーヘッドを除きます。高速化の推定ではありません。公式 quantize APIがグループの割り切れ性と形式を説明しています。
新しい低ビット形式は、後の Apple チップのハードウェアを使うと仮定せず、実際の M3 Max バックエンドに対して評価すべきです。MLX の NAX 可用性チェックは、記録された applegpu_g15s デバイスより新しいアーキテクチャ世代を要求します。MLX 0.32.2 のデバイスチェックを参照してください。
入力が実際に同一な箇所で CPU 準備を再利用する
build_sequence は、同じ state を質問ごとに別々にシリアライズ、サニタイズ、トークナイズします。各 instruction と選択肢も別々にトークナイズします。Rust トークナイザはすでに直接使われており、Transformers のトークナイズを置き換えることは残った最適化ではありません。
state を prepare 呼び出しごとに 1 回シリアライズしてサニタイズし、1 回エンコードし、そのトークン ID を各質問の使える余地へスライスしてください。同じルーブリックが複数の state で使われるときは、不変な準備済み質問プレフィックスをキャッシュし、キーにトークナイザの同一性/リビジョン、質問タイプ、順序づけられた criteria、instruction のシリアライズ、特殊トークンのサニタイズ、トークン予算を含めます。上限付きキャッシュは、トークナイザや構成が変わった後に結果を再利用してはなりません。バッチ化したトークナイザのエンコードは、その出力が現在の独立したエンコードの系列と正確に一致するなら、もう 1 つの実験です。
新しく連結したプロンプトをトークナイズすることを、独立にエンコードした断片を連結する代わりにしないでください。サブワードの境界が変わることがあります。バイト単位の入力 ID、注意マスク、マーカー位置、qtype、切り詰めの挙動、構造化 criteria、マスクリテラル、空入力、出力の対応を検証してください。
長いベンチマークでは、state は切り詰めの前に文を 200 回繰り返します。N 回の繰り返し state エンコードを避けることは CPU の準備に役立つかもしれませんが、既存のエンドツーエンドとフォワードの計測差はその節約を測っていません。prepare、collate/配列構築、フォワード、後処理を独立に計測し、その後、繰り返しのないホールドアウトコーパスでエンドツーエンドの結果を確認してください。
decoder の KV キャッシュはこのエンコーダには当てはまりません。 その第 1 層はグローバルな双方向注意で、state トークンの表現は質問、選択肢、それらの位置に依存します。state の隠れ状態や K/V を異なる質問間で再利用すると結果が変わります。トークナイズと、入力全体が同一の結果はキャッシュできます。任意の文脈的なエンコーダ状態はキャッシュできません。
最終 decision head の出力を厳密に枝刈りする
最後の HeadLayer の後で消費されるのは、[CLS] トークンと選択肢マーカーのトークンだけです。最終層がそれらの K/V を読むため、それ以前の head 層は依然としてすべてのトークンを生成しなければなりません。最終層だけでは:
- すべての入力トークンを正規化し、すべての K/V を計算する。
[CLS]と有効な選択肢位置で Q を集め、それらのクエリをマスク済みの完全な K/V 系列に対して実行する。- 出力射影、残差、2 番目の norm、フィードフォワードネットワークを、それらの選択位置にだけ適用する。
- action head には選択された
[CLS]出力を、スコアリングには選択されたマーカー出力を使い、マーカーのパディングと元の順序を保つ。
最初の実装は、融合した完全な QKV 射影を保って後から Q を集めることができます。より踏み込んだ変種は、重みを完全長の KV 射影と選択トークンの Q 射影に分割します。それにより演算はより多く節約できますが、GEMM のスケジューリングが効率を落とすかもしれません。パディングされた重複マーカー索引は、マスクされた結果が観測不能なままであって初めて無害です。1 選択肢、多選択肢、可変マーカーの各ケースには明示的な同等性チェックが必要です。クエリが少なくなると別の SDPA カーネルが選ばれうるため、数学的な等価性はビット単位で同一の浮動小数点結果を意味しません。
R = 1 + number of option slots とすると、完全な QKV を保つと、最終 head 層からおおよそ 18 * B * (L-R) * D^2 の密な FLOPs と 4 * B * L * (L-R) * D の注意 FLOPs が除かれます。Q/KV を分割すると、密な係数が 18 から 20 に変わります。上のモデル全体の演算推定に対して、R=5 を使うと:
| チェックポイント / 長さ | 融合した完全 QKV を保持 | 選択した Q のみを計算 |
|---|---|---|
| Laya, L=93 | 2.44% | 2.70% |
| Laya, L=512 | 2.60% | 2.86% |
| 型付き意思決定, L=1024 | 2.66% | 2.90% |
| 多言語, L=93 | 4.03% | 4.47% |
| 多言語, L=1024 | 4.22% | 4.58% |
これらは静的な FLOP の削減であり、予測されるレイテンシの削減ではありません。この手法が除くのは 1 つの head 層の作業の大半であり、モデルの作業の大半ではありません。依存関係を保ち、再訓練なしで実装できるから有用なのであって、モデル全体の速度の倍数を約束するからではありません。
その寄与を計測してから真のローカル注意を作る
エンコーダのすべての注意呼び出しはすでに mx.fast.scaled_dot_product_attention を使っており、RoPE はすでに mx.fast.rope で、nn.LayerNorm は高速な正規化プリミティブを呼びます。MLX の注意 APIは真偽値マスクを受け付け、softmax を FP32 で行います。現在の head 次元は 64 です。MLX 0.32.2 の Metal ディスパッチはこの形状を配列マスクでサポートし、推論中に非融合のフォールバックを選びません。Laya の真偽値マスクが融合注意を無効にする証拠はありません。 インストール済みバージョンで使える force_fused=True は、診断の assertion として有用ですが、ここで新しい高速経路として宣伝すべきではありません。
残る制限は構造的スパース性です。実装は [B,1,L,L] の形状の密なローカル真偽値マスクを構築します。従来の Metal 注意カーネルでは、非因果ループが KV タイルの全範囲を走査し、配列マスクは QK 乗算の後にスコアへ適用されます。それはローカル注意の意味を、ローカルなタイル範囲を活用せずに保ちます。
厳密な特化カーネルは、各クエリタイルを重なり合う K/V ウィンドウに限定し、FP32 の softmax 累積を保ち、密な L×L マスクを避けられます。正しいウィンドウは 双方向で境界を含みます:abs(query_position - key_position) <= 64。内側のクエリは、設定名 local_attention=128 にもかかわらず 129 位置を見られます。完全注意の層と 2 つの decision-head 層はグローバルのままにせねばなりません。パディングされたキーは引き続き除外し、未使用のパディングクエリには定義された有限の挙動が必要です。
より手間の少ないプロトタイプは、重なり合う K/V スライスでクエリブロックをまとめ、既存の SDPA を小さな厳密マスクで呼べます。すでに位置づけられた RoPE の Q/K を使うか、絶対オフセットを明示的に保ってください。多数の Python 呼び出しよりバッチ化したブロックを好み、K/V の実体化の重複を考慮してください。このプロトタイプは短い長さでは現在のカーネルに負けるかもしれません。カスタム Metal を保守する前の、正しさと損益分岐の実験です。
禁止されたすべてのローカル注意ペアを除くことによる、モデル化した モデル全体 の FLOPs の最大削減は、短い入力では小さく、長い入力ではより見込みがあります:
| チェックポイント / 長さ | 厳密なローカルスパース性による理想的な FLOP 削減合計 |
|---|---|
| Laya, L=93 | 0.086% |
| Laya, L=512 | 3.61% |
| 型付き意思決定, L=1024 | 7.69% |
| 多言語, L=93 | 0.147% |
| 多言語, L=1024 | 11.92% |
推定は L>r に対して local_pairs = L*(2*r+1) - r*(r+1) を使い、r=64 です。すべての密な射影と 2 つの完全注意の decision-head 層を含みます。マスクの生成とメモリのトラフィックは除外します。注意と GEMM の効率が異なるため、ランタイムの利得は FLOP の割合を上回ることも下回ることもあり、プロファイリングだけがそれを確かめられます。8192 トークンではトレードオフが変わるでしょうが、同梱のエージェントは入力を 512 か 1024 に制限するため、8192 トークンの主張には別途対応するワークロードが必要です。
コンパイルを超えた融合
インストール済みの厳密な nn.gelu はすでに shapeless コンパイルで装飾されており、nn.Linear は適切な場合にバイアス対応の addmm をすでに使います。ブロック全体のコンパイルはさらに、GELU をその gate 乗算、残差加算、キャスト、マスク、小さなスコア特徴量の操作と融合できるかもしれません。同等のカスタムカーネルを実装する前に、コンパイル済みのカーネルグラフを調べてください。
活性化のトラフィックが依然として大きいなら、厳密な GELU と gate、または residual と LayerNorm の融合を試作してください。現在の厳密な erf ベースの GELU を保ってください。tanh や sigmoid の近似はモデルを変え、別途の品質計測が必要です。レイアウト変換を加える前に、実際の Q/K/V のストライドとコピーを調べてください。MLX の完全注意実装は、他のストライドを持つ連続した head 次元を受け付け、ヘッドの統合に都合のよい出力レイアウトを書き出します。無条件の連続コピーは作業を増やしえます。
マーカーの softmax、上位 2 件のソート、エントロピー、小さな action head、NumPy の結果整形は、計測された場合にのみ妥当な後回しの対象です。選択肢の位置は、何百もの全幅の transformer 操作と比べてわずかしかないため、それらを先に最適化しても支配的な経路には効きそうにありません。
積極的な高速化を追求しつつベンチマークの意味を守る
現在のワークロード生成器は、5、10、50 問を構成するために 3 つの質問定義を循環させます。これらのバッチには高々 3 つの一意なモデル入力しかありません。呼び出しごとの厳密な重複排除は実アプリケーションで冗長な推論を避けられますが、これらのフィクスチャを過度に改善してしまいます。この機能はカーネル最適化とは分けておき、questions、unique_forward_inputs、キャッシュヒット、実際に評価したトークンを報告してください。各元の回答を、それ自身のラベル、順序づけられた criteria、較正メタデータを使って再構成します。50 の真に異なる質問を持つスイートと、意図的に重複した入力を持つスイートを保ってください。
主要な推論ベンチマークに呼び出しをまたぐ結果キャッシュを使わないでください。それはまったく同じリクエストを繰り返し呼びます。キャッシュの実験はそのように報告してください。トークナイザキャッシュのベンチマークは、反復するルーブリックのシナリオと新しい入力のシナリオの両方を含むべきです。
各候補について、この実験設計を使ってください:
- 対象を一定に保つ。 ソースのリビジョン/ハッシュ、モデルのリビジョン、dtype、コンパイルフラグ、選択した量子化モジュール、トークン ID またはそのハッシュ、形状、マーカー数、バッチングポリシー、ウォームアップ、同期、デバイスを記録する。既存の
input_sha256は実際のトークンテンソルではなく state/質問をハッシュするもので、トークナイザをまたぐテンソルの同一性を確立しません。過去の JSON のソースハッシュは異なるため、同じ最終ソースリビジョンからベースラインを再実行する。 - ワークロードのクラスを分ける。 制御されたカーネル比較には固定形状、スケジューリングとコンパイルには実際の可変長、スループットには異なる質問、正当な CPU キャッシュには反復するルーブリック、重複排除には意図的に重複した質問を使う。長い長さの裾と異なる選択肢数を含める。バックエンド比較の各内部でソーステキストと切り詰めを同一に保つ。
- コールドとウォームの挙動を計測する。 モデルのロードと初回コンパイルを別に記録する。準備、グラフ構築、同期された評価済みフォワード、出力変換、エンドツーエンドのレイテンシを、独立した中央値を加算可能として扱わずに計測する。トレースはレイテンシを乱しうるので、カーネルのプロファイルは別の実行で行う。
- 1 度に 1 つの最適化を変える。 既存の反復数でふるいにかけ、その後、最終候補をベースライン/候補の交互ブロックで繰り返し、信頼できる p95 に足るサンプルを集める。たとえばワークロードあたり少なくとも 200 回の計時リクエスト。単一のアクティブな GPU ベンチマークを使い、電力/熱の条件を一定に保ち、生のサンプルを保つ。計測された実行変動より大きな改善を要求する。
- 正しさと安定性を確認する。 同じ dtype の MLX と既存の FP32 リファレンスに対して比較する。スケジューリングと CPU 準備の変更ではトークンの同一性を強制する。64、128、バケット境界付近の長さ、チャンク上限付近のバッチ、1 と多数の選択肢、多言語入力、パディング、コンパイル後の形状変化を試す。形状の変わるリクエストを繰り返し、ウォームアップ後のアクティブメモリとキャッシュメモリの両方を見て、各構成で有限で決定的な結果を確認する。
- 近似的な変更にはより強いゲートを適用する。 量子化、活性化の近似、トークンの枝刈り、早期終了、蒸留は、小さな回帰フィクスチャを超えたホールドアウトのタスクと較正の結果を必要とする。訓練した挙動を変えるときは、別個のモデル同一性とベンチマークラベルを保つ。より速い多言語チェックポイントや蒸留モデルは別のモデルであり、同一の Laya チェックポイントの高速化ではありません。
エンドツーエンド時間の割合 f を占め、係数 s だけ高速化された任意の計測済みホットスポットについて、予想される全体への影響を評価するにはアムダールの限界 1 / (1 - f + f/s) を使ってください。f には計測した時間割合を使います。上の算術的な割合はその代わりになりません。次の具体的なエンジニアリング上の判断は、検証されていない倍数ではなく、コンパイル/バッチングのアブレーションと、短い場合と長い場合のカーネルプロファイルに従うべきです。
ドキュメントと再現性の注意
ドキュメントの参照には、求められた Context7 ワークフローを使いました:library MLX を 1 回解決し、その後、コンパイルと高速注意について別々に公式ドキュメントを照会し、/websites/ml-explore_github_io_mlx_build_html を使いました(コマンドは合計 3 つ)。インストール済みの .pyi と Python ソースを調べ、MLX 0.32.2 の挙動(force_fused、量子化 API、コンパイル済み GELU、高速 LayerNorm を含む)を確認しました。ディスパッチとタイルループの詳細のために、バージョンを固定した上流の C++/Metal ソースを読みました。この調査のためにライブラリをアップグレードすることはありませんでした。
詳細な観察に使った 2 つの FP16 ベースラインファイルは、調査時点でこれらの SHA-256 ダイジェストを持っていました:
laya-mlx-float16.json
63146dd664d039dde1a728b17aad896e491bd01ea36ea0786953691180e55b09
laya-multilingual-mlx-float16.json
9af74bd5a11e4edc15e6a8c9dc929a7b9fd2d19cb06f348cd0e04a076f912473
主要なベンチマークプロセスは、この調査中も追加の成果物を生成し続けていました。表は、レビュー時にすでに利用可能だった完全なベースラインファイルを意図的に引用し、計測していない候補実装について何も主張していません。