modelo de aprendizagem profundidade implantação TensorRT

1. Antecedentes

A velocidade do quadro de aprendizagem profunda mainstream atual (caffe, mxnet, tensorflow, pytorch, etc.) não são bom modelo para inferir o quadro para a implantação do modelo com o projeto real que eles tendem a ser relativamente ineficiente. O modelo treinados para implantar a estrutura convencional pode melhorar muito a velocidade do modelo inferido pela Nvidia lançou ferramentas tensorRT, muitas vezes comparado ao quadro original para ter pelo menos 1 vezes o aumento da velocidade, mas vai ocupar mais dispositivos de memória menos. Portanto, a necessidade de implantar todo o modelo gay, o domínio de métodos para implantar modelo de aprendizagem profunda com tensorRT é muito útil.

2. Arte Relacionada

A imagem acima é tirado de TensorRT site oficial, existem algumas técnicas tensorRT uso. Podemos ver uma técnica de pouso aprender mais madura profunda: modelo para quantificar otimização de memória dinâmica, tecnologias da camada de integração foram integrados em tensorRT, que é a razão que pode aumentar significativamente a velocidade do modelo de inferência. tensorRT Em geral, o modelo treinado através de uma série de técnicas de otimização podem ser convertidos em código de execução de alto desempenho é gerado no último motor FIG Inferência em uma plataforma particular (GPU). Existem também algumas outras ferramentas podem alcançar funções tensorRT semelhantes, como TVM , TensorComprehensions pode efetivamente melhorar o modelo para inferir a velocidade em uma plataforma particular, mas devido aos dispositivos de computação atuais são Nvidia uso empresa de produção dominante nesses dispositivos NVIDIA lançou desempenho tensorRT comparação com outras ferramentas terão uma vantagem de alguns. E tensorRT base de código dependente inclui somente C ++ e CUDA, em oposição a um número de outras ferramentas para ser mais simplificado.

3. tensorflow tutorial modelo de implantação tensorRT

Implantação no uso do projeto real c ++ para implantação, de modo que este tutorial também usando tensorRT a API C ++, tensorRT versão 5.1.5. referência específica pode ser montado Guia tensorRT [profunda aprendizagem] TensorRT instalado , e instruções de instalação site oficial.

modelo de persistência

O primeiro passo na implantação de modelo tensorflow é a persistência modelo, o modelo de estrutura e economia de peso para um arquivo .pb eles.

pb_graph = tf.graph_util.convert_variables_to_constants(sess, sess.graph.as_graph_def(), [v.op.name for v in outputs])
with tf.gfile.FastGFile('./pbmodel_name.pb', mode='wb') as f:
    f.write(pb_graph.SerializeToString())

DETALHADA realizada somente após a definição do código do modelo acima e uma leitura do peso, a função de ponderação chama tf.graph_util.convert_variables_to_constants em constante, em que uma lista de saídas necessárias tensor é de saída, e finalmente pb_graph.SerializeToString () A serialização gráfico e gravação para o arquivo pb-los, gerando modelo pb.

modelo de geração Uff

Com o modelo pb, você precisa convertê-lo para uff modelo tensorRT disponíveis, basta ligar para uff pacote vem com um script para converter

python /usr/lib/python2.7/site-packages/uff/bin/convert_to_uff.py   pbmodel_name.pb

Informações tais como o número de saídas de conversão bem sucedida do seguinte informação, resumidos na Fig compreendendo um ponto de entrada e um nó de saída inferida

tensorRT C ++ modelo de implantação API

Implementação gerado usando tensorRT boa uff modelo uff armazenadas na estrutura de modelo para os pesos de rede, e em, em seguida, executar o algoritmo de otimização para gerar um correspondente necessidades motor de inferência para falar. código específico da seguinte forma, você primeiro precisa definir um IBuilder * construtor, um arquivo usado para analisador de rede determinação uff e construtor criou a parâmetros do modelo e estrutura de rede analisador irá analisar a uff arquivo salvo para rede, para ser resolvido antes do analisador predito nó de saída de rede de entrada. Depois de analisar construtor de motores pode criar uma rede com base na estrutura de rede definido. Batchsize será necessário especificar o tamanho máximo antes de criar motor, batchsize entrou quando depois de usar o motor não deve exceder esse valor caso contrário ocorre um erro. Se inferindo maior batchsize e definir a mesma eficiência máxima. Por exemplo, se a máxima é definida como 10 batchsize, introduzir um lote raciocínio real figura 10, quando o tempo médio é de 4 ms por estimativa, em seguida, introduzir um lote de menos do que 10 por FIG quando o tempo médio é maior do que a FIG inferida. 4ms.

