PyTorch documents how to use torch.save but not the bytes; this page
describes what PyTorch’s own code writes and reads:
torch/serialization.py,
the ZIP writer in caffe2/serialize/inline_container.cc and
.h, versions.h and torch/_utils.py, all read
2026-11-12. Loading a .pt file runs a
pickle; PyTorch 2.6 changed the default of
torch.load’s weights_only argument from
False to True, and its own warning says that loading with
False can result in arbitrary code execution.
ZIP entries
Since PyTorch 1.6 the file is a ZIP archive (always written as ZIP64) with stored (uncompressed) entries, all inside one folder, the archive name:
| Entry | Holds |
|---|---|
data.pkl | The saved object, pickled with protocol 2, tensors replaced by persistent IDs. |
data/0, data/1… | The raw bytes of each storage, named by its key. |
version or .data/version | Text: the archive format version as a decimal number and a line feed. The writer starts at 3; it uses .data/version instead when the version is 6 or more. |
byteorder | Text: little or big. When it is missing, the reader falls back to a configurable byte order, native by default. |
.format_version | 1: storages are ordered numerically by key. |
.storage_alignment | The storage alignment used. |
.data/serialization_id | An ID the reader records with the file name. |
Every entry’s data starts at an offset aligned to 64 bytes by default (the Python
setting storage_alignment); the padding goes in the ZIP local header’s
extra field under the key FB, so the data can be memory-mapped.
Tensors in data.pkl
- A tensor is pickled as a call to
torch._utils._rebuild_tensor_v2(storage, storage_offset, size, stride, requires_grad, backward_hooks, metadata=None). - The storage is a persistent ID, a tuple
('storage', storage_type, key, location, numel): the storage type (atorchattribute such as a typed storage class), the key namingdata/key, the location tag of its device, and its size: elements for a typed storage, bytes for an untyped one. - Several tensors can share one storage at different offsets and strides; saving two views of the same data as different types is an error.
- Parameters are rebuilt through
torch._utils._rebuild_parameter(or_rebuild_parameter_with_state).
TorchScript archives
TorchScript models use the same container. The writer’s header comment describes
a code/ folder holding the serialised TorchScript source for modules
with methods; the other entries are not described there.
Legacy format
Before 1.6 (and with _use_new_zipfile_serialization=False), the file
is several pickles one after another:
- The magic number
0x1950A86A20F9469CFC6C, pickled as an integer. - The protocol version, 1001.
- A dictionary of system information: the protocol version, whether the machine is little-endian, and the sizes of short, int and long.
- The object, with storages as persistent IDs
('storage', type, key, location, numel, view_metadata). - The sorted list of the storage keys.
- Then each storage’s data, written by the storage’s own
_write_file.
torch.load also still reads a legacy tar
format, with a storages member among others.