How to re-align external weights without loading them in memory#
This page documents the recommended recipe for re-aligning the tensor
offsets of an existing two-file (or multi-file) ONNX model without ever
loading the weights in RAM. The driver is
onnx_light.onnx.align_external_data_streaming() in Python and
onnx_light::AlignExternalDataStreaming() in C++.
When to use it#
Use this how-to when all of the following are true:
The model is already saved on disk as a
(.onnx, .data[, .data.1, ...])pair where the initializers point at the weights file(s) through theirexternal_dataentries.You want every tensor offset in the destination weights file to be aligned to a power-of-two boundary (for example
4096for page-aligned mmap or accelerator-friendly loading).The model is too large — or the host too memory-constrained — to load the full set of weights into memory just to re-serialize them.
Recipe#
The function parses only the proto metadata and streams each tensor’s bytes
from the source weights file to the destination weights file in chunks of
chunk_size bytes, zero-padding to the requested alignment between
tensors. Peak heap usage is therefore bounded by (metadata size +
chunk_size), independent of the total weights size.
import onnx_light.onnx as onnxl
total_bytes = onnxl.align_external_data_streaming(
src_onnx_path="src.onnx",
dst_onnx_path="dst.onnx",
dst_weights_path="dst.data",
alignment=4096,
chunk_size=4 * 1024 * 1024,
)
print(f"Wrote {total_bytes} bytes (including alignment padding) to dst.data")
#include "onnx_helper.h"
#include "stream.h"
#include <iostream>
onnx::offset_t total_bytes = onnx::AlignExternalDataStreaming(
/*src_onnx_path=*/"src.onnx",
/*dst_onnx_path=*/"dst.onnx",
/*dst_weights_path=*/"dst.data",
/*alignment=*/4096,
/*chunk_size=*/4 * 1024 * 1024);
std::cout << "Wrote " << total_bytes
<< " bytes (including alignment padding) to dst.data\n";
After the call:
dst.onnxis a fresh.onnxfile whose initializers all referencedst.datawith aligned offsets.dst.datais a single consolidated weights file — even when the source spread tensors across multipleexternal_data.locationfiles.The source files (
src.onnxand its.datacompanions) are not modified.
Comparison with the in-memory variant#
The “usual” path is to load(load_external_data=True) the model and then
re-serialize it with SerializeOptions.alignment set to the desired
value. Functionally the two approaches produce byte-equivalent tensor
payloads at the same aligned offsets; the only difference is the peak
memory footprint:
Aspect |
|
|
|---|---|---|
Peak heap |
O(metadata + |
O(total weights size) |
Source files |
Untouched |
Untouched |
Destination weights |
Single consolidated file |
Single consolidated file (with |
Recommended when |
Weights do not fit in RAM |
Weights comfortably fit in RAM |
See Benchmark streaming vs in-memory alignment of external data for a runnable benchmark of both approaches.
See also#
onnx_light.onnx.align_external_data_streaming()/onnx_light::AlignExternalDataStreaming()– API reference.Complex loading and saving scenarios – design notes on complex load/save scenarios this function was designed for.
How to save a model that shares weights with another on-disk model – companion how-to for sharing weights across multiple models.
html_theme.sidebar_secondary.remove – common load/save patterns.