常见算子操作

15 分钟阅读

激活函数

Relu

\[f(x) = \begin{cases} x,\quad & if & x \ge 0 \\ 0,\quad & if & x \lt 0 \end{cases}\]

LeakyRelu

\[f(x) = \begin{cases} x,\quad & if & x \ge 0 \\ x \times negative\_slope,\quad & if &x \lt 0 \end{cases}\]

PRelu

\[f(x) = \begin{cases} x,\quad & if & x \ge 0 \\ x \times slope\_data[c],\quad & if &x \lt 0 \end{cases}\]

Sigmoid

\[f(x) = \frac{1}{1 + e^{-x}}\]

将变量映射到(0,1),S型曲线,求导方便,求导过程:$ f’(x) = \frac{e^{-x}}{(1+e^{-x})^2} = f(x)\times (1 - f(x)) $

Tanh

\[f(x) = \frac{sinh(x)}{cosh(x)}=\frac{e^x - e^{-x}}{e^x + e^{-x}}\]

将变量映射到(-1,1),S型曲线.

Mish

\[f(x) = x \times tanh(ς(x)),\quad 其中ς(x) = ln(1 + e ^x)\]

YOLOv4网络使用的激活函数,类似relu,但是负值保持光滑非单调。

元素操作

Scale

\[f(x) = scale[c] \times x + bias[c]\]

Power

\[f(x) = (scale \times x + shift)^{power}\]

BatchNorm

\[mean = \frac{1}{m} \sum_{i=1}^{m}{x_i} \quad 求均值 \\ variance = \frac{1}{m} \sum_{i=1}^{m}{(x_i - mean)^2} \quad 求方差 \\ u_i = \frac{x_i - mean}{\sqrt{variance + eps}} \quad 归一化, eps用于防止除0 \\ y_i = \gamma \times u_i + \beta \Rightarrow BN_{\gamma,\beta}(x_i) \quad \gamma,\beta训练生成\]

归一化,将网络层的输入转化到均值为 0方差为1的标准正态分布上,使梯度变化增大,加快训练收敛速度。

caffe中batchnorm,通常没有第四步,推理运算过程如下:

\[mean = blobs_0,\quad variance = blobs_1,\quad scale = blobs_2[0] \\ y_i = \frac{x_i - \frac{mean_c}{scale}}{\sqrt{\frac{variance_c}{scale} + eps}}\\\]

LRN

\[b^i_{x,y} = a^i_{x,y} / \bigg(k + \alpha \sum^{min(N-1, i + n/2)}_{j = max(0, i- n/2)}(a^j_{x,y})^2\bigg)^\beta\]

局部相应归一化,基本上只有googlenet在用。通俗来说就是局部相邻元素归一,分通道间相邻和通道内相邻。

LayerNorm

torch.nn.LayerNorm(normalized_shape: Union[int, List[int], torch.Size],
                   eps: float = 1e-05,
                   elementwise_affine: bool = True)

计算过程与BatchNorm相同,区别在于BatchNorm会在train阶段跟踪统计全局的均值方差;而LayerNorm不受train影响,推理时直接计算指定范围的均值方差。

向量操作

Pooling

\[\begin{bmatrix} 1 & 2 & 3 & 4\\ 5 & 6 & 7 & 8 \end{bmatrix} \Rightarrow \begin{cases} \begin{bmatrix} 6 & 8 \end{bmatrix},\quad & if & max \\ \begin{bmatrix} 3.5 & 5.5 \end{bmatrix},\quad & if & average \end{cases}\]

从大feature map转为小feature map,防止过拟合,减少参数

Upsample

\[\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \Rightarrow \begin{bmatrix} 1 & 1 & 2 & 2 \\ 1 & 1 & 2 & 2 \\ 3 & 3 & 4 & 4 \\ 3 & 3 & 4 & 4 \\ \end{bmatrix}\]

上采样,用于扩大feature map,通常有这几种:

  • 如图中所示,各个元素翻倍
  • unpooling max,只有在pooling max位置填值,其余补0
  • deconv,input填0后做卷积操作

Tile

\[\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \Rightarrow \begin{bmatrix} 1 & 2 & 1 & 2 \\ 3 & 4 & 3 & 4 \\ 1 & 2 & 1 & 2 \\ 3 & 4 & 3 & 4 \\ \end{bmatrix}\]

维度翻倍,上图是将(h,w)转换为(2h,2w)

Permute (Transpose)

\[\begin{bmatrix} 1 & 2 & 3 & 4\\ 5 & 6 & 7 & 8 \end{bmatrix} \Rightarrow \begin{bmatrix} 1 & 5 \\ 2 & 6 \\ 3 & 7 \\ 4 & 8 \end{bmatrix}\]

