Implementación del modelo de aprendizaje profundo basado en C ++

1.1 Introducción

 Como marco de aprendizaje profundo de un extremo a otro, PyTorch tiene buenas condiciones de implementación del entorno de producción después de la versión 1.0. Además de escribir la API REST para la implementación en el lado web (referencia), también existen requisitos amplios para la implementación del lado del software. Especialmente la versión 1.5 recientemente lanzada proporciona una API de front-end C ++ más estable.

     La mayor diferencia entre el mundo industrial y el mundo académico es que el modelo industrial debe implementarse sobre el terreno. El mundo académico está más preocupado por los requisitos de precisión del modelo y menos por el rendimiento de implementación del modelo. En términos generales, después de entrenar un modelo con un marco de aprendizaje profundo, Python es suficiente para implementar una demostración de razonamiento simple. Pero en un entorno de producción, la portabilidad y el rendimiento de velocidad de Python son muy inferiores a C ++. Por lo tanto, para los ingenieros de algoritmos de aprendizaje profundo, Python generalmente se usa para la implementación rápida de ideas y entrenamiento de modelos, y C ++ se usa como una herramienta de producción para modelos. En la actualidad, PyTorch puede combinar perfectamente los dos. Los componentes tecnológicos centrales que implementan la implementación del modelo PyTorch son TorchScript y libtorch .

     Por lo tanto, el proceso de ingeniería del algoritmo de aprendizaje profundo basado en PyTorch es aproximadamente como se muestra en la siguiente figura:

                                                                                                                                          

1.2 TorchScript

     TorchScript se puede considerar como una representación intermedia del modelo PyTorch, y el modelo PyTorch representado por TorchScript se puede leer directamente en C ++. PyTorch puede usar TorchScript para construir modelos serializados después de la versión 1.0. TorchScript proporciona dos métodos de aplicación: rastreo y script.

     Los ejemplos de aplicaciones de rastreo son los siguientes:

