tensorrt 分割_TensorRT 5 开发者手册 中文版 使用深度学习框架(三-6)

NVIDIA TensorRT是一种高性能神经网络推理(Inference)引擎,用于在生产环境中部署深度学习应用程序,应用有图像分类、分割和目标检测等,可提供最大的推理吞吐量和效率。TensorRT是第一款可编程推理加速器,能加速现有和未来的网络架构。本手册为TensorRT 4.0.1.6 GA版英文手册翻译而来,主要作为备忘所用,分享出来以供更多开发者使用。

TensorRT Developer Guide手册一共分为四个章节,主要内容在第二、三章,看懂这两章,写代码够用了。第一章为TensorRT综述。第四章为示例,介绍demo的代码结构及功能。开篇是目录,前三章每章为两到三篇,最后第四章示例,会拆分几个关键示例进行详细说明。

注意,2018年10月份,NVIDIA又更新TensorRT 5.0.2.6 Linux版本和TensorRT 5.0.1.3 Windows版,正式支持Windows10,经测试向下兼容Windows7也可以用。

本来这章应该是TensorRT4的第3章,在TensorRT5的手册上直接到了第8章,这里暂时先从第8章开始,继续翻译。

第8章 使用深度学习框架

8.1 框架支持的算子

8.2 使用TensorFlow

8.2.1 TensorFlow模型生成冻结图

8.2.2 Keras模型生成冻结图

8.2.3 冻结图转换为UFF

8.2.4 使用TensorFlow RNN权重

8.2.5 使用Graph Surgeon API预处理TensorFlow图

8.3 使用PyTorch和其他框架

第8章 使用深度学习框架

使用Python API,利用TensorFlow,Caffe或ONNX等兼容框架构建的模型使用TensorRT提供的解析器构建加速引擎。Python API还支持以NumPy兼容格式存储权重的框架,如PyTorch。

8.1 框架支持的算子

Caffe

Caffe框架支持的操作:

Convolution:3D,with or without bias

Pooling :Max, Average, Max_Average_blend

InnerProduct

Softmax

Activation: ReLu, Sigmoid,Tanh

LRN

Power

ElementWise: sum, product, maximum, subtraction,division, power

Concatenation: across channel

Deconvolution

BatchNormalization

Scale

Crop

Reduction : sum,prod,max,min,avg

Reshape

Permute

Dropout

Concat

ElementWise

RNN : Input,Output,Forget,Update,Reset,Cell,Hidden

Unary : exp,log,sqrt,recip,abs,neg

Padding

Shuffle

Topk max,min

Gather

Matrix_Multiply

Ragged_Softmax

Constant : Uff模型的权值就是保存为常量类型

RNN_v2

Plugin : FasterRCNN fused plugin (RPN + ROI pooling). Normalize plugin. Permute plugin. PriorBox plugin. SSD DetectionOutput plugin. Concat plugin. YOLO PReLU Plugin. YOLO Reorg Plugin. YOLO Region Plugin.

TensorFlow

TensorFlow框架支持的算子:

Placeholder

Const

Add, Sub, Mul, Div, Minimum and Maximum

BiasAdd

Negative, Abs, Sqrt, Rsqrt, Pow, Exp and Log

注意:NvUffParser只支持Neg, Abs, Sqrt, Rsqrt, Exp和Log的常量节点

FusedBatchNorm

ReLU, TanH, and Sigmoid

SoftMax

Mean

ConcatV2

Reshape

Transpose

Conv2D

DepthwiseConv2dNative

ConvTranspose2D

MaxPool

AvgPool

Pad

ONNX

ONNX解析器是一个开源项目,可以在GitHub:ONNX TensorRT中找到有关支持算子的最新信息。

8.2 使用TensorFlow

有关TensorFlow模型直接使用TensorRT的信息,请参阅:

Python示例 - [9.2.2 end_to_end_tensorflow_mnist]

8.2.1 TensorFlow模型生成冻结图

为了使用UFF命令行工具,TensorFlowGraph必须保存为.pd的冻结图文件,请参阅:

