テクノロジー

`.safetensors` の中身、説明できる? AIモデルファイル形式の歴史と仕組み

エンジニアの又川です。

皆さんは Hugging Face でモデルのページを開いたことはあるでしょうか? 「Files and versions」タブを開くと、pytorch_model.binflax_model.msgpack、最近では model.safetensors など、見慣れないファイルがずらっと並んでいますよね。

「AI モデルのパラメータが入っているのだろうな」となんとなくは分かります。しかし、パラメータ数 8B(80 億) のモデルに対応するファイルが 16 GB もあったり、ファイルが model-00001-of-00004.safetensors のように複数に分かれていたり、よく分からないことだらけです。

ひとまず「Tensor type: BF16」と書いてあれば、「1 パラメータあたり 16 bit = 2 byte だから、ファイルサイズがパラメータ数の約 2 倍になるのだな」という推察はつきます。しかし 「4-bit 量子化版」「GPTQ 版」「GGUF 版」 など亜種が山ほどあって、もう訳が分かりません。

ということで、AI モデルのファイルフォーマットを登場順に整理してみました。それぞれのフォーマットについて 「中身は何なのか」「バイナリなのかテキストなのか」「パラメータだけなのかネットワーク構造も含むのか」 といった点も見ていきます。

前提知識: モデルファイルに保存されるもの

まず、モデルファイルに保存される可能性のあるデータを整理しておきましょう。

要素説明
重み (weights)ニューラルネットワークの各層のパラメータ(重み行列やバイアスベクトル)。学習の成果そのもの
ネットワーク構造層の種類(Linear, Conv2d など)、層の接続関係、活性化関数の種類など
オプティマイザ状態学習の途中経過(Adam の移動平均など)。学習再開に必要
メタデータハイパーパラメータ、トークナイザ情報、量子化設定など

フォーマットによって、このうちどれを保存するかが異なります。推論だけが目的なら重みとネットワーク構造があれば十分ですし、学習を再開したいならオプティマイザ状態も必要です。

深層学習以前: 独自フォーマットの時代(〜2012 年頃)

ニューラルネットワーク自体は 1980 年代から研究されていましたが、この頃のモデルは数百〜数千パラメータ程度の小規模なものでした。共通のファイルフォーマットなど存在せず、研究者ごとに独自の方法で保存していました。

  • プレーンテキスト / CSV: 重み行列をスペース区切りやカンマ区切りで書き出す方法。人間が読めるのは利点ですが、ファイルサイズが大きくなります
  • MATLAB の .mat ファイル: 学術研究では MATLAB の Neural Network Toolbox が広く使われており、save('model.mat', 'weights', 'biases') のように MATLAB の変数として保存するのが一般的でした
  • 独自バイナリ形式: 研究者がそれぞれ独自のバイナリ形式で保存。他の人のモデルを読み込むにはコードを読むしかない、という状態です

この時代はモデルが小さかったのでこれで十分でしたが、互換性は皆無でした。

深層学習フレームワーク黎明期(2013〜2015 年頃)

2012 年の AlexNet の登場で深層学習ブームが始まると、モデルの規模が大きくなり、共通のツールやフォーマットが求められるようになりました。

Caffe: .caffemodel + .prototxt(2013 年)

深層学習フレームワークの草分けとも言える Caffe(*1) は、Google の Protocol Buffers (protobuf) をシリアライゼーション形式に採用しました。

ファイル中身形式
.prototxtネットワーク構造(層の定義、接続関係)テキスト形式の protobuf
.caffemodel重み(学習済みパラメータ)バイナリ形式の protobuf

構造と重みが別ファイルに分かれているのが特徴です。Caffe は「Caffe Model Zoo」というモデル共有の仕組みも作り、学習済みモデルを共有する文化の先駆けとなりました。

Keras: .h5(2015 年頃)

Keras は HDF5 (Hierarchical Data Format version 5) という科学データ向けの汎用フォーマットを採用しました(*2)

項目内容
シリアライゼーション形式HDF5
保存内容重み+ネットワーク構造(JSON でメタデータに格納)+オプティマイザ状態
保存方法model.save('model.h5') の一行で保存完了

HDF5 は階層構造でデータを格納でき、圧縮にも対応しています。model.save() 一行でモデル全体を保存できる手軽さから広く普及しました。

Chainer: .npz(2015 年)