IBuilder* builder = createInferBuilder(gLogger.getTRTLogger());
auto parser = createUffParser();
parser->registerInput(inputtensor_name, Dims3(INPUT_C, INPUT_H, INPUT_W), UffInputOrder::kNCHW);
parser->registerOutput(outputtensor_name);
    INetworkDefinition* network = builder->createNetwork();
    if (!parser->parse(uffFile, *network, nvinfer1::DataType::kFLOAT))
    {
        gLogError << "Failure while parsing UFF file" << std::endl;
        return nullptr;
    }  
    builder->setMaxBatchSize(maxBatchSize);
    builder->setMaxWorkspaceSize(MAX_WORKSPACE);
    ICudaEngine* engine = builder->buildCudaEngine(*network);
    if (!engine)
    {
        gLogError << "Unable to create engine" << std::endl;
        return nullptr;
    }

Depois de gerar o motor pode-se inferir a necessidade de um contexto de execução contexto IExecutionContext * contexto inferência é realizada, pode ser obtido por engine-> createExecutionContext (). O código do núcleo está realizando inferência

 context->execute(batchSize, &buffers[0]);  

Em que o tampão é uma matriz * vazio correspondendo às entradas e saídas de tensores endereço do dispositivo modelo, um ponteiro correspondente é armazenada na matriz de tampão por cudaMalloc abrir o espaço equipamento (memória) de entrada e saída necessária por cudaMemcpy os dados de entrada antes da operação de executar (imagem de entrada) para o espaço do dispositivo correspondente para a entrada de cópia, ou após a execução pelo cudaMemcpy executar o resultado de saída a partir do aparelho de cópia.

A rotinas mais detalhadas podem referenciar amostras oficiais TensorRT no Código sampleUffMNIST

caso speedup

O projeto real eu usei tensorRT para acelerar ao longo ResNet-50 em Tesla M40, Inception-ResNet-v2, o Google pesquisa de imagens modelo Delf (características profundas Local), acelerou em torno de uma visão única de inferido comparar a figura abaixo (em ms) ao usar

tutorial implantação 4. Caffe modelo tensorRT

Em comparação com a conversão modelo tensorflow caffe modelo mais simples, o modelo não exige tensorflow uff virar modelo a referida operação, tensorRT capaz de analisar e arquivo caffemodel prototxt direta aquisição de estrutura de rede e modelos de peso pesado. Procedimento de análise constante e específico descrito acima, excepto que o modelo de analisador caffe não exige uma camada de entrada pré-determinado, o qual já está definido como camada de entrada prototxt, Analisador pode analisar automaticamente a entrada, a rede devolve um adicional caffeparser analisada IBlobNameToTensor * blobNameToTensor registra a correspondência entre a rede e o nome do pototxt tensor, precisará passar esta correspondência, de acordo com a lista de nomes de ordem tensor saída saídas para encontrar o tensor correspondente após a análise através da rede> função markOutput para marcá-lo como saída , então você pode gerar o motor.

IBuilder* builder = createInferBuilder(gLogger);
    INetworkDefinition* network = builder->createNetwork();
    ICaffeParser* parser = createCaffeParser();
    DataType modelDataType = DataType::kFLOAT;
    const IBlobNameToTensor *blobNameToTensor =	parser->parse(deployFile.c_str(),
                                                              modelFile.c_str(),
                                                              *network,
                                                              modelDataType);
    assert(blobNameToTensor != nullptr);
    for (auto& s : outputs) network->markOutput(*blobNameToTensor->find(s.c_str()));

    builder->setMaxBatchSize(maxBatchSize);
    builder->setMaxWorkspaceSize(1 << 30);
    engine = builder->buildCudaEngine(*network);

modo de geração é executado depois de o motor e uma consistência descrita em pormenor com referência à rotina pode SampleMNIST

caso speedup

projecto real I acelerado em Tesla M40 com tensorRT caffe através da VGG19, SSD velocidade torna-se 1,6 vezes, ResNet50, MobileNetV2 única estimativa aceleração longitudinal comparando FIG abaixo (em ms) quando um

5. Adicione o tensorRT camada de costume

tensorRT atualmente suporta apenas uma operação muito comum, há muitas operações que não suportam tais uma amostragem operações upsample, desta vez você precisa escrever nossos próprios plug-ins para a camada tensorRT, para que estas operações não podem ser suportados em uso em tensorRT . Para definir camada upsample, por exemplo, que definem um primeiro herda classe de tensorRT upsample de encaixe base de classe

class Upsample: public IPluginExt

Então necessário implementar alguns métodos da classe, dois primeiros construtor, um parâmetro é passado para construir, e o outro é construído a partir do fluxo de bits em série.

 Upsample(int scale = 2) : mScale(scale) {
        assert(mScale > 0);
    }
