[Implementación del modelo] Tutorial de introducción (7): construcción y razonamiento del modelo TensorRT

Tutorial de introducción a la implementación del modelo (7): Construcción y razonamiento del modelo TensorRT - Zhihu (zhihu.com)

Tabla de contenido

Introducción a TensorRT

Instalar TensorRT

ventanas

linux

construcción del modelo

construir directamente

modelo de conversión IR

modelo de razonamiento

Inferencia usando la API de Python

Razonamiento usando la API de C++

Resumir

Preguntas más frecuentes

referencia

Portal de la serie


¡El tutorial de introducción a la implementación de modelos continúa actualizándose! Creo que después de los estudios anteriores, todos tienen una comprensión más completa de la representación intermedia de ONNX, pero en un entorno de producción específico, el modelo ONNX a menudo debe convertirse en un formato de modelo que pueda usar el back-end de razonamiento específico. En este tutorial, conoceremos contigo el famoso backend de razonamiento TensorRT.

Introducción a TensorRT

TensorRT es un marco de aprendizaje profundo lanzado por NVIDIA para ejecutar inferencias de aprendizaje profundo en su hardware. TensorRT proporciona capacitación consciente de la cuantificación y funciones de cuantificación fuera de línea, y los usuarios pueden elegir dos modos de optimización, INT8 y FP16, para aplicar modelos de aprendizaje profundo a implementaciones de producción de diferentes tareas, como transmisión de video, reconocimiento de voz, recomendación, detección de fraude, generación de texto , y manejo del lenguaje natural. TensorRT está altamente optimizado para ejecutarse en GPU NVIDIA y es probablemente el motor de inferencia más rápido que actualmente ejecuta modelos en GPU NVIDIA. Puede encontrar información más específica sobre TensorRT en  el sitio web oficial de TensorRT  .

Instalar TensorRT

ventanas

De manera predeterminada, en una máquina con una tarjeta gráfica NVIDIA, instale  CUDA  y  CUDNN con anticipación e inicie sesión en el sitio web oficial de NVIDIA para descargar el paquete comprimido de TensorRT que es compatible con la versión host de CUDA.

Tomando CUDA versión 10.2 como ejemplo, seleccione  el paquete zip que se adapta a CUDA 10.2 Una vez completada la descarga, los usuarios con el entorno virtual conda pueden cambiar primero al entorno virtual y luego ejecutar comandos similares a los siguientes en powershell para instalar y prueba:

cd \the\path\of\tensorrt\zip\file 
Expand-Archive TensorRT-8.2.5.1.Windows10.x86_64.cuda-10.2.cudnn8.2.zip . 
$env:TENSORRT_DIR = "$pwd\TensorRT-8.2.5.1" 
$env:path = "$env:TENSORRT_DIR\lib;" + $env:path 
pip install $env:TENSORRT_DIR\python\tensorrt-8.2.5.1-cp36-none-win_amd64.whl 
python -c "import tensorrt;print(tensorrt.__version__)" 

El comando anterior verificará la versión de TensorRT después de la instalación.Si el resultado impreso es 8.2.5.1, significa que el paquete de Python se instaló correctamente.

linux

Similar a la instalación en el entorno de Windows, CUDA  y  CUDNN se instalan por adelantado en una máquina con una tarjeta gráfica NVIDIA de forma predeterminada, y puede  iniciar sesión en el sitio web oficial de NVIDIA para descargar el paquete comprimido TensorRT que es compatible con el host CUDA versión.

Tome CUDA versión 10.2 como ejemplo, seleccione  el paquete tar que se adapta a CUDA 10.2 y luego ejecute comandos similares a los siguientes para instalar y probar:

cd /the/path/of/tensorrt/tar/gz/file 
tar -zxvf TensorRT-8.2.5.1.linux.x86_64-gnu.cuda-10.2.cudnn8.2.tar.gz 
export TENSORRT_DIR=$(pwd)/TensorRT-8.2.5.1 
export LD_LIBRARY_PATH=$TENSORRT_DIR/lib:$LD_LIBRARY_PATH 
pip install TensorRT-8.2.5.1/python/tensorrt-8.2.5.1-cp37-none-linux_x86_64.whl 
python -c "import tensorrt;print(tensorrt.__version__)" 

