4.2. bases de tensorRT (1) - le premier programme trt pour réaliser le processus de compilation de modèles

avant-propos

L'enseignant Du a lancé le cours de déploiement haute performance tensorRT à partir de zéro . Je l'ai déjà lu, mais je n'ai pas pris de notes et j'ai oublié beaucoup de choses. Cette fois je vais le refaire, et prendre des notes au passage.

Ce cours apprend les bases de tensorRT - le premier programme trt pour réaliser le processus de compilation de modèles

Le plan du cours peut être vu dans la carte mentale ci-dessous

insérez la description de l'image ici

1. bonjour cas

Apprenez à utiliser l'API de TensorRT-CPP pour construire un modèle et compiler le processus

Le code de cas est le suivant :


// tensorRT include
#include <NvInfer.h>
#include <NvInferRuntime.h>

// cuda include
#include <cuda_runtime.h>

// system include
#include <stdio.h>

class TRTLogger : public nvinfer1::ILogger{
    
    
public:
    virtual void log(Severity severity, nvinfer1::AsciiChar const* msg) noexcept override{
    
    
        if(severity <= Severity::kVERBOSE){
    
    
            printf("%d: %s\n", severity, msg);
        }
    }
};

nvinfer1::Weights make_weights(float* ptr, int n){
    
    
    nvinfer1::Weights w;
    w.count = n;
    w.type = nvinfer1::DataType::kFLOAT;
    w.values = ptr;
    return w;
}

int main(){
    
    
    // 本代码主要实现一个最简单的神经网络 figure/simple_fully_connected_net.png 
     
    TRTLogger logger; // logger是必要的,用来捕捉warning和info等

    // ----------------------------- 1. 定义 builder, config 和network -----------------------------
    // 这是基本需要的组件
    //形象的理解是你需要一个builder去build这个网络,网络自身有结构,这个结构可以有不同的配置
    nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(logger);
    // 创建一个构建配置,指定TensorRT应该如何优化模型,tensorRT生成的模型只能在特定配置下运行
    nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();
    // 创建网络定义,其中createNetworkV2(1)表示采用显性batch size,新版tensorRT(>=7.0)时,不建议采用0非显性batch size
    // 因此贯穿以后,请都采用createNetworkV2(1)而非createNetworkV2(0)或者createNetwork
    nvinfer1::INetworkDefinition* network = builder->createNetworkV2(1);

    // 构建一个模型
    /*
        Network definition:

        image
          |
        linear (fully connected)  input = 3, output = 2, bias = True     w=[[1.0, 2.0, 0.5], [0.1, 0.2, 0.5]], b=[0.3, 0.8]
          |
        sigmoid
          |
        prob
    */

    // ----------------------------- 2. 输入,模型结构和输出的基本信息 -----------------------------
    const int num_input = 3;   // in_channel
    const int num_output = 2;  // out_channel
    float layer1_weight_values[] = {
    
    1.0, 2.0, 0.5, 0.1, 0.2, 0.5}; // 前3个给w1的rgb,后3个给w2的rgb 
    float layer1_bias_values[]   = {
    
    0.3, 0.8};

    //输入指定数据的名称、数据类型和完整维度,将输入层添加到网络
    nvinfer1::ITensor* input = network->addInput("image", nvinfer1::DataType::kFLOAT, nvinfer1::Dims4(1, num_input, 1, 1));
    nvinfer1::Weights layer1_weight = make_weights(layer1_weight_values, 6);
    nvinfer1::Weights layer1_bias   = make_weights(layer1_bias_values, 2);
    //添加全连接层
    auto layer1 = network->addFullyConnected(*input, num_output, layer1_weight, layer1_bias);      // 注意对input进行了解引用
    //添加激活层 
    auto prob = network->addActivation(*layer1->getOutput(0), nvinfer1::ActivationType::kSIGMOID); // 注意更严谨的写法是*(layer1->getOutput(0)) 即对getOutput返回的指针进行解引用
    
    // 将我们需要的prob标记为输出
    network->markOutput(*prob->getOutput(0));

    printf("Workspace Size = %.2f MB\n", (1 << 28) / 1024.0f / 1024.0f); // 256Mib
    config->setMaxWorkspaceSize(1 << 28);
    builder->setMaxBatchSize(1); // 推理时 batchSize = 1 

    // ----------------------------- 3. 生成engine模型文件 -----------------------------
    //TensorRT 7.1.0版本已弃用buildCudaEngine方法,统一使用buildEngineWithConfig方法
    nvinfer1::ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
    if(engine == nullptr){
    
    
        printf("Build engine failed.\n");
        return -1;
    }

    // ----------------------------- 4. 序列化模型文件并存储 -----------------------------
    // 将模型序列化,并储存为文件
    nvinfer1::IHostMemory* model_data = engine->serialize();
    FILE* f = fopen("engine.trtmodel", "wb");
    fwrite(model_data->data(), 1, model_data->size(), f);
    fclose(f);

    // 卸载顺序按照构建顺序倒序
    model_data->destroy();
    engine->destroy();
    network->destroy();
    config->destroy();
    builder->destroy();
    printf("Done.\n");
    return 0;
}

L'effet courant est le suivant :

insérez la description de l'image ici

Figure 1-1 effet courant du cas hello

