What I thought would be a bit of a hassle to install libTorch turned out to be a smooth, step-by-step installation, according to the official Guide. The main reason is that I am not familiar with how cmake builds a c++ project. The first is to download libtorch from the official website. The address given below is the libtorch download address that I will use later in the sharing.

Libtorch purposes

Libtorch is used to load trained models into a c++ environment for reasoning or extra work, as many network implementations are implemented using the python version of torch, also known as pytorch.

wget https://download.pytorch.org/libtorch/nightly/cpu/libtorch-shared-with-deps-latest.zip
unzip libtorch-shared-with-deps-latest.zip
Copy the code

The example given on the official website is a project built using CMakeLists, of course you can build projects using tools that are handy to you. In fact, I am also a c++ entry-level developer.

Cmake_minimum_required (VERSION 3.0 FATAL_ERROR) project(example-app) find_package(Torch REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}") add_executable(example-app main.cpp) target_link_libraries(example-app "${TORCH_LIBRARIES}") set_property(TARGET example-app PROPERTY CXX_STANDARD 14)Copy the code

Cmake, an advanced compilation and configuration tool, will be shared later as you learn more about it.

  • Cmake_minimum_required Basically specifies the lowest supported version of Cmake
  • Add_executable adds an executable file
  • Find_package torch installation can be found
  • Set can set some parameters
  • target_link_libraries
  • Set_property Sets the property
#include <iostream>

int main

{
std::cout << "hello world" std::endl;
}
Copy the code
mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=/absolute/path/to/libtorch ..
cmake --build . --config Release
Copy the code

Note here is absolute/path/to/libtorch is an absolute path, then

CMAKE_PREFIX_PATH indicates the installation directory to compile. You need to replace /absolute/path/to with the directory where you just unzipped libtorch

Download data set

Do some preparatory work, that is, first need to download the database, otherwise running the program will report an error. Here’s some Python code

import torch
import torchvision
from torchvision import transforms

if __name__ == "__main__":
    train_dataset = torchvision.datasets.MNIST(root='./data',
                    train=True,
                    transform=transforms.ToTensor(),
                    download=True
                    )
Copy the code

After downloading, we need to copy the train-allagrams-idx3-ubyte and train-images-idx3-ubyte files to build folder data otherwise we will get an error at runtime.

Cmake_minimum_required (VERSION 3.1 FATAL_ERROR) project (NNet) set (CMAKE_PREFIX_PATH/home/ubuntu16 / Downloads/libtorch) find_package(Torch REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}") add_executable(main src/main.cpp include/network.h) target_include_directories(main PRIVATE include) target_link_libraries(main ${TORCH_LIBRARIES}) set_property(TARGET main PROPERTY CXX_STANDARD 14)Copy the code

Once we have configured how to compile a project, we can do more interesting things. In fact, we can use c++ as a front end to develop a neural network. First, let’s take a look at how to define and operate a module in c++. You can develop a small neural network in Python under the PyTorch framework, or you have experience implementing a classic neural network, such as VGG ResNet.

This is similar to pytorch’s interface for python in that it provides a reusable interface for C++ to build neural network infrastructure modules. All other modules are derived from this base module. In python, this class is torch.nn.Module, while in C++ the equivalent is torch::nn::Module. The module encapsulates the forward propagation method forward(), and also includes parameters, buffers, and submodules.

Parameters and buffers store state as tensors. Parameters record gradients, buffers do not. The parameters are usually the trainable weights of your neural network. Examples of buffers include mean and variance for batch normalization. PyTorch’s API allows module nesting in order to reuse specific logic and state blocks. A nested module is called a submodule.

#pragma once

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

struct NetImpl:torch::nn::Module{

    NetImpl(int fc1_dims, int fc2_dims):fc1(fc1_dims,fc1_dims),fc2(fc1_dims,fc2_dims),out(fc2_dims,1) {register_module("fc1",fc1);
    register_module("fc2",fc2);
    register_module("out",out);

}

torch::Tensor forward(torch::Tensor x){
    x = torch::relu(fc1(x));
    x = torch::relu(fc2(x));
    x = out(x);

    return x;

}

torch::nn::Linear fc1{nullptr}, fc2{nullptr}, out{nullptr};

};

TORCH_MODULE(Net);
Copy the code
#include "network.h" #include <iostream> #include <torch/torch.h> \ using namespace std; using namespace torch; Int main() {Net network(50,10); cout << network << endl; cout << "hello world" << endl; }Copy the code

Set up the network

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


// Define a simple network consisting of a full connection layer

struct Net: torch::nn::Module{
  Net() {// Construct and register the network architecture layer
    fc1 = register_module("fc1",torch::nn::Linear(784.64));
    fc2 = register_module("fc2",torch::nn::Linear(64.32));
    fc3 = register_module("fc3",torch::nn::Linear(32.10));
  }
  // Implement forward propagation
  torch::Tensor forward(torch::Tensor x){
    x = torch::relu(fc1->forward(x.reshape({x.size(0),784})));
    x = torch::dropout(x, /*p=*/0.5./*train=*/is_training());
    x = torch::relu(fc2->forward(x));
    x = torch::log_softmax(fc3->forward(x), /*dim=*/1);
    return x;
  }

  torch::nn::Linear fc1{nullptr}, fc2{nullptr}, fc3{nullptr};
};

int main(a) {
  Create a new network
  auto net = std::make_shared<Net>();

  auto data_loader = torch::data::make_data_loader(
      torch::data::datasets::MNIST("./data").map(
          torch::data::transforms::Stack<>()),
      /*batch_size=*/64);

  torch::optim::SGD optimizer(net->parameters(), /*lr=*/0.01);

  for (size_t epoch = 1; epoch <= 10; ++epoch) {
    size_t batch_index = 0;
    // Iterate the data loader to yield batches from the dataset.
    for (auto& batch : *data_loader) {
      // Reset the gradient
      optimizer.zero_grad(a);// Run the model on input data
      torch::Tensor prediction = net->forward(batch.data);
      // Calculate the loss value according to the gap between the predicted value and the real value
      torch::Tensor loss = torch::nll_loss(prediction, batch.target);
      // Calculate the gradient of parameters in backpropagation
      loss.backward(a);// Update parameters based on calculated gradients
      optimizer.step(a);if (++batch_index % 100= =0) {
        std::cout << "Epoch: " << epoch << " | Batch: " << batch_index
                  << " | Loss: " << loss.item<float>() << std::endl;
        // Save the model
        torch::save(net, "net.pt"); }}}}Copy the code