Si el resultado impreso es 8.2.5.1, significa que el paquete de Python se instaló correctamente.

construcción del modelo

Usamos TensorRT para generar modelos de dos maneras principales:

  1. Construya la red capa por capa directamente a través de la API de TensorRT;
  2. Convierta el modelo de representación intermedia en un modelo TensorRT, como convertir un modelo ONNX en un modelo TensorRT.

A continuación, usaremos estos dos métodos para construir el modelo TensorRT en Python y C++, y usaremos el modelo generado para la inferencia.

construir directamente

Usando la API de TensorRT para construir una red capa por capa, este proceso es similar a usar un marco de entrenamiento general, como usar Pytorch o TensorFlow para construir una red. Cabe señalar que para la parte de peso, como la convolución o la capa de normalización, el contenido de peso debe asignarse a la red TensorRT. Este artículo no lo mostrará en detalle, sino que solo construirá una red simple que agrupe la entrada.

Compilación con la API de Python

El primero es usar la API de Python para construir directamente la red TensorRT. Este método usa principalmente funciones  tensorrt.Builder y  create_builder_config funciones  create_network para construir la configuración y la red respectivamente. El primero se usa para establecer parámetros como el espacio de trabajo máximo de la red y el Este último es el cuerpo principal de la red, que debe agregarse capa por capa.

Además, es necesario definir los nombres de entrada y salida, serializar la red construida y guardarla como un archivo local. Vale la pena señalar que si desea que la red acepte entrada y salida con diferentes resoluciones, debe usar  tensorrt.Builder la  create_optimization_profile función y establecer los tamaños mínimo y máximo.

El código de implementación es el siguiente:

import tensorrt as trt 
 
verbose = True 
IN_NAME = 'input' 
OUT_NAME = 'output' 
IN_H = 224 
IN_W = 224 
BATCH_SIZE = 1 
 
EXPLICIT_BATCH = 1 << (int)( 
    trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) 
 
TRT_LOGGER = trt.Logger(trt.Logger.VERBOSE) if verbose else trt.Logger() 
with trt.Builder(TRT_LOGGER) as builder, builder.create_builder_config( 
) as config, builder.create_network(EXPLICIT_BATCH) as network: 
    # define network 
    input_tensor = network.add_input( 
        name=IN_NAME, dtype=trt.float32, shape=(BATCH_SIZE, 3, IN_H, IN_W)) 
    pool = network.add_pooling( 
        input=input_tensor, type=trt.PoolingType.MAX, window_size=(2, 2)) 
    pool.stride = (2, 2) 
    pool.get_output(0).name = OUT_NAME 
    network.mark_output(pool.get_output(0)) 
 
    # serialize the model to engine file 
    profile = builder.create_optimization_profile() 
    profile.set_shape_input('input', *[[BATCH_SIZE, 3, IN_H, IN_W]]*3)  
    builder.max_batch_size = 1 
    config.max_workspace_size = 1 << 30 
    engine = builder.build_engine(network, config) 
    with open('model_python_trt.engine', mode='wb') as f: 
        f.write(bytearray(engine.serialize())) 
        print("generating file done!") 

Compilación con la API de C++

Para los socios pequeños que desean usar directamente el lenguaje C++ para construir una red, todo el proceso es muy similar al proceso de ejecución de Python mencionado anteriormente. Los puntos principales a tener en cuenta son:

  1. nvinfer1:: createInferBuilder En correspondencia con eso en Python  ,  la instancia de la clase  tensorrt.Builderdebe pasarse  , pero  es una clase abstracta, y el usuario debe heredar la clase e implementar la función virtual interna. Pero aquí usamos directamente  la  subclase de implementación  en el archivo de la carpeta de muestras  después de descomprimir el paquete TensorRT.ILoggerILogger../samples/common/logger.hLogger
  2. Establecer el tamaño de entrada del modelo TensorRT requiere varias llamadas  IOptimizationProfile ,  setDimensions lo que es un poco más engorroso que Python. IOptimizationProfile Se requieren  funciones createOptimizationProfile , correspondientes a  create_builder_config las funciones de Python.

