llm.export — Model Export¶
Export models to ONNX, TorchScript, and GGUF formats. Supports custom
export backends registered via the llm.export_backends entry point
group.
Overview¶
| Format | Status |
|---|---|
| ONNX | Reference implementation, stable API |
| TorchScript | Entry-point registered |
| GGUF | Entry-point registered (v1: F16/F32/Q4_0/Q8_0/Q2_K..Q6_K, ADR-011) |
| Custom | Via EXPORT_REGISTRY plugin points |
Export Registry¶
registry
¶
Export backend registry and bootstrap.
Mirrors the generation/registry.py pattern so third-party
export targets (e.g. torch.compile, vLLM, TensorRT-LLM,
torch.export, OpenVINO) can plug in via the
llm.export_backends setuptools entry-point group without
forking export/.
Built-in targets
onnx — wraps the existing export_to_onnx function. This
is the canonical reference implementation; the entry-point load
raises if a plugin claims the same name, which is intentional
(the built-in is the source of truth).
torchscript / gguf — registered via the
llm.export_backends entry-point group in pyproject.toml.
Usage::
>>> from llm.export.registry import export_model
>>> export_model("onnx", model, "out.onnx", input_shape=(1, 32)) # doctest: +SKIP
Plugin authors can register a target via pyproject.toml:
[project.entry-points."llm.export_backends"]
my_target = "my_pkg.exporters:build_my_target"
build_onnx_exporter
¶
Factory for the built-in ONNX export target.
Thin wrapper over :func:llm.export.onnx.export_to_onnx so the
registry contract ((model, output_path, **kwargs) -> Path)
matches every other target. The wrapper exists purely so the
registry doesn't have to special-case keyword forwarding for
ONNX's wider surface (opset_version, dynamic_axes,
verbose, ...).
源代码位于: src/llm/export/registry.py
ensure_exporters_registered
¶
Idempotently register built-in exporters and load entry points.
Built-ins are registered BEFORE the entry-point load so a plugin
that claims onnx raises loudly — the built-in is the
reference implementation. This matches the convention in
generation/registry.ensure_backends_registered.
源代码位于: src/llm/export/registry.py
export_model
¶
Resolve a registered export target and run it.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
name
|
str
|
Registered export target name (e.g. |
必需 |
model
|
Module
|
The model to export. |
必需 |
output_path
|
str | Path
|
Where to write the artifact. |
必需 |
**kwargs
|
Any
|
Target-specific kwargs forwarded to the factory. |
{}
|
返回:
| 类型 | 描述 |
|---|---|
Path
|
The resolved output path. |
引发:
| 类型 | 描述 |
|---|---|
ValueError
|
If |
源代码位于: src/llm/export/registry.py
ONNX Export¶
onnx
¶
export_to_onnx
¶
export_to_onnx(model, output_path, input_shape=(1, 32), opset_version=17, dynamic_axes=None, verbose=False)
Export a model to ONNX format.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
The model to export (e.g., DecoderModel) |
必需 |
output_path
|
str | Path
|
Path to save the ONNX file |
必需 |
input_shape
|
tuple[int, int]
|
(batch_size, seq_len) for dummy input |
(1, 32)
|
opset_version
|
int
|
ONNX opset version (default: 17) |
17
|
dynamic_axes
|
dict | None
|
Dynamic axes for variable-length inputs |
None
|
verbose
|
bool
|
Print export details |
False
|
返回:
| 类型 | 描述 |
|---|---|
Path
|
Path to the exported ONNX file |
Example::
>>> model = DecoderModel(vocab_size=1000, hidden_size=64, num_layers=2, num_heads=4) # doctest: +SKIP
>>> export_to_onnx(model, "model.onnx", input_shape=(1, 32)) # doctest: +SKIP
源代码位于: src/llm/export/onnx.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
verify_onnx
¶
Verify ONNX model correctness by comparing with PyTorch output.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
onnx_path
|
str | Path
|
Path to ONNX file |
必需 |
model
|
Module | None
|
Original PyTorch model (optional, for comparison) |
None
|
input_shape
|
tuple[int, int]
|
Input shape for verification |
(1, 32)
|
rtol
|
float
|
Relative tolerance for comparison |
0.001
|
atol
|
float
|
Absolute tolerance for comparison |
1e-05
|
返回:
| 类型 | 描述 |
|---|---|
bool
|
True if verification passes |
引发:
| 类型 | 描述 |
|---|---|
ImportError
|
If onnxruntime is not installed |
源代码位于: src/llm/export/onnx.py
get_onnx_info
¶
Get information about an ONNX model.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
onnx_path
|
str | Path
|
Path to ONNX file |
必需 |
返回:
| 类型 | 描述 |
|---|---|
dict
|
Dictionary with model info (inputs, outputs, opset) |
引发:
| 类型 | 描述 |
|---|---|
ImportError
|
If onnx is not installed |
源代码位于: src/llm/export/onnx.py
TorchScript Export¶
torchscript
¶
TorchScript export backend.
This is the second target of :data:llm.export.registry.EXPORT_REGISTRY
and the first one to register through the llm.export_backends
setuptools entry-point group (rather than the in-code registration
used by the built-in onnx target). See
:func:llm.export._plugins.register_torchscript_exporter for the
hook the entry point points at.
TorchScript ships with PyTorch, so this backend adds no runtime
dependencies. The exported artifact is a .pt file loadable via
torch.jit.load — useful for deployment paths that can't or
won't bring up an ONNX runtime.
Two export modes are supported:
method='trace'(default): records operations with example inputs. Works for any model that isforward-passable with static shapes. The cache wrapper forcesuse_cache=Falseso the tracer doesn't record KV-cache branching.method='script': compiles the model with the TorchScript compiler. Requires a model whose forward uses only TorchScript-supported constructs. Models with dynamic Python control flow may not script; in that case, fall back totrace.
export_to_torchscript
¶
export_to_torchscript(model, output_path, *, method='trace', input_shape=(1, 32), example_inputs=None, strict=True, **kwargs)
Export a model to TorchScript.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
The model to export. |
必需 |
output_path
|
str | Path
|
Path to write the |
必需 |
method
|
str
|
|
'trace'
|
input_shape
|
tuple[int, int]
|
|
(1, 32)
|
example_inputs
|
Tensor | None
|
Pre-built dummy tensor. Overrides
|
None
|
strict
|
bool
|
Forwarded to :func: |
True
|
**kwargs
|
Any
|
Forwarded to :func: |
{}
|
返回:
| 类型 | 描述 |
|---|---|
Path
|
The resolved output path. |
引发:
| 类型 | 描述 |
|---|---|
ValueError
|
If |
源代码位于: src/llm/export/torchscript.py
build_torchscript_exporter
¶
Factory for the TorchScript export target.
Thin wrapper over :func:export_to_torchscript so the registry
contract ((model, output_path, **kwargs) -> Path) matches
every other target.
源代码位于: src/llm/export/torchscript.py
GGUF Export¶
gguf
¶
GGUF model format module (ADR-011).
Implements the GGUF v3 container — header / typed metadata / tensor
info plus reader and writer — and the two GGML block-quantization
schemes shipped in v1 (Q4_0 and Q8_0), then exposes the GGUF export
target for :data:llm.export.registry.EXPORT_REGISTRY.
Public surface:
- format: :class:
GGUFHeader, :class:GGUFTensorInfo, :class:GGUFValueType, :class:GGMLQuantizationType, :class:GGUFError, and theGGUF_*constants; - I/O: :class:
GGUFWriter/ :class:GGUFReader; - quantization: :func:
quantize_q4_0/ :func:dequantize_q4_0and :func:quantize_q8_0/ :func:dequantize_q8_0; - dequantization (reader side): :func:
dequantize_q4_1/ :func:dequantize_q5_0/ :func:dequantize_q5_1and the K-quant family :func:dequantize_q2_k.. :func:dequantize_q6_k(import real llama.cpp files); - export: :func:
export_to_gguf/ :func:build_gguf_exporter; - load-back: :func:
load_gguf_model(re-build a model from a GGUF the exporter wrote withmodel_config=).
GGUFReader
¶
Parse and read a GGUF file.
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
path |
The source file path. |
|
header |
Parsed :class: |
|
metadata |
Ordered metadata dict (typed Python values). |
|
tensors |
|
源代码位于: src/llm/export/gguf/reader.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | |
close
¶
read_tensor_raw
¶
Return the exact on-disk payload bytes for name (no dequantization).
read_tensor
¶
Read and dequantize name into a float32 array of its logical shape.
F32/F16 payloads are returned as-is (F16 widened); Q4_0/Q8_0 and the reader-side legacy/K-quant types (Q4_1/Q5_0/Q5_1, Q2_K..Q6_K) are dequantized with the reference ggml math.
源代码位于: src/llm/export/gguf/reader.py
GGMLQuantizationType
¶
Bases: IntEnum
GGML tensor data types as stored in GGUF tensor info (ggml_type).
The integer type codes were renumbered by ggml PR #6050. F32 /
F16 / Q4_0 / Q8_0 have stable codes across all versions and
are the types this repo exports. Reading additionally supports the
legacy 32-wide schemes (Q4_1 / Q5_0 / Q5_1) and the 256-wide
K-quant family (Q2_K .. Q6_K) that make up virtually every
downloadable llama.cpp GGUF. The remaining values follow the current
ggml.h enumeration.
源代码位于: src/llm/export/gguf/spec.py
GGUFError
¶
GGUFHeader
dataclass
¶
GGUFTensorInfo
dataclass
¶
Parsed GGUF tensor info.
shape is the LOGICAL shape in row-major (PyTorch/NumPy) order —
e.g. (out_features, in_features). GGUF stores dimensions in the
reverse order on disk; reader and writer translate at the boundary.
源代码位于: src/llm/export/gguf/spec.py
GGUFValueType
¶
Bases: IntEnum
GGUF metadata value types (spec §Value Types).
源代码位于: src/llm/export/gguf/spec.py
GGUFWriter
¶
Incremental GGUF v3 writer.
Usage::
writer = GGUFWriter("model.gguf")
writer.add_metadata("general.name", "tiny")
writer.add_tensor("w", weight_numpy, ggml_type="q8_0")
path = writer.write()
源代码位于: src/llm/export/gguf/writer.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | |
add_metadata
¶
Register one metadata KV pair (later duplicates overwrite).
源代码位于: src/llm/export/gguf/writer.py
add_tensor
¶
Register one tensor with an explicit GGML type.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
name
|
str
|
Tensor name (must be unique). |
必需 |
data
|
Any
|
|
必需 |
ggml_type
|
GGMLQuantizationType | str
|
One of |
必需 |
引发:
| 类型 | 描述 |
|---|---|
ValueError
|
For duplicate names, non-float input, or a block-quantized type whose last dimension is not a multiple of 32. |
GGUFError
|
For unsupported tensor types. |
源代码位于: src/llm/export/gguf/writer.py
write
¶
Assemble and atomically write the GGUF file; returns the output path.
源代码位于: src/llm/export/gguf/writer.py
build_gguf_exporter
¶
Factory for the GGUF export target (EXPORT_REGISTRY contract).
export_to_gguf
¶
export_to_gguf(model, output_path, *, quantize=None, metadata=None, model_name=None, quantize_min_ndim=2, model_config=None)
Export model.state_dict() to a GGUF v3 file.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
The model to export (evaluated state, tensors are detached on CPU). |
必需 |
output_path
|
str | Path
|
Destination |
必需 |
quantize
|
str | GGMLQuantizationType | None
|
|
None
|
metadata
|
dict[str, Any] | None
|
Extra |
None
|
model_name
|
str | None
|
Override for |
None
|
quantize_min_ndim
|
int
|
Minimum tensor rank eligible for block-quantization. |
2
|
model_config
|
dict[str, Any] | None
|
Optional architecture config as a JSON-safe dict
(e.g. |
None
|
返回:
| 类型 | 描述 |
|---|---|
Path
|
The resolved output path. |
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
If the model has a non-floating tensor in its state dict (v1 scope). |
ValueError
|
For unknown |
源代码位于: src/llm/export/gguf/exporter.py
load_gguf_model
¶
Rebuild a model from a GGUF file — self-export or llama.cpp import.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
path
|
str | Path
|
GGUF file path. |
必需 |
device
|
device | str | None
|
Optional target device (default: CPU). |
None
|
返回:
| 类型 | 描述 |
|---|---|
Module
|
The rebuilt model in |
Module
|
weights. |
引发:
| 类型 | 描述 |
|---|---|
GGUFError
|
If the file is malformed; if a self-export carries an
invalid |
RuntimeError
|
If the tensor names/shapes in a self-export do not match
the model rebuilt from the embedded config (strict
|
Note
F32/F16 files round-trip or import exactly (widened to float32); block-quantized files (Q4_0/Q8_0) come back dequantized and therefore approximately, within the quantizer's expected error.
源代码位于: src/llm/export/gguf/loader.py
dequantize_q2_k
¶
Dequantize Q2_K blocks: 256 2-bit values, 16 per-block (d,s) pairs.
Layout: scales(16) + qs(64) + d(2) + dmin(2). Per 16-element group,
dl = d * (scales & 0xF) and ml = dmin * (scales >> 4); value is
dl * q2 - ml.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q3_k
¶
Dequantize Q3_K blocks: 256 3-bit values + 16 scale bytes packed 6-bit.
Layout: hmask(32) + qs(64) + scales(12) + d(2). The 16 per-block scales
are packed 6 bits each across the 12 scales bytes.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q4_0
¶
Dequantize Q4_0 blocks back to float32.
Matches ggml's dequantize_row_q4_0: (q - 8) * d with the same
(negative) per-block scale used at quantize time.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
packed
|
ndarray
|
|
必需 |
scales
|
ndarray
|
|
必需 |
n
|
int
|
Total element count to reconstruct. |
必需 |
源代码位于: src/llm/export/gguf/quant.py
dequantize_q4_1
¶
Dequantize Q4_1 blocks: value = q * d + m (q in 0..15).
源代码位于: src/llm/export/gguf/quant.py
dequantize_q4_k
¶
Dequantize Q4_K blocks: value = d*sc*q - dmin*m.
Layout: d(2) + dmin(2) + scales(12) + qs(128); 8 (scale, min) pairs cover eight 32-element groups.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q5_0
¶
Dequantize Q5_0 blocks: value = (q - 16) * d; element p keeps
its fifth bit at qh bit p (file/quantizer layout — see module doc).
源代码位于: src/llm/export/gguf/quant.py
dequantize_q5_1
¶
Dequantize Q5_1 blocks: value = q * d + m with the same qh layout.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q5_k
¶
Dequantize Q5_K blocks: 32-element groups with 5-bit values.
Layout: d(2) + dmin(2) + scales(12) + qh(32) + qs(128); the 5th bit of
element p lives in qh bit (p % 32) of byte p // 32.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q6_k
¶
Dequantize Q6_K blocks: 256 6-bit values, 16 per-block fp16*int8 scales.
Layout: ql(128) + qh(64) + scales(16) + d(2); value = d * sc * (q - 32)
with sc an int8 per 16-element group.
源代码位于: src/llm/export/gguf/quant.py
dequantize_q8_0
¶
Dequantize Q8_0 blocks back to float32.
源代码位于: src/llm/export/gguf/quant.py
quantize_q4_0
¶
Quantize float data to Q4_0 blocks.
Byte-compatible with ggml's quantize_row_q4_0_reference so the
packed tensor is readable by llama.cpp / the wider GGUF ecosystem.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
data
|
ndarray
|
Float array with a multiple of 32 elements (any shape is flattened row-major). |
必需 |
返回:
| 类型 | 描述 |
|---|---|
ndarray
|
|
ndarray
|
per two elements and |
tuple[ndarray, ndarray]
|
per ggml) scale per 32-element block. |
源代码位于: src/llm/export/gguf/quant.py
quantize_q8_0
¶
Quantize float data to Q8_0 blocks.
Returns (values, scales) where values is int8 (one per
element) and scales is float16 (one per 32-element block).
源代码位于: src/llm/export/gguf/quant.py
Shared Wrapper¶
_wrapper
¶
Shared helpers for export backends.
Right now the only shared piece is the cache-contract wrapper used
by every trace-based export target (torch.onnx.export,
torch.jit.trace). Both exporters need the model to be called
with use_cache=False and to return a single tensor so the
tracer doesn't record KV-cache boolean conditionals or shape
expressions.
This module is intentionally tiny — it only holds what two or more backends need. Anything specific to a single backend stays in that backend's file.
ExportCacheWrapper
¶
Bases: Module
Wrap a model so trace-based exporters see a clean contract.
Forces use_cache=False (avoiding KV-cache tracer branching)
and unwraps the (logits, kv_cache) tuple to just logits
so the traced graph's output is a single tensor.
The class is shared across every trace-based backend. script
backends don't need it, but using it is harmless — the wrapper
is just a thin nn.Module subclass.
源代码位于: src/llm/export/_wrapper.py
model_vocab_size
¶
Return the model's vocab size (embedding row count), or None.
Trace-based exporters build a random token-id dummy input and must
bound it by the REAL vocabulary — a hardcoded randint(0, 100)
crashes with IndexError inside the embedding for any model with
vocab_size < 100 (RIL ISS-058). This helper resolves the vocab
from the common embedding layouts (DecoderModel and friends);
returns None when the model exposes no recognizable embedding so
callers keep their historical default.
源代码位于: src/llm/export/_wrapper.py
dummy_token_ids
¶
Build a random token-id dummy input bounded by the model's vocab.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
The model being exported. |
必需 |
shape
|
tuple[int, int]
|
|
必需 |
device
|
device | str | None
|
Torch device for the tensor. |
None
|
Uses :func:model_vocab_size; falls back to the historical 100
upper bound when the vocab can't be resolved (keeps existing
behaviour for models without a discoverable embedding).