Tracks
最近 Hugging Face からモデルをダウンロードしたなら、.bin や .pkl ではなく .safetensors ファイルに気づいたはずです。見た目以上に大きな変化です。
長年、多くの ML フレームワークはモデルのチェックポイント保存に pickle ベースのシリアライゼーションに依存してきました。十分に機能していましたが、見えない代償がありました。チェックポイントの読み込み時、逆シリアル化の過程で任意の Python コードが実行される可能性があり、サプライチェーン攻撃や一見無害なモデルファイルに埋め込まれた悪意あるペイロードへの扉を開いてしまうのです。
SafeTensors はそのギャップを埋めるために作られました。生のテンソル重みだけを保存し、読み込み時にコードを一切実行しません。これにより Hugging Face Hub 全体でデフォルトのフォーマットになっています。2026年4月には、PyTorch、vLLM、DeepSpeed、Ray などのプロジェクトとともに、Linux Foundation 傘下の PyTorch Foundation に正式に参加しました。
この先では、フォーマットの仕組みと他フォーマットとの比較を解説します。
SafeTensors とは?
SafeTensors は、モデルの重みを安全に保存するために特化して設計されたファイルフォーマットです。
このフォーマットは、生の数値テンソルデータと実行可能コードを分離し、重みのみを保存します。ここがpickle ベースのフォーマットとの違いです。
また、SafeTensors は多くのチェックポイントがすでに含んでいるもの、すなわち次の点に焦点を当てているため、現代的な ML パイプラインに自然に適合します。
- テンソル
- 形状
- データ型
- 重みの値
汎用の Python シリアライゼーションとして振る舞うのではなく、SafeTensors はモデルパラメータのための専用ストレージ層として機能します。
もともと Hugging Face が自社エコシステム向けに SafeTensors を開発しましたが、フォーマット自体はフレームワークに依存しません。直近(2026年4月)に PyTorch Foundation に参加し、PyTorch、TensorFlow、JAX、Flax、NumPy などの ML フレームワークをサポートしています。
Pickle の問題:新しいフォーマットが必要だった理由
Python の Pickle フォーマットは、開発者が内部状態、メソッド、復元ロジックとともに Python オブジェクト全体を保存・復元する必要がある一般的な Python アプリケーション向けに作られました。
しかし機械学習のチェックポイントでは、そこまでの保存は通常不要です。多くのモデルファイルは、重み行列、埋め込み、バイアスなどの数値パラメータ、つまり主にテンソルを保存します。実際には、チェックポイントは大部分が構造化された数値データなのです。
ところが .pkl ファイルは、単なるデータ保存以上のことを行います。読み込み時に Python がオブジェクトをどう再構築するかの指示を含められます。つまり逆シリアル化は受動的な読み取りではなく、コードを実行し得るのです。もしそのコードが悪意あるものなら、深刻なセキュリティ問題になります。
pickle が任意コード実行を可能にする仕組み
Python は pickle の逆シリアル化の際、__reduce__() のような特別なメソッドを使ってオブジェクトを再構築します。クラスはこのメソッドを定義し、読み込み時にオブジェクトをどう再構築すべきかを pickle に正確に伝えられます。
例えば、__reduce__() は関数呼び出し可能オブジェクトと、その引数を返せます。逆シリアル化の間、Python はその呼び出し可能オブジェクトを実行してオブジェクトを再構築します。例コード:
import pickle
import os
class Demo:
def __reduce__(self):
return (os.system, ("echo 'Code executed during deserialization'",))
payload = pickle.dumps(Demo())
pickle.loads(payload)
pickle.loads() が実行されると、Python は __reduce__() が返した関数を実行します。この例では、逆シリアル化が os.system() を通してシェルコマンドをトリガーします。
問題はシェルコマンドそのものではありません。__reduce__() はロジック次第で任意の呼び出し可能オブジェクトと任意の引数を返せます。つまり Pickle ファイルは他の関数を呼び出したり、ファイルをダウンロードしたり、環境を変更したり、読み込み時に悪意のあるコードを実行したりできるのです。だからこそ Python のドキュメントは、信頼できないソースからの pickle データを読み込まないよう明確に警告しています。
モデル共有時代のリスク
Hugging Face Hub のようなプラットフォームには今や、研究者、スタートアップ、ホビイスト、匿名の投稿者らが共有した100万以上のモデルがホストされています。開発者がモデルをすぐにダウンロードして試せるため、エコシステムは高速に進化しています。しかし、アップロードされたチェックポイントの多くは配布前に個別に監査されていません。
多くの PyTorch チェックポイントは依然として .pt や .bin といった pickle ベースのフォーマットに依存しています。これらのファイルを読み込むと、Python はチェックポイント内部に埋め込まれた逆シリアル化ロジックを実行する可能性があります。もし悪意あるチェックポイントであれば、そのロジックは認証情報の窃取、環境変数の読み取り、ペイロードのダウンロード、読み込み時のリモートコード実行などを行い得ます。