日本の Preferred Networks 社が開発した Chainer は、NumPy の NPZ 形式を採用しました(*3)

項目内容
シリアライゼーション形式NumPy NPZ(numpy.savez)
保存内容重み+オプティマイザ状態。構造はコード側で定義

NPZ は ZIP アーカイブ内に NumPy 配列を格納するシンプルな形式です。NumPy さえあれば読み書きできるのが利点でした。なお Chainer は 2019 年 12 月に開発終了を発表し、PyTorch への移行を推奨しています。

主要フレームワークの確立(2015〜2017 年頃)

TensorFlow: .ckpt, SavedModel, .pb(2015 年〜)

TensorFlow はバージョンや用途によって複数の保存形式を持っています(*4)

Checkpoint (.ckpt) は学習途中の保存・復元に使われる形式で、複数のファイルに分散します。

ファイル内容
.ckpt.metaグラフ構造(GraphDef)
.ckpt.data-00000-of-00001変数の値(重み、バイアスなど)
.ckpt.indexテンソル名とメタデータのインデックス
checkpoint最新のチェックポイントを指すテキストファイル

Frozen Graph (.pb) は推論用の形式で、グラフ構造と重みを単一の Protocol Buffers ファイルにまとめたものです。変数を定数に変換(freeze)するため学習の再開はできませんが、デプロイに適しています。

SavedModel は TensorFlow 2.x で標準となった形式で、ディレクトリ構造で保存されます。saved_model.pb(グラフ)、variables/(チェックポイント)、assets/(追加ファイル)を含みます。TensorFlow Serving との統合に対応した公式推奨の形式です。

PyTorch: .pt / .pth / .bin(2016 年〜)

PyTorch のモデル保存は Python の pickle をベースにしています(*5)。PyTorch 1.6(2020 年)以降では、pickle + ZIP アーカイブの構造になりました。

項目内容
シリアライゼーション形式pickle + ZIP アーカイブ(PyTorch 1.6 以降)
保存内容torch.save() で何でも保存可能

保存方法にはいくつかのパターンがあります。

# パターン1: 重みのみ保存(推奨)
torch.save(model.state_dict(), 'model.pt')

# パターン2: モデルオブジェクト全体を保存
torch.save(model, 'model.pt')

# パターン3: 学習状態をまとめて保存
torch.save({
    'model': model.state_dict(),
    'optimizer': optimizer.state_dict(),
    'epoch': epoch,
}, 'checkpoint.pt')

.pt は「PyTorch」の略と広く解釈されていますが、公式に明言されたものではありません。また、.pth は Python のパス設定ファイル(sys.path に追加するディレクトリを指定する .pth ファイル)と名前が衝突するため、PyTorch 共同創始者の Soumith Chintala 氏が .pt の使用を支持しており(*13)、現在では .pt の方が推奨されています。

Hugging Face で見かける pytorch_model.bin も中身は同じ pickle + ZIP 形式で、state_dict(重みのみ)が格納されています。これは Hugging Face Transformers ライブラリの命名規則で、config.json(ネットワーク構造)と組み合わせてモデル全体を復元します。

ただし、pickle には重大なセキュリティ上の問題があります。pickle はデシリアライズ(読み込み)時に任意の Python コードを実行できてしまうのです。悪意のある pickle ファイルを読み込むと、攻撃者のコードがユーザのマシン上で実行される可能性があります。この問題は後に SafeTensors が開発される大きな動機となりました。

フレームワーク非依存の形式(2017 年)

ONNX: .onnx(2017 年)

ONNX (Open Neural Network Exchange) は Facebook(現 Meta)と Microsoft が共同で発表したフレームワーク非依存の形式です(*6)

項目内容
シリアライゼーション形式Protocol Buffers
保存内容重み+ネットワーク構造(計算グラフ)+メタデータ
対応フレームワークPyTorch, TensorFlow, Caffe2 などからエクスポート可能

「PyTorch で学習したモデルを TensorFlow で推論したい」「ONNX Runtime で高速に推論したい」といったユースケースに対応しています。ただし全ての演算子がサポートされているわけではなく、最新の研究モデルでは変換できないことがあるのが弱点です。ONNX は特定のフレームワークに紐づいているわけではなく、現在は Linux Foundation 傘下で管理されています。

エッジ・モバイル向け形式(2017 年)

同じ 2017 年には、特定のプラットフォーム向けに最適化されたフォーマットも登場しました。