注意:一般是在模型导出的过程中直接转换成冻结图

8.2.2 Keras模型生成冻结图

使用如下代码生成Keras模型的冻结图:

from keras.models import load_model

import keras.backend as K

from tensorflow.python.framework import graph_io

from tensorflow.python.tools import freeze_graph

from tensorflow.core.protobuf import saver_pb2

from tensorflow.python.training import saver as saver_lib

def convert_keras_to_pb(keras_model, out_names, models_dir,model_filename):

model = load_model(keras_model)

K.set_learning_phase(0)

sess = K.get_session()

saver = saver_lib.Saver(write_version=saver_pb2.SaverDef.V2)

checkpoint_path = saver.save(sess, 'saved_ckpt', global_step=0,

latest_filename='checkpoint_state')

graph_io.write_graph(sess.graph, '.', 'tmp.pb')

freeze_graph.freeze_graph('./tmp.pb', '',

False, checkpoint_path, out_names,

"save/restore_all", "save/Const:0",

models_dir+model_filename, False, "")

8.2.3 冻结图转换为UFF

使用如下示例代码将.pb冻结图转换成.uff格式文件:

convert-to-uff input_file [-o output_file] [-O output_node]

convert-to-uff input_file -l #打印TensorFlow层

8.2.4 使用TensorFlow RNN权重

本节提供有关TensorFlow权重及其存储格式的信息。此外,以下部分将指导您如何从TensorFlow处理和解密RNN权重。

这节主要内容是将各种训练框架下输出的模型权重转换成TensorRT格式(planner格式)

8.2.4.1 TensorRT支持的TensorFlow RNN单元

TensorRT中的循环神经网络层来自TensorFlow的MultiRNNCell算子。每一层由具有相同配置的多个子层组成,换句话说,隐藏和嵌入大小。完成该封装使得多个子层之间的内部连接可以从用户抽象出来(其实和DenseBlock、ResBlock一个意思,内部包含多个层)。当涉及更深层的网络时,这允许更简单的代码。

TensorRT支持四种不同的RNN层类型。这些层类型是RNN relu,RNN tanh,LSTM和GRU。与这些类型匹配的TensorFlow Cells是:

TensorRT RNN Relu/Tanh Layer

BaiscRNNCells

允许的激活函数有:tf.tanh 和 tf.nn.relu

这是一个独立于平台的单元

TensorRT LSTM Layer

BasicLSTMCell

在TensorFlow中创建这个算子的实例时,forget_bias必须设置为0。为了支持非0的遗忘偏置,需要通过添加一个参数化的遗忘偏置去转存TensorFlow的遗忘偏置。

这是一个独立于平台的单元

CudnnCompatibleLSTMCell

对forget bias的条件和BasicLSTMCell一样

目前不支持peepholes(gate由当前输入xt、上一时刻隐藏状态ht-1、上一时刻单元状态ct-1),use_peepholes必须设置成False

cudnn兼容

TensorRT GRU Layer

CudnnCompatibleGRUCell

cudnn兼容

由于与标准的、平台独立的GRUCell不同,所以CudnnCompatibleGRUCell可以在TensorRT中正确使用

8.2.4.2 保持TensorFlow和TensorRT之间的模型一致性

对于未在TensorFlow RNN Cells Supported In TensorRT中列出的任何TensorFlow Cell,请参阅TensorRT API和TensorFlow API以确保Cell在数学上等同于TensorRT支持的Cell,并且存储格式与您期望的格式一致。 这样做的一个好方法是设计单元测试,使用TensorFlow作为正确输出来验证TensorRT的输出。

8.2.4.3 工作流

使用如下工作流来萃取和使用TensorFlow权重

8.2.4.4 转存(dumped)TensorFlow权重

Python脚本dumpTFWts.py可用于从给定的TensorFlow检查点转储所有变量和权重。 该脚本位于tensorrt / samples / common / dumpTFWts.py目录中。通过[dumpTFWts.py ]https://xn--dumptfwts-zo31ac0a.py/)-h获取有关此脚本用法的更多信息。

!/usr/bin/python

