Reading tensors in C++ saved with `torch.save`

dfalbel: <p>I am trying to read tensors saved with <code>torch.save()</code> from C++. I tried reproducing this test case:</p>
<aside class="onebox githubblob">
  <header class="source">
      <a href="https://github.com/pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/test_misc.cpp#L503-L524" target="_blank" rel="nofollow noopener">github.com</a>
  </header>
  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/test_misc.cpp#L503-L524" target="_blank" rel="nofollow noopener">pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/test_misc.cpp#L503-L524</a></h4>
<pre class="onebox"><code class="lang-cpp"><ol class="start lines" start="503" style="counter-reset: li-counter 502 ;">
<li>void testSerializationInterop() {</li>
<li>  if (isSandcastle()){</li>
<li>    // The module file to load is not generated in Sandcastle</li>
<li>    return;</li>
<li>  }</li>
<li>
</li><li>  // This should be generated by `test/cpp/jit/tests_setup.py`</li>
<li>  std::ifstream input_stream("ivalue.pt");</li>
<li>  std::vector&lt;char&gt; input;</li>
<li>  input.insert(</li>
<li>      input.begin(),</li>
<li>      std::istream_iterator&lt;char&gt;(input_stream),</li>
<li>      std::istream_iterator&lt;char&gt;());</li>
<li>  IValue ivalue = pickle_load(input);</li>
<li>
</li><li>  auto elements = ivalue.toTuple()-&gt;elements();</li>
<li>  auto ones = torch::ones({2, 2});</li>
<li>  ASSERT_TRUE(ones.equal(elements.at(0).toTensor()));</li>
<li>
</li><li>  auto twos = torch::ones({3, 5}) * 2;</li>
</ol></code></pre>

  This file has been truncated. <a href="https://github.com/pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/test_misc.cpp#L503-L524" target="_blank" rel="nofollow noopener">show original</a>

  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>

<p>That is reading a file created with:</p>
<aside class="onebox githubblob">
  <header class="source">
      <a href="https://github.com/pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/tests_setup.py#L43-L51" target="_blank" rel="nofollow noopener">github.com</a>
  </header>
  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/tests_setup.py#L43-L51" target="_blank" rel="nofollow noopener">pytorch/pytorch/blob/2a7a39c1af96fc7816c886644eaf127c5ab53b89/test/cpp/jit/tests_setup.py#L43-L51</a></h4>
<pre class="onebox"><code class="lang-py"><ol class="start lines" start="43" style="counter-reset: li-counter 42 ;">
<li>path = 'ivalue.pt'</li>
<li>
</li><li>def setup(self):</li>
<li>    ones = torch.ones(2, 2)</li>
<li>    twos = torch.ones(3, 5) * 2</li>
<li>
</li><li>    value = (ones, twos)</li>
<li>
</li><li>    torch.save(value, self.path, _use_new_zipfile_serialization=True)</li>
</ol></code></pre>


  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>

<p>I modified the test case example to:</p>
<pre><code class="lang-auto">#include &lt;torch/torch.h&gt;
#include &lt;iostream&gt;

int main()
{
  std::ifstream input_stream("ivalue.pt");
    std::vector&lt;char&gt; input;
    input.insert(
        input.begin(),
        std::istream_iterator&lt;char&gt;(input_stream),
        std::istream_iterator&lt;char&gt;());
    std::cout &lt;&lt; input.size() &lt;&lt; std::endl;
    torch::IValue ivalue = torch::pickle_load(input);
    auto elements = ivalue.toTuple()-&gt;elements();
    torch::Tensor a = elements.at(0).toTensor();
    std::cout &lt;&lt; a &lt;&lt; std::endl; 
}
</code></pre>
<p>However I get the following error when running the program:</p>
<pre><code class="lang-auto">dfalbel@Daniels-MBP build % ./example-app  
1079
libc++abi.dylib: terminating with uncaught exception of type c10::Error: [enforce fail at inline_container.cc:144] . PytorchStreamReader failed reading zip archive: invalid header or archive is corrupted
frame #0: c10::ThrowEnforceNotMet(char const*, int, char const*, std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;, std::__1::allocator&lt;char&gt; &gt; const&amp;, void const*) + 191 (0x10aec51bf in libc10.dylib)
frame #1: caffe2::serialize::PyTorchStreamReader::valid(char const*, char const*) + 131 (0x110883f03 in libtorch_cpu.dylib)
frame #2: caffe2::serialize::PyTorchStreamReader::init() + 315 (0x110882f9b in libtorch_cpu.dylib)
frame #3: caffe2::serialize::PyTorchStreamReader::PyTorchStreamReader(std::__1::unique_ptr&lt;caffe2::serialize::ReadAdapterInterface, std::__1::default_delete&lt;caffe2::serialize::ReadAdapterInterface&gt; &gt;) + 133 (0x110883df5 in libtorch_cpu.dylib)
frame #4: torch::jit::pickle_load(std::__1::vector&lt;char, std::__1::allocator&lt;char&gt; &gt; const&amp;) + 186 (0x11207761a in libtorch_cpu.dylib)
frame #5: torch::pickle_load(std::__1::vector&lt;char, std::__1::allocator&lt;char&gt; &gt; const&amp;) + 14 (0x11229790e in libtorch_cpu.dylib)
frame #6: main + 318 (0x10ae65b4e in example-app)
frame #7: start + 1 (0x7fff72a1dcc9 in libdyld.dylib)
frame #8: 0x0 + 1 (0x1 in ???)
</code></pre>
<p>Any idea of what I am doing wrong?</p>
<p>Thanks a lot!</p>
<p>Edit: this might be releated: <a href="https://github.com/pytorch/pytorch/issues/42651" rel="nofollow noopener">https://github.com/pytorch/pytorch/issues/42651</a></p>

glaringlee: <p><a class="mention" href="/u/dfalbel">@dfalbel</a> see my comment in the following code. You can also check c++ reference for std::istream_iterator.</p>
<pre><code class="lang-auto">std::ifstream input_stream("ivalue.pt");

// a. You need this line, otherwise istream_iterator will skip all the whitespace in the file
//     which will skip characters when reading "ivalue.pt"
// b. try std::istreambuf_iterator instead, it seems to me that it doesn't skip any characters.
input_stream &gt;&gt; std::noskipws;

std::vector&lt;char&gt; input;
input.insert(
      input.begin(),
      std::istream_iterator&lt;char&gt;(input_stream),
      std::istream_iterator&lt;char&gt;());
  IValue ivalue = pickle_load(input);
</code></pre>

dfalbel: <p>Thanks very much <a class="mention" href="/u/glaringlee">@glaringlee</a>! That worked great!</p>

dfalbel: <p>For reference, the above solution worked for macOS and ubuntu but failed on windows.<br>
In order for it to work i had to read the stream in binary mode with:</p>
<p><code>std::ifstream input_stream("ivalue.pt", std::ios::binary);</code></p>
<p>Thanks again!</p>

eval: <p>Or use <code>istreambuf_iterator</code></p>