class MyModel(torch.nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.linear = torch.nn.Linear(4, 4)
 
 
    def forward(self, x, h):
        new_h = torch.tanh(self.linear(x) + h)
        return new_h, new_h
 
 
# 创建模型实例 
my_model = MyModel()
# 输入示例
x, h = torch.rand(3, 4), torch.rand(3, 4)
# torch.jit.trace方法对模型构建TorchScript
traced_model = torch.jit.trace(my_model, (x, h))
# 保存转换后的模型
traced_model.save('model.pt')

     En este código, primero definimos un modelo simple y creamos una instancia de modelo, y luego, dado un ejemplo de entrada, el paso más crítico del método Tracing es usar el método torch.jit.trace para transformar el modelo en TorchScript. Podemos obtener el objeto traced_model transformado para obtener sus atributos de gráfico computacional y atributos de código. Propiedades del gráfico de cálculo: 

print(traced_model.graph)
graph(%self.1 : __torch__.torch.nn.modules.module.___torch_mangle_1.Module,
      %input : Float(3, 4),
      %h : Float(3, 4)):
  %19 : __torch__.torch.nn.modules.module.Module = prim::GetAttr[name="linear"](%self.1)
  %21 : Tensor = prim::CallMethod[name="forward"](%19, %input)
  %12 : int = prim::Constant[value=1]() # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
  %13 : Float(3, 4) = aten::add(%21, %h, %12) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
  %14 : Float(3, 4) = aten::tanh(%13) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0
  %15 : (Float(3, 4), Float(3, 4)) = prim::TupleConstruct(%14, %14)
  return (%15)

 Atributos de código:

print(traced_cell.code)
def forward(self,
    input: Tensor,
    h: Tensor) -> Tuple[Tensor, Tensor]:
  _0 = torch.add((self.linear).forward(input, ), h, alpha=1)
  _1 = torch.tanh(_0)
  return (_1, _1)

     De esta manera, podemos guardar todo el modelo en el disco duro, y el modelo guardado de esta manera se puede cargar en otros entornos de lenguaje.

     Otra implementación de TorchScript es el método Script, que puede considerarse un complemento del método Tracing. Cuando el código del modelo contiene programas de control de flujo como if o for-loop, el método Tracing no es válido. En este momento, el método Script se puede utilizar para implementar TorchScript. El método de implementación no es muy diferente de Tracing. La clave es reemplazar jit.tracing con el método jit.script. El ejemplo es el siguiente.

scripted_model = torch.jit.script(MyModel)
scripted_model.save('model.pt')

      Además de Tracing y Script, también podemos mezclar los dos métodos, que no se detallarán aquí. En resumen, TorchScript nos proporciona una forma de representación que el compilador puede optimizar para proporcionar una ejecución más eficiente.

1.3 libtorch

     Después de convertir el modelo entrenado en el entorno Python, necesitamos PyTorch en el entorno C ++ para leer el modelo y compilar e implementar. PyTorch en este entorno C ++ es libtorch. Debido a que libtorch se usa generalmente como la interfaz de C ++ del modelo de PyTorch, libtorch también se llama la interfaz de C ++ de PyTorch.

     Podemos descargar el paquete de instalación de libtorch compilado directamente desde el sitio web oficial de PyTorch. Por supuesto, también podemos descargar el código fuente y compilarlo nosotros mismos. Cabe señalar aquí que la versión instalada de libtorch debe ser coherente con la versión de PyTorch en el entorno de Python.

     Después de instalar libtorch, simplemente puede probar si es normal. Por ejemplo, usamos TorchScript para convertir un modelo previamente entrenado, un ejemplo es el siguiente: 

import torch
import torchvision.models as models
vgg16 = models.vgg16()
example = torch.rand(1, 3, 224, 224).cuda() 
model = model.eval()
traced_script_module = torch.jit.trace(model, example)
output = traced_script_module(torch.ones(1,3,224,224).cuda())
traced_script_module.save('vgg16-trace.pt')
print(output)

La salida es: 

tensor([[ -0.8301, -35.6095, 12.4716]], device='cuda:0',
        grad_fn=<AddBackward0>)

     Luego cambie al entorno C ++ y escriba el archivo CmakeLists de la siguiente manera:

cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
project(libtorch_test)
find_package(Torch REQUIRED)
message(STATUS "Pytorch status:")
message(STATUS "libraries: ${TORCH_LIBRARIES}")
add_executable(libtorch_test test.cpp)
target_link_libraries(libtorch_test "${TORCH_LIBRARIES}")
set_property(TARGET libtorch_test PROPERTY CXX_STANDARD 11)

 Continúe escribiendo el código test.cpp de la siguiente manera:

#include "torch/script.h"
#include "torch/torch.h"
#include <iostream>
#include <memory>
using namespace std;
 
 
int main(int argc, const char* argv[]){
    if (argc != 2) {
        std::cerr << "usage: example-app <path-to-exported-script-module>\n";
        return -1;
    }
 
 
    // 读取TorchScript转化后的模型
    torch::jit::script::Module module;
    try {
        module = torch::jit::load(argv[1]);
    }
 
 
    catch (const c10::Error& e) {
        std::cerr << "error loading the model\n";
        return -1;
    }
 
 
    module->to(at::kCUDA);
    assert(module != nullptr);
    std::cout << "ok\n";
 
 
    // 构建示例输入
    std::vector<torch::jit::IValue> inputs;
    inputs.push_back(torch::ones({1, 3, 224, 224}).to(at::kCUDA));
 
 
    // 执行模型推理并输出tensor
    at::Tensor output = module->forward(inputs).toTensor();
    std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';}

     Compile test.cpp y ejecútelo. El resultado es el siguiente. Al comparar los resultados de ejecución en el entorno de Python, podemos encontrar que son básicamente los mismos, lo que también muestra que no hay ningún problema con la instalación de libtorch en el entorno actual. 

ok
-0.8297, -35.6048, 12.4823
[Variable[CUDAFloatType]{1,3}]

 1.4 Proceso de implementación completo

     A través de la descripción anterior de TorchScript y libtorch, de hecho, básicamente hemos hablado sobre el despliegue en C ++ de PyTorch, y aquí daremos un vistazo completo a todo el proceso. El proceso de implementación del modelo PyTorch basado en C ++ es el siguiente.

primer paso:

     Utilice el método torch.jit.trace para convertir el modelo PyTorch a TorchScript. Un ejemplo es el siguiente:

import torch
from torchvision.models import resnet18
model =resnet18()
example = torch.rand(1, 3, 224, 224)
tracing.traced_script_module = torch.jit.trace(model, example)

El segundo paso:

     Serialice TorchScript en un archivo de modelo .pt.

traced_script_module.save("traced_resnet_model.pt")

tercer paso:

     Importa el modelo TorchScript serializado en C ++, para esto necesitamos escribir el archivo cpp que contiene el programa que llama, el archivo CMakeLists.txt para su configuración y compilación. El contenido de muestra del archivo CMakeLists.txt es el siguiente:

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(custom_ops)
find_package(Torch REQUIRED)
add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 14)

      El código de ejemplo de example-app.cpp que contiene el programa de llamada del modelo es el siguiente:

#include <torch/script.h> // torch头文件.
#include <iostream>#include <memory>
 
 
int main(int argc, const char* argv[]) {
  if (argc != 2) {
    std::cerr << "usage: example-app <path-to-exported-script-module>\n";
    return -1;
  }
 
 
  torch::jit::script::Module module;
  try {
    // 反序列化:导入TorchScript模型
    module = torch::jit::load(argv[1]);
  }
 
 
  catch (const c10::Error& e) {
    std::cerr << "error loading the model\n";
    return -1;
  }
  std::cout << "ok\n";}

     Una vez escritos los dos archivos, se pueden compilar:

mkdir example_test
cd example_test
cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..
cmake --example_test . --config Release

el cuarto paso:

Agregue el código de inferencia del modelo a example-app.cpp y ejecute:

std::vector<torch::jit::IValue> inputs;inputs.push_back(torch::ones({1, 3, 224, 224}));
// 执行推理并将模型转化为Tensor
output = module.forward(inputs).toTensor();std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';

     Lo anterior es todo el proceso de implementación del modelo PyTorch en C ++. Para obtener tutoriales relacionados, consulte el PyTorch oficial: https://pytorch.org/tutorials/

para resumir

     La implementación del modelo es muy importante para los ingenieros de algoritmos y está relacionada con si su trabajo puede generar valor real. En consecuencia, también debe tener suficientes capacidades de ingeniería, como MySQL, Redis, C ++, algunos conocimientos y técnicas de desarrollo de front-end y back-end, todos los ingenieros de algoritmos deben poder comprenderlo y poder usarlo.

Supongo que te gusta

Origin blog.csdn.net/wzhrsh/article/details/109552923
Recomendado
Clasificación