Created
October 11, 2018 17:21
-
-
Save zeryx/526dbc05479e166ca7d512a670e6b82d to your computer and use it in GitHub Desktop.
minimal pytorch 1.0 pytorch -> C++ full example demo image at: https://i.imgur.com/hiWRITj.jpg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.0 FATAL_ERROR) | |
project(cpp_shim) | |
set(CMAKE_PREFIX_PATH ../libtorch) | |
find_package(Torch REQUIRED) | |
find_package(OpenCV REQUIRED) | |
add_executable(testing main.cpp) | |
message(STATUS "OpenCV library status:") | |
message(STATUS " config: ${OpenCV_DIR}") | |
message(STATUS " version: ${OpenCV_VERSION}") | |
message(STATUS " libraries: ${OpenCV_LIBS}") | |
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") | |
message(STATUS "TORCHLIB: ${TORCH_LIBRARIES}") | |
#target_include_directories(testing PRIVATE ${TORCH_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}) | |
target_link_libraries(testing ${OpenCV_LIBS}) | |
target_link_libraries(testing ${TORCH_LIBRARIES}) | |
target_compile_definitions(testing PRIVATE -D_GLIBCXX_USE_CXX11_ABI=0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import torch | |
import torch.nn as nn | |
import torch.nn.functional as F | |
from torch.jit import ScriptModule, script_method, trace | |
class MyScriptModule(ScriptModule): | |
# class MyScriptModule(nn.Module): | |
def __init__(self): | |
super(MyScriptModule, self).__init__() | |
# trace produces a ScriptModule's conv1 and conv2 | |
self.conv1 = trace(nn.Conv2d(3, 2, 5).to("cpu"), torch.rand(1, 3, 1266, 1900)) | |
self.conv2 = trace(nn.Conv2d(2, 1, 5).to("cpu"), torch.rand(1, 2, 1266, 1900)) | |
self.lin = trace(nn.Linear(1258*1892, 5), torch.rand(1258*1892)) | |
@script_method | |
def forward(self, input): | |
input = F.relu(self.conv1(input)) | |
input = F.relu(self.conv2(input)) | |
input = input.squeeze() | |
input = input.view(1258*1892) | |
output = self.lin(input) | |
return output | |
test_module = MyScriptModule() | |
print(test_module.graph) | |
if __name__ == "__main__": | |
test_module.save("/tmp/model.pl") | |
# if __name__ == "__main__": | |
# import numpy as np | |
# from PIL import Image | |
# img_path = "/tmp/cat_image.jpg" | |
# img = np.asarray(Image.open(img_path)) | |
# tensor = torch.from_numpy(img).float() | |
# tensor = tensor.view(1, 3, tensor.shape[0], tensor.shape[1]) | |
# test_module.forward(tensor) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by zeryx on 10/5/18. | |
// | |
#include <torch/script.h> | |
#include <iostream> | |
#include <memory> | |
#include <opencv2/core/core.hpp> | |
#include <opencv2/highgui/highgui.hpp> | |
using namespace cv; | |
int main() { | |
std::string model_path = "/tmp/model.pl"; | |
std::string image_path = "/tmp/cat_image.jpg"; | |
Mat image = imread(image_path); | |
std::vector<int64_t> sizes = {1, 3, image.rows, image.cols}; | |
at::TensorOptions options(at::ScalarType::Byte); | |
at::Tensor tensor_image = torch::from_blob(image.data, at::IntList(sizes), options); | |
tensor_image = tensor_image.toType(at::kFloat); | |
std::ifstream is (model_path, std::ifstream::binary); | |
std::shared_ptr<torch::jit::script::Module> module = torch::jit::load(is); | |
std::vector<torch::jit::IValue> inputs; | |
inputs.emplace_back(tensor_image); | |
at::Tensor result = module->forward(inputs).toTensor(); | |
auto max_result = result.max(0, true); | |
auto max_index = std::get<1>(max_result).item<float>(); | |
std::cout << max_index << std::endl; | |
} |
generator.py works now, here the output:
$ python3 generator.py
graph(%input.1 : Tensor
%1 : Tensor
%2 : Tensor
%25 : Tensor
%26 : Tensor
%55 : Tensor
%56 : Tensor) {
%19 : bool = prim::Constant[value=1](), scope: Conv2d
%12 : bool = prim::Constant[value=0](), scope: Conv2d
%6 : int = prim::Constant[value=0](), scope: Conv2d
%3 : int = prim::Constant[value=1](), scope: Conv2d
%50 : int = prim::Constant[value=1258]()
%51 : int = prim::Constant[value=1892]()
%5 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d
%8 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d
%11 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d
%15 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d
%20 : Float(1, 2, 1262, 1896) = aten::_convolution(%input.1, %1, %2, %5, %8, %11, %12, %15, %3, %12, %12, %19), scope: Conv2d
%result.3 : Tensor = prim::If(%12)
block0() {
%result.4 : Tensor = aten::relu_(%20)
-> (%result.4)
}
block1() {
%result.5 : Tensor = aten::relu(%20)
-> (%result.5)
}
%29 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d
%32 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d
%35 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d
%39 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d
%44 : Float(1, 1, 1262, 1896) = aten::_convolution(%result.3, %25, %26, %29, %32, %35, %12, %39, %3, %12, %12, %19), scope: Conv2d
%result : Tensor = prim::If(%12)
block0() {
%result.1 : Tensor = aten::relu_(%44)
-> (%result.1)
}
block1() {
%result.2 : Tensor = aten::relu(%44)
-> (%result.2)
}
%input.2 : Tensor = aten::squeeze(%result)
%52 : int = aten::mul(%50, %51)
%53 : int[] = prim::ListConstruct(%52)
%input : Tensor = aten::view(%input.2, %53)
%57 : Float(2380136!, 5!) = aten::t(%55), scope: Linear
%output.1 : Float(5) = aten::matmul(%input, %57), scope: Linear
%output : Float(5) = aten::add_(%output.1, %56, %3), scope: Linear
return (%output);
}
@zeryx when i call the binary and try to load the model i get, why isnt it able to load the model?
$ make clean; make; ./testing
Scanning dependencies of target testing
[ 50%] Building CXX object CMakeFiles/testing.dir/main.cpp.o
[100%] Linking CXX executable testing
[100%] Built target testing
libc++abi.dylib: terminating with uncaught exception of type c10::Error: INVALID_ARGUMENT:tensors[5]: Cannot find field. (deserialize at /Users/administrator/nightlies/2018_12_03/wheel_build_dirs/libtorch_2.7/pytorch/torch/csrc/jit/import.cpp:92)
frame #0: c10::Error::Error(c10::SourceLocation, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 135 (0x11351df87 in libc10.dylib)
frame #1: torch::jit::(anonymous namespace)::ScriptModuleDeserializer::deserialize(std::__1::function<std::__1::shared_ptr<torch::jit::script::Module> (std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)>) + 6408 (0x10ca94c78 in libtorch.1.dylib)
frame #2: torch::jit::load(std::__1::basic_istream<char, std::__1::char_traits<char> >&) + 538 (0x10ca95d4a in libtorch.1.dylib)
frame #3: main + 2188 (0x10b61f13c in testing)
frame #4: start + 1 (0x7fff8a8605ad in libdyld.dylib)
Abort trap: 6
generator.py works now, here the output:
$ python3 generator.py graph(%input.1 : Tensor %1 : Tensor %2 : Tensor %25 : Tensor %26 : Tensor %55 : Tensor %56 : Tensor) { %19 : bool = prim::Constant[value=1](), scope: Conv2d %12 : bool = prim::Constant[value=0](), scope: Conv2d %6 : int = prim::Constant[value=0](), scope: Conv2d %3 : int = prim::Constant[value=1](), scope: Conv2d %50 : int = prim::Constant[value=1258]() %51 : int = prim::Constant[value=1892]() %5 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d %8 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d %11 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d %15 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d %20 : Float(1, 2, 1262, 1896) = aten::_convolution(%input.1, %1, %2, %5, %8, %11, %12, %15, %3, %12, %12, %19), scope: Conv2d %result.3 : Tensor = prim::If(%12) block0() { %result.4 : Tensor = aten::relu_(%20) -> (%result.4) } block1() { %result.5 : Tensor = aten::relu(%20) -> (%result.5) } %29 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d %32 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d %35 : int[] = prim::ListConstruct(%3, %3), scope: Conv2d %39 : int[] = prim::ListConstruct(%6, %6), scope: Conv2d %44 : Float(1, 1, 1262, 1896) = aten::_convolution(%result.3, %25, %26, %29, %32, %35, %12, %39, %3, %12, %12, %19), scope: Conv2d %result : Tensor = prim::If(%12) block0() { %result.1 : Tensor = aten::relu_(%44) -> (%result.1) } block1() { %result.2 : Tensor = aten::relu(%44) -> (%result.2) } %input.2 : Tensor = aten::squeeze(%result) %52 : int = aten::mul(%50, %51) %53 : int[] = prim::ListConstruct(%52) %input : Tensor = aten::view(%input.2, %53) %57 : Float(2380136!, 5!) = aten::t(%55), scope: Linear %output.1 : Float(5) = aten::matmul(%input, %57), scope: Linear %output : Float(5) = aten::add_(%output.1, %56, %3), scope: Linear return (%output); }
@zeryx when i call the binary and try to load the model i get, why isnt it able to load the model?
$ make clean; make; ./testing Scanning dependencies of target testing [ 50%] Building CXX object CMakeFiles/testing.dir/main.cpp.o [100%] Linking CXX executable testing [100%] Built target testing libc++abi.dylib: terminating with uncaught exception of type c10::Error: INVALID_ARGUMENT:tensors[5]: Cannot find field. (deserialize at /Users/administrator/nightlies/2018_12_03/wheel_build_dirs/libtorch_2.7/pytorch/torch/csrc/jit/import.cpp:92) frame #0: c10::Error::Error(c10::SourceLocation, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 135 (0x11351df87 in libc10.dylib) frame #1: torch::jit::(anonymous namespace)::ScriptModuleDeserializer::deserialize(std::__1::function<std::__1::shared_ptr<torch::jit::script::Module> (std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)>) + 6408 (0x10ca94c78 in libtorch.1.dylib) frame #2: torch::jit::load(std::__1::basic_istream<char, std::__1::char_traits<char> >&) + 538 (0x10ca95d4a in libtorch.1.dylib) frame #3: main + 2188 (0x10b61f13c in testing) frame #4: start + 1 (0x7fff8a8605ad in libdyld.dylib) Abort trap: 6
This is due to the different CUDA version between LibTorch and PyTorch. For example, maybe your PyTorch is under CUDA10 but LibTorch is under CUDA9.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@zeryx thanks for providing your example.
i installed pytorch:
i installed libtorch following these steps:
https://pytorch.org/cppdocs/installing.html
but i downloaded the libtorch from here:
https://download.pytorch.org/libtorch/nightly/cpu/libtorch-macos-latest.zip
instead:
https://download.pytorch.org/libtorch/nightly/cpu/libtorch-shared-with-deps-latest.zip