//定义上采样倍数
 Upsmaple(const void *data, size_t length) {
        const char *d = reinterpret_cast<const char *>(data), *a = d;
        mScale = read<int>(d);
        mDtype = read<DataType>(d);
        mCHW = read<DimsCHW>(d);
        assert(mScale > 0);
        assert(d == a + length);
    }
~Upsample()
    {

    }

Algumas camadas de método de produção de informação, tal como definido

   int getNbOutputs() const override {
        return 1;
    }
//模型的输出个数

    Dims getOutputDimensions(int index, const Dims *inputs, int nbInputDims) override {
       // std::cout << "Get ouputdims!!!" << std::endl;
        assert(nbInputDims == 1);
        assert(inputs[0].nbDims == 3);
        return DimsCHW(inputs[0].d[0], inputs[0].d[1] * mScale, inputs[0].d[2] * mScale);
    }
//获取模型输出的形状

O método e a forma do número de dados de entrada e verificar a validade do tipo de parâmetros de configuração da camada empregue

    bool supportsFormat(DataType type, PluginFormat format) const override {
        return (type == DataType::kFLOAT || type == DataType::kHALF || type == DataType::kINT8)
               && format == PluginFormat::kNCHW;
    }
//检查层是否支持当前的数据类型和格式
    void configureWithFormat(const Dims *inputDims, int nbInputs, const Dims *outputDims, int nbOutputs,
                             DataType type, PluginFormat format, int maxBatchSize) override
       {
         mDtype = type;
         mCHW.c() = inputDims[0].d[0];
         mCHW.h() = inputDims[0].d[1];
         mCHW.w() = inputDims[0].d[2];
        }
//配置层的参数

sequcia de camadas Método

 size_t getSerializationSize() override {
        return sizeof(mScale) + sizeof(mDtype) + sizeof(mCHW);
    }
//输出序列化层所需的长度
    void serialize(void *buffer) override {
        char *d = reinterpret_cast<char *>(buffer), *a = d;
        write(d, mScale);
        write(d, mDtype);
        write(d, mCHW);
        assert(d == a + getSerializationSize());
    }
//将层参数序列化为比特流

O método de cálculo camada

 size_t getWorkspaceSize(int maxBatchSize) const override {
        return 0;
    }
//层运算需要的临时工作空间大小
 int enqueue(int batchSize, const void *const *inputs, void **outputs, void *workspace,
                cudaStream_t stream) override;
//层执行计算的具体操作

Em enqueue chamamos gravação kenerl boa CUDA para cálculos upsample

Upsample completar a definição da classe, podemos adicionar diretamente à rede da tomada estamos preparados, pela seguinte declaração definimos a amostra sobre uma camada de amostra 2 vezes. A primeira entrada é addPluginExt itensor ** categoria, que é apoiar a multi-saída, e o segundo parâmetro é o número de entradas, plug-in terceiro parâmetro classe objecto é a necessidade de criar.

Upsample up(2);
auto upsamplelayer=network->addPluginExt(inputtensot,1,up)

6. Adicione um CaffeParser apoio camada de costume

Porque, se a nossa camada de costume escreveu prototxt caffe, caffeparser chamada ao implantar modelos analíticos dará um erro.

Ou em upsample exemplo, se você tem a seguinte parte para adicionar uma camada em um upsample em prototxt

layer {
  name: "upsample0"
  type: "Upsample"
  bottom: "ReLU11"
  top: "Upsample1"
}

A próxima vez que você chamar

const IBlobNameToTensor *blobNameToTensor =	parser->parse(deployFile.c_str(),
                                                              modelFile.c_str(),
                                                              *network,
                                                              modelDataType);

Haverá erros

Temos escrito anteriormente upsample plug-ins, como fazer um tensorRT analisador caffe identificado upsample camada prototxt construção automática nossos próprios plug-ins escrito nele? Então precisamos definir uma classe plug-engenharia herda a nvinfer1 classe base :: IPluginFactory, nvcaffeparser1 :: IPluginFactoryExt.

class PluginFactory : public nvinfer1::IPluginFactory, public nvcaffeparser1::IPluginFactoryExt

O método deve ser implementado em que existe uma camada determina se a abordagem de encaixe, o parâmetro de entrada é o nome prototxt na camada, tal como avaliado por um nome de camada é registado como Widget

bool isPlugin(const char *name) override {
        return isPluginExt(name);
    }

bool isPluginExt(const char *name) override {

        char *aa = new char[6];
        memcpy(aa, name, 5);
        aa[5] = 0;
        int res = !strcmp(aa, "upsam");
        return res;
}
//判断层名字是否是upsample层的名字

O método de acordo com o nome criado widget, há duas maneiras de um reconstruídos pelo peso, eo outro pela corrente de bits criada serializado, correspondendo a dois construtores Widget upsample nenhum peso, por outras pessoas que tenham ficha de peso pode ser pesos de entrada de inicialização camada. mplugin um vector é utilizado para armazenar todos os plug-ins camada criada.

