C++ traced model crashes on CPU

Xavier31: <p>Hi.<br>
I have been using tracing to export pytorch models to C++ libtorch with no trouble so far on several different models. I usually train and export the models on linux GPU, and actually use them on windows, CPU. All good.</p>
<p>I however ran into a crash trying to do the same thing with this model:<br>
<aside class="onebox whitelistedgeneric">
  <header class="source">
      <img src="https://github.githubassets.com/favicons/favicon.svg" class="site-icon" width="32" height="32">
      <a href="https://github.com/naoto0804/pytorch-inpainting-with-partial-conv" target="_blank" rel="nofollow noopener">GitHub</a>
  </header>
  <article class="onebox-body">
    <img src="https://avatars0.githubusercontent.com/u/7067992?s=400&amp;v=4" class="thumbnail onebox-avatar" width="400" height="400">

<h3><a href="https://github.com/naoto0804/pytorch-inpainting-with-partial-conv" target="_blank" rel="nofollow noopener">naoto0804/pytorch-inpainting-with-partial-conv</a></h3>

<p>Unofficial pytorch implementation of 'Image Inpainting for Irregular Holes Using Partial Convolutions' [Liu+, ECCV2018] - naoto0804/pytorch-inpainting-with-partial-conv</p>


  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>
</p>
<ul>
<li>Tracing and running the libtorch model on GPU is fine</li>
<li>on CPU, the model crashes when calling the forward() method.</li>
</ul>
<p>I then tried to generate the traced model on CPU. Using this cpu model I am able to:</p>
<ul>
<li>load and run the traced model in python. Feeding it with the expected entries (i.e. a couple (image, mask)) produces the expected result</li>
<li>load and run the model in c++  with dummy entries (random at::tensor of the correct size)</li>
</ul>
<p>however,  loading the model and running it with correct entries (image mask) crash when calling  forward()<br>
using this cpu model on GPU does not crash but produces erroneous output (black or uninitialized image output)</p>
<p>I am not able not isolate where the error might come from, although I suspect something goes wrong in the model tracing. I do not have any error message while tracing.<br>
Any ideas ?<br>
I’m using pytorch 1.3 as well as libtorch1.3 on both linux and windows</p>

Xavier31: <p>I am loading the network like this:</p>
<pre><code class="lang-auto">def load_network(model_path, device): 
    if 'cuda' in device:
        torch.backends.cudnn.benchmark = True
    else:
        torch.backends.cudnn.benchmark = False
            
    inpainting_model = PConvUNet().to(device)
    inpainting_model.eval()
    load_ckpt(model_path, [('model', inpainting_model)], device=device)

def load_ckpt(ckpt_name, models, optimizers=None, device=None):
    ckpt_dict = torch.load(ckpt_name, map_location=device)
    for prefix, model in models:
        assert isinstance(model, nn.Module)
        model.load_state_dict(ckpt_dict[prefix], strict=False)
    if optimizers is not None:
        for prefix, optimizer in optimizers:
            optimizer.load_state_dict(ckpt_dict[prefix])
    return ckpt_dict['n_iter']
</code></pre>
<p>and then just calling jit.trace:</p>
<pre><code class="lang-auto">net = load_network(net_path, device)
#dummy input for tracing the model
image = torch.rand(1, 3, inpainting_size[0], inpainting_size[1])
mask = torch.rand(1, 3, inpainting_size[0], inpainting_size[1])
                
image = image.to(device)
mask = mask.to(device)
# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
traced_script_module = torch.jit.trace(net, (image, mask))
traced_script_module.save("model/InpaintNet_cpp.pt")
</code></pre>

ptrblck: <p>Could you post the error message, please?<br>
Also, what’s the difference between the random input tensors and the correct entries?<br>
While the first approach seems to work, the latter crashes, correct?</p>

Xavier31: <p>Yes, all these different configurations make the problem a bit confusing. I am testing on 2 different machines. Linux with a GPU, and Windows with no GPU. Here is the state of it right now in C++:</p>
<p>// crash results on CPU/Windows:<br>
<em>DUMMY_INPUT</em> + <em>CPU_MODEL</em> -&gt; no crash<br>
<em>REAL_INPUT</em> + <em>CPU_MODEL</em>-&gt; crash<br>
<em>DUMMY_INPUT</em> + <em>GPU_MODEL</em>-&gt; crash<br>
<em>REAL_INPUT</em> + <em>GPU_MODEL</em>-&gt;crash</p>
<p>// crash results on GPU/Linux<br>
<em>DUMMY_INPUT</em> + <em>CPU_MODEL</em>-&gt; no crash<br>
<em>REAL_INPUT</em> + <em>CPU_MODEL</em>-&gt; no crash, wrong result<br>
<em>DUMMY_INPUT</em> + <em>GPU_MODEL</em>-&gt; no crash<br>
<em>REAL_INPUT</em> + <em>GPU_MODEL</em>-&gt;ok, good result</p>
<p>What i call “<em>CPU_MODEL</em>” is the model traced using the CPU.</p>
<p>I do not have a specific error message other than  segmentation fault (core dumped)<br>
Debugging with Visual C++ raises an exception in kernel_lambda.h, in this specific function in class WrapRuntimeKernelFunctor_:</p>
<pre><code class="lang-auto">auto operator()(Parameters... args) -&gt; decltype(std::declval&lt;FuncType&gt;()(std::forward&lt;Parameters&gt;(args)...)) {

      return kernel_func_(std::forward&lt;Parameters&gt;(args)...);
</code></pre>

Xavier31: <p>The thing is that if I load the CPU model on my Windows machine using python with</p>
<pre><code class="lang-auto">torch.jit.load
</code></pre>
<p>then, the output is correct, which seems to indicate that model tracing was done correctly. A libtorch problem then ?</p>

ptrblck: <p>Hard to tell, where this error is coming from, but please feel free to create an issue in GitHub.<br>
If possible, attach a code snippet to reproduce this error.</p>

Xavier31: <p>for the record, I managed to debug this after a while.<br>
There were two issues:<br>
I was creating a tensor from an opencv matrix using torch::from_blob(). This function does not copy the data, so when the opencv matrix goes out of scope, the tensor points to garbage. That does not happen on GPU because the data is copied into the GPU memory before the opencv matrix goes out of scope.<br>
Cloning the tensor after the torch::from_blob() solved the crash on CPU with the CPU-traced model</p>
<p>The second issue is that in python model, some tensors are created on the fly in the forward method, They are created as cuda tensors and seem to be traced with a cuda flag (?). When using on CPU, this results in:</p>
<blockquote>
<p>RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!</p>
</blockquote>
<p>I am happy to use a separate cpu model for now, but I guess this is solvable by moving these tensors to the right device</p>