# Script to dump TensorFlow weights in TRT v1 and v2 dump format.

# The V1 format is for TensorRT 4.0. The V2 format is for TensorRT 4.0 and later.

import sys

import struct

import argparse

try:

import tensorflow as tf

from tensorflow.python import pywrap_tensorflow

except ImportError as err:

sys.stderr.write("""Error: Failed to import module ({})""".format(err))

sys.exit()

parser = argparse.ArgumentParser(description='TensorFlow Weight Dumper')

parser.add_argument('-m', '--model', required=True, help='The checkpoint file basename, example basename(model.ckpt-766908.data-00000-of-00001) -> model.ckpt-766908')

parser.add_argument('-o', '--output', required=True, help='The weight file to dump all the weights to.')

parser.add_argument('-1', '--wtsv1', required=False, default=False, type=bool, help='Dump the weights in the wts v1.')

opt = parser.parse_args()

if opt.wtsv1:

print "Outputting the trained weights in TensorRT's wts v1 format. This format is documented as:"

print "Line 0: "

print "Line 1-Num: [buffer name] [buffer type] [buffer size] "

else:

print "Outputting the trained weights in TensorRT's wts v2 format. This format is documented as:"

print "Line 0: "

print "Line 1-Num: [buffer name] [buffer type] [(buffer shape{e.g. (1, 2, 3)}] "

inputbase = opt.model

outputbase = opt.output

def float_to_hex(f):

