Convert to onnx a model trained with libtorch 1.1.0 (c++)

username: jillemash
cooked: <p>Hi,</p>
<p>TL;DR: how to convert a C++ libtorch model file .pt to onnx ?</p>
<p>I have this model that I trained in C++ with libtorch, model.pt, saved with torch::save().<br>
I use it in a C++ application using torch::load(), it works just fine.</p>
<p>I would like to convert it to ONNX.</p>
<p>I cannot find documentation on how to do it, nor do I find documentation about the format of the .pt model files.</p>
<p>I’ve tried to use this piece of code to import my model in Python and use torch.onnx.export() to produce the ONNX model.<br>
<a href="https://www.learnopencv.com/pytorch-model-inference-using-onnx-and-caffe2/" class="onebox" target="_blank" rel="nofollow noopener">https://www.learnopencv.com/pytorch-model-inference-using-onnx-and-caffe2/</a></p>
<p>First the torch.load() call in the Python script resulted in an error, suggesting me to use torch.jit instead:<br>
<code>model.pt is a zip archive (did you mean to use torch.jit.load()?)</code></p>
<p>I did that, and it passed the load() step.</p>
<p>But then torch.onnx.export() step gives me:<br>
RuntimeError: ‘forward’ method must be a script method</p>
<p>I’m confused.<br>
I’ve read the documentation about TorchScript, and how to use tracing and ScriptModule in Python to then read them in C++.</p>
<p>But from the error message, torch::save() does not seem to generate the same format that the Python counterpart, since I cannot load it in Python.<br>
Since using torch.jit.load() seemed to work, I assumed that in C++, the model was already converted to TorchScript or something when saved with torch::save.<br>
(But then what do torch::jit::save/load methods are here for ?)</p>
<p>But then the fact that the conversion to onnx tells me the method is not a script method, I wonder how to fox this.<br>
In the documentation I found that to make a method a script method, one has to use <span class="mention">@torch.jit.script_method</span>.<br>
<a href="https://pytorch.org/tutorials/beginner/hybrid_frontend/learning_hybrid_frontend_through_example_tutorial.html?highlight=torch%20jit" class="onebox" target="_blank" rel="nofollow noopener">https://pytorch.org/tutorials/beginner/hybrid_frontend/learning_hybrid_frontend_through_example_tutorial.html?highlight=torch%20jit</a><br>
But that’s for Python, how am I supposed to use it on my C++ method … ?</p>
<p>Is there a documentation of the format of files generated by torch.save (Python), torch::save (C++) if they differ ?<br>
I can see my model is an archive I can unzip, with the following layout:</p>
<pre><code class="lang-auto">├── attributes.pkl
├── model.json
├── **tensors**
│   ├── 0
...
│   └── 99
└── version
</code></pre>
<p>And I get that torch.save()/load() uses Pickle in Python.</p>
<p>I think I saw an initiative to use Pickle for C++ as well, is this to be able to torch::load in C++ models saved in Python with torch.save ? Would it then work the other way around ?<br>
(merged in v1.3.0, see Pull Request 23241, commit 75c1419b46624e2bcd01709d93def0bceaaf05a2)</p>
<p>In short, I have a model that I suppose I have managed to import in Python, but cannot convert to onnx with torch.onnx.export().</p>
<p>Thanks for your help.</p>
<p>Libtorch version: 1.1.0</p>
<p>Edit: I saw in “Serialization semantics” page that saving the model and not just the parameters can lead to this:<br>
“However in this case, the serialized data is bound to the specific classes and the exact directory structure used, so it can break in various ways when used in other projects, or after some serious refactors.”</p>
<p>Is this also the case with libtorch ?</p>

username: jillemash
cooked: <p>Ok about <span class="mention">@torch.jit.script_method</span>, it seems that documentation wasn’t up to date here and there, so that’s why I was confused with torchscript, sometimes modules needed to inherit from torch.jit.ScriptModule, sometimes not, I thought this was y a typo…<br>
So here, I’ve learned that starting from 1.2, no need to inherit from ScriptModule but use torch.jit.script( model ) instead.<br>
<a href="https://pytorch.org/docs/stable/jit.html#migrating-to-pytorch-1-2-recursive-scripting-api" class="onebox" target="_blank" rel="nofollow noopener">https://pytorch.org/docs/stable/jit.html#migrating-to-pytorch-1-2-recursive-scripting-api</a></p>
<p>So maybe I should, in C++:<br>
-update my Pytorch version (I’m using 1.1.0)<br>
-load my trained model .pt<br>
-use torch::jit::script() on it<br>
-save it<br>
-retry the Python conversion script to onnx</p>
<p>I hope this does not require I restart my training, and that I can use my .pt as is.</p>
<p>What do you think ? (I’m still open for answers to my other question to better understand how model I/O work.</p>
<p>Thanks.</p>
<p>Edit: Ok I guess it’s not the way it works, I cannot find torch::jit::script() in C++.</p>

username: Sebastien_Maraux
cooked: <p>Hello,</p>
<p>Up on this matter, I meet the exact same problem with current version, trained a module with libtorch and want to use tensorRT, which requires a TorchScript as exchange format at some point.</p>
<p>Any updated advice about that ?</p>

username: abloom5448
cooked: <p>hello</p>
<p>Why don’t you try this?</p>
<p>=======================================</p>
<p><span class="hashtag">#include</span> “torch/csrc/jit/serialization/export.h”</p>
<p>torch::jit::export_onnx();</p>
<p>=======================================</p>

username: Sebastien_Maraux
cooked: <p>Thank you for that reply.</p>
<p>I tried this, but as the original model is trained on c++, it is not a torch::jit::module but a c++ torch::module , it does not work. I also tried the conversion to jit via python without success (same thing as above, mssing forward method). From my understanding, libtorch API does not let you convert a whole torch::nn::module in jit. I have read some things about pickle_save which was also unsuccessful</p>

username: Sebastien_Maraux
cooked: <p>As a follow up, I ended rewriting the network directly in tensorRT, this is not too hard for a model with standard layers (I use fully connected, relu and batch norm - done via a scale layer). It relies only on C++, and it is much simpler.</p>
<p>Simply make a tensorRT builder, create a network and add layers by copying weights of existing model.</p>