TensorFlow Lite (.tflite) はモバイル・組み込みデバイス向けの形式で、Google が開発した FlatBuffers をシリアライゼーションに使っています(*7)。FlatBuffers はデシリアライズなしで直接データにアクセスできる(ゼロコピー)のが特徴で、リソースの限られたデバイスに適しています。重みとネットワーク構造を 1 ファイルに格納します。なお TensorFlow Lite は 2024 年に「LiteRT」にリブランドされています。

Core ML (.mlmodel) は Apple の機械学習フレームワーク Core ML 向けの形式で、Protocol Buffers ベースです(*8)。重み、ネットワーク構造、入出力の型情報、メタデータを 1 ファイルに格納します。Apple Neural Engine (ANE) に最適化されており、iPhone や Mac で AI モデルを実行する際に使われます。

JAX/Flax とモダンな保存形式(2020 年〜)

Flax: flax_model.msgpack(2020 年頃)

Google の JAX をベースとしたフレームワーク Flax は、MessagePack をシリアライゼーション形式に採用しました(*9)

項目内容
シリアライゼーション形式MessagePack
保存内容モデルパラメータ(重み)

MessagePack は JSON に似たバイナリ形式で、JSON より高速かつコンパクトです。Hugging Face の JAX モデルで flax_model.msgpack として見かけるのはこの形式です。

現在の Flax では Orbax というチェックポイントライブラリに移行しており、より高度なチェックポイント管理が可能になっています。

SafeTensors: セキュリティ問題への回答(2022 年)

なぜ SafeTensors が作られたのか

先述の通り、PyTorch のモデルファイルは内部で pickle を使っています。pickle はデシリアライズ時に __reduce__ メソッドを通じて任意の Python コードを実行できるという根本的な問題を抱えています。

Hugging Face Hub をはじめとするモデル共有プラットフォームが急速に普及する中、「誰が作ったか分からないモデルファイルをダウンロードして読み込む」という行為のリスクが深刻化しました。Hugging Face は pickle ファイルのスキャンを実施していますが、全ての攻撃パターンを検出するのは不可能です。

そこで Hugging Face が開発したのが SafeTensors です(*10)

SafeTensors のファイル構造

SafeTensors は非常にシンプルな構造をしています。

SafeTensors のファイル構造
項目内容
シリアライゼーション形式JSON ヘッダ+生バイナリデータ
保存内容重みのみ(実行可能コードを一切含まない)
セキュリティ任意コード実行が不可能。外部セキュリティ監査済み

ポイントは、テンソルの名前・型・形状・オフセットを JSON で記述し、実データは連続したバイナリとして直後に配置するというシンプルな設計です。実行可能コードを一切含まないため、読み込み時に悪意のあるコードが実行される心配がありません。

また、ゼロコピーアクセスや遅延読み込みにも対応しており、pickle ベースの形式より高速です。現在では Hugging Face Hub のデフォルト形式となっています。

ただし、SafeTensors は重みしか保存しないため、ネットワーク構造は config.json、トークナイザ設定は tokenizer.jsontokenizer_config.json など、別ファイルと組み合わせて使います。

GGML / GGUF: CPU 推論に特化した形式(2023 年)

GGML(2022 年〜)

Georgi Gerganov 氏が設計したテンソル演算ライブラリおよび独自バイナリ形式です(*11)。2023 年 3 月にリリースされた llama.cpp で広く知られるようになりました。Meta の LLaMA モデルを一般的な PC の CPU で動かすことを目的として作られ、量子化(後述)に対応しており、GPU がなくてもそれなりの速度で LLM を推論できるのが画期的でした。

しかし、GGML にはメタデータの拡張性が乏しく、新しいモデルアーキテクチャへの対応や後方互換性の維持が困難という問題がありました。

GGUF(2023 年 8 月)

GGML の後継として設計された GGUF (GGML Unified File) は、これらの問題を解決しています(*12)

GGUF のファイル構造
項目内容
シリアライゼーション形式独自バイナリ
保存内容重み(量子化済み)+豊富なメタデータ(アーキテクチャ、トークナイザ設定など)
対応ツールllama.cpp, Ollama, GPT4All, LM Studio など

GGUF の大きな特徴は、モデルの推論に必要な情報を 1 ファイルに全て格納することです。メタデータセクション(キー・バリュー形式)にはモデルのアーキテクチャ情報やトークナイザ設定が含まれるため、config.jsontokenizer.json のような追加ファイルは不要です。