return hex(struct.unpack('

def getTRTType(tensor):

if tf.as_dtype(tensor.dtype) == tf.float32:

return 0

if tf.as_dtype(tensor.dtype) == tf.float16:

return 1

if tf.as_dtype(tensor.dtype) == tf.int8:

return 2

if tf.as_dtype(tensor.dtype) == tf.int32:

return 3

print("Tensor data type of %s is not supported in TensorRT"%(tensor.dtype))

sys.exit();

try:

# Open output file

if opt.wtsv1:

outputFileName = outputbase + ".wts"

else:

outputFileName = outputbase + ".wts2"

outputFile = open(outputFileName, 'w')

# read vars from checkpoint

reader = pywrap_tensorflow.NewCheckpointReader(inputbase)

var_to_shape_map = reader.get_variable_to_shape_map()

# Record count of weights

count = 0

for key in sorted(var_to_shape_map):

count += 1

outputFile.write("%s\n"%(count))

# Dump the weights in either v1 or v2 format

for key in sorted(var_to_shape_map):

tensor = reader.get_tensor(key)

file_key = key.replace('/','_')

typeOfElem = getTRTType(tensor)

val = tensor.shape

if opt.wtsv1:

val = tensor.size

print("%s %s %s "%(file_key, typeOfElem, val))

flat_tensor = tensor.flatten()

outputFile.write("%s 0 %s "%(file_key, val))

if opt.wtsv1:

for weight in flat_tensor:

hexval = float_to_hex(float(weight))

outputFile.write("%s "%(hexval[2:]))

else:

outputFile.write(flat_tensor.tobytes())

outputFile.write("\n");

outputFile.close()

except Exception as e: # pylint: disable=broad-except

print(str(e))

if "corrupted compressed block contents" in str(e):

print("It's likely that your checkpoint file has been compressed "

"with SNAPPY.")

if ("Data loss" in str(e) and

(any([e in inputbase for e in [".index", ".meta", ".data"]]))):

proposed_file = ".".join(inputbase.split(".")[0:-1])

v2_file_error_template = """

It's likely that this is a V2 checkpoint and you need to provide the filename

*prefix*. Try removing the '.' and extension. Try:

inspect checkpoint --file_name = {}"""

print(v2_file_error_template.format(proposed_file))

8.2.4.5 加载转存权重

//!

//! \brief 加载权重到map容器.

//!

//! \param 权重文件路径, 权重文件必须由dumpTFWts.py脚本转换才能使用.

//! \param 要提取的权重名称

//!

//! \return A map containing the extracted weights.

//!

//! \note Weight V2 files are in a very simple space delimited format.

//!

//! for each buffer: [name] [type] [shape] \n

//! Note: type is the integer value of the DataType enum in NvInfer.h.

//!

std::map<:string weights> loadWeights(const std::string file, std::unordered_set<:string> names)

{

std::map<:string weights> weightMap;

std::ifstream input(file, std::ios_base::binary);

assert(input.is_open() && "Unable to load weight file.");

int32_t count;

input >> count;

assert(count > 0 && "Invalid weight map file.");

while (count--)

{

if (names.empty())

break;

Weights wt{DataType::kFLOAT, nullptr, 0};

// parse name and DataType

std::string name;

uint32_t type;

input >> name >> std::dec >> type;

wt.type = static_cast(type);

// extract shape

std::string temp, shape;

std::getline(std::getline(input, temp, '('), shape, ')');

// calculate count based on shape

wt.count = 1;

std::istringstream shapeStream(shape);

while (std::getline(shapeStream, temp, ','))

wt.count *= std::stoul(temp);

size_t numOfBytes = samplesCommon::getElementSize(wt.type) * wt.count;

// skip reading of weights if name is not in the set of names requested for extraction

if (names.find(name) == names.end())

{

input.seekg(input.tellg() + static_cast<:streamoff>(2 + numOfBytes));

continue;

}

else

{

names.erase(name);

}

// Read weight values

input.seekg(input.tellg() + static_cast<:streamoff>(1)); // skip space char

char* wtVals = static_cast(malloc(numOfBytes));

input.read(wtVals, numOfBytes);

input.seekg(input.tellg() + static_cast<:streamoff>(1)); // skip new-line char

wt.values = wtVals;

weightMap[name] = wt;

}

input.close();

return weightMap;

}

这个函数通过设置需要提取的权重的名称,返回对应的权重map。

8.2.4.6 将权重转换为TensorRT格式

此时,我们已经准备好转换的权重,接着需要去执行以下步骤:

1.理解并使用TensorFlow checkpoint来获取张量

2.理解并使用张量来提取和重新格式化相关权重,并将它们设置为TensorRT相应层的权重

8.2.4.6.1 TensorFlow checkpoint存储格式

TensorFlow checkpoint可能有两种存储格式:

1.独立于平台的格式 - 由层分隔

Cell_i_kernel

Cell_i_bias

2.cuDNN兼容格式 - 由输入和循环分隔

Cell_i_Candidate_Input_kernel

Cell_i_Candidate_Hidden_kernel

换句话说,1.1 Cell_i_kernel 是 2.1 Cell_i_Candidate_Input_kernel 和 2.2 Cell_i_Candidate_Hidden_kernel 的串联形式. 因此, 存储格式2相对于存储格式1是一种更加精细的存储方式。

8.2.4.6.2 TensorFlow kernel张量存储格式

在存储checkpoint权重之前,TensorFlow先转置再将转置矩阵交错行的位置,交错方式在下届众描述。BaiscLSTMCell示例中提供一个图来进一步说明此格式。

基于层操作类型的门顺序转置的权重矩阵按以下顺序交错:

1、RNN relu/tanh

a.输入门(i)

2、LSTM

a.输入门(i),状态门(c),遗忘门(g),输出门(o)

3、GRU

a.重置门(r),更新门(u)

8.2.4.6.3 Kernel权重转换为TensorRT格式

从TensorFlow格式转换权重可以分为两个步骤:

1、转换权重维度来调整交错格式,去成为更低的维度

转置权重来完全解除交错格式,让权重连续存储在存储器中

2、为了帮助正确执行这些转换,转换代码提供了reorderSubBuffers(),transposeSubBuffers(), and reshapeWeights()这些函数。

有关更多信息,请参阅include/NvUtil.h。

8.2.4.6.4 TensorFlow Bias权重存储格式

Bias张量简单地存储为以TensorFlow Kernel张量存储格式中指定的顺序连接的连续向量。如果checkpoint存储与平台无关,则TensorFlow通过将它们添加在一起,将循环和输入偏差合并为单个张量。否则,循环和输入偏差并存储在单独的张量中。

8.2.4.6.5 Bias张量转换成TensorRT格式

因为bias存储方式为连续向量,所以不需要应用任何转换,它与TensorRT格式是相同的。

8.2.4.7 BasicLSTMCell示例

8.2.4.7.1 BasicLSTMCell Kernel张量

为了理解这些张量存储的格式,让我们说明一个BasicLSTMCell的例子。图6说明了TensorFlow checkpoint中张量的样子。

图6 TensorFlow checkpoint张量的存储格式

对于第一层的DS/Data Size与隐藏层Size是不同的,对于以下所有子层,Data Size等于隐藏层Size

在图6中,W代表输入权重,R代表隐藏权重,DS代表数据大小,HS代表隐藏层大小。由于这是一个独立于平台的单元,因此输入门权重和隐藏门权重已经连接在一起。如果我们使用CudnnCompatibleLSTMCell,那么这些权重将被分成两个独立的张量。

使用前面讨论的转换程序,将得到转换的张量如图7所示。

8.2.4.7.2 BasicLSTMCell Bais张量

Bias张量的存储格式如下图

因为这是一个独立于平台的格式,所以上图W代表ElementWise将输入和循环偏置加在一起的结果。在存储张量之前,TensorFlow在内部执行此加法以节省内存。

这已经是我们需要的格式,因此,我们不需要进行任何转换。

8.2.4.8 设置转换的权重和偏差

准备好转换好的Weight和Bias就可以分別调用IRNNv2Layer::setWeightsForGate()和IRNNv2Layer::setBiasForGate()来设置TensorRT的权重和偏置。

实际的例子通常是训练、转储、转换、设置处理。更多信息参考sampleCharRNN例子。

8.2.5 使用Graph Surgeon API预处理TensorFlow图

Graph Surgeon APISurgeon翻译为“外科医生”很贴切,对TensorFlow Graph进行搜索、操作,类似外科手术,功能如下:

搜索:搜索功能允许您查找节点

操作:操作功能允许您修改,添加或删除节点

使用Graph Surgeon API,您可以将某些节点(或节点集)标记为图中的Plugin节点。这些插件可以是TensorRT自带的插件,也可以是您编写的插件。有关更多信息,请参阅使用自定义层扩展TensorRT。

如果您正在编写Plugin,请参阅有关如何实现IPluginExt和IPluignCreator类以及注册Plugin的详细信息,请参阅使用自定义层扩展TensorRT。

以下代码片段示例如何使用Graph Surgeon API将TensorFlow Leaky ReLU算子映射到TensorRT Leaky ReLU插件节点。

import graphsurgeon as gs

# 创建leaky relu节点

lrelu_node = gs.create_plugin_node(name=”trt_lrelu”, op=”LReLU_TRT”, negSlope=0.2)

namespace_plugin_map = { “tf_lrelu” : lrelu_node }

# 使用Graph surgeon API转换TensorFlow图,并保存到uff格式文件中

dynamic_graph = gs.DynamicGraph(tf_lrelu.graph)

dynamic_graph.collapse_namespaces(namespace_plugin_map)

# 运行UFF转换器转换新的Graph

uff_model = uff.from_tensorflow(dynamic_graph.as_graph_def(), ["trt_lrelu"], output_filename="test_lrelu.uff", text=True)

在上面的代码中,create_plugin_node方法中的op字段应该与注册的插件名称匹配。这使得UFF解析器能够使用该字段查找插件注册表,来将插件节点插入网络中。

有关Graph Surgeon API示例,请参阅C++ sampleUffSSD。

有关Graph Surgeon API的更多详细信息,请参阅Graph Surgeon API。

8.3 使用PyTorch和其他框架

将TensorRT与PyTorch和其他框架一起使用,涉及使用TensorRT API复制网络架构,然后从PyTorch(或具有NumPy兼容权重的任何其他框架)复制权重。有关将TensorRT与PyTorch模型一起使用的更多信息,请参阅:

9.2.3节network_api_pytorch_mnist Python示例

微信公众号: 极市平台(ID: extrememart )

每天推送最新CV干货

你可能感兴趣的:(tensorrt,分割)