神经网络学习笔记

前置知识

导数 VS 微分

导数就是导函数。

\(f\) 的微分 \(df\) 可以看作一个函数,(一维的情况下)它将 \(dx\) 映射到 \(f'(x)dx\)

\(dx\) 怎么理解看个人,我没有把它当成函数,而是把它当成了一个单纯的记号。

梯度 VS 微分

梯度是高维意义下的导数。

  1. 梯度的定义: 梯度是一个向量,包含函数的所有偏导数。对于函数 \(f(x,y)\),其梯度为: \[ \nabla f = \left( \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y} \right) \] 梯度指向函数值增加最快的方向。

  2. 微分的定义: 微分描述了函数在自变量微小变化时的改变。对于函数 \(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 函数,这个时候会采取某些方式来处理。

  1. 归到某一边:反正概率挺小的,直接认为可导归到其中一边就行。
  2. 使用次梯度:如果它是个凸函数,可以用次梯度近似替代。
  3. 用可导函数近似:找个长得差不多的可导函数,不可微的点用这个函数的微分替代。

批次训练与梯度累计

神经网络一般采用批次训练的方式,利用 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)

结构

输入

  1. 当前时刻的输入 \(x_t\):表示当前时间步的输入数据,例如在自然语言处理中,*\(x_t\) 可以是一个单词的嵌入向量。
  2. 上一时刻的隐藏状态 \(h_{t-1}\):表示上一时间步的输出状态,用于传递之前的信息。

输出

  1. 当前时刻的隐藏状态 \(h_t\):用于传递给下一个时间步。
  2. 当前时刻的输出 \(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 中的梯度消失问题。

结构

  1. 更新门(Update Gate)
    • 决定当前隐藏状态中保留多少过去的信息,以及从当前输入中引入多少新信息。
    • 其计算公式为:\(z_t = \sigma(W_z\cdot[h_{t-1}, x] + b_z)\)
  2. 重置门(Reset Gate)
    • 决定当前输入信息对当前隐藏状态的影响程度,控制对过去信息的依赖。
    • 其计算公式为:\(r_t = \sigma(W_r\cdot[h_{t-1}, x] + b_r)\)

状态转移

  1. 计算候选隐藏状态\[ \tilde{h_t} = \tanh(W_h\cdot[h_{t-1}, x] + b_h) \]

    在考虑重置门的作用后,通过当前输入和经过重置门处理后的前一时刻隐藏状态计算得到。

  2. 隐藏状态更新\[ h_t=z_t\odot h_{t-1}+(1-z_t)\odot\tilde{h_t} \]

    最终的隐藏状态由更新门控制,结合了前一时刻的隐藏状态和当前的候选隐藏状态。