El código de implementación es el siguiente:

#include <fstream> 
#include <iostream> 
 
#include <NvInfer.h> 
#include <../samples/common/logger.h> 
 
using namespace nvinfer1; 
using namespace sample; 
 
const char* IN_NAME = "input"; 
const char* OUT_NAME = "output"; 
static const int IN_H = 224; 
static const int IN_W = 224; 
static const int BATCH_SIZE = 1; 
static const int EXPLICIT_BATCH = 1 << (int)(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); 
 
int main(int argc, char** argv) 
{ 
        // Create builder 
        Logger m_logger; 
        IBuilder* builder = createInferBuilder(m_logger); 
        IBuilderConfig* config = builder->createBuilderConfig(); 
 
        // Create model to populate the network 
        INetworkDefinition* network = builder->createNetworkV2(EXPLICIT_BATCH); 
        ITensor* input_tensor = network->addInput(IN_NAME, DataType::kFLOAT, Dims4{ BATCH_SIZE, 3, IN_H, IN_W }); 
        IPoolingLayer* pool = network->addPoolingNd(*input_tensor, PoolingType::kMAX, DimsHW{ 2, 2 }); 
        pool->setStrideNd(DimsHW{ 2, 2 }); 
        pool->getOutput(0)->setName(OUT_NAME); 
        network->markOutput(*pool->getOutput(0)); 
 
        // Build engine 
        IOptimizationProfile* profile = builder->createOptimizationProfile(); 
        profile->setDimensions(IN_NAME, OptProfileSelector::kMIN, Dims4(BATCH_SIZE, 3, IN_H, IN_W)); 
        profile->setDimensions(IN_NAME, OptProfileSelector::kOPT, Dims4(BATCH_SIZE, 3, IN_H, IN_W)); 
        profile->setDimensions(IN_NAME, OptProfileSelector::kMAX, Dims4(BATCH_SIZE, 3, IN_H, IN_W)); 
        config->setMaxWorkspaceSize(1 << 20); 
        ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config); 
 
        // Serialize the model to engine file 
        IHostMemory* modelStream{ nullptr }; 
        assert(engine != nullptr); 
        modelStream = engine->serialize(); 
 
        std::ofstream p("model.engine", std::ios::binary); 
        if (!p) { 
                std::cerr << "could not open output file to save model" << std::endl; 
                return -1; 
        } 
        p.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size()); 
        std::cout << "generating file done!" << std::endl; 
 
        // Release resources 
        modelStream->destroy(); 
        network->destroy(); 
        engine->destroy(); 
        builder->destroy(); 
        config->destroy(); 
        return 0; 
} 

modelo de conversión IR

Además de construir la red capa por capa y serializar el modelo directamente a través de la API de TensorRT, TensorRT también admite la conversión de modelos de representación intermedios (como ONNX) en modelos de TensorRT.

Convertir utilizando la API de Python

Primero usamos Pytorch para implementar un modelo consistente con lo anterior, es decir, solo agrupamos la entrada y la generamos una vez; luego convertimos el modelo Pytorch al modelo ONNX; finalmente convertimos el modelo ONNX al modelo TensorRT.

La función TensorRT se usa principalmente aquí  OnnxParser , que puede analizar el modelo ONNX en la red TensorRT. Finalmente, también podemos obtener un modelo TensorRT cuya función es consistente con la del modelo implementado en el método anterior.

El código de implementación es el siguiente:

import torch 
import onnx 
import tensorrt as trt 
 
 
onnx_model = 'model.onnx' 
 
class NaiveModel(torch.nn.Module): 
    def __init__(self): 
        super().__init__() 
        self.pool = torch.nn.MaxPool2d(2, 2) 
 
    def forward(self, x): 
        return self.pool(x) 
 
device = torch.device('cuda:0') 
 
