我个人倾向于把神经网络和其中的传播过程当作水流一样,神经网络本质就是一个双向管道系统,不同激活函数都是不同的水阀,权重就是管道的粗细。输入前向传播,误差根据梯度反向传播。
全连接网络包括输入层、隐藏层和输出层,每一层的神经元与下一层的神经元全部相连。对于第i层的神经元,其输出为:$a_i = \sigma(W_i a_{i-1} + b_i)$,其中$W_i$为第i层的权重矩阵,$b_i$为第i层的偏置,$\sigma$为激活函数。
# 个人项目里dueling DQN的VAnet,注意其中pytorch实现的forward方法,本质就是水管套娃
class VAnet(torch.nn.Module):
def __init__(self, state_dim, hidden_dim, action_dim):
super(VAnet, self).__init__()
# self.fc1 = torch.nn.Linear(state_dim, hidden_dim)
self.fc0 = torch.nn.Linear(state_dim, 128) # 4 modes
self.fc1 = torch.nn.Linear(128, hidden_dim)
self.fcA = torch.nn.Linear(hidden_dim, action_dim)
self.fcV = torch.nn.Linear(hidden_dim, 1)
def forward(self, x):
x = F.relu(self.fc0(x))
A = self.fcA(F.relu(self.fc1(x)))
V = self.fcV(F.relu(self.fc1(x)))
Q = V + A - A.mean(1).view(-1, 1)
return Q
前向传播的是数据输入流,从输入层开始,通过激活函数传播到输出层,得到预测值。对于第i层的神经元,其输入为$i-1$层的输出:
$z_i = W_i a_{i-1} + b_i$
$a_i = \sigma(z_i)$
其中$z_i$为第i层的输入,$a_i$为第i层的输出,$\sigma$为激活函数。其实就是简单复读上述的全连接网络结构。
从特征映射角度看激活函数对于输入输出之间,构建了一个非线性映射,使得神经网络可以拟合非线性函数。如果不加激活函数那么不管叠多少层都是线性变换。
激活函数按照映射关系可分为饱和(Sigmoid, tanh等,一般有一个$e^{-x}$)、非饱和(各种Rectified Linear Unit,ReLU, Leaky ReLU. etc)。饱和激活函数在abs(x)很大时,由于函数收敛,梯度接近于0,容易出现梯度消失问题。(sigmoid和tanh)因为有指数运算计算开销大。
线性激活函数:$f(x) = x$,就是没有激活。
Sigmoid:$f(x) = \frac{1}{1+e^{-x}}$,常用于二分类,输出在(0,1)之间,函数曲线光滑平缓,可以防止梯度突变;但是在两端梯度接近于0,且导数$f’(x) =f(x)(1-f(x))= e^{-x}/(1+e^{-x})^2$在0到0.25之间,容易出现梯度消失问题。
tanh:$f(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$,常用于多分类,输出在(-1,1)之间,函数曲线光滑平缓,可以防止梯度突变;但是在两端梯度接近于0,且导数$f’(x)=1 - f(x)^2$在0到1之间,容易出现梯度消失问题。
ReLU:$f(x) = max(0,x)$,订书机函数,负数部分梯度为0,容易出现神经元死亡问题。
Leaky ReLU:$f(x) = max(0.01x,x)$,大开口订书机,其中负数部分的线性权重可以调整,若自动学习权重就变为PReLU。在负数部分梯度不为0,解决了神经元死亡问题。
PReLU:$f(x) = max(\alpha x,x)$ 其中$\alpha$为学习参数。
ELU:$f(x) = \begin{cases} x & x>0 \ \alpha(e^x - 1) & x \leq 0 \end{cases}$,ELU会让输出均值接近0(因为负数部分梯度绝对值在0附近),这样有利于梯度接近自然梯度,但是有指数计算,计算量大。
SELU:$f(x) = \lambda \begin{cases} x & x>0 \ \alpha(e^x - 1) & x \leq 0 \end{cases}$,其中$\lambda$和$\alpha$为超参数。 可学习版ELU
Softmax:$f(x)i = \frac{e^{x_i}}{\sum{j}e^{x_j}}$,常用于多分类,输出在(0,1)之间,(公式和离散选择模型是一样的,可以看作不同神经元的概率)常用于最后的输出层。 $\sum_{i}f(x)_i = 1$
在神经网络训练过程中(以监督学习为例),对于输入特征x,输出Y,记神经网络作为一个泛函为$f(x;\omega)$,其中$\omega$为每一层权重/模型参数,损失函数为$L(Y,f(x))$,反向传播只是求解损失函数对于模型参数梯度的一个方法,求出梯度后再进行梯度下降来更新模型,无奈总有公司要手推反向传播,以下是推导过程:
同一个问题的一体两面,梯度消失是指在反向传播过程中,梯度逐渐变小,导致模型参数无法更新,梯度爆炸是指梯度逐渐变大,导致模型参数更新过大,两者都会导致模型训练困难。
解决方法: