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

I am trying to read tensors saved with torch.save() from C++. I tried reproducing this test case:

That is reading a file created with:

I modified the test case example to:

#include <torch/torch.h>
#include <iostream>

int main()
{
  std::ifstream input_stream("ivalue.pt");
    std::vector<char> input;
    input.insert(
        input.begin(),
        std::istream_iterator<char>(input_stream),
        std::istream_iterator<char>());
    std::cout << input.size() << std::endl;
    torch::IValue ivalue = torch::pickle_load(input);
    auto elements = ivalue.toTuple()->elements();
    torch::Tensor a = elements.at(0).toTensor();
    std::cout << a << std::endl; 
}

However I get the following error when running the program:

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<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, 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<caffe2::serialize::ReadAdapterInterface, std::__1::default_delete<caffe2::serialize::ReadAdapterInterface> >) + 133 (0x110883df5 in libtorch_cpu.dylib)
frame #4: torch::jit::pickle_load(std::__1::vector<char, std::__1::allocator<char> > const&) + 186 (0x11207761a in libtorch_cpu.dylib)
frame #5: torch::pickle_load(std::__1::vector<char, std::__1::allocator<char> > const&) + 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 ???)

Any idea of what I am doing wrong?

Thanks a lot!

Edit: this might be releated: https://github.com/pytorch/pytorch/issues/42651

@dfalbel see my comment in the following code. You can also check c++ reference for std::istream_iterator.

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 >> std::noskipws;

std::vector<char> input;
input.insert(
      input.begin(),
      std::istream_iterator<char>(input_stream),
      std::istream_iterator<char>());
  IValue ivalue = pickle_load(input);
1 Like

Thanks very much @glaringlee! That worked great!

For reference, the above solution worked for macOS and ubuntu but failed on windows.
In order for it to work i had to read the stream in binary mode with:

std::ifstream input_stream("ivalue.pt", std::ios::binary);

Thanks again!

1 Like

Or use istreambuf_iterator