# generate ONNX model 
torch.onnx.export(NaiveModel(), torch.randn(1, 3, 224, 224), onnx_model, input_names=['input'], output_names=['output'], opset_version=11) 
onnx_model = onnx.load(onnx_model) 
 
# create builder and network 
logger = trt.Logger(trt.Logger.ERROR) 
builder = trt.Builder(logger) 
EXPLICIT_BATCH = 1 << (int)( 
    trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) 
network = builder.create_network(EXPLICIT_BATCH) 
 
# parse onnx 
parser = trt.OnnxParser(network, logger) 
 
if not parser.parse(onnx_model.SerializeToString()): 
    error_msgs = '' 
    for error in range(parser.num_errors): 
        error_msgs += f'{parser.get_error(error)}\n' 
    raise RuntimeError(f'Failed to parse onnx, {error_msgs}') 
 
config = builder.create_builder_config() 
config.max_workspace_size = 1<<20 
profile = builder.create_optimization_profile() 
 
profile.set_shape('input', [1,3 ,224 ,224], [1,3,224, 224], [1,3 ,224 ,224]) 
config.add_optimization_profile(profile) 
# create engine 
with torch.cuda.device(device): 
    engine = builder.build_engine(network, config) 
 
with open('model.engine', mode='wb') as f: 
    f.write(bytearray(engine.serialize())) 
    print("generating file done!") 
 

Durante la conversión IR, si se requieren múltiples lotes, múltiples entradas y formas dinámicas, se pueden configurar  set_shape llamando a la función varias veces. set_shape Los parámetros aceptados por la función son: nombre del nodo de entrada, tamaño de entrada mínimo aceptable, tamaño de entrada óptimo y tamaño de entrada máximo aceptable. Generalmente se requiere que la relación de tamaño de estas tres dimensiones sea monótonamente creciente.

Convertir utilizando la API de C++

Después de presentar cómo convertir el modelo ONNX al modelo TensorRT con lenguaje Python, luego presente cómo convertir el modelo ONNX al modelo TensorRT con C++. A través de esto  NvOnnxParser, podemos analizar directamente en la red el archivo ONNX obtenido en la sección anterior.

El código de implementación es el siguiente:

#include <fstream> 
#include <iostream> 
 
#include <NvInfer.h> 
#include <NvOnnxParser.h> 
#include <../samples/common/logger.h> 
 
using namespace nvinfer1; 
using namespace nvonnxparser; 
using namespace sample; 
 
int main(int argc, char** argv) 
{ 
        // Create builder 
        Logger m_logger; 
        IBuilder* builder = createInferBuilder(m_logger); 
        const auto explicitBatch = 1U << static_cast<uint32_t>(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); 
        IBuilderConfig* config = builder->createBuilderConfig(); 
 
        // Create model to populate the network 
        INetworkDefinition* network = builder->createNetworkV2(explicitBatch); 
 
        // Parse ONNX file 
        IParser* parser = nvonnxparser::createParser(*network, m_logger); 
        bool parser_status = parser->parseFromFile("model.onnx", static_cast<int>(ILogger::Severity::kWARNING)); 
 
        // Get the name of network input 
        Dims dim = network->getInput(0)->getDimensions(); 
        if (dim.d[0] == -1)  // -1 means it is a dynamic model 
        { 
                const char* name = network->getInput(0)->getName(); 
                IOptimizationProfile* profile = builder->createOptimizationProfile(); 
                profile->setDimensions(name, OptProfileSelector::kMIN, Dims4(1, dim.d[1], dim.d[2], dim.d[3])); 
                profile->setDimensions(name, OptProfileSelector::kOPT, Dims4(1, dim.d[1], dim.d[2], dim.d[3])); 
                profile->setDimensions(name, OptProfileSelector::kMAX, Dims4(1, dim.d[1], dim.d[2], dim.d[3])); 
                config->addOptimizationProfile(profile); 
        } 
 
 
        // Build engine 
        config->setMaxWorkspaceSize(1 << 20); 
        ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config); 
 
        // Serialize the model to engine file 
        IHostMemory* modelStream{ nullptr }; 
        assert(engine != nullptr); 
        modelStream = engine->serialize(); 
 
        std::ofstream p("model.engine", std::ios::binary); 
        if (!p) { 
                std::cerr << "could not open output file to save model" << std::endl; 
                return -1; 
        } 
        p.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size()); 
        std::cout << "generate file success!" << std::endl; 
 
        // Release resources 
        modelStream->destroy(); 
        network->destroy(); 
        engine->destroy(); 
        builder->destroy(); 
        config->destroy(); 
        return 0; 
} 
 

