1 Caffe to ONNX Conversion
Abhishek Gola edited this page 2026-06-04 22:13:44 +05:30
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Converting Caffe Models to ONNX

A short, practical guide to the two techniques used to convert the Caffe DNN test models (WeChatQR detector/super-resolution and the colorization network) into ONNX for use with OpenCV's DNN module. Use it as a recipe if you need to convert your own Caffe models.

TL;DR — Try Method A (direct conversion) first. If a model uses layers or post-processing that don't translate cleanly, fall back to Method B (re-implement in PyTorch and export).


Which method do I need?

Method A — caffe2onnx Method B — PyTorch re-export
Idea Read .prototxt + .caffemodel directly and emit ONNX Rebuild the network in PyTorch with equivalent weights, then torch.onnx.export
Best for Standard conv/pool/fc networks (e.g. WeChatQR detect, sr) Models with Caffe-specific post-processing or layers that don't map 1:1 (e.g. colorization: temperature scaling + softmax + palette decode)
Effort Low — a few lines Higher — you must reproduce the math

Prerequisites

pip install onnx numpy
pip install caffe2onnx          # for Method A
pip install torch               # for Method B

You only need the .prototxt (architecture) and .caffemodel (weights) files. A real Caffe build is not required for either method.


Method A — Direct Conversion with caffe2onnx

This approach programmatically maps the legacy Caffe protocol buffer architecture directly onto standard ONNX operator nodes. Because it serves as a pure structural translator rather than an active computation execution engine, it isolates and converts the graph cleanly without runtime performance overhead.

This approach was successfully used to migrate the WeChatQR detect and sr models.

Execution Options

  • Command Line Interface (Quickest for single models):
python -m caffe2onnx.convert --prototxt model.prototxt --caffemodel model.caffemodel --onnx model.onnx

  • Python API (Best for automated batch processing scripts):
from caffe2onnx.src.load_save_model import loadcaffemodel, saveonnxmodel
from caffe2onnx.src.caffe2onnx import Caffe2Onnx

graph, params = loadcaffemodel("model.prototxt", "model.caffemodel")
onnx_model = Caffe2Onnx(graph, params, "model.onnx").createOnnxModel()
saveonnxmodel(onnx_model, "model.onnx")

For multi-model batching templates (such as OpenPose or SSD-VGG16), you can reference the automated loop implementations located in the OpenCV Extra Conversion.


Method B — Re-implement in PyTorch and export

Some models can't be converted layer-for-layer because the Caffe deploy graph bakes in operations that don't have a clean ONNX equivalent. For the colorization network this is the tail end Colorization Discussion: a temperature scaling, a softmax over the 313 quantized ab bins, and a 1×1 convolution that decodes those probabilities into 2 ab channels using the pts_in_hull color palette.

  1. Use or build a clean PyTorch port of the model architecture populated with the trained weights.
  2. Code the exact Caffe mathematical transformations directly into your module's forward() execution block.
  3. Run torch.onnx.export using opset_version=11 and operator_export_type=torch.onnx.OperatorExportTypes.ONNX_FALLTHROUGH to maintain full structural compatibility with OpenCV's internal DNN parser.

Verification

Always confirm the converted model behaves like the original before publishing.

  1. Record a checksum of every .onnx you produce (the scripts above print a SHA-256). This lets reviewers confirm they have the exact file.
  2. Compare outputs on a fixed input. Load the original with the Caffe importer and the new model with the ONNX importer in OpenCV, run the same blob through both, and check the results agree within a small tolerance:

If the difference is large, the post-processing (scaling, softmax axis, decode kernel) is the usual culprit — recheck the values listed under Method B.


References & Historical Discussions