神经网络如果仅仅是由线性的卷积运算堆叠组成, 则其无法形成复杂的表达空间, 也就很难提取出高语义的信息, 因此还需要加入非线性的映射, 又称为激活函数, 可以逼近任意的非线性函数, 以提升整个神经网络的表达能力。 在物体检测任务中, 常用的激活函数有Sigmoid、ReLU及Softmax函数。
1. Sigmoid函数
Sigmoid型函数又称为Logistic函数, 模拟了生物的神经元特性, 即当神经元获得的输入信号累计超过一定的阈值后, 神经元被激活而处于兴奋状态, 否则处于抑制状态。 其函数表达如式(3-1) 所示。
Sigmoid函数曲线与梯度曲线如图3.4所示。 可以看到, Sigmoid函数将特征压缩到了(0,1)区间, 0端对应抑制状态, 而1对应激活状态, 中间部分梯度较大。
PyTorch实现Sigmoid函数很简单, 示例如下:
PyTorch实现Sigmoid函数很简单, 示例如下:
1 import torch 2 from torch import nn 3 4 input = torch.ones(1, 1, 2, 2) 5 print(input) 6 7 sigmoid = nn.Sigmoid() 8 out = sigmoid(input) 9 10 print(out)
Sigmoid函数可以用来做二分类, 但其计算量较大, 并且容易出现梯度消失现象。 从曲线图(图3.4) 中可以看出, 在Sigmoid函数两侧的特征导数接近于0, 这将导致在梯度反传时损失的误差难以传递到前面的网络层(因为根据链式求导, 梯度接近于0) 。
2. ReLU函数
为了缓解梯度消失现象, 修正线性单元(Rectified Linear Unit,ReLU) 被引入到神经网络中。 由于其优越的性能与简单优雅的实现, ReLU已经成为目前卷积神经网络中最为常用的激活函数之一。 ReLU函
数的表达式如式(3-2) 所示。
ReLU函数及其梯度曲线如图3.5所示。 可以看出, 在小于0的部分,值与梯度皆为0, 而在大于0的部分中导数保持为1, 避免了Sigmoid函数中梯度接近于0导致的梯度消失问题。
下面是PyTorch实现ReLU激活函数示例。
1 from torch import nn 2 3 input = torch.ones(1, 1, 2, 2) 4 print(input) 5 >> tensor([[[[1., 1.], 6 [1., 1.]]]]) 7 8 # nn.ReLU()可以实现inplace操作, 即可以直接将运算结果覆盖到输入中, 以节省内存 9 relu = nn.ReLU(inplace=True) 10 print(relu(input)) 11 # # 可以看出大于0的值保持不变, 小于0的值被置为0 12 >> tensor([[[[1., 1.], 13 [1., 1.]]]])
ReLU函数计算简单, 收敛快, 并在众多卷积网络中验证了其有效性。
3. Leaky ReLU函数
ReLU激活函数虽然高效, 但是其将负区间所有的输入都强行置为0, Leaky ReLU函数优化了这一点, 在负区间内避免了直接置0, 而是赋予很小的权重, 其函数表达式如式(3-3) 所示。
以上公式中的ai代表权重, 即小于0的值被缩小的比例。 Leaky ReLU的函数曲线如图3.6所示。
下面使用PyTorch来实现简单的Leaky ReLU激活函数过程。
1 import torch 2 from torch import nn 3 4 input = torch.randn(1, 1, 2, 2) 5 print(input) 6 >> tensor([[[[-0.7955, 0.3595], 7 [ 0.1483, 0.2836]]]]) 8 9 # 利用nn.LeakyReLU()构建激活函数, 并且其为0.04, 即ai为25, True代表in-place操作 10 leakrelu = nn.LeakyReLU(0.04, True) 11 # 从结果看大于0的值保持不变, 小于0的值被以0.04的比例缩小 12 print(leakrelu(input)) 13 >> tensor([[[[-0.0318, 0.3595], 14 [ 0.1483, 0.2836]]]])
虽然从理论上讲, Leaky ReLU函数的使用效果应该要比ReLU函数好, 但是从大量实验结果来看并没有看出其效比ReLU好。 此外, 对于ReLU函数的变种, 除了Leaky ReLU函数之外, 还有PReLU和RReLU 函数等, 这里不做详细介绍。
4. Softmax函数
在物体检测中, 通常需要面对多物体分类问题, 虽然可以使用Sigmoid函数来构造多个二分类器, 但比较麻烦, 多物体类别较为常用
的分类器是Softmax函数。
在具体的分类任务中, Softmax函数的输入往往是多个类别的得分, 输出则是每一个类别对应的概率, 所有类别的概率取值都在0~1之间, 且和为1。 Softmax函数的表达如式(3-4) 所示, 其中, Vi表示第i个类别的得分, C代表分类的类别总数, 输出Si为第i个类别的概率。
在PyTorch中, Softmax函数在torch.nn.functional库中, 使用方法如
下
在PyTorch中, Softmax函数在torch.nn.functional库中, 使用方法如下 :
1 import torch 2 3 import torch.nn.functional as F 4 score = torch.randn(1, 4) 5 print(score) 6 >> tensor([[ 0.4768, 0.8797, 0.9180, -0.3224]]) 7 8 # 利用torch.nn.functional.softmax()函数, 第二个参数表示按照第几个维度进行 9 # Softmax计算 10 out = F.softmax(score, 1) 11 print(out) 12 >> tensor([[0.2222, 0.3324, 0.3454, 0.0999]])