modelo de razonamiento

Anteriormente, usamos dos formas de construir modelos TensorRT y generamos cuatro modelos TensorRT en Python y C++ respectivamente.Las funciones de estos cuatro modelos son teóricamente idénticas.

A continuación, usaremos Python y C++ para realizar inferencias en el modelo TensorRT generado.

Inferencia usando la API de Python

El primero es usar la API de Python para inferir el modelo TensorRT Parte del código aquí se refiere a  MMDeploy . Ejecute el siguiente código, puede encontrar que  1x3x224x224 se ingresa un tensor y  1x3x112x112 se genera un tensor, lo que está exactamente en línea con nuestra expectativa del resultado después de la agrupación de entrada.

from typing import Union, Optional, Sequence,Dict,Any 
 
import torch 
import tensorrt as trt 
 
class TRTWrapper(torch.nn.Module): 
    def __init__(self,engine: Union[str, trt.ICudaEngine], 
                 output_names: Optional[Sequence[str]] = None) -> None: 
        super().__init__() 
        self.engine = engine 
        if isinstance(self.engine, str): 
            with trt.Logger() as logger, trt.Runtime(logger) as runtime: 
                with open(self.engine, mode='rb') as f: 
                    engine_bytes = f.read() 
                self.engine = runtime.deserialize_cuda_engine(engine_bytes) 
        self.context = self.engine.create_execution_context() 
        names = [_ for _ in self.engine] 
        input_names = list(filter(self.engine.binding_is_input, names)) 
        self._input_names = input_names 
        self._output_names = output_names 
 
        if self._output_names is None: 
            output_names = list(set(names) - set(input_names)) 
            self._output_names = output_names 
 
    def forward(self, inputs: Dict[str, torch.Tensor]): 
        assert self._input_names is not None 
        assert self._output_names is not None 
        bindings = [None] * (len(self._input_names) + len(self._output_names)) 
        profile_id = 0 
        for input_name, input_tensor in inputs.items(): 
            # check if input shape is valid 
            profile = self.engine.get_profile_shape(profile_id, input_name) 
            assert input_tensor.dim() == len( 
                profile[0]), 'Input dim is different from engine profile.' 
            for s_min, s_input, s_max in zip(profile[0], input_tensor.shape, 
                                             profile[2]): 
                assert s_min <= s_input <= s_max, \ 
                    'Input shape should be between ' \ 
                    + f'{profile[0]} and {profile[2]}' \ 
                    + f' but get {tuple(input_tensor.shape)}.' 
            idx = self.engine.get_binding_index(input_name) 
 
            # All input tensors must be gpu variables 
            assert 'cuda' in input_tensor.device.type 
            input_tensor = input_tensor.contiguous() 
            if input_tensor.dtype == torch.long: 
                input_tensor = input_tensor.int() 
            self.context.set_binding_shape(idx, tuple(input_tensor.shape)) 
            bindings[idx] = input_tensor.contiguous().data_ptr() 
 
        # create output tensors 
        outputs = {} 
        for output_name in self._output_names: 
            idx = self.engine.get_binding_index(output_name) 
            dtype = torch.float32 
            shape = tuple(self.context.get_binding_shape(idx)) 
 
            device = torch.device('cuda') 
            output = torch.empty(size=shape, dtype=dtype, device=device) 
            outputs[output_name] = output 
            bindings[idx] = output.data_ptr() 
        self.context.execute_async_v2(bindings, 
                                      torch.cuda.current_stream().cuda_stream) 
        return outputs 
 
model = TRTWrapper('model.engine', ['output']) 
output = model(dict(input = torch.randn(1, 3, 224, 224).cuda())) 
print(output) 

