神经网络学习笔记
前置知识
导数 VS 微分
导数就是导函数。
\(f\) 的微分 \(df\) 可以看作一个函数,(一维的情况下)它将 \(dx\) 映射到 \(f'(x)dx\)。
\(dx\) 怎么理解看个人,我没有把它当成函数,而是把它当成了一个单纯的记号。
梯度 VS 微分
梯度是高维意义下的导数。
梯度的定义: 梯度是一个向量,包含函数的所有偏导数。对于函数 \(f(x,y)\),其梯度为: \[ \nabla f = \left( \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y} \right) \] 梯度指向函数值增加最快的方向。
微分的定义: 微分描述了函数在自变量微小变化时的改变。对于函数 \(f(x,y)\),其微分 \(df\) 为: \[ df = \frac{\partial f}{\partial x} dx + \frac{\partial f}{\partial y} dy \]
这表示函数在自变量 \(x\) 和 \(y\) 分别变化 \(dx\) 和 \(dy\) 时的总变化。
常用函数
- sigmoid:记作 \(\sigma(x)\),\(\sigma(x) = \frac{1}{1+e^{-x}}\)。
- 双曲正切函数:记作 \(\tanh(x)\),\(\tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}\)。
常用记号
- 逐元素相乘(Hadamard Product):\(A \odot B = C\) 表示张量 \(A,B\) 逐元素得到一个同结构的张量 \(C\)。
- 矩阵乘法:\(A\cdot B = C\) 表示两个矩阵按矩阵乘法规则乘出来是 \(C\),没有特殊说明一定不是点乘。
神经网络
权重矩阵
权重矩阵用于在层之间做转移,是神经网络结构的主要组成部分。
激活函数
激活函数用于调整函数结构,使神经网络能够学习复杂的非线性函数。
偏置项
偏置项用于对激活范围进行调整,能够有效提升模型表达能力。
没有偏置项时,激活函数的输出只取决于输入信号的加权和,这样拟合会让模型变得复杂,引入偏置项能够有效改善学习过程。
反向传播算法
通过链式求导法则,计算每一项的梯度,以减少损失函数为目的按照梯度调整权重矩阵和偏置项的值。
不完全可微函数的处理
激活函数有时候不是完全可微的,例如 ReLU 函数,这个时候会采取某些方式来处理。
- 归到某一边:反正概率挺小的,直接认为可导归到其中一边就行。
- 使用次梯度:如果它是个凸函数,可以用次梯度近似替代。
- 用可导函数近似:找个长得差不多的可导函数,不可微的点用这个函数的微分替代。
批次训练与梯度累计
神经网络一般采用批次训练的方式,利用 GPU 的并行计算能力,一个批次跑出多个数据的 loss 和梯度。然后取平均后进行一次下降。
一般来说 batch_size 设置大一点可以让学习过程更加稳定,减少个别数据的极端偏移。
有时候显存不够甚至可以多跑几次积累一下梯度,然后进行更新。
注意这里是对梯度取平均,不是对 loss 或者中间过程的值取平均。
过拟合与缓解方式
Early Stop
训到训练集 Loss 连续一段时间不再下降时就停止。
L1/L2 Standardization
给 Loss 加个正则化项:
- L1 正则化:\(\lambda\sum|w_i|\)
- L2 正则化:\(\lambda\sum w_i^2\)
为啥有用:
- L1 促进一些参数变零,可以实现特征选择,以去除不重要的特征。
- L2 鼓励减小参数大小,降低对训练数据的敏感性。
- 总的来说都是限制了模型复杂度以减小过拟合的可能。
Dropout
实现方式:
- 每轮训练的时候以一个概率 \(p\in[0.2,0.5]\) 让(特定的 Dropout 层)激活函数变零。
- 测试的时候启用全部神经元,同时乘上一个系数 \((1-p)\) 补偿训练过程的丢弃。
为啥有用:
- 取平均作用:不同轮次的 Dropout 可以视作不同的神经网络,产生不同的过拟合,能够相互抵消。
- 减少共适性关系:不应该对某些特定的特征特别敏感,迫使神经网络学习到具有鲁棒性的特征。
其它训练技巧
Batch Normalization
实现方式:
- 在神经网络的每一层输入层前加一个 BN 层,将输入归一化为均值为 0,方差为 1 的输入。
- BN 层增加两个可学习参数 \(\gamma, \beta\),用于对归一化后的数据进行线性变换。
生效原理:
- 缓解内部协变量偏移问题:使各层输入分布稳定,加速网络收敛,对于深度神经网络作用更大。
- 提升梯度传播效率:使输入保持在激活函数非饱和区内,有利于缓解梯度消失和梯度爆炸,同时也能避免参数初始化时使训练陷入困境。
- 增强泛化能力*:由于 \(\gamma,\beta\) 是可学习的,因此训练过程会对数据进行一些小扰动,可能能增强泛化能力。
卷积神经网络(CNN)
卷积层
卷积核
我不懂为啥要叫卷积,但是卷积核是对对应的小矩阵做点乘,然后得到一个数作为特征值。
一个卷积层可能有多个卷积核,不同卷积核可以提取不同的特征,最后卷出来的结果是个张量。
参数
大小:常见的有 3x3 和 5x5,较小的卷积核能够捕捉精细特征,较大的可以捕获更广泛的上下文信息。
步长:决定卷积核在数据上滑动的间隔,步长越大,特征图输出越小。
填充:在图像边缘添加额外像素,控制输出特征图的大小。
权重:卷积核每个位置的值叫做权重,这个是可以学习的。
偏置:每个卷积核有一个偏置值,也是可以学习的。
作用
有效提取各种局部特征。
池化层
结构
- 池化窗口:一般设置为 2x2 或者 3x3,决定每次考虑的局部区域大小
- 池化方式:最大池化或者平均池化,前者取最大值并保留,后者取平均值并保留。
- 池化步长:和卷积层的步长差不多,决定特征图大小用的。
用途
降低特征图维度,减少计算量,同时保留重要的局部特征信息。
全连接层
一般放在最后几层,用于整合前面提取的特征,输出最终的结果。
优势
- 天然适用于处理图像,能够有效提取图像局部特征并完成图像相关任务。
一般使用方式
- 通常会堆很多层,非常深,一层卷积带一层池化这样。
改进
ResNet
引入了残差块,解决了深层神经网络梯度消失的问题。卧槽了这 TM
也能管用。
残差块是在两个卷积层的基础上直接拉了一个恒等偏置过来。假设一个残差块的输入是 \(x\),输出 \(H(x)\),卷积层结构是 \(F(x, W_i)\),那么令: \[ H(x) = x + F(x, W_i) \]
参与学习的参数只有 \(W_i\),这样反向传播链式求导的时候梯度能直接从 \(x\) 这一项传到前面去,神秘的解决了梯度消失问题。
循环神经网络(RNN)
结构
输入
- 当前时刻的输入 \(x_t\):表示当前时间步的输入数据,例如在自然语言处理中,*\(x_t\) 可以是一个单词的嵌入向量。
- 上一时刻的隐藏状态 \(h_{t-1}\):表示上一时间步的输出状态,用于传递之前的信息。
输出
- 当前时刻的隐藏状态 \(h_t\):用于传递给下一个时间步。
- 当前时刻的输出 \(y_t\)(可选):在某些任务中,RNN 的每个时间步都会产生一个输出,例如在字符级语言模型中,\(y_t\) 可以表示下一个字符的概率分布。
状态公式
\[ h_t=\sigma(W_{hh}h_{t-1}+W_{xh}x_t+b_t) \]
- \(W_{hh}\):隐藏状态转移公式。
- \(W_{xh}\):输入到隐藏贡献公式。
- \(\sigma\):激活函数。
- \(b_h\):偏置项。
训练过程
一般用 BackPropagation Through Time(BPTT)算法进行权重更新,过程如下:
- 前向传播:从 \(t=1\) 开始一次计算隐藏状态和输出。
- 计算损失:计算所有输出的损失函数。
- 反向传播:从 \(t=T\) 开始依次计算每个时间步的梯度,最后梯度加在一起更新。
优缺点
优势
- 能处理变长的输入。
缺点
- 梯度消失:处理过长的序列时,容易发生梯度消失,导致无法捕捉长距离的依赖。
- 梯度爆炸:处理过长的序列时,容易发生梯度爆炸,导致权重更新过大,训练过程不稳定。
长短期记忆网络(LSTM)
RNN 的问题很大,所以衍生出了 RNN 的变体:LSTM。
LSTM 通过门控机制巧妙地解决了 RNN 的长距离依赖问题。遗忘门能够控制信息的遗忘,输入门能够选择性地添加新信息,而输出门则能够控制信息的输出。这三个门的协同作用使得 LSTM 能够有效地学习和存储长期序列信息,并且能够避免梯度消失问题。
结构
LSTM 的核心是记忆单元(cell)。
关键状态
记忆状态:cell 状态能够长时间的存储时间序列中的信息,其信息数据受门的控制,能够将所需的信息稳定的沿时间轴传递。
隐藏状态:同基础 RNN 的隐藏状态。
门
- 遗忘门:
- 功能:决定 cell 中旧信息的遗忘程度。
- 运行:通过一个 sigmoid 函数来产生一个值在 0 和 1 之间的遗忘率。0 表示完全遗忘,1 表示完全保留。它接受前一时间步的隐藏状态和当前时间步的输入作为输入,产生遗忘矩阵 \(f_t\) 作为输出。
- 公式:\(f_t=\sigma(W_f\cdot [h_{t-1}, x_t]+b_f)\)。
- 输入门:
- 功能:决定是否需要将新的信息存储到细胞状态中。
- 运行方式:输入门同样通过一个 sigmoid 函数计算一个值在 0 和 1 之间的输入率。这个输入率决定了有多少新信息会被允许存储到细胞状态中,输入同遗忘门。
- 公式表示:\(i_t=\sigma(W_i\cdot [h_{t-1}, x_t]+b_i)\)
- 输出门:
- 功能:决定当前时间步的输出。
- 运行方式:通过 sigmoid 函数计算一个输出矩阵,决定细胞状态信息的输出率,输出率描述了多大比例的细胞状态信息会被激活并传递出去。
- 公式表示:\(o_t=\sigma(W_o\cdot[h_{t-1}, x_t]+b_o)\)。
状态更新
计算候选细胞状态
\[ \tilde{C_t}=\tanh{W_C\cdot[h_{t-1}, x_t]+b_C} \]
候选细胞状态描述了当前信息对长期记忆的影响,参与细胞状态的更新。
更新细胞状态
\[ C_t=f_t\odot C_{t-1}+i_t\odot \tilde{C_t} \]
新细胞状态由上次细胞状态遗忘一部分,加上当前信息的候选状态补充进去。
更新隐藏状态
\[ h_t = o_t\odot \tanh{C_t} \]
隐藏状态通过当前的记忆来更新。
BiLSTM
BiLSTM 对传统的 LSTM 的扩展。相较于传统的单向 LSTM 只能捕捉序列中过去的信息,BiLSTM 能够同时捕捉序列中的过去和未来信息。
结构
BiLSTM 就是两个 LSTM 拼接起来的,一个输入的是正向序列,另一个输入反向序列。
两个序列算出对应位置的 \(h^{f}_t,h_{t}^{b}\) 后,再拼接成一个新向量 \(h_t\)。
最后从 \(h_t\) 里面解析信息出来。
GRM
GRM 是 LSTM 爆改过来的,减少了门的数量以降低复杂度但效果能得到一定保证。
GRU 通过更新门和重置门的协同作用,实现了对隐藏状态的有效更新。更新门决定了保留多少过去的信息,重置门决定了当前输入对隐藏状态的影响程度。这种门控机制使得 GRU 能够在低计算成本下处理长期依赖序列数据,避免了传统 RNN 中的梯度消失问题。
结构
- 更新门(Update Gate):
- 决定当前隐藏状态中保留多少过去的信息,以及从当前输入中引入多少新信息。
- 其计算公式为:\(z_t = \sigma(W_z\cdot[h_{t-1}, x] + b_z)\)。
- 重置门(Reset Gate):
- 决定当前输入信息对当前隐藏状态的影响程度,控制对过去信息的依赖。
- 其计算公式为:\(r_t = \sigma(W_r\cdot[h_{t-1}, x] + b_r)\)。
状态转移
计算候选隐藏状态: \[ \tilde{h_t} = \tanh(W_h\cdot[h_{t-1}, x] + b_h) \]
在考虑重置门的作用后,通过当前输入和经过重置门处理后的前一时刻隐藏状态计算得到。
隐藏状态更新: \[ h_t=z_t\odot h_{t-1}+(1-z_t)\odot\tilde{h_t} \]
最终的隐藏状态由更新门控制,结合了前一时刻的隐藏状态和当前的候选隐藏状态。