IPlugin *createPlugin(const char *layerName, const nvinfer1::Weights *weights, int nbWeights) override {
        assert(isPlugin(layerName));
        mPlugin.push_back(std::unique_ptr<Upsample>(new Upsample(2)));
        return mPlugin[mPlugin.size() - 1].get();
    }
IPlugin *createPlugin(const char *layerName, const void *serialData, size_t serialLength) override {
        assert(isPlugin(layerName));

        return new Upsample(serialData, serialLength);
    }
 std::vector <std::unique_ptr<Upsample>> mPlugin;

Finalmente, precisamos definir um método de destruir a liberar todos os plug-ins criados camada.

 void destroyPlugin() {
        for (unsigned int i = 0; i < mPlugin.size(); i++) {
            mPlugin[i].reset();
        }
}

Para o caso onde há uma pluralidade de vários prototxt ficha, você pode adicionar um novo isPlugin ramo condicional, método createPlugin, de acordo com a criar plug-ins camada nome da camada correspondentes.

A realização de um PluginFactory ao chamar caffeparser a necessidade de configurar a usá-lo, chamando parser-> adicione o seguinte código antes do analisador

PluginFactory pluginFactory;
parser->setPluginFactoryExt(&pluginFactory);

Você pode configurar regras analisador definido de acordo com o interior pluginFactory para criar um plug-in camada, o erro não pode ser resolvido antes do surgimento de tal camada upsample não ocorrerá novamente.

A amostra adicionada oficial plug-camada samplePlugin pode ser usado como referência

7. experiências (pisou registro pit)

modelo 1. sua vez tensorflow, modelo de geração pb, ea conversão modelo uff ao chamar uffparser nós de entrada registo, de saída, de entrada e saída destes três nomes deve prestar atenção ao processo de consistente, caso contrário, os eventuais erros ao analisar o analisador, não é possível localizar os nós de entrada e saída.

2. Para além da aqui exemplificado pluginExt, tensorRT de encaixe classe base também IPlugin, IPluginV2, uma classe de base de herdar os métodos de classe são necessários para conseguir as diferenças subtis, particularmente onde a auto-instalação vista tensorRT pasta incluem / NvInfer.h arquivo. Enquanto a adição de sua própria camada de gravação para as funções de rede têm addPlugin, addPluginExt, addPluginV2 estes tipos e IPlugin, IPluginExt, IPluginV2 correspondência não pode ser mista, caso contrário, algum padrão método de classe invocação não chama, como a adição de um addPlugin a camada PluginExt configureWithFormat não chamar o método, porque o método não IPlugin classe. Também lá caffeparser de setPluginFactory e setPluginFactoryExt também não podem ser misturados.

3. Execute o fracasso programa CUDA ocorre em circunstâncias normais devido a dados memória de cópia para o disco quando houve um acesso à memória ilegal, prestar atenção para verificar se o tamanho do espaço de buffer de cópia e abriu a consistência dos dados passado.

4. Existem algumas operações podem ser combinadas, mas não é suportada por algumas das suportado operar alternativamente em tensorRT, tais como  [Oficial] , de modo poupar algum tempo para escrever uma camada de costume.

5. tensorflow achatar quando operando na keepdims default = false, mas quando uff convertido conversão de texto padrão de acordo keepdims = true, portanto achatar a transposta vector realizado no tensorflow, expanddims como operação, após a conversão para uff propenso a erros ao analisar com tensorRT, como "tamanho Ordem não está combinando as dimensões número de TensorRT". É de preferência fornecida tensorflow reduzir, keepdims = operação achatar Verdadeiro, mantendo sempre a forma dimensional camada de saída 4, pode efectivamente evitar erros quando vários estranhas para tensorRT.

Depois há certos problemas no 6.tensorRT camada de fatia, I da rede> addSlice adicionar uma fatia para a camada de rede, essa etapa na implementação de buildengine quando ocorre um erro nvinfer1 :: construtor :: checkSanity (const nvinfer1 :: construtor :: Graph &) : declaração `tensors.size () == g.tensors.size () 'falhou, melhor evitar o uso da camada de fatia é construído de rede, para realizar seu ou camada costume operação fatia é executada.

github 7. tensorRT em código aberto e tem uma riqueza de seção de código de exemplo, e um monte de aprender a ajuda captar rapidamente o tensorRT uso

8. Referências

Amostras Nvidia TensorRT

tensorrt-developer-guia

TensorRT API Docs

TensorRT Github

Publicado 482 artigos originais · Louvor obteve 789 · Visualizações 1,71 milhões +

Acho que você gosta

Origin blog.csdn.net/weixin_42137700/article/details/105214333
Recomendado
Clasificación