Razonamiento usando la API de C++

Finalmente, en muchos entornos de producción reales, usaremos el lenguaje C++ para completar tareas específicas para lograr efectos de ejecución de código más eficientes. Además, los usuarios de TensoRT generalmente valoran su uso en C++, por lo que también usamos el lenguaje C++ Implementar el razonamiento del modelo nuevamente, lo que puede también puede compararse con el uso de la API de Python para razonar sobre el modelo.

El código de implementación es el siguiente:

#include <fstream> 
#include <iostream> 
 
#include <NvInfer.h> 
#include <../samples/common/logger.h> 
 
#define CHECK(status) \ 
    do\ 
    {\ 
        auto ret = (status);\ 
        if (ret != 0)\ 
        {\ 
            std::cerr << "Cuda failure: " << ret << std::endl;\ 
            abort();\ 
        }\ 
    } while (0) 
 
using namespace nvinfer1; 
using namespace sample; 
 
const char* IN_NAME = "input"; 
const char* OUT_NAME = "output"; 
static const int IN_H = 224; 
static const int IN_W = 224; 
static const int BATCH_SIZE = 1; 
static const int EXPLICIT_BATCH = 1 << (int)(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); 
 
 
void doInference(IExecutionContext& context, float* input, float* output, int batchSize) 
{ 
        const ICudaEngine& engine = context.getEngine(); 
 
        // Pointers to input and output device buffers to pass to engine. 
        // Engine requires exactly IEngine::getNbBindings() number of buffers. 
        assert(engine.getNbBindings() == 2); 
        void* buffers[2]; 
 
        // In order to bind the buffers, we need to know the names of the input and output tensors. 
        // Note that indices are guaranteed to be less than IEngine::getNbBindings() 
        const int inputIndex = engine.getBindingIndex(IN_NAME); 
        const int outputIndex = engine.getBindingIndex(OUT_NAME); 
 
        // Create GPU buffers on device 
        CHECK(cudaMalloc(&buffers[inputIndex], batchSize * 3 * IN_H * IN_W * sizeof(float))); 
        CHECK(cudaMalloc(&buffers[outputIndex], batchSize * 3 * IN_H * IN_W /4 * sizeof(float))); 
 
        // Create stream 
        cudaStream_t stream; 
        CHECK(cudaStreamCreate(&stream)); 
 
        // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host 
        CHECK(cudaMemcpyAsync(buffers[inputIndex], input, batchSize * 3 * IN_H * IN_W * sizeof(float), cudaMemcpyHostToDevice, stream)); 
        context.enqueue(batchSize, buffers, stream, nullptr); 
        CHECK(cudaMemcpyAsync(output, buffers[outputIndex], batchSize * 3 * IN_H * IN_W / 4 * sizeof(float), cudaMemcpyDeviceToHost, stream)); 
        cudaStreamSynchronize(stream); 
 
        // Release stream and buffers 
        cudaStreamDestroy(stream); 
        CHECK(cudaFree(buffers[inputIndex])); 
        CHECK(cudaFree(buffers[outputIndex])); 
} 
 
int main(int argc, char** argv) 
{ 
        // create a model using the API directly and serialize it to a stream 
        char *trtModelStream{ nullptr }; 
        size_t size{ 0 }; 
 
        std::ifstream file("model.engine", std::ios::binary); 
        if (file.good()) { 
                file.seekg(0, file.end); 
                size = file.tellg(); 
                file.seekg(0, file.beg); 
                trtModelStream = new char[size]; 
                assert(trtModelStream); 
                file.read(trtModelStream, size); 
                file.close(); 
        } 
 
        Logger m_logger; 
        IRuntime* runtime = createInferRuntime(m_logger); 
        assert(runtime != nullptr); 
        ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream, size, nullptr); 
        assert(engine != nullptr); 
        IExecutionContext* context = engine->createExecutionContext(); 
        assert(context != nullptr); 
 
        // generate input data 
        float data[BATCH_SIZE * 3 * IN_H * IN_W]; 
        for (int i = 0; i < BATCH_SIZE * 3 * IN_H * IN_W; i++) 
                data[i] = 1; 
 
        // Run inference 
        float prob[BATCH_SIZE * 3 * IN_H * IN_W /4]; 
        doInference(*context, data, prob, BATCH_SIZE); 
 
        // Destroy the engine 
        context->destroy(); 
        engine->destroy(); 
        runtime->destroy(); 
        return 0; 
} 

