ONNX and Cross-Language Model Export
How a model trained in Python gets deployed inside a low-latency C++ trading system without rewriting it by hand, using a shared, framework-neutral file format for the model's computation graph.
Prerequisites: Packaging and Serialising Model Artefacts
A research team trains a model in Python using a deep learning framework, and it needs to run inside a trading system's low-latency execution path, written in C++ for speed. Rewriting the model's forward pass by hand in C++ — reimplementing every layer, matching floating-point behavior exactly — is slow, error-prone, and has to be redone every time the model changes. This is a recurring problem: research and production live in different languages for good reasons, and models still need to cross that boundary reliably.
The idea: a shared blueprint instead of a rewrite
ONNX (Open Neural Network Exchange) is a file format describing a model's computation graph — its layers, operations, and learned weights — independent of the framework or language it was built in. Exporting to ONNX is like translating a recipe into a standardized, unambiguous notation any kitchen can follow, rather than one written in a particular chef's slang. Once a model is in ONNX form, a runtime (available for Python, C++, Java, and others) can load the file and execute the same computation in a different language, without anyone hand-translating its internals.
This matters because it decouples where a model is trained from where it needs to run. Research keeps using whatever framework is most productive for experimentation; production loads the exported ONNX file inside whatever language the trading system actually runs in, and the two sides never need to reimplement each other's code by hand every time the model changes.
Worked example: an export that silently drops behavior
A team trains a model in Python with a custom preprocessing step — a manually written function clipping input values to a fixed range before they reach the network. They export to ONNX, and the standard layers translate cleanly: the C++ runtime reproduces the same weights and operations. But the clipping function, written as ordinary Python code rather than a graph layer, isn't part of what gets exported — ONNX only captures the graph, not arbitrary surrounding code.
In production, the C++ system feeds raw, unclipped inputs directly into the exported model. Most inputs are fine, but on a day with an extreme market move, a feature value far outside the training range — one Python's preprocessing would have clipped — reaches the model unclipped, producing an unreliable prediction on exactly the high-volatility day when it matters most. The bug isn't the export process; it's that a piece of the prediction pipeline lived outside the exported graph and nobody reimplemented it in C++.
Read that curve as roughly "prediction error" against "distance of an input from the training range": ordinary inputs are all fine, but anything sitting where the un-exported clipping logic used to protect the model shows how quickly error can grow once that guard is silently missing on one side of the export.
What this means in practice
Exporting to ONNX handles the model's learned layers reliably, but does not automatically carry over preprocessing or postprocessing written as separate code — that logic must be built into the exported graph (many frameworks support this) or reimplemented and tested against the Python version. Before trusting an exported model in production, the standard check is running identical inputs through both versions and confirming outputs match to a tight tolerance, including on extreme inputs.
ONNX lets a model trained in one framework and language run inside a different production language without a manual reimplementation of its layers — but it only captures the model's computation graph, so any preprocessing or postprocessing written as separate code needs to be folded into that graph or reimplemented and verified independently.
The easy mistake is assuming "the model was exported to ONNX" means the entire prediction pipeline was exported. Any custom logic living outside the model's own graph — clipping, feature construction, thresholding — has to be carried across the language boundary separately, and forgetting it produces a production system that matches research on typical inputs but silently diverges on the extreme ones.
Related concepts
Practice in interviews
Further reading
- ONNX project documentation, onnx.ai
- ONNX Runtime documentation