変換ノート
このページでは通常の Core ML エクスポートについて説明します。別途書き直された ANE グラフと任意の重みパレット化は ANE_ENGINEERING.md に記載されています。
エクスポートは 元の Laya チェックポイントを FP32 の PyTorch モジュールにロードし、すべての state-dict キーを厳密にチェックし、推論専用の実装をトレースし、Core ML の ML Program を保存します。公開されているチェックポイントファイル自体は主に FP16 テンソルを含みます。ここでの FP32 はエクスポート/参照の計算を指し、より高精度なソース重みを指すものではありません。学習、プルーニング、重み量子化は行われません。FP16 は変換精度の選択であり、FP32 は診断用に選択できます。
ランタイムは、チェックポイントの tokenizer、プロンプトレイアウト、選択肢マーカー、質問タイプ埋め込み、意思決定ヘッド、アクションヘッド、較正温度を使います。choice、score、noul、構造化 criteria、トークン会計、生成トークンがゼロであることは、アップストリーム API に従います。エンコーダは双方向で、各質問が依然として独自のエンコーダシーケンスを実行します。共有状態の隠れ状態キャッシュはありません。
検証された変換の選択
coremltools==9.0、torch==2.7.0、numpy==2.1.3、Python 3.12。- グラフチェック付きの TorchScript トレース、評価モード、元の重みを FP32 モジュールにロード。
- ML Program、macOS 15 / iOS 18 のデプロイ対象。実際の実行は macOS 27.2 を実行する M3 Max でテストされました。iPhone/iPad と古い macOS での実行はテストされていません。
- 既定のシーケンス長は 16、32、64、96、128、192、256、384、512、768、1024 から選択され、チェックポイントのコンテキスト上限で頭打ちになります。ランタイムは利用可能な最小の長さにパディングし、追加されたトークンをマスクします。
- 既定のバッチサイズは 1 で、32 のマーカースロットを持ちます。それより多い質問はチャンク単位で実行されます。
--batch-sizeと--max-optionsは異なるエクスポートシグネチャを生成します。 - 既知のワークロードには固定シェイプを利用できます。エクスポートの長さまたは選択肢容量を超える入力はエラーを送出し、より小さいエクスポートに収めるために黙って切り詰められることはありません。元のチェックポイントのコンテキスト切り詰めは保持されます。
Apple は TorchScript 変換と列挙された入力シェイプを文書化しています。複数の列挙入力は同じ数のシェイプを必要とし、インデックスで対応付けられます。このエクスポートはそれに従って input ID とアテンションマスクを対にします。
再現性のために保持された失敗
これらはこのマシンと OS での観測であり、すべての Core ML バージョンに関する主張ではありません。
- PyTorch の
__or__ブール演算子は変換されませんでした。明示的なtorch.logical_or/torch.logical_andが同じマスクの意味を保持します。 - NumPy 2.5 は、coremltools 9.0 内の非推奨の配列からスカラーへの変換を拒否しました。サポートされるプロジェクト依存は NumPy 2.2 未満に固定されています。PyTorch はコンバーターがテストした 2.7.0 に固定され、2.7.1 ではありません。
- 強制的な
CPU_AND_GPUを伴うRangeDimは、大きな数値誤差と、同一入力の繰り返しに対する異なる結果を生みました。元の SDPA エクスポートは 47/63 の参照回答にしか一致せず、明示的な matmul/softmax アテンションは 20/63 に一致しました。FP32 は観測された短入力の GPU 失敗を解決しませんでした。CPU / 自動選択は SDPA グラフに対して正しい出力を与えました。 - 列挙された長さが GPU の忠実性と再現性を回復しました。その後、別途の小さな回帰テストが、定数のブール局所アテンション行列をスライスする際の MPSGraph コンパイラの
SIGTRAPを露呈しました。診断はElementsAttr::getValues<bool>/FoldStridedSliceOpを名指ししました。 - 最終的な実装は 整数の位置をスライスし、その後でブールの局所マスクを構築します。これによりコンパイラのトラップは取り除かれます。一般的な RangeDim の GPU 失敗を治すものではありません。後続の実験は依然として 49/63 にしか一致せず、再現可能でもありませんでした。列挙された長さが既定のままです。
ランタイムは、診断実験のために明示的に許可されない限り、RangeDim + cpu_gpu を拒否します。その失敗した構成を再現するには:
laya-coreml convert laya-multilingual models/range-experiment --shape-mode range
python -m benchmarks.validate models/range-experiment \
--name laya-multilingual --compute-units cpu_gpu --allow-unvalidated-gpu \
--repeats 10 --output artifacts/range-experiment.json
このテストは測定環境で失敗することが想定されています。失敗と成功の生レポートは benchmarks/results/ に保持されています。"passed": false を含むレポートは、検証済み構成として引用してはなりません。
デバイスの証拠
CPU_AND_NE は、CPU と Neural Engine が許可されるという意味であり、すべての演算子が Neural Engine で実行されるという意味ではありません。ベンチマークは、Core ML の計算計画の優先/対応デバイスと推定コストを記録します。これは想定された計画であり、Instruments のランタイムハードウェアトレース、電力測定、あるいは Neural Engine だけでの実行の証明ではありません。
Hub スナップショットのロード
リリースのスモークテストで、別のパッケージング問題が見つかりました。共有 Hugging Face キャッシュからシンボリックリンクの重みファイルをロードすると、Core ML のネイティブコンパイラが model.mlmodelc/weights/weight.bin の欠落を報告しました。同等のローカルバンドル 6 つはすべて正常にロードされました。ランタイムは現在、MLModel を構築する前に、シンボリックリンクに支えられたパッケージを通常ファイルの内容アドレス指定キャッシュへコピーします。ハッシュはコピーの前後と再利用時にチェックされ、変更または破損したキャッシュはエラーを送出します。通常ファイルのローカルバンドルはこのコピー経路を取りません。キャッシュの場所と上書きについては USAGE.md を参照してください。
再現性
すべてのエクスポートには coreml_config.json が含まれます:元の重みの SHA256、ソースリビジョン、シェイプ、精度、アテンション実装、ツールのバージョン、変換時刻、そしてすべてのパッケージ/tokenizer/設定ファイルのハッシュです。エクスポートは既存のディレクトリの上書きを拒否します。失敗したエクスポートは、新しく作成した出力ディレクトリだけを削除します。
コミットされたゴールデン参照は、変更されていないアップストリーム Laya リビジョン 573e5b62696ba441230cd6be71d593331b5d23af から、FP32 PyTorch MPS を使って生成されました。完全な入力トークン ID と丸められていないロジットを含みます。検証はそれらのトークンを正確に比較し、選択回答、較正確率、アクション確率、トークン会計、繰り返しの公開結果をチェックします。
アップストリーム互換の環境でゴールデン参照を再生成するには:
git clone https://github.com/NandhaKishorM/laya .upstream
git -C .upstream checkout 6a5819129eb220570792e417e49723d697efd76f
python -m benchmarks.reference --upstream .upstream --model-root /path/to/original/checkpoints
正確な参照依存は生成された JSON に記録されています。それらは固定されたエクスポート環境とは別です。Transformers は laya-coreml のランタイム依存でもエクスポート依存でもありません。