また、多様な量子化形式(Q4_0, Q4_K_M, Q5_K_M, Q8_0 など)をフォーマット仕様レベルでサポートしているのも特徴です。これらの量子化形式については次のセクションで説明します。

量子化とファイルフォーマット

Hugging Face で見かける「4-bit 量子化版」「GPTQ 版」などは、量子化形式ファイルフォーマットの組み合わせで成り立っています。この 2 つは別の概念です。

量子化とは

モデルの重みを低い精度に変換することで、ファイルサイズとメモリ使用量を削減する手法です。例えば BF16(16 bit)の重みを 4 bit に量子化すれば、サイズは約 4 分の 1 になります。

GPU 向け量子化形式

アルゴリズム精度保存形式特徴
GPTQ主に 4-bitsafetensors / pytorch_model.binキャリブレーションデータを使って量子化誤差を最小化する。最も普及している
AWQ主に 4-bitsafetensors重要な重みチャネルを自動検出し、スケーリングにより量子化誤差を軽減する
bitsandbytes4-bit / 8-bitsafetensorsコード上で load_in_4bit=True と指定するだけで使える手軽さが特徴

重要なのは、同じ量子化形式でも異なるファイルフォーマットで保存できるということです。例えば GPTQ で量子化したモデルは safetensors 形式でも pytorch_model.bin 形式でも保存できます。

CPU 向け量子化形式

CPU 向け量子化形式の代表格が GGUF の量子化形式です。GGUF のファイル名でよく見かける Q4_0, Q4_K_M などが量子化形式で、先頭の数字がビット数を表します(Q4 なら 4-bit、Q8 なら 8-bit)。_0 は最も素朴な量子化方式を意味し、_K_M のような接尾辞は層ごとにビット数を変える「K-quant」と呼ばれる手法のバリエーションです(_K_S が小サイズ寄り、_K_M が中間、_K_L が高精度寄り)。

よく使われるものを抜粋します。

量子化形式ビット数サイズ目安 (8B モデル)特徴
Q6_K6-bit約 6.5 GB精度重視。BF16 に近い品質が欲しいときに
Q5_K_M5-bit約 5.5 GB精度とサイズのバランスが良い
Q4_K_M4-bit約 4.5 GB最も人気のある選択肢。実用上十分な精度
Q4_04-bit約 4 GBK-quant 以前の素朴な方式。現在は Q4_K_M が上位互換

モデルのシャーディング(分割保存)

大規模モデルでは、ファイルが複数に分割されていることがあります。例えば以下のようなファイル構成です。

model-00001-of-00004.safetensors
model-00002-of-00004.safetensors
model-00003-of-00004.safetensors
model-00004-of-00004.safetensors
model.safetensors.index.json

これはシャーディングと呼ばれる仕組みで、数十〜数百 GB にもなる大規模モデルを扱うために使われます。

model.safetensors.index.json はインデックスファイルで、各パラメータがどのシャードファイルに格納されているかのマッピングが記述されています。Hugging Face Transformers ライブラリではメモリ効率のため、デフォルトで約 5 GB ごとにシャード分割されます。

シャーディングにはメモリ効率の面でも利点があります。シャードを 1 つずつ順番に読み込めば、「モデル全体のサイズ+最大シャードのサイズ」程度の RAM で済むため、巨大なモデルでも扱いやすくなります。

最新のフォーマットは?

GGUF(2023 年 8 月)以降、広く普及した新フォーマットは特に登場していません。現状は SafeTensors が GPU 学習・推論のデファクトGGUF が CPU ローカル推論のデファクトとして棲み分けが安定しています。

強いて挙げるなら、Apple が 2023 年 12 月に公開した MLX フレームワーク(*14)は独自の保存形式(SafeTensors または NumPy ベース)を持ち、Apple Silicon に特化した推論・学習を提供しています。また、Meta が 2024 年に公開した ExecuTorch (*15)はオンデバイス推論に特化したフレームワークで、.pte という独自形式を使用します。

ただし、いずれもプラットフォーム特化のニッチな存在であり、Hugging Face 上で見かけるファイルはほぼ SafeTensors か GGUF です。フォーマット戦争は一段落したと言えそうです。

まとめ: フォーマット年表

最後に、主要なフォーマットを年表にまとめます。

