Docs Export Formats

Export Formats

How KynML saves trained models: torch state dict, onnx cross-platform graph, and torchscript compiled script.


Overview

The export block is optional. When present it runs after training and evaluation:

export:
    format = <torch|onnx|torchscript>
    path = "models/output.pt"
    input_shape = [1, 10]   # required for onnx only
    opset = 17              # onnx only, default 17

Export happens in export_model() in the generated script. If no export block is present, export_model() is a no-op.


torch — state dict

The simplest format. Saves the model's parameter tensors as a Python dict using torch.save(model.state_dict(), path).

export:
    format = torch
    path = "models/house_price_model.pt"

Generated code

if EXPORT_FORMAT == "torch":
    torch.save(model.state_dict(), path)
    print(f"Saved model to {path}")

Loading

import torch
import torch.nn as nn

class HousePriceModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(10, 64), nn.ReLU(),
            nn.Linear(64, 32), nn.ReLU(),
            nn.Linear(32, 1),
        )
    def forward(self, x):
        return self.net(x)

model = HousePriceModel()
model.load_state_dict(torch.load("models/house_price_model.pt", map_location="cpu", weights_only=True))
model.eval()

Or use the KynML serving module to get a ready-made FastAPI app:

from kynml.parser import parse_file
from kynml.semantic import validate_program
from kynml.serving.generator import generate_service

program = parse_file("house_price.kyn")
validate_program(program)
generate_service(program, model_path="models/house_price_model.pt", out_dir="service/")

When to use

  • Default choice. Compatible with everything in the PyTorch ecosystem.
  • Requires the model class definition at load time — the generated .py file or the spec is your source of truth.
  • Not portable to non-PyTorch runtimes (use ONNX or TorchScript for that).

onnx — cross-platform inference graph

Exports a static computation graph to the ONNX interchange format. No Python or PyTorch required at inference time — load with ONNX Runtime, TensorRT, CoreML, or any ONNX-compatible runtime.

export:
    format = onnx
    path = "models/churn_model.onnx"
    input_shape = [1, 15]
    opset = 17

input_shape is required for ONNX. The semantic validator rejects ONNX exports without it:

KynMLSemanticError: Export format 'onnx' requires input_shape

Generated code

elif EXPORT_FORMAT == "onnx":
    if EXPORT_INPUT_SHAPE is None:
        raise RuntimeError("ONNX export requires input_shape")
    dummy = torch.randn(*EXPORT_INPUT_SHAPE)
    torch.onnx.export(
        model,
        dummy,
        str(path),
        opset_version=EXPORT_OPSET,     # default 17
        input_names=["input"],
        output_names=["output"],
    )
    print(f"Saved ONNX model to {path}")

input_shape

A list of integers matching [batch_size, num_features]. The dummy tensor (torch.randn(*input_shape)) is traced through the model to build the ONNX graph. Typical shapes:

Model input_shape
10-feature regression [1, 10]
15-feature binary classifier [1, 15]
4-feature multiclass [1, 4]

The batch dimension can be symbolic. To export with a dynamic batch axis, edit the generated script and pass dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}} to torch.onnx.export.

opset

ONNX operator set version. Default: 17. Minimum supported by most runtimes: 11. ONNX Runtime 1.16+ supports opset 18. Use the newest opset your target runtime supports.

Loading with ONNX Runtime

import onnxruntime as ort
import numpy as np

sess = ort.InferenceSession("models/churn_model.onnx", providers=["CPUExecutionProvider"])
input_name = sess.get_inputs()[0].name

features = np.array([[1.0, 35.0, 2.0, 80.0, 1.0, 0.0, 12.0, 3.0, 1.0, 4.0, 0.0, 2.0, 7.0, 1.0, 0.0]], dtype=np.float32)
result = sess.run(None, {input_name: features})
print(result[0])  # [[0.1234]]

Install ONNX Runtime:

pip install onnxruntime          # CPU
pip install onnxruntime-gpu      # CUDA

When to use

  • Deploying to a non-Python environment (mobile, embedded, browser via WASM).
  • Serving with TensorRT for maximum GPU inference throughput.
  • A/B testing different frameworks without retraining.
  • Regulatory/audit contexts where you need a frozen, inspectable graph.

torchscript — compiled PyTorch script

Serialises the model via torch.jit.script, which traces the Python model class into a language-agnostic IR. The output is a self-contained .pt file that includes both weights and computation graph — no model class definition required at load time.

export:
    format = torchscript
    path = "models/deepnet.pt"

Generated code

elif EXPORT_FORMAT == "torchscript":
    scripted = torch.jit.script(model)
    scripted.save(str(path))
    print(f"Saved TorchScript model to {path}")

Note: torch.jit.script (not torch.jit.trace). Scripting handles control flow; tracing does not. All KynML-generated models use nn.Sequential with standard PyTorch modules, which script cleanly.

Loading

import torch

model = torch.jit.load("models/deepnet.pt", map_location="cpu")
model.eval()

x = torch.tensor([[1.0, 2.0, 3.0, 4.0]])  # shape [1, input_size]
with torch.no_grad():
    prediction = model(x)
print(prediction)

No Python class definition needed. The file is portable between machines with the same PyTorch version.

Loading from C++

#include <torch/script.h>

auto model = torch::jit::load("models/deepnet.pt");
model.eval();

auto input = torch::ones({1, 10});
auto output = model.forward({input}).toTensor();
std::cout << output << std::endl;

When to use

  • Deploying within a Python or C++ application where ONNX is not needed.
  • Self-contained model files without needing the class source code at load time.
  • Mobile deployment via torch.jit mobile interpreter (requires additional compilation step).

Format comparison

torch onnx torchscript
Requires class at load Yes No No
Portable to non-PyTorch runtimes No Yes Partial (C++ libtorch)
Requires input_shape No Yes No
Inspectable graph No Yes (Netron, etc.) Partial
Supports torch.compile'd models Yes Needs uncompiled Needs uncompiled
File extension convention .pt .onnx .pt
Opset versioning N/A Yes (opset) N/A

Full spec examples

Torch export (regression)

export:
    format = torch
    path = "models/house_price_model.pt"

ONNX export (binary classifier, 15 features)

export:
    format = onnx
    path = "models/churn_model.onnx"
    input_shape = [1, 15]
    opset = 17

TorchScript export (multiclass, 4 features)

export:
    format = torchscript
    path = "models/iris_classifier.pt"

ONNX with older opset for maximum runtime compatibility

export:
    format = onnx
    path = "models/legacy_model.onnx"
    input_shape = [1, 10]
    opset = 12

Troubleshooting

Export format 'onnx' requires input_shape — add input_shape = [batch, features] to your export block. The batch dimension is typically 1 for the dummy input.

torch.jit.frontend.UnsupportedNodeError — a module in your model is not scriptable. All standard KynML layers (Dense, Dropout, BatchNorm1d, standard activations) are scriptable. Custom post-compile edits using Lambda layers or dynamic Python are not.

opset version X not supported — your installed ONNX Runtime version does not support the opset you specified. Lower opset (e.g. from 17 to 12) or upgrade onnxruntime.

Model exported but predictions differ — check that normalize = true was applied consistently. The StandardScaler fit during training is not saved in the exported model file. For inference, normalise inputs manually using the same mean/std before passing to the model.