Model Serialization Format(モデルシリアライゼーションフォーマット)
SafeTensors/GGUF/ONNX/pickle/TFLite/CoreML/.mlpackage/.pte/TensorRT engine の内部構造、mmap・アライメント・トークナイザ埋め込み・シャーディング・セキュリティ・10 種アンチパターン俯瞰。
article technology ja SafeTensors/GGUF/ONNX/pickle/TFLite/CoreML/.mlpackage/.pte/TensorRT engine の内部構造、mmap・アライメント・トークナイザ埋め込み・シャーディング・セキュリティ・10 種アンチパターン俯瞰。Model Serialization Format(モデルシリアライゼーションフォーマット)
学習済み重みをロスレス固定する永続化層。tech-67 が IR・ランタイム・量子化なら、本稿は バイトレイアウト・mmap・メタデータ・シャーディング・セキュリティ・バージョン互換。圧縮は tech-66、カーネル/メモリは tech-76。
ファイルフォーマット内部構造
| フォーマット | エンコーディング | mmap | 主用途 |
|---|---|---|---|
| SafeTensors 0.4.x | u64 ヘッダ + JSON + 生 tensor、8 B 整列 | 完全 | HF 配布、RCE フリー |
| GGUF v3 | magic+version+KV+tensor_info+data、32 B 整列 | 完全 | llama.cpp LLM |
PyTorch .pt/.bin | pickle-in-ZIP | 部分 (2.1+ mmap=True) | PyTorch 標準、RCE リスク |
| ONNX | protobuf ModelProto、2 GB 上限 + external data | 非 | クロス FW 交換 |
| TF SavedModel | saved_model.pb + variables/ | 部分 | TF 2.x |
Keras .keras | ZIP (config.json + .h5) | 非 | Keras 3 |
| TFLite/LiteRT | FlatBuffers Model | 完全 | エッジ推論 |
CoreML .mlpackage | Manifest + MIL protobuf + weight.bin | 部分 | Apple ANE/GPU |
ExecuTorch .pte | FlatBuffer ExecutionPlan + デリゲート | 完全 | PyTorch エッジ |
TensorRT .engine | プロプライエタリ、GPU/TRT 固定 | mmap 可 | NVIDIA 推論 |
NumPy .npy | magic+header+raw、64 B 整列 | mmap_mode='r' | 数値配列 |
| Orbax (JAX) | フラットキーツリー + msgpack | 対応 | JAX/Flax |
.mlmodel と .h5 は deprecated → .mlpackage、Keras 3 .keras。MLX は .npz と SafeTensors を直接ロード。
SafeTensors と GGUF のバイトレイアウト
SafeTensors: u64 LE ヘッダ JSON 長 → UTF-8 JSON {"name":{"dtype":"F16","shape":[...],"data_offsets":[s,e]},"__metadata__":{...}} → 8 B 0x00 パディング → 生 tensor。コード実行経路ゼロ、Rust 境界チェック、memmap2 ゼロコピー。
GGUF v3: magic 0x47475546 + u32 version + u64 tensor_count + u64 kv_count → KV (gguf_string + u32 value_type 0=u8〜12=f64・9=array + 値) → tensor_info (name + n_dims + dims + ggml_type + offset) → general.alignment (32) パディング → offset 順 tensor。全 LE、big-endian は変換要 [要確認]。ランタイムが mmap() で (file_base + offset) ゼロコピー view を構築。
GGUF メタデータ KV と埋め込みトークナイザ
GGUF はトークナイザを重みファイルに完全埋め込み。階層名前空間:
general.*:architecture(llama/mistral/qwen/gemma/phi)、name/license、file_type(量子化)、quantization_version、alignment。<arch>.*:context_length、embedding_length、block_count、attention.head_count/head_count_kv(GQA/MQA)、rope.freq_base、rope.scaling.type、vocab_size。tokenizer.ggml.*:model(llama/gpt2/bert)、tokens[]、scores[](SP)、merges[](BPE)、bos_token_id/eos_token_id、add_bos_token/add_eos_token。tokenizer.chat_template: Jinja2 文字列。
HF SafeTensors は外部サイドカー (tokenizer.json/tokenizer.model/special_tokens_map.json/tokenizer_config.json) に持ち、整合性は配布側責任。
ONNX protobuf と external data
ModelProto: ir_version (v9/v10 [要確認])、opset_import[]、metadata_props[] 自由 KV、graph (node[]/input[]/output[]/initializer[])。
protobuf 単一メッセージは 2 GB 上限。LLM 7B+ は TensorProto.data_location=EXTERNAL + external_data で .onnx + .data ペア配布。.onnx のみコピーで .data 欠損はサイレントゼロ化 (AP-4)。
ロードセマンティクス — mmap・遅延ロード
mmap 完全対応は SafeTensors/GGUF/TFLite/ExecuTorch、対応 .npy、部分 PyTorch .pt (2.1+ storage のみ)、非対応 ONNX。利点は (1) ゼロコピー (2) 遅延ロード (3) プロセス間ページ共有 (COW)。落とし穴は NFS v3 / overlay2 で MAP_SHARED → MAP_PRIVATE フォールバック → OOM (AP-2)、コールドキャッシュで first-token 急増 (vmtouch/madvise(MADV_WILLNEED))、CIFS/SMB アライメント無保証。
大規模モデル遅延ロードは accelerate.init_empty_weights() (meta) → load_checkpoint_and_dispatch(model, "index.json", device_map="auto") で tensor 単位振り分け。
セキュリティモデル
Pickle RCE: .pt/.bin、Keras .h5 の lambda、tf.py_function は __reduce__ 経由で os.system(...) を torch.load() 時実行可能。緩和は torch.load(weights_only=True) (2.4+ 警告、2.6+ デフォルト [要確認])。完全回避は SafeTensors。
SafeTensors: コード実行経路ゼロ、Rust 境界チェック、JSON + raw のみ。__metadata__ はプロンプトインジェクションを排除しない。
ONNX カスタム op: .so/.dll を dlopen 実行、ORT はサンドボックスなし、信頼できない .onnx は DLL リスク。
トークナイザ注入: 重みが安全でも tokenizer.json 改ざんで BOS/EOS 改変、ホモグリフ、chat_template 経由のシステムプロンプト埋め込み可能。
HF Hub: LFS SHA256 検証、revision="main" は branch 更新で別重み (AP-7)。revision="<commit-sha>" / タグ固定が安全。
シャーディングと巨大モデル
SafeTensors: model.safetensors.index.json の weight_map + metadata.total_size、各シャードは独立有効ファイル、from_pretrained() が必要分のみロード。ONNX External Data: .onnx + .data ペア、--all-tensors-to-one-file で単一 .data。GGUF split (2024+): model-00001-of-00005.gguf、general.split.count/general.split.no KV [要確認]。PyTorch シャード (レガシー): pytorch_model.bin.index.json、新規未使用。
変換可逆性と精度損失
ロスレス: PyTorch ↔ SafeTensors (同一 tensor バイト、コンテナのみ差替え)、.pt ↔ .bin、シャード再結合/分割、量子化なし GGUF (F32/F16) — tokenizer KV 正確再現が前提。
損失あり:
- PyTorch → ONNX:
torch.onnx.exportは動的制御フロー喪失、dynamo_exportも全 op 保証なし、opset 互換性確認必須。 - PyTorch → GGUF: 重みは lossless だがトークナイザ再エンコード要、特殊トークンミスで EOS 未生成 / BOS 二重付与。
- ONNX → TFLite (
onnx2tf):Einsum/ScatterND/GridSampleop ギャップ。 - TF → ONNX (
tf2onnx):tf.functionのinput_signature明示なしで型推論失敗。 - JAX → ONNX: 直接パスなし、
jax2tf→tf2onnxの 2 段。 - bf16 → fp16: bf16 (~3.4×10³⁸) → fp16 (65504) でオーバーフロー NaN/Inf、clamp か bf16 → fp32 → 量子化の 2 段 (AP-10)。
バージョニング — opset / GGUF v1→v3 / SafeTensors
ONNX opset 17→22、ORT 1.16=18 / 1.17=19 / 1.18=20 [要確認]、opset_import が ORT サポート外なら InvalidGraph、onnx.version_converter でダウングレード可だが op 不在で失敗あり。ONNX IR v7→v10。GGUF: v1 u32 count → v2 u64 count・パディング正式化 → v3 (2024) general.file_type・split 対応 [要確認]。SafeTensors 0.3→0.5 はバージョンフィールドなし、additive。TFLite FlatBuffers は後方互換維持。CoreML coremltools 7+ で .mlpackage + ML Program デフォルト、8+ 変更 [要確認]。PyTorch state_dict バージョンなし、torch.compile() 後は _orig_mod. プレフィクス、strict=False か strip 要。
アンチパターン 10 種
- Pickle RCE —
.pt/.binをweights_only=Falseでロード。対策:weights_only=True、SafeTensors 移行。Critical。 - NFS/overlay2 mmap OOM —
MAP_SHAREDフォールバックで heap コピー。対策: ローカル SSD/tmpfs へコピー後 mmap、またはuse_mmap=False。High。 - GGUF tokenizer KV ドリフト — Fine-tune で重みのみ更新、KV は古いまま。対策:
convert_hf_to_gguf.pyで全体再変換、既存 GGUF パッチ禁止。High。 - ONNX external data 紛失 —
.onnxのみコピーで.data欠損→サイレントゼロ。対策:--all-tensors-to-one-file、ペア検証。High。 - 精度メタデータ不整合 —
config.jsontorch_dtypeと実 tensor 不一致で silent NaN。対策: ロード後model.dtype照合、変換時 perplexity 再評価。Medium-High。 - シャード index 不整合 —
*.index.jsonのweight_map乖離でKeyErrorか silent ゼロ。対策: 変更時 index 再生成、save_pretrained()で自動化。High。 - HF
revision="main"非固定 — branch 更新で別重み、再現性破壊。対策:<commit-sha>/ タグ pin。Medium。 - Keras
.h5lambda RCE —lambda/tf.py_functionが任意コード実行。対策:compile=False、サブクラス置換、Keras 3 移行。Critical。 - TensorRT エンジン GPU 固定 — Ampere → Ada コピーで起動失敗 / 誤出力。対策:
.engine配布せずtrtexecリビルド、ONNX を配布単位。High。 - bf16 → fp16 直接キャスト — bf16 値域が fp16 (65504) 超過で NaN/Inf。対策: 事前 clamp / bf16 → fp32 → 量子化。Medium-High。
関連記事
- tech-35 / tech-43 / tech-44 / tech-45 / tech-46
- tech-50 / tech-51 / tech-64
- tech-66 / tech-67 / tech-69 / tech-73 / tech-76
未確認事項 (確認時点 2026-05)
情報カットオフ ~2025-08 で confidence: medium。最新は各公式 spec 参照。
- SafeTensors 0.5+ フォーマット拡張
- GGUF v4 仕様策定と llama.cpp 実装
- PyTorch
weights_only=True2.6 デフォルト確定 - ONNX opset 22→23 / ORT 1.18.x/1.19.x サポート上限
- GGUF split KV
general.split.*名前 - HuggingFace Xet LFS 置き換え採用状況
- Orbax v1.0 JAX 公式推奨
- CoreML coremltools 8+ ML Program spec 変更
- ExecuTorch FlatBuffer 1.0 GA 後の後方互換
- Apple Foundation Models iOS/macOS 26 配布形式
- GGUF v3 big-endian サポート
- TensorRT
.engine内部構造 (非公開)
Backlinks
- related Edge Inference(エッジ推論)
- related ML Model Deployment