<p><strong>更新09/28/2019</strong></p>
<p>Nvidia大约两周前发布了<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-release-notes/tensorrt-6.html#rel_6-0-1" rel="nofollow noreferrer">TensorRT 6.0.1</a>,并添加了一个名为“IResizeLayer”的新API。该层支持“最近”插值,因此可用于实现上采样。不再需要使用自定义层/插件!在</p>
<p><strong>原始答案:</strong></p>
<p>感谢所有的答案和建议张贴在这里!在</p>
<P>最后,在TySRRT C++ API中直接实现了网络,并从H5模型文件中加载了权重。我们还没有时间对解决方案进行分析和改进,但根据我们输入的测试图像,推断似乎正在起作用。在</p>
<p>以下是我们采用的工作流程:</p>
<p><em>第1步:对上采样层进行编码。</em></p>
<p>在我们的U-Net模型中,所有上采样层的比例因子为(2,2),它们都使用resizenearest近邻插值。本质上,原始张量中(x,y)处的像素值将变成新张量中的四个像素:(2x,2y),(2x+1,2y),(2x,2y+1)和(2x+1,2y+1)。这可以很容易地编码成一个CUDA内核函数。在</p>
<p>一旦我们得到了upsampling内核,我们需要用tensorrtapi包装它,特别是<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_plugin_v2_ext.html" rel="nofollow noreferrer">IPluginV2Ext class</a>。开发人员参考有一些关于需要实现什么功能的描述。我认为enqueue()是最重要的函数,因为CUDA内核在那里执行。在</p>
<p>在TensorRT Samples文件夹中也有示例。对于我的版本,这些资源很有用:</p>
<ul>
<li><a href="https://github.com/LitLeo/TensorRT_Tutorial/blob/master/blogs/TensorRT%20Plugin%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%E7%AE%80%E4%BB%8B-%E4%BB%A5leaky%20relu%E5%B1%82%E4%B8%BA%E4%BE%8B.md" rel="nofollow noreferrer">Github: Leaky Relu as custom layer</a></li>
<li>TensorRT-5.1.2.2/样品/样品</li>
<li>TensorRT-5.1.2.2/样品/样品</li>
</ul>
<p><em>第2步:使用TensorRT API对网络的其余部分进行编码</p>
<p>网络的其他部分应该很简单。只需找到从<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_network_definition.html" rel="nofollow noreferrer">TensorRT network definitions</a>调用不同的“addxxxLayer”函数。在</p>
<p>有一点要记住:
根据您使用的TRT版本,添加填充的方法可能不同。我认为最新版本(5.1.5)允许开发人员在<code>addConvolution()</code>中添加参数,以便选择合适的填充模式。在</p>
<p>我的模型是用Keras训练的,默认的填充模式是如果填充的总数不是偶数,那么右边和底部会得到更多的填充。查看此<a href="https://stackoverflow.com/questions/53819528/how-does-tf-keras-layers-conv2d-with-padding-same-and-strides-1-behave">Stack Overflow link</a>以获取详细信息。在5.1.5中有一个<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_convolution_layer.html#a55b28cb09af34d6c4645455f8861ae34" rel="nofollow noreferrer">mode</a>表示这个填充方案。在</p>
<p>如果您使用的是旧版本(5.1.2.2),则需要在卷积层之前添加填充作为<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_network_definition.html#a334d849cb8720a8a66a95fc84487b132" rel="nofollow noreferrer">a separate layer</a>,卷积层有两个参数:前填充和后填充。在</p>
<p>而且,所有的东西都是NCHW在TensorRT</p>
<p>有用示例:</p>
<ul>
<li>TensorRT-5.1.2.2/样品/样品</li>
</ul>
<p><em>第3步:加载重量</em></p>
<p>TensorRT希望权重的格式为[out\uc,in_c,filter_h,filter_w],这在<a href="https://docs.nvidia.com/deeplearning/sdk/tensorrt-archived/tensorrt_210/tensorrt-user-guide/index.html#reshapedata" rel="nofollow noreferrer">archived documentation</a>中提到。Keras的权重格式为[filter_h,filter_w,c_in,c_out]。在</p>
<p>我们通过在Python中调用<code>model.save_weights('weight.h5')</code>得到一个纯权重文件。然后我们可以使用h5py将权重读入Numpy数组中,执行转置并将转置后的权重保存为新文件。我们还使用h5py计算出组和数据集名称。此信息是在使用<a href="https://portal.hdfgroup.org/pages/viewpage.action?pageId=50073884" rel="nofollow noreferrer">HDF5 C++ API</a>将权重加载到C++代码中时使用的。在</p>
<P>我们比较了C++代码和Python代码之间的逐层输出。对于我们的U-Net,所有的激活图在第三个块之前都是相同的(在2个池之后)。之后,像素值之间会有微小的差别。绝对百分比误差是10^-8,所以我们不认为它是那么糟糕。我们仍然在抛光C++实现的过程中。在</p>
<p>再次感谢您在这篇文章中给出的所有建议和答案。希望我们的解决方案也能有所帮助!在</p>