维度转换,比如图片三维HWC转换为CHW,可以用numpy如下操作:

x = np.transpose(x, (2,0,1))

Concat

\[\begin{bmatrix} 1 & 2 \end{bmatrix}, \begin{bmatrix} 3 & 4 \end{bmatrix}, \begin{bmatrix} 5 & 6 \end{bmatrix} \Rightarrow \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \\ \end{bmatrix}\]

按指定维度进行合并。例子中axis=1;如果axis=0,则结果为[1 2 3 4 5 6]

Reshape

\[\begin{bmatrix} 1 & 2 & 3 & 4\\ 5 & 6 & 7 & 8 \end{bmatrix} \Rightarrow \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \\ 7 & 8 \end{bmatrix}\]

不改变存储顺序,只改变tensor shape。

在caffe中由reshape_param.shape.dim指定新shape,如果dim=0,则保持不变;dim=-1,则指定为剩余维度。

Reorg

\[\begin{bmatrix} \begin{bmatrix} 1 & 3 & 2 & 4 \\ 5 & 7 & 6 & 8 \end{bmatrix} \end{bmatrix} \Rightarrow \begin{bmatrix} \begin{bmatrix} 1 & 2 \end{bmatrix}, \begin{bmatrix} 3 & 4 \end{bmatrix}, \begin{bmatrix} 5 & 6 \end{bmatrix}, \begin{bmatrix} 7 & 8 \end{bmatrix} \end{bmatrix}\]

重组,stride指定间隔,reverse指定是否反向。令r = stride, 则:

当reverse为false时,$ [N,C,H,W] \Rightarrow [N, r^2 \times C, \frac{H}{r}, \frac{W}{r}] $

当reverse为true时,$ [N,C,H,W] \Rightarrow[N,\frac{C}{r^2}, H \times r, W \times r] $,注意$ C = r^2 \times \frac{C}{r^2} $

pixelshuffle

$ [N,C,H,W] \Rightarrow [N,\frac{C}{r^2}, H \times r, W \times r] $,注意 $ C = \frac{C}{r^2} \times r^2 $

与reorg reverse为true比较类似,区别在于C维降维的次序不同

Eltwise

\[\begin{bmatrix} \begin{bmatrix} 1 & 2 \end{bmatrix}, \begin{bmatrix} 3 & 4 \end{bmatrix}, \begin{bmatrix} 5 & 6 \end{bmatrix}, \begin{bmatrix} 7 & 8 \end{bmatrix} \end{bmatrix} \Rightarrow \begin{cases} \begin{bmatrix} 105 & 384 \end{bmatrix},\quad if \quad prod \\ \begin{bmatrix} 16 & 20 \end{bmatrix},\quad if \quad sum \\ \begin{bmatrix} 7 & 8 \end{bmatrix},\quad if \quad max \end{cases}\]

Softmax

\[x_i = x_i - max(x_0,...,x_n) \\ y_i = \frac{e^{x_i}}{\sum^{n}_{j=0}e^{x_j}}\]

通常用于分类网络中判断类别的概率。举例如下:

\[\begin{bmatrix} 3 & 1 & -3 \end{bmatrix} \Rightarrow \begin{bmatrix} 0 & -2 & -6 \end{bmatrix} \Rightarrow \begin{bmatrix} 0.88 & 0.12 & 0 \end{bmatrix}\]

Argmax

\[\begin{bmatrix} 0 & 9 & 2 \\ 5 & 3 & 4 \end{bmatrix} \Rightarrow \begin{cases} [1 & 0 & 1], & if \quad axis = 0 \\ [1 & 0], & if & axis = 1 \end{cases}\]

指定维度,得到最大值的index,对应操作numpy.argmax()。比如[n, c, h, w],如果axis = 0, 得到[c,h,w];如果axis = 1, 得到[n, h, w];如果 axis = 2, 得到[n, c, w]。

InnerProduct (FullyConnected)

二维矩阵运算,$ (M \quad N) \times (N \quad K) \Rightarrow (M \quad K) $

其他操作

GridSample

参见torch.nn.functional.grid_sample,输入和输出关系如下: \(Input_{(N, C, H_{in}, W_{in})}, Grid_{(N, H_{out}, W_{out}, 2)} \Rightarrow Output_{(N,C,H_{out},W_{out})}\) 网格在输入中采用,其中2对应Input的H和W坐标。坐标不一定是范围内的整数,

ScatterND

参见ScatterND,它等同于torch的索引操作,对局部向量进行更新。它对应三个输入,和一个输出。举例如下:

data    = [1, 2, 3, 4, 5, 6, 7, 8]
indices = [[4], [3], [1], [7]]
updates = [9, 10, 11, 12]
output  = [1, 11, 3, 10, 9, 6, 7, 12]