フォーマットシリアライゼーション保存内容
〜2012.mat, テキスト, 独自形式各種重みのみ
2013.caffemodel + .prototxtprotobuf重み / 構造(別ファイル)
2015.h5 (Keras)HDF5重み+構造+オプティマイザ
2015.npz (Chainer)NumPy NPZ重み+オプティマイザ
2015.ckpt (TensorFlow)独自重み+構造(複数ファイル)
2016.pt / .pth (PyTorch)pickle (+ZIP)何でも
2017.onnxprotobuf重み+構造
2017.tfliteFlatBuffers重み+構造
2017.mlmodel (Core ML)protobuf重み+構造
2020flax_model.msgpackMessagePack重みのみ
2022.safetensorsJSON+バイナリ重みのみ
2022GGML独自バイナリ重み(量子化済み)
2023.keras (Keras 3.0)ZIP (JSON+H5)重み+構造+オプティマイザ
2023/8GGUF独自バイナリ重み+メタデータ(量子化済み)
2023/12MLX 形式SafeTensors / NumPy重みのみ
2024.pte (ExecuTorch)FlatBuffers重み+構造

こうして並べてみると、各フォーマットが「その時代の課題」を解決するために生まれてきたことが分かります。

  • 互換性がない → Caffe が protobuf ベースの共通形式を導入
  • 手軽に保存したい → Keras が model.save() 一行で保存できる HDF5 形式を普及
  • フレームワーク間で変換したい → ONNX が登場
  • pickle は危険 → SafeTensors が実行可能コードを排除した形式を提供
  • CPU でも LLM を動かしたい → GGML/GGUF が量子化対応の形式を提供

次に Hugging Face でモデルのファイル一覧を見るときは、「あ、これは safetensors だから安全に読めるな」「GGUF だから CPU で動かす用だな」と分かるようになっているはずです。


数ヶ月で状況が変わる AI 分野に対して、アシアルでは開発やデザイン、事務業務など、立場によらず AI を積極的に理解・活用する取り組みを行っています。興味のある方は会社情報採用情報もご覧ください。

ではまた!

参考文献

(*1) Caffe | Deep Learning Framework
https://caffe.berkeleyvision.org/

(*2) モデルの保存と読み込み | TensorFlow Core(Keras の .h5 形式についても言及あり)
https://www.tensorflow.org/tutorials/keras/save_and_load?hl=ja

(*3) Serialization of Link hierarchies — Chainer documentation
https://docs.chainer.org/en/stable/guides/serializers.html

(*4) SavedModel 形式の使用 | TensorFlow Core
https://www.tensorflow.org/guide/saved_model?hl=ja

(*5) Saving And Loading Models — PyTorch Tutorials
https://docs.pytorch.org/tutorials/beginner/saving_loading_models.html

(*6) ONNX | Home
https://onnx.ai/

(*7) LiteRT(旧 TensorFlow Lite)| Google AI Edge
https://ai.google.dev/edge/litert?hl=ja

(*8) Core ML Model Format Specification
https://apple.github.io/coremltools/mlmodel/index.html

(*9) Save and load checkpoints — Flax documentation
https://flax-linen.readthedocs.io/en/latest/guides/training_techniques/use_checkpointing.html

(*10) Safetensors — Hugging Face documentation
https://huggingface.co/docs/safetensors/index

(*11) ggml-org/llama.cpp — GitHub
https://github.com/ggml-org/llama.cpp

(*12) GGUF File Format Specification — GitHub
https://github.com/ggml-org/ggml/blob/master/docs/gguf.md

(*13) Recommend a different file extension for models (.PTH is a special extension for Python) — GitHub
https://github.com/pytorch/pytorch/issues/14864

(*14) ml-explore/mlx — GitHub
https://github.com/ml-explore/mlx

(*15) pytorch/executorch — GitHub
https://github.com/pytorch/executorch

author img for Naoki Matagawa
Naoki Matagawa

2016年4月、アシアル株式会社に新卒で入社。Onsen UI の開発に2年ほど参加した後、Monaca のバックエンド・フロントエンド開発や、iOS/Android アプリ開発、AIソリューションの開発に従事。CPU や GPU、ファイルフォーマットの仕様書を読むのが好き。

記事一覧

前の記事へ

一覧へ戻る

「テクノロジー」カテゴリの最新記事

PAGE TOP