Resumir

A través del estudio de este artículo, hemos dominado dos formas de construir el modelo TensorRT: construir directamente la red capa por capa a través de la API de TensorRT; convertir el modelo de representación intermedia en el modelo TensorRT. No solo eso, también completamos la construcción y razonamiento del modelo TensorRT en C++ y Python respectivamente ¡Creo que todos han ganado algo! En el próximo artículo, aprenderemos cómo agregar operadores personalizados de TensorRT contigo, así que permanece atento~

Preguntas más frecuentes

  • P : Se informa un error al ejecutar el código: No se pudo encontrar: cudnn64_8.dll ¿Está en su RUTA?
  • R: Primero verifique si su variable de entorno contiene la ruta de cudnn64_8.dll.Si encuentra que la ruta de cudnn está en C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v10.2\\bin, Pero solo contiene cudnn64_7.dll.La solución es descargar el paquete zip cuDNN del sitio web oficial de NVIDIA, descomprimirlo y copiar cudnn64_8.dll en el directorio bin de CUDA Toolkit. En este momento, también puede copiar una copia de cudnn64_7.dll y luego cambiar el nombre de la copia copiada a cudnn64_8.dll, lo que también puede resolver este problema.

referencia

GitHub - wang-xinyu/tensorrtx: Implementación de redes populares de aprendizaje profundo con la red TensorRT

GitHub - NVIDIA/TensorRT: TensorRT es una biblioteca de C++ para inferencia de alto rendimiento en GPU NVIDIA y

Portal de la serie

OpenMMLab: Introducción a la implementación de modelos (1): Introducción a la implementación de modelos 172 De acuerdo 22 Comentarios 213 De acuerdo 24 Comentarios 241 De acuerdo 31 Comentarios 498 De acuerdo 50 Los comentarios se están cargando...RecargarCancelar

OpenMMLab: Tutorial de Introducción a la Implementación de Modelos (2): Resolviendo las Dificultades en la Implementación de Modelos

OpenMMLab: Tutorial de introducción a la implementación del modelo (3): PyTorch a ONNX Explicación detallada 131 De acuerdo 25 Comentarios 146 De acuerdo 32 Comentarios 153 De acuerdo 34 Comentarios 315 De acuerdo 54 Los comentarios se están cargando...

OpenMMLab: Introducción al tutorial de implementación de modelos (4): Compatibilidad con más operadores ONNX en PyTorch

OpenMMLab: Introducción al tutorial de implementación de modelos (5): Modificación y depuración del modelo ONNX 86 De acuerdo 4 Comentarios 115 De acuerdo 10 Comentarios 122 De acuerdo 16 Comentarios 217 De acuerdo 25 Comentarios Cargando...Recargar Cancelar

OpenMMLab: Tutorial de introducción a la implementación de modelos (6): Implementación de la herramienta de alineación de precisión PyTorch-ONNX 129 De acuerdo· 10 Comentarios El artículo se está cargando...RecargarCancelar

OpenMMLab: Interpretación de TorchScript (1): Conociendo TorchScript83 De acuerdo· 10 Comentarios 106 De acuerdo· 15 Comentarios 118 De acuerdo· 15 Comentarios 239 De acuerdo· 21 Comentarios uploading...ReuploadCancel

OpenMMLab: Interpretación de TorchScript (2): análisis de implementación de Torch jit tracer

OpenMMLab: Interpretación de TorchScript (3): reescritura de subgrafos en jit

OpenMMLab: Interpretación de TorchScript (4): Análisis de alias en Torch jit

Supongo que te gusta

Origin blog.csdn.net/qq_43456016/article/details/130264255
Recomendado
Clasificación