C++ Load and Save Npy File Load Using xtensor

Introduction

In many use cases for deep learning, such as neural network inference and deployment, we would like to load and save the numpy files generated by Python in C++ and vice versa for debugging and testing purposes. xtensor is a well-maintained C++ library that provides a convenient way to load and save numpy files in C++.

In this blog post, I will introduce how to load and save numpy files in C++ using the xtensor library.

C++ Load and Save Npy File Load Using xtensor

The examples demonstrated how to load and save numpy files in C++ using the xtensor library and how to load and save numpy files in Python using the numpy library. The examples are available on GitHub.

Load Numpy File In C++

load_npy.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <cassert>
#include <iostream>
#include <string>

#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>
#include <xtensor/xnpy.hpp>

int main(int argc, char* argv[])
{
// Print the usage of the program.
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " <npy_file_path>" << std::endl;
return 1;
}
std::string const npy_file_path{argv[1]};

// Load the 4D array from the npy file.
xt::xarray<float> const float_array{xt::load_npy<float>(npy_file_path)};

// Get the shape of the array.
auto const shape = float_array.shape();
assert(shape.size() == 4);
assert(shape[0] == 2);
assert(shape[1] == 3);
assert(shape[2] == 4);
assert(shape[3] == 5);

// Access the elements of the array using a pointer.
float const* const ptr{float_array.data()};
for (size_t i{0}; i < float_array.size(); ++i)
{
assert(ptr[i] == static_cast<float>(i));
}

bool data_type_mismatch{false};
try
{
xt::xarray<int> const int_array{xt::load_npy<int>(npy_file_path)};
}
catch (std::runtime_error const& e)
{
data_type_mismatch = true;
}
assert(data_type_mismatch);

return 0;
}

Save Numpy File In C++

save_npy.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <cassert>
#include <filesystem>
#include <iostream>
#include <string>

#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>
#include <xtensor/xnpy.hpp>

int main(int argc, char* argv[])
{
// Print the usage of the program.
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " <npy_file_path>" << std::endl;
return 1;
}
std::string const npy_file_path{argv[1]};

// Create a 4D array.
auto const shape = xt::dynamic_shape<std::size_t>{2, 3, 4, 5};
auto const volume = shape[0] * shape[1] * shape[2] * shape[3];
xt::xarray<float> const float_array{
xt::arange<float>(0, volume).reshape(shape)};
xt::dump_npy(npy_file_path, float_array);
}

Load Numpy File In Python

load_npy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import argparse
import numpy as np

if __name__ == "__main__":

# Create argument parser that allows the user to specify the path to the npy file.
parser = argparse.ArgumentParser()
parser.add_argument("--npy_file_path", type=str, required=True)
args = parser.parse_args()
npy_file_path = args.npy_file_path

# Load the data
tensor = np.load(npy_file_path)

assert tensor.shape == (2, 3, 4, 5)

for i in range(2):
for j in range(3):
for k in range(4):
for l in range(5):
assert tensor[i, j, k,
l] == i * 3 * 4 * 5 + j * 4 * 5 + k * 5 + l

assert tensor.dtype == np.float32

Save Numpy File In Python

save_npy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import argparse
import numpy as np

if __name__ == "__main__":

# Create argument parser that allows the user to specify the path to the npy file.
parser = argparse.ArgumentParser()
parser.add_argument("--npy_file_path", type=str, required=True)
args = parser.parse_args()
npy_file_path = args.npy_file_path

# Create a 4D numpy float array of linear layout.
tensor_shape = (2, 3, 4, 5)
tensor = np.arange(np.prod(tensor_shape)).reshape(tensor_shape).astype(
np.float32)

# Save the data
np.save(npy_file_path, tensor)

Build and Run the Examples

The examples could be built using CMake in a Docker container by following the instructions on the README.

Once the examples are built, the examples could be run using the following commands.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ mkdir -p data

# Save npy file from Python
$ python python/save_npy.py --npy_file_path data/npy_data_from_python.npy
# Verify npy file from Python
$ python python/load_npy.py --npy_file_path data/npy_data_from_python.npy
# Verify npy file from C++
$ ./build/src/load_npy data/npy_data_from_python.npy

# Save npy file from C++
$ ./build/src/save_npy data/npy_data_from_cpp.npy
# Verify npy file from Python
$ python python/load_npy.py --npy_file_path data/npy_data_from_cpp.npy
# Verify npy file from C++
$ ./build/src/load_npy data/npy_data_from_cpp.npy

References

C++ Load and Save Npy File Load Using xtensor

https://leimao.github.io/blog/CPP-Npy-Load-Save-xtensor/

Author

Lei Mao

Posted on

02-16-2025

Updated on

02-16-2025

Licensed under


Comments