L'exemple de code ci-dessus illustre le processus de création d'un modèle de réseau neuronal simple à l'aide de tensorRT. Créez le modèle Engine en définissant la structure du modèle, en définissant les informations d'entrée et de sortie et en utilisant l'objet Builder et l'objet de définition de réseau de TensorRT. Ensuite, sérialisez et enregistrez le modèle généré sous forme de fichier. L'exemple de code montre également comment configurer les paramètres et les contraintes d'optimisation de TensorRT. Grâce à cet exemple de code, vous pouvez comprendre le flux de travail de base de TensorRT pour créer un modèle et comment utiliser les objets associés.

Tout d'abord, les fichiers d'en-tête et bibliothèques nécessaires sont introduits, et les fichiers d'en-tête et bibliothèques associés de TensorRT et CUDA sont introduits dans le code. Ensuite, une classe de journal est définie, héritée de nvinfer1::ILogger, pour capturer les avertissements et les informations TensorRT.

Définissez les informations de base de l'entrée, de la structure du modèle et de la sortie : spécifiez le nom, le type de données et la dimension du tenseur d'entrée, ajoutez la couche entièrement connectée et la couche d'activation, et marquez la sortie comme la sortie du réseau. Ensuite, configurez TensorRT en définissant la taille maximale de l'espace de travail et la taille maximale du lot, puis créez le modèle Engine et utilisez la buildEngineWithConfigméthode pour créer le modèle Engine. Sérialisez et enregistrez le modèle, sérialisez le modèle en données binaires et enregistrez-le sous forme de fichier. Enfin, les ressources sont libérées et les ressources liées à TensorRT sont libérées dans l'ordre inverse de la création.

Le workflow général de TensorRT pour construire un modèle peut être divisé en quatre parties :

  • 1. Définir le constructeur, la configuration et le réseau
  • 2. Informations de base sur l'entrée, la structure du modèle et la sortie requises pour construire le réseau
  • 3. Générer un fichier de modèle de moteur
  • 4. Sérialisez le fichier modèle et stockez-le

Faits saillants sur l'exemple de code :

  1. CreateNetworkV2 doit être utilisé et spécifié comme 1 (indiquant un lot explicite). createNetwork est obsolète et le lot non explicite n'est pas officiellement recommandé. Cette méthode affecte directement enqueue ou enqueueV2 pendant le raisonnement
  2. N'oubliez pas de libérer des pointeurs tels que builder et config, sinon il y aura des fuites de mémoire, utilisez ptr->destroy() pour libérer
  3. markOutput représente le nœud de sortie du modèle, il y a plusieurs sorties pour plusieurs instants de mark, et plusieurs entrées pour plusieurs instants de addInput, ce qui fait écho au raisonnement
  4. workspaceSize est la taille de l'espace de travail. Lorsque certaines couches ont besoin d'utiliser du stockage supplémentaire, elles n'alloueront pas d'espace par elles-mêmes, mais pour la réutilisation de la mémoire, demandez directement à tensorRT l'espace de l'espace de travail. signifie ceci
  5. Il faut se rappeler que le modèle enregistré ne peut être adapté qu'à la version de trt au moment de la compilation et au périphérique spécifié au moment de la compilation. Il ne peut être garanti qu'optimal dans cette configuration. Si vous utilisez trt pour exécuter sur différents appareils, cela peut parfois fonctionner, mais ce n'est pas optimal et non recommandé

2. Connaissances supplémentaires

Points de connaissance pertinents sur le premier programme trt : ( de M. Du )

  • main.cpp construit le réseau entièrement connecté le plus simple
  • Le workflow de tensorrt est le suivant :
    • Définir d'abord le réseau
    • Optimiser les paramètres du générateur
    • Générer un moteur via le constructeur pour la sauvegarde du modèle, le raisonnement, etc.
    • Le moteur peut convertir le type de données du modèle via la sérialisation et la désérialisation (convertir en un fichier d'octets binaires pour accélérer le taux de transmission), et promouvoir davantage le raisonnement du modèle du tenseur d'entrée au tenseur de sortie

insérez la description de l'image ici

  • structure de code
    • 1. Définissez builder, config et network, où builder représente le builder créé, config représente la configuration de build créée (spécifiez comment TensorRT doit optimiser le modèle) et network définit le réseau créé.
    • 2. Informations de base sur l'entrée, la structure du modèle et la sortie (comme indiqué dans la figure ci-dessous)
    • 3. Générer un fichier de modèle de moteur
    • 4. Sérialisez le fichier modèle et stockez-le

insérez la description de l'image ici

Résumer

Ce cours apprend à utiliser l'interface C++ de tensorRT pour créer une structure de réseau de neurones simple. Le processus global peut être divisé en : constructeur, configuration, définition du réseau ; informations d'entrée, de structure de modèle et de sortie ; génération de fichier de modèle de moteur ; fichier de modèle sérialisé et quatre parties sont stockés.

Pour certains détails, vous devez examiner le code à des fins d'analyse. Par exemple, n'oubliez pas de libérer des pointeurs tels que builder et config. Avant que tensorRT ne crée un réseau, vous devez définir une classe log Logger pour capturer les informations tensorRT, etc.

Je suppose que tu aimes

Origine blog.csdn.net/qq_40672115/article/details/131751472
conseillé
Classement