これは SafeTensors がまさに解決するために作られた問題です。任意の Python オブジェクトをシリアライズするのではなく、テンソルデータと、それらを正しく読み込むために必要なメタデータだけを保存します。.safetensors ファイルの読み込みには Python の再構築ロジックの実行が不要で、攻撃対象領域を大幅に減らします。
SafeTensors フォーマットの仕組み
SafeTensors が何で、なぜ存在するのかが分かったところで、その構造と動作を見ていきましょう。
ヘッダーとデータの二部構成
SafeTensors ファイルは、JSON ヘッダーとそれに続く生のテンソルデータの 2 部で構成されています。
このヘッダーは各テンソルのメタデータ、具体的には
- テンソル名
- 形状
- データ型
- バイトオフセット
を保存します。ヘッダーの後に、ファイル本体は生のテンソルのバイト列を連続して格納します。
ヘッダーは目次のように機能します。どのテンソルが存在し、ファイル内のどこにあるかをローダに伝えます。これはデータベースのインデックスが保存レコードを指し示すのに似ています。SafeTensors はヘッダーサイズを 100MB に制限し、過大なメタデータを防いでいます。
ゼロコピーとメモリマップド読み込み
SafeTensors はメモリマップド読み込みによってロード速度を高めます。逆シリアル化で Python オブジェクトを再構築する代わりに、フレームワークはディスク上のテンソルデータをメモリに直接マップできます。これにより不要なメモリコピーが削減され、読み込み時の CPU 負荷が下がります。
Hugging Face の ベンチマークによれば、SafeTensors は CPU 上で PyTorch 比およそ 76 倍、GPU ワークロードでおよそ 2 倍高速に重みを読み込みました。もちろん、実際の高速化はハードウェアやチェックポイントのサイズに依存しますが、Python の逆シリアル化を避けることで、ロード性能は一貫して向上します。
レイジーロードと部分的な逆シリアル化
SafeTensors は、チェックポイント全体を一度にメモリへ読み込むのではなく、テンソル名を指定して個別にロードできます。
これは複数 GPU にまたがって動作する大規模な分散モデルで有用です。例えば BLOOM の 176B パラメータモデルでは、標準の PyTorch チェックポイントだと、デバイス間で分割する前にまずモデル全体の重みを逆シリアル化する必要があり、約 10 分を要しました。
SafeTensors では、各 GPU が実際に必要なテンソルシャードだけを読み込みました。これにより、8GPU 構成でモデルの起動時間が約 45 秒まで短縮されました。
SafeTensors と他のシリアライゼーション形式の比較
SafeTensors はモデル重みの安全かつ効率的な保存・読み込みに優れていますが、あらゆるフォーマットの完全な代替というわけではありません。何を保存するのか、モデルがパイプラインのどこに位置するのかによって最適解は変わります。
pickle については十分に触れたので、ここでは別のフォーマットに焦点を当てます。
SafeTensors と GGUF
SafeTensors と GGUF は異なる問題を解きます。
GGUF(GGML Unified Format の略)は、llama.cpp のようなランタイムでの量子化推論ワークロード向けに作られました。このフォーマットは、特に CPU 推論やエッジデバイスにおける圧縮モデルの効率的なデプロイに注力しています。
SafeTensors はパイプラインのより前段に位置します。多くの SafeTensors チェックポイントは、学習、ファインチューニング、マージ、分散推論ワークフローで使われる、学習可能もしくは学習準備済みのフル精度テンソルを保存します。フォーマットは安全な読み込み、PyTorch などのフレームワークとの互換性、学習や提供時の効率的なテンソルアクセスを優先しています。
両者は競合するのではなく補完し合えます。ワークフロー例:
- PyTorch と SafeTensors チェックポイントでモデルを学習またはファインチューニング
- 最終モデルを量子化
- llama.cpp やエッジ推論ランタイムでのデプロイに向けて GGUF にエクスポート
SafeTensors と ONNX
SafeTensors は、PyTorch のようなフレームワーク内部でモデル重みを安全に保存し、効率よく読み込むことに特化しています。テンソルとメタデータのみを保存するため、チェックポイント共有、ファインチューニング、学習ワークフローにおいて軽量かつ高速です。
ONNX はより広いアプローチを取ります。モデルパラメータに加えて計算グラフ全体を保存します。これにより、あるフレームワークからモデルをエクスポートし、まったく別の場所で実行したい場合に有用です。
例えば、PyTorch で LLM を学習・ファインチューニングするチームは、チェックポイントの読み込みが速く既存ワークフローに直接統合できるため、通常は SafeTensors を好みます。しかし同じチームがモデルを TensorRT、ONNX Runtime、またはエッジ推論エンジンにデプロイする必要があるなら、ONNX へのエクスポートが理にかないます。
実務での SafeTensors の使い方
SafeTensors が PyTorch エコシステム全体で急速に広まった理由の一つは、API が馴染みやすいことです。これまでと同じように state dict とテンソルを扱えます。
テンソルの保存と読み込み
基本的なワークフローは標準的な PyTorch のチェックポイント処理とほぼ同じです。例を示します:
import torch
from safetensors.torch import save_file, load_file
tensors = {
"weights": torch.randn(2, 2),
"bias": torch.zeros(2)
}
save_file(tensors, "model.safetensors")
loaded_tensors = load_file("model.safetensors")
print(loaded_tensors["weights"])
save_file() はテンソルを .safetensors 形式に書き出し、load_file() はそれらをメモリに読み戻します。
SafeTensors は safe_open() による選択的読み込みにも対応しており、必要なテンソルだけが欲しい大規模チェックポイントで有用です。
from safetensors import safe_open
with safe_open("model.safetensors", framework="pt") as f:
weights = f.get_tensor("weights")
print(weights)
フルチェックポイントを読み込む代わりに、get_tensor() は指定したテンソルだけを読み出します。
既存モデルを safetensors に変換する
標準的な手順は以下の通りです。
- 既存モデルを読み込む
- state dict を取り出す
save_file()で保存する
from transformers import AutoModel
from safetensors.torch import save_file
model = AutoModel.from_pretrained("bert-base-uncased")
save_file(model.state_dict(), "model.safetensors")
state_dict() はモデル重みをテンソルとして返し、SafeTensors がそのまま保存できます。
モデルがすでに Hugging Face Hub 上にある場合は、ローカルで変換コードを書く必要すらないかもしれません。Hub のインターフェースを通じて、ホストされたモデルのチェックポイント変換が組み込みでサポートされています。
シリアライゼーション形式:比較表
| 機能 | SafeTensors | Pickle (.pkl/.bin/.pt) |
GGUF | ONNX |
|---|---|---|---|---|
| 任意コード実行 | いいえ | はい | いいえ | いいえ |
| 主な用途 | 学習、ファインチューニング、チェックポイント共有 | 汎用 Python シリアライゼーション | 量子化済みのエッジ/CPU 推論 | フレームワーク横断のデプロイ |
| 計算グラフの保存 | いいえ | いいえ | いいえ | はい |
| メモリマップド読み込み | 対応 | 非対応 | 対応 | 非対応 |
| レイジー/部分的テンソル読み込み | 対応 | 非対応 | 対応 | 非対応 |
| フレームワーク対応 | PyTorch、TF、JAX、Flax、NumPy | Python(全フレームワーク) | llama.cpp、エッジランタイム | ONNX Runtime、TensorRT、エッジ |
| 量子化サポート | 拡大中(FP8、GPTQ、AWQ) | いいえ | はい(ネイティブ) | はい |
| Hugging Face Hub でのデフォルト | はい | いいえ | いいえ | いいえ |
2026 年の SafeTensors:PyTorch Foundation と今後
2026年4月、Hugging Face は SafeTensors を Linux Foundation 傘下の PyTorch Foundation に寄贈しました。これにより、プロジェクトは PyTorch、vLLM、DeepSpeed、Ray と並び、財団のガバナンスのもとに置かれることになりました。
この動きは、SafeTensors がもはや Hugging Face 単独のプロジェクトではないことを示します。ML エコシステムの共有インフラになりつつあるのです。
発表では、フォーマットの今後の方向性にも触れられています。
デバイス認識型の読み込み
大きな焦点の一つはデバイス認識型の読み込みです。今日の多くのワークフローでは、依然としてテンソルを CPU メモリに読み込んでから CUDA や ROCm デバイスへ転送しています。この中間段階が特に大規模分散システムの起動遅延を増やします。
SafeTensors のメンテナは、不要な CPU コピーを減らし、テンソルをアクセラレータへ直接移すためのダイレクトデバイスロード経路に取り組んでいます。
分散読み込み
分散読み込みのサポートも進化しています。 最新の推論システムは、もはや単一 GPU だけでモデルを走らせることはまれです。テンソル並列やパイプライン並列が大規模モデルの標準的なデプロイ手法になっていますが、フレームワーク間でのチェックポイント読み込み API はまだ断片的です。
SafeTensors はシャード認識型読み込みや分散テンソルレイアウトのサポートを拡充し、フレームワークがデバイス間でのチェックポイント読み込みをより効率的に調整できるようにしています。
最新の量子化ワークフロー
フォーマットは新しい量子化ワークフローにも適応しています。 推論システムは、FP8、GPTQ、AWQ などの形式にますます依存し、メモリ使用量と提供コストを抑えています。
フレームワーク側にカスタムのシリアライゼーションロジックを強いるのではなく、SafeTensors は低精度やブロック量子化されたテンソル形式の正式サポートをフォーマット自体に追加しています。
現時点では、保存・読み込みワークフローを切り替えることで開発者が手動で SafeTensors を選ぶ必要があります。しかし、PyTorch のネイティブなシリアライゼーションシステムとのより深い統合に向けた取り組みが進んでいます。もしそれが実現すれば、SafeTensors は代替チェックポイント形式ではなく、PyTorch がモデルを保存するデフォルト手段になり得ます。
まとめ
長年にわたり、開発者は読み込み時に任意の Python コードを実行し得るシリアライゼーションシステムでモデルのチェックポイントを共有してきました。公開モデルハブが何百万ものチェックポイントをホストするようになると、そのセキュリティリスクは無視しがたくなりました。
SafeTensors はフォーマットの範囲を絞ることで状況を変えました。Python オブジェクト全体のシリアライズを試みるのではなく、テンソルとそれらを読み込むために必要なメタデータだけに注力します。このシンプルな設計により、pickle ベースのチェックポイントに伴う逆シリアル化リスクを取り除きつつ、読み込み速度とメモリ効率も向上します。
必要なのがモデルの重みだけなら、逆シリアル化の最中に任意のコードを実行する理由はありません。そうしたケースでは SafeTensors を使うのが賢明です。
もし現代の ML ツール群、モデルフォーマット、Hugging Face のワークフローをより深く学びたいなら、Deep Learning in Python と Working with Hugging Face のコースが次の一歩として適しています。今日の AI エコシステムで使われているツールを用いた学習、ファインチューニング、デプロイの実践的なワークフローをカバーします。
SafeTensors のよくある質問
既存の .bin や .pt モデルを SafeTensors に変換できますか?
はい。PyTorch または Transformers で通常どおりモデルを読み込み、state_dict() を抽出して、safetensors ライブラリの save_file() で保存できます。Hugging Face Hub でも多くのホスト済みモデルについて自動変換がサポートされています。
SafeTensors は量子化モデルを保存できますか?
はい。SafeTensors はすでに複数の低精度テンソル型をサポートしており、量子化推論が一般化するにつれて FP8、GPTQ、AWQ などへの対応が拡大しています。
モデル全体を読み込まずに SafeTensors ファイルの中身を確認できますか?
はい。フォーマットはテンソルのメタデータをヘッダーに分離して保存するため、チェックポイント全体をメモリに読み込まずに、テンソル名、形状、データ型を確認できます。
SafeTensors を使うとモデル精度に影響しますか?
いいえ。SafeTensors は重みの保存・読み込み方法を変えるだけで、数値そのものは変えません。読み込み後のモデルの動作は同じです。
SafeTensors は推論ワークロードにしか役立ちませんか?
いいえ。学習、ファインチューニング、チェックポイント共有、分散読み込みなどでも使われます。
