[Inferencia del modelo] Enseñarle cómo implementar el operador mish en tensorrt

  ¡Acostúmbrate a escribir juntos! Este es el día 11 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de abril", haga clic para ver los detalles del evento .

欢迎关注我的公众号 [极智视界],获取我的更多笔记分享

   Hola a todos, mi nombre es Jizhi Vision. Este artículo presenta el método de usar tensorrt para implementar el operador mish.

  Creo que los estudiantes que han realizado detección de objetivos deben estar familiarizados con yolo. Yolov4 se propuso a principios de 2020, seguido de yolov5 y algunas otras variantes. Hay muchos trucos en yolov4, incluida la función de activación de mish. mish se presentó en detalle en este documento "Mish: una función de activación no monotónica autoregulada", aquí hice algunas introducciones a la función en sí y cómo tensorrt implementa el operador mish.

1. Expresión matemática de la función mish

   La expresión matemática de mish es la siguiente:

  La representación gráfica de la función es la siguiente, donde:

  • La curva azul es: mish
  • La curva naranja es: ln(1 + e^(x))

   Veamos cómo se ve mish en yolov4:

   Mish también puede verse como una combinación de tanh y softplus. A ver, la expresión matemática de tanh es la siguiente:

   La expresión matemática de softplus es la siguiente, softplus puede considerarse como el suavizado de relu.

   Lo anterior compara las expresiones matemáticas de mish, tanh y softplus.Puede encontrar fácilmente que mish también se puede escribir así:

2. Mish contra relu

  Se puede decir que Relu es la función de activación más utilizada porque puede superar la desaparición del gradiente y acelerar la convergencia del entrenamiento. Relu es una función por partes, y la expresión matemática es la siguiente:

  La imagen de la función se expresa de la siguiente manera:

   Comparar mish y relu aquí es una sensación de cabeza a cabeza. Tome algunos experimentos en el documento "Mish: una función de activación no monotónica autoregulada" como ilustración.

   这是 relu 和 mish 的梯度对比,可以看到 mish 的梯度更加平滑。

精度方面,在 ImageNet-1K 数据集上对 mish、swish、relu、leaky relu 激活函数对网络精度的提升对了对比,数据如下:

   以下是在 MS-COCO 目标检测数据集的对比数据:

  从实测的精度提升数据来看,mish 具有十分明显的优势。

   性能方面,在 pytorch 框架中,对 relu、softplus、mish、mish-cuda (RTX-2070) 在 fp32 和 fp16 精度下进行了性能对比,数据如下,可以看到 relu 在推理效率上要比 mish 快,mish-cuda 在用 cuda 进行优化后性能能提升很多。

3、tensorrt 实现 mish 算子

   先让我们来看一下 tensorrt API 直接支持的激活函数算子:

//!
//! \enum ActivationType
//!
//! \brief Enumerates the types of activation to perform in an activation layer.
//!
enum class ActivationType : int32_t
{
    kRELU = 0,             //!< Rectified linear activation.
    kSIGMOID = 1,          //!< Sigmoid activation.
    kTANH = 2,             //!< TanH activation.
    kLEAKY_RELU = 3,       //!< LeakyRelu activation: x>=0 ? x : alpha * x.
    kELU = 4,              //!< Elu activation: x>=0 ? x : alpha * (exp(x) - 1).
    kSELU = 5,             //!< Selu activation: x>0 ? beta * x : beta * (alpha*exp(x) - alpha)
    kSOFTSIGN = 6,         //!< Softsign activation: x / (1+|x|)
    kSOFTPLUS = 7,         //!< Parametric softplus activation: alpha*log(exp(beta*x)+1)
    kCLIP = 8,             //!< Clip activation: max(alpha, min(beta, x))
    kHARD_SIGMOID = 9,     //!< Hard sigmoid activation: max(0, min(1, alpha*x+beta))
    kSCALED_TANH = 10,     //!< Scaled tanh activation: alpha*tanh(beta*x)
    kTHRESHOLDED_RELU = 11 //!< Thresholded ReLU activation: x>alpha ? x : 0
};
复制代码

   可以看到像 relu、sigmoid、tanh ... 这些你都不用自己去写,直接调 trt 的 api 就好了。我们这里的 mish 不是直接支持的,所以用 trt 来实现的话基本有两种思路:

   (1) 用已有算子组合,mish 的话可以用 tanh 和 softplus 组合起来;

   (2) 用 cuda kernel 实现,用 plugin 注册进 trt 使用;

下面进行介绍。

3.1 已有算子组合实现

   这个其实很好写,看看 mish 的数学表达:

  所以基本思路就是先调一个 softplus,再调一个 tanh,把 softplus 的结果传给 tanh,tanh 的输出就等效于一个 mish 的输出。关键代码如下:

########### softplus ############
# 需要注意,trt 里的 softplus 长这样:alpha*log(exp(beta*x)+1)
activationSP = network->addActivation(*Layers[inputName], nvinfer1::ActivationType::kSOFTPLUS);
# 将 alpha 和 beta 设置为 1
activationSP->setAlpha(1);
activationSP->setBeta(1);

############# tanh ##############
nvinfer1::ITensor *activationSP_Out = activationSP->getOutput(0);
mish = network->addActivation(*activationSP_Out, nvinfer1::ActivationType::kTANH);
复制代码

  以上就完成了使用 tensorrt 已有算子组合来实现 mish 操作。

3.2 cuda + plugin 实现

   Convierta mish al equivalente matemático y conviértalo en la siguiente expresión matemática:

   La idea básica es usar cuda para implementar directamente, y la combinación original de tanh y softplus requiere que dos operadores se conviertan en un solo operador. No hablo sobre cómo usar cuda kernel para lograrlo aquí, hablemos sobre cómo registrar .cu en tensorrt a través del complemento.

  Primero necesitas un encabezado, algo como esto:

/// mish.h
#include<NvInfer.h>
#include<NvInferPlugin.h>

calss MishLayerPlugin : public IPluginExt
{
    void mish_infer(...);
}
复制代码

   Luego está .cu, que es la implementación del operador gpu_infer, que es casi así:

/// mish.cu
#include "mish.h"

__global__ void mish(...)
{
    ...;
}

void MishLayerPlugin::mish_infer(...)
{
    mish<<<xx, xx>>>(...);
}
复制代码

  Finalmente, el .cpp se registra en tensorrt a través del complemento, que es casi así:

/// tensort-mish.cpp

#include "mish.h"

void addmish_layer(...)
{
	nvinfer1::DataType Dtype;
	Dtype = nvinfer1::DataType::kFLOAT;
	nvinfer1::IPluginExt *mish = new MishLayerPlugin(xxx, Dtype);
	nvinfer1::IPluginLayer *mish_layer = m_network->addPluginExt(&Layers[inputName], 1, *mish);
   ...
}
复制代码

  De acuerdo, llámalo un día ~ Lo anterior compartió el método de tensorrt para implementar el operador Mish. Espero que mi intercambio pueda ayudarlo un poco en su estudio.


 【Transmisión de número público】

"[Razonamiento del modelo] Enséñale tensorrt a implementar el operador mish"


logo_show.gif

Supongo que te gusta

Origin juejin.im/post/7085636157307879438
Recomendado
Clasificación