Jack He's Blog

some idea or work

输入为向量序列

[!question] 在图像识别的时候,假设输入的图像大小都是一样的。但如果输入是一组向量,并且输入的向量的数量是会改变的,即每次模型输入的序列长度都不一样,这个时候应该要怎么处理呢?
eg. 文字处理、声音信号

  • one-hot encoding:看不到词汇之间的关系
  • word embedding: 对每个词汇投影成一个向量

输入和输出数量相同

  • 词性标注(Part-Of-Speech, POS)
    image.png|475

输入为一个序列,输出为一个标签

  • 情感分析
    image.png|475

序列到序列

我们不知道应该输出多少个标签,机器要自己决定输出多少个标签

  • 翻译
  • 语音识别

image.png|475

自注意力运作原理

对第一种类型处理

与RNN那节一样,如果直接用FC的话,会丢失上下文信息。
对于这种问题,可以考虑将前后向量串起来丢到FC中

问题:window有长有短,按照最大的设置window,会导致FC参数太多
image.png|500

自注意力

自注意力模型会“吃”整个序列的数据,输入几个向量,它就输出几个向量

在注意力下的全连接网络不是只考虑一个非常小的范围或一个小的窗口,而是考虑整个序列的信息,再来决定现在应该要输出什么样的结果

image.png|425

自注意力模型不是只能用一次,可以叠加很多次。如图,self-attention -> FC -> self-attention。全连接网络专注于处理某一个位置的信息,自注意力把整个序列信息再处理一次。
image.png|425

运作

输入是一串的向量,这个向量可能是整个网络的输入,也可能是某个隐藏层的输出,用 $a$ 来表示它,代表它可能是前面已经做过一些处理,是某个隐藏层的输出。输入一组向量 $a$,自注意力要输出一组向量 $b$,每个 $b$ 都是考虑了所有的 $a$ 以后才生成出来的。

$b^1、b^2、b^3、b^4$ 是考虑整个输入的序列$a^1、a^2、a^3、a^4$ 才产生出来的。

$b^i$产生过程

根据$a^1$找出输入序列中与$a^1$有关的向量,怎么判断关联性?需要有一个计算关联度的模块
image.png|350

计算注意力的模块使用两个向量作为输入,直接输出数值 α,α 可以当做两个向量的关联的程度。

常见的计算$\alpha$的方法是做点积,将输入的两个向量分别乘上不同的矩阵,左边的乘上$W^q$,右边的乘上$W^k$,得到向量$q$和$k$后,再对两个向量做点积,得到标量$\alpha$
image.png

自注意力模型一般采用查询-键-值(Query Key-Value,QKV)模式。分别计算 $a^1$ 与 $a^2$、$a^3$、$a^4$ 之间的关联性 $α$。

image.png|500

把 $a^{1}$ 乘上 $W^{q}$ 得到 $q^1$。$q$ 称为查询(query),它就像是我们使用搜索引擎查找相关文章所使用的关键字,所以称之为查询。

接下来要去把 $a^2$、$a^3$、$a^4$ 乘上 $W^k$ 得到向量 $k$,向量 $k$ 称为键(key)。把查询 $q^1$ 跟键$k^2$ 算内积(inner-product)就得到 $α_{1,2}$,代表查询是 $q^1$ 提供的,键是 $k^2$ 提供的时候,$q^1$ 跟 $k^2$ 之间的关联性。关联性 $α$ 也被称为注意力的分数。后面同理。

一般$a^1$和自己也有关联性,故用$q^1$与$k^1$做内积得到$\alpha_{1,1}$

得到关联性之后,还需要过一层softmax(不一定要softmax,其他激活也可以)
$$
\alpha’{1,i}=\left( \frac{\exp \alpha{1,i}}{\sum_{j}^{} \exp(\alpha_{1,j})} \right)
$$
$\alpha$说明哪些向量与$a^1$最有关系。
image.png

再根据关联性抽取信息:

  • 将向量$a^1,\dots,a^4$分别乘以矩阵$W^v$,得到新的向量$v^1,\dots,v^4$,将每个向量乘以注意力分数$\alpha’$再加起来

$$
b^1 = \sum_{i}^{}\alpha’_{1,i}v^i
$$

  • 关联性大,那么$\alpha_{1,i}$就回答,对应的$v$就会主导抽取结果

image.png|475

矩阵计算角度

image.png|475

image.png|475
image.png|500

整理

image.png|475

唯一需要学习的内容是$W^k,W^q,W^v$,需要通过训练数据找到

多头自注意力

在一些任务,如翻译、语音识别等,用较多的头可以得到比较好的结果。但是需要多少个头是一个超参数

[!question] 为什么要多头
相关有很多种不同的形式,也许可以有多个$q$,不同的$q$负责不同种类的相关性,这就是多头注意力

简单来说,就是先得到$q$,再让$q$乘以两个不同的矩阵,得到$q^1,q^2$。$q^{i,1},q^{i,2}$代表两个头,1和2代表这个位置的第几个$q$,$i$代表的是位置。对$k,v$同理

image.png|400
image.png|400

最后得到的$b^{i,1},b^{i,2}$需要再过一个矩阵才能得到$b^i$

位置编码

发现目前还没有考虑输入的位置对结果的影响,即每一个输入是出现在序列的最前面还是最后面?对一个自注意力层而言,它是完全没有这个信息的

即$q^1,q^2,q^3,q^4$的距离并没有进行特殊处理

但位置信息很重要,例如词性标注,动词很少在句首

故引入了位置编码

每一个位置设定一个vector,不同的位置就有不同的向量,用$e^i$来表示
于是用$e^i + a^i$来表示现在出现的位置在$i$这个位置

[!info] 这里不一定是 + ,在《Attention is all you need》里面是相加的形式,但是后来的RoPE就是乘的形式了

image.png

最早的位置编码是人设的,但在Attention文章中使用的是正弦函数和余弦函数产生位置向量
image.png|275

截断自注意力

在特定领域上,向量可能会很长。而在计算注意力矩阵时,计算复杂度是向量序列长度的平方。假设向量序列长度为$L$,则计算注意力矩阵$A’$需要$L \times L$次内积,如果$L$过大,计算量和需要的内存就会很大。不容易训练。

截断自注意力可以解决向量序列过长问题。只看一个小的范围。
在做自注意力的时候,也许没有必要让自注意力考虑一整个句子,只需要考虑一个小范围就好。(eg. 做语音辨识,如果要辨识某个位置的音标、内容,可以只看这句话和其前后范围的信息,并不需要看整段话)

对比自注意力和卷积神经网络

自注意力还可以被用在图像上。
到目前为止,在提到自注意力的时候,自注意力适用的范围是输入为一组向量的时候。

一张图像可以看作是一个向量序列,如图所示,一张分辨率为 5 × 10 的图像可以表示为一个大小为 5 × 10 × 3 的张量。

3 代表 RGB 这 3 个通道(channel),每一个位置的像素可看作是一个三维的向量,整张图像是5 × 10 个向量。所以可以换一个角度来看图像,图像其实也是一个向量序列,它既然也是一个向量序列,完全可以用自注意力来处理一张图像。

image.png

CNN: 简化版的self-attention,神经元只学习感受野内的信息

在做内积的时候,自注意力考虑的不是一个小的感受野范围,而是整个图像的信息。好像感受野是自动学出来的,网络自行决定感受野大小。

但更灵活的模型需要更多的数据进行学习,如果不够就容易过拟合。

image.png|425

随着资料量增多,self-attention效果会提高。

自注意力与RNN

image.png

区别1

假设把循环神经网络的输出跟自注意力的输出拿来做对比,就算使用双向循环神经网络还是有一些差别的。

如图,对于循环神经网络,如果最右边黄色的向量要考虑最左边的输入,它就必须把最左边的输入存在记忆里面,才能不“忘掉”,一路带到最右边,才能够在最后一个时间点被考虑。

但自注意力输出一个查询,输出一个键,只要它们匹配(match)得起来,“天涯若比邻”。自注意力可以轻易地从整个序列上非常远的向量抽取信息

区别2

更主要的不同是,循环神经网络在处理输入、输出均为一组序列的时候,是没有办法并行化的。比如计算第二个输出的向量,不仅需要第二个输入的向量,还需要前一个时间点的输出向量。

当输入是一组向量,输出是另一组向量的时候,循环神经网络无法并行处理所有的输出,但自注意力可以。

自注意力输入一组向量,输出的时候,每一个向量是同时并行产生的,因此在运算速度上,自注意力会比循环神经网络更有效率。

图上的自注意力机制

图也可以看作是一堆向量,如果是一堆向量,就可以用自注意力来处理。

但把自注意力用在图上面,会有些地方不一样。图中的每一个节点(node)可以表示成一个向量。但我们不只有节点的信息,还有边(edge)的信息

如果节点之间是有相连的,这些节点也就是有关联的。之前在做自注意力的时候,所谓的关联性是网络自己找出来的。但是现在既然有了图的信息,关联性就不需要机器自动找出来,图上面的边已经暗示了节点跟节点之间的关联性

所以当把自注意力用在图上面的时候,我们可以在计算注意力矩阵的时候,只计算有边相连的节点就好

image.png|450

深度神经网络更难训练。我们提出了一个残差学习框架来简化网络的训练,这些网络比以前使用的要深得多。

Resnet到底在解决一个什么问题呢? - 薰风初入弦的回答 - 知乎

Introduction

[!question] 学习更好的网络就像堆叠更多的层一样简单吗?
回答这个问题的一个障碍是臭名昭著的梯度消失/爆炸问题,它从一开始就阻碍了收敛。

然而,这个问题已经通过规范化初始化(Normalization)和中间规范化层(Batch Normalization)得到了很大程度的解决,这使得具有数十层的网络能够开始收敛随机梯度下降(SGD),并可以反向传播

[!question] 更深的网络性能会变好吗?
image.png
不是欠拟合,而是梯度消失无法继续训练
随着网络深度的增加,精度趋于饱和

判断是否过拟合:过拟合情况应该训练误差也变得很低,但是在上图中会看到与实际情况不符

这一段有点反直觉:

[!note] 更深的网络效果不会比浅的网络效果差
(训练精度的)退化表明,并非所有系统都同样容易优化。让我们考虑一个较浅的体系结构和它的更深的对应物,它在上面添加了更多的层。
通过构造更深的模型存在一个解决方案:添加的层是身份映射(identify mapping,输入 $x$ 输出 $x$ ),其他层是从学习的较浅模型复制的。这种构造解的存在表明,较深的模型不会比较浅的模型产生更高的训练误差。但实验表明,我们现有的求解器无法找到与构建的解决方案相当或更好的解决方案(或者无法在可行时间内做到这一点)。

解决上面的问题,提出残差网络

在本文中,我们通过引入深度残差学习框架来解决退化问题。我们不是希望每几个堆叠层直接符合期望的底层映射,而是明确地让这些层符合残差映射

形式上,将期望的底层映射表示为$H(x)$,我们让堆叠的非线性层适合另一个映射$F(x):= H(x) - x$(学习的内容)。原始映射被重铸为$F(x)+x$。我们假设优化残差映射比优化原始的、未引用的映射更容易。在极端情况下,如果一个恒等映射是最优的,将残差推至零要比用一堆非线性层拟合一个恒等映射容易得多。

学习的不是原本的$x$,而是残差

image.png|475
shortcut connection实际上做的就是identity mapping
不会增加模型复杂度

越深,精度越高

Related work

残差表示:统计和机器学习里面用的多,比如GBDT、线性模型的残差拟合

shortcut connection

Deep Residual Learning

$$
\mathbf{y}=\mathcal F(\mathbf{x}, {W_{i}}) +\mathbf{x}
$$

$\mathbf{x}, \mathbf{y}$ 是输入和输出层,$\mathcal F(\mathbf{x}, {W_{i}})$是学习的残差映射$\mathcal F=W_{2} \sigma (W_{1}\mathbf{x})$

要求:$\mathbf{x}$和$\mathcal F$的维度需要匹配
不匹配的解决方法,使用投影:
$$
\mathbf{y}=\mathcal F(\mathbf{x}, {W_{i}}) +W_{s}\mathbf{x}
$$

当输入和输出维度相同时(图中的实线快捷方式),可以直接使用标识快捷方式(Eqn.(1))。当维度增加时(图中的虚线快捷方式),我们考虑两种选择:(A)增加维度时填充额外的零项。这个选项不引入额外的参数;(B) Eqn.(2)中的投影方式用于匹配维度(通过1×1卷积完成)。对于这两个选项,当shortcuts跨越两个大小的feature maps时,它们的步幅为2

这里的意思是增加维度填充0,降维的时候使用$1 \times 1$卷积核?

image.png

Experiment

实验预处理:随机裁剪、翻转、标准化、批归一化

image.png

conv2_x这些表示的是一个块,一个块里面有里面有多个层
18的计算:$(2+2+2+2)(每个块的卷积层之和)\times 2(均出现2次) + 头卷积+ 尾全连接$
注意pooling一般不算层

实验结果

image.png
左侧为没加残差,右侧为加了残差。
中间突然下降是因为学习率乘了0.1

可以看到,有残差连接的收敛会快,且准确率更高

方案比较

当shortcuts输入输出维度不同时

  • A: 做0填充
  • B: 用$1 \times 1$卷积做投影
  • C: 对所有都做投影

结果:B和C差不多,但是B的参数量少
image.png

bottle neck

image.png

先做降维,再做$3 \times 3$卷积,再用$1 \times 1$卷积映射回去

总结

实际在做的事情

原本梯度计算

$$
\frac{\partial f(g(x))}{\partial x} = \frac{\partial f(g(x))}{\partial g(x)} \cdot \frac{\partial g(x)}{\partial x}
$$
会因为一直累乘而趋于0

但现在的求梯度:

$$
\frac{\partial f(g(x)) + g(x)}{\partial x} = \frac{\partial f(g(x))}{\partial g(x)} \cdot \frac{\partial g(x)}{\partial x} + \frac{\partial g(x)}{\partial x}
$$

这样可以把梯度变大

残差块

使得网络没那么快收敛,能够训练的动,就更难陷入局部最优解

这里的residual和GBDT的residual不同

到目前为止我们默认数据都来自于某种分布, 并且所有样本都是独立同分布的 (independently and identically distributed,i.i.d.)。 然而,大多数的数据并非如此。例如,文章中的单词是按顺序写的,如果顺序被随机地重排,就很难理解文章原始的意思。同样,视频中的图像帧、对话中的音频信号以及网站上的浏览行为都是有顺序的。 因此,针对此类数据而设计特定模型,可能效果会更好。
另一个问题来自这样一个事实: 我们不仅仅可以接收一个序列作为输入,而是还可能期望继续猜测这个序列的后续。例如,一个任务可以是继续预测2,4,6,8,10,…。这在时间序列分析中是相当常见的,可以用来预测股市的波动、患者的体温曲线或者赛车所需的加速度。 同理,我们需要能够处理这些数据的特定模型。
简言之,如果说卷积神经网络可以有效地处理空间信息,那么本章的 循环神经网络 (recurrent neural network,RNN)则可以更好地处理序列信息。 循环神经网络通过引入状态变量存储过去的信息和当前的输入,从而可以确定当前的输出。

基本介绍

为了让神经网络有记忆力,能够对一段长序列进行处理
前馈神经网络只能针对单个向量处理,因此对于同一个输入会得到同一个输出,但却没有考虑前面的输入对当前的时刻带来的影响
image.png|575

在 RNN 里面,每一次隐藏层的神经元产生输出的时候,该输出会被存到记忆元(memory cell),图中的蓝色方块表示记忆元。下一次有输入时,这些神经元不仅会考虑输入 $x_1$, $x_2$,还会考虑存到记忆元里的值。除了 $x_1$, $x_2$,存在记忆元里的值 $a_1$, $a_2$ 也会影响神经网络的输出。

image.png|525

发现即使是对于相同的输入,由于有隐状态的存在,会使得输出也是不同的

有了记忆元以后,输入同一个单词,希望输出不同的问题就有可能被解决。
image.png|575

数学表达

RNN的基本单元与传统的前馈神经网络类似,但其隐藏层会在每一个时间步(time step)将当前输入和前一个时间步的隐藏状态结合起来。具体来说,RNN 在每一个时间步t的隐藏状态$ℎ_t$是由当前输入$x_t$和前一个时间步的隐藏状态$ℎ_{t−1}$共同决定的

$$
h_{t} = \sigma(W_{h} \cdot h_{t-1} + W_{x} \cdot x_{t} + b)
$$

  • $h_{t}$时间步$t$的隐藏状态
  • $x_{t}$ 为时间步 $t$ 的输入
  • $W_{h}$和$W_{x}$是权重矩阵
  • $b$是偏置
  • $\sigma$是激活函数(如tanh或ReLU)

image.png

最终的输出公式:
$$
y_{t} = g(W_{y} h_{t}+c)
$$

其他RNN

之前提到的 RNN 只有一个隐藏层,但 RNN 也可以是深层的。比如把 $x_t$ 丢进去之后,它可以通过一个隐藏层,再通过第二个隐藏层,以此类推 (通过很多的隐藏层) 才得到最后的输出。每一个隐藏层的输出都会被存在记忆元里面,在下一个时间点的时候,每一个隐藏层会把前一个时间点存的值再读出来,以此类推最后得到输出,这个过程会一直持续下去。

image.png|600

Elman & Jordan

Elman: 把隐藏层的值存起来,下一个时间点读出来
Jordan:存的是整个网络输出的值,会把输出值在下一个时间点读进来,并把输出都存到记忆元里

image.png|600

双向

网络不只是看过 $x_1$, 到 $x_{t+1}$ 所有的输入,它也看了从句尾到 $x_{t+1}$ 的输入。网络就等于整个输入的序列。假设考虑的是槽填充,网络就等于看了整个句子后,才决定每一个单词的槽,这样会比看句子的一半还要得到更好的性能。

image.png|600

RNN的梯度计算

随时间反向传播

在RNN中,参数的更新通过反向传播算法进行,具体是在时间维度上展开的反向传播,称为“时间反向传播”(BPTT)。与标准的反向传播不同,BPTT需要处理RNN的循环结构,即在多个时间步之间传播误差。

BPTT的基本步骤包括:

  1. 前向传播:
    在前向传播过程中,从 $t = 1$ 到 $t = T$ 按顺序计算隐状态和输出。

  2. 误差计算:
    对于每个时间步 $t$,计算输出层的误差 $\delta_t$:
    $$
    \delta_t = \frac{\partial L}{\partial \mathbf{y}_t} \cdot g’(\mathbf{y}_t)
    $$
    其中,$L$ 是损失函数,$g’(\mathbf{y}_t)$ 是输出激活函数的导数。$\dfrac{\partial y_t}{\partial L​}​$ 是损失函数对输出的梯度。$g’(\mathbf{y}_t)$ 是输出激活函数的导数(如果使用softmax激活函数,通常是一个雅可比矩阵)。

  3. 反向传播误差到隐状态:
    接着,将误差从输出层传递到隐状态层,计算隐状态误差 $\delta_h$:$$
    \delta_h = \frac{\partial L}{\partial \mathbf{h}_t} = \delta_t \cdot W_y^T \cdot f’(\mathbf{h}_t)
    $$
    其中,$f’(\mathbf{h}t)$ 是隐状态激活函数的导数。$\delta{t}$​ 是输出误差,$W_y^T$​ 是输出层到隐状态的权重矩阵的转置。

  4. 时间步之间误差的传播:
    由于RNN的隐状态依赖于前一时间步的隐状态,误差需要反向传播回多个时间步。对于每个时间步 $t$,计算误差在前一时间步的传播:
    $$
    \delta_{h_{t-1}} = \delta_h \cdot W_h^T \cdot f’(\mathbf{h}_{t-1})
    $$
    这种方式从后往前(从 $T$ 到 $1$)递归地传递误差,直到到达序列的开始。

  5. 梯度计算:
    一旦计算了误差,使用链式法则计算各个参数的梯度:

    • 对于 $W_h$,梯度计算为:
      $$
      \frac{\partial L}{\partial W_h} = \sum_{t=1}^T \delta_{h_{t}} \cdot \mathbf{h}{t-1}^T
      $$
      这个梯度的含义是:每个时间步的误差 $\delta
      {h_t}$​​ 乘以前一个时间步的隐状态 $\mathbf{h}_{t-1}$​,然后在所有时间步上求和,得到参数 $W_h$​ 的梯度。
    • 对于 $W_x$,梯度计算为:
      $$
      \frac{\partial L}{\partial W_x} = \sum_{t=1}^T \delta_{h_{t}} \cdot \mathbf{x}_t^T
      $$
    • 对于 $W_y$,梯度计算为:
      $$
      \frac{\partial L}{\partial W_y} = \sum_{t=1}^T \delta_{t} \cdot \mathbf{h}_t^T
      $$
    • 对于偏置项 $b$ 和 $c$,梯度计算为:
      $$
      \frac{\partial L}{\partial b} = \sum_{t=1}^T \delta_{h_{t}}
      $$
      $$
      \frac{\partial L}{\partial c} = \sum_{t=1}^T \delta_{t}
      $$
  6. 参数更新:
    使用梯度下降或其他优化算法(如Adam)更新模型的参数:
    $$
    W_h = W_h - \eta \cdot \frac{\partial L}{\partial W_h}
    $$
    $$
    W_x = W_x - \eta \cdot \frac{\partial L}{\partial W_x}
    $$
    $$
    W_y = W_y - \eta \cdot \frac{\partial L}{\partial W_y}
    $$
    $$
    b = b - \eta \cdot \frac{\partial L}{\partial b}
    $$
    $$
    c = c - \eta \cdot \frac{\partial L}{\partial c}
    $$
    其中,$\eta$ 是学习率。

总结

  • RNN的核心:通过隐状态的循环连接处理序列数据,每个时间步的输出依赖于当前输入和前一时间步的隐状态。
  • BPTT:是RNN中用于训练的反向传播算法,通过反向传播误差在时间步之间传播,计算每个时间步的梯度,最终更新网络参数。

训练问题

RNN 的训练是比较困难的,一般而言,在做训练的时候,期待学习曲线是像蓝色这条线,这边的纵轴是总损失(total loss),横轴是回合的数量,我们会希望随着回合的数量越来越多,随着参数不断的更新,损失会慢慢地下降,最后趋向收敛。但是不幸的是,在训练循环神经网络的时候,有时候会看到绿色这条线。

image.png

出现这种状况的原因是RNN的误差表面有的地方非常平坦,但有的地方又非常陡峭,可能会导致损失快速震荡以及梯度消失问题。
image.png|400

  • 梯度消失:在长时间序列的训练过程中,通过反向传播计算梯度时,误差在传播回前面时间步时会逐渐变小。如果RNN中使用的是tanh或sigmoid等激活函数,它们的梯度会在某些情况下变得非常小(尤其是在极端输入的情况下)。当误差被反向传播到很远的时间步时,梯度会变得几乎为零,这导致网络无法有效地学习长期依赖关系。
    • 具体来说,假设在每个时间步 ttt,隐状态 $\mathbf{h}t$​ 的更新包含了一个梯度乘积 $\prod{i=1}^t W_{h}$ ​(每一步都包含一个与权重相关的梯度)。当该梯度过小时,整个梯度也会被缩小,导致远程时间步的信息几乎无法传递。
  • 梯度爆炸:每次梯度传播时,如果权重矩阵的值过大,就可能导致梯度变得过大,进而导致数值不稳定,甚至出现溢出。
    • 这种情况出现的原因不是因为激活函数,而是由于同样的权重在不同的时间点被反复使用。

现代循环神经网络

我们可能会遇到这样的情况:

  • 早期观测值对预测所有未来观测值具有非常重要的意义。
    • 考虑一个极端情况,其中第一个观测值包含一个校验和,目标是在序列的末尾辨别校验和是否正确。在这种情况下,第一个词元的影响至关重要。我们希望有某些机制能够在一个记忆元里存储重要的早期信息。如果没有这样的机制,我们将不得不给这个观测值指定一个非常大的梯度,因为它会影响所有后续的观测值。
  • 一些词元没有相关的观测值
    • 例如,在对网页内容进行情感分析时,可能有一些辅助HTML代码与网页传达的情绪无关。我们希望有一些机制来 跳过 隐状态表示中的此类词元。
  • 序列的各个部分之间存在逻辑中断
    • 例如,书的章节之间可能会有过渡存在,或者证券的熊市和牛市之间可能会有过渡存在。 在这种情况下,最好有一种方法来 重置 我们的内部状态表示。

同时,考虑到上面提出的长程依赖问题,需要对梯度进行处理

长短期记忆网络

[!info] Lee 在这部分使用的符号表示比较特别(混乱),下面有其他的表示方式

image.png|300

4个输入,1个输出,LSTM 通过引入“记忆单元”(cell state)和“门机制”(gates)来更好地管理信息的流动。

三个门

  • 输入门:输入门要被打开的时候,才能把值写到记忆元里面。如果把这个关起来的话,就没有办法把值写进去。
  • 输出门:会决定外界其他的神经元能否从这个记忆元里面把值读出来。把输出门关闭的时候是没有办法把值读出来,输出门打开的时候才可以把值读出来。
  • 遗忘门:决定什么时候记忆元要把过去记得的东西忘掉。

“-”应该在 short-term 中间,是长时间的短期记忆。之前的循环神经网络,它的记忆元在每一个时间点都会被洗掉,只要有新的输入进来,每一个时间点都会把记忆元洗掉,所以的短期是非常短的,但如果是长时间的短期记忆元,它记得会比较久一点,只要遗忘门不要决定要忘记,它的值就会被存起来。

网络自己会学到什么时候开门和关门

image.png|500

记忆元计算公式
$$
c’=g(z)f(z_{i})+cf(z_{f})
$$
也有写作
$$
c_{t} = \tilde{c_{t}} \odot i_{t} + c_{t-1} \odot f_{t}
$$
其中,$\odot$ 是按元素乘

假设:

  • 存到单元的输入叫做 $z$ (这里是因为有可能前面还过了LSTM层,所以记成 $z$,但是一般也可以直接写成 $\mathbf{x_{t}}$,这里这么写是因为把 $\mathbf{x_{t}}$ 进行了拆分:$\mathbf{x}{t} = [z, z{i}, z_{f}, z_{o}]$)
  • 操控输入门的信号为 $z_i$ ,对应激活后的结果是$f(z_{i})$(也可写作$i_{t}$,$i_{t} = \sigma (W_{i} \cdot [\mathbf{h}{t-1},\mathbf{x{t}}] + b_{i}$)
  • 操控遗忘门的信号为 $z_f$ ,对应激活后的结果是$f(z_{f})$(也可写作$f_{t}$,$f_{t} = \sigma(W_{f} \cdot [\mathbf{h_{t-1}, \mathbf{x}{t}}] + b{f})$)
  • 操控输出门为 $z_o$,对应激活后的结果为 $f(o_{t})$(也可写作$o_{t}$,$o_{t} = \sigma(W_{o} \cdot [\mathbf{h}{t-1}, \mathbf{x{t}}] + b_{o})$)
  • 输出记为 $a$,即隐状态$\mathbf{h_{t}}$,$\mathbf{h_{t}} = o_{t} \odot \tanh(c_{t})$
  • 单元初始值 $c$,即 $c_{t-1}$
  • 激活后的候选状态即为 $g(z)$,也可写作$\tilde{c_{t}}$,即为激活后的新信息,$\tilde{c_{t}} = \tanh(W_{c} \mathbf{x}{t}+U{c}\mathbf{h}{t-1}+b{c})$

把 $z$ 通过激活函数得到 $g(z)$,$z_i$ 通过另外一个激活函数得到 $f(z_i)$ (激活函数通常会选择 sigmoid 函数,因为其值介在 0 到 1 之间的,这个 0 到 1 之间的值代表了这个门被打开的程度).如果 $f$ 的输出是 1,表示为被打开的状态,反之代表这个门是关起来的

接着把$g(z)$乘以$f(z_{i})$,得到$g(z)f(z_{i})$,遗忘门也通过sigmoid函数得到$f(z_{f})$,接下来相加得到上式。

遗忘门的开关是跟直觉是相反的,遗忘门打开的时候代表的是记得,关闭的时候代表的是遗忘

计算输出:$c’$通过tanh得到$h(c’)$,将其乘以激活的$f(z_{o})$得到$a=h(c’)f(z_{o})$。输出门受$f(z_{o})$操控

示意图2:
image.png

举例

网络里面只有一个 LSTM 的单元,输入都是三维的向量,输出都是一维的输出。这三维的向量跟输出还有记忆元的关系是这样的。假设 $x_2$ 的值是 1 时,$x_1$ 的就会被写到记忆元里;假设 $x_2$ 的值是-1 时,就会重置这个记忆元;假设 $x_3$ 的值为 1 时,才会把输出打开,才能看到输出,看到记忆元的数字。

于是更新过程如下
image.png|500

运算举例

image.png|450

直接代入,发现输入门通常是关闭的,只有当$x_{2}$有大于1的值才会打开;遗忘门通常是打开的,只有$x_{2}$是个大的负值才会关闭;输出门通常关闭,只有$x_{3}$有大于1的值才会打开

LSTM网络原理

可以把LSTM想成一个神经元

image.png|475

假设只有2个神经元,输入$x_{1},x_{2}$会乘以不同的权重当作输入,去控制输出门、输入门、底部输入和遗忘门。因此,假设用的神经元的数量跟 LSTM 是一样的,则 LSTM 需要的参数量是一般神经网络的四倍。

假设有一整排的 LSTM,这些 LSTM 里面的记忆元都存了一个值,把所有的值接起来就变成了向量,写为 $c_{t−1}$(一个值就代表一个维度)。现在在时间点 $t$,输入向量 $x_{t}$,经过矩阵乘法会变成$z,z_{i},z_{o},z_{f}$四个向量,向量维度与单元数量相同,随后将其作为输入,去操控所有的cell。
image.png|475

输入cell都是z的一个dimension,因此所有cell可以一起运算
image.png|500

但还不是最后的LSTM,还需要加上上一时刻输出的值$h_{t}$和peephole连接,即存在记忆元里面的值$c_{t}$。先将3个向量并在一起执行不同的变换,得到4个不同的向量,之后再操控LSTM。

image.png|500

于是多层的LSTM:
image.png|500

处理梯度问题

回到记忆单元更新的式子:
$$
c_{t} = f_{t} \odot c_{t-1} + i_{t} \odot \tilde{c_{t}}
$$

  • 记忆单元状态的梯度传递:在 LSTM 中,记忆单元状态的更新涉及到加法操作,使得梯度在时间步之间的传递变为:
    $$
    \frac{\partial \mathcal{L}}{\partial c_{t-1}} = \frac{\partial \mathcal{L}}{\partial c_t} \cdot \frac{\partial c_t}{\partial c_{t-1}} = \frac{\partial \mathcal{L}}{\partial c_t} \cdot f_t
    $$
    $$
    \frac{\partial \mathcal{L}}{\partial c_{t-k}} = \frac{\partial \mathcal{L}}{\partial c_t} \cdot \prod_{i=t-k+1}^{t} f_i
    $$
    这里的乘积$\prod_{i=t-k+1}^t f_{i}$中每个$f_{i}$的值都在 [0,1] 之间。如果所有的$f_{i}$都接近于1,梯度可以顺利传递;如果 $f_{i}$有一些接近0,会导致梯度快速衰减,从而避免梯度爆炸

  • 门控机制的设计:LSTM 的遗忘门、输入门和输出门是通过 sigmoid 函数来实现的,sigmoid 的输出范围是[0, 1]。这种门控机制可以灵活地控制信息流动,使得梯度在传播过程中不会出现极端的情况(如全是 0 或全是 1)

  • 记忆单元状态的加法更新:LSTM 的记忆单元状态更新是通过加法操作,而不是乘法操作。加法操作在反向传播时,梯度不会像乘法那样呈指数级增长或衰减。这是 LSTM 相比于传统 RNN 的一个重要改进。

  • 长短期记忆的平衡:LSTM 的设计初衷是平衡短期和长期记忆。遗忘门控制着旧信息的遗忘,输入门控制着新信息的记忆。通过这种平衡机制,LSTM 可以在处理长序列数据时,动态地选择保留或丢弃信息,从而在一定程度上缓解梯度消失或爆炸的问题。

[!info] 为什么Ilya说LSTM是一个旋转90度的ResNet?
这是Ilya在NIPS上的发言,虽然时间上ResNet比LSTM晚出,但当时应该没有人想到这两个网络之间存在的关联。也就是说,时间维度(LSTM)在一定程度上和深度是可以挂钩的。
我们考虑两个维度:网络深度和时间维度。网络深度指不同feature 存在于不同的layer然后在前向过程中不断地传到下一层的深度。时间维度指类似于 next word prediction 不断地通过过去的输出预测下一个词的时间步。

  • 对于 Resnet 来说,不同层的 feature 通过跨层residual直接将feature相加建立了联系,而不是通过 不同layer 的网络参数建立联系
  • 对于 LSTM 来说,不同时间步的 feature 通过反复经过同样的网络参数而建立联系, 而不是通过 直接将feature相加建立联系
  • 一个是网络深度维度的跨层链接(通过feauture共享),一个是时间维度 feature 在不同步的链接(通过参数共享)。
  • 不过这又引出了一个有意思的问题:其他维度是否也有一些 skip-connection的方法?

GRU 门控循环单元

[!info] 此处主要参考d2l

只有两个门,但性能差不多,且不太容易过拟合

门控循环单元与普通的循环神经网络之间的关键区别在于:前者支持隐状态的门控。这意味着模型有专门的机制来确定应该何时更新隐状态,以及应该何时重置隐状态。

重置门与更新门

我们把它们设计成(0,1)区间中的向量,这样我们就可以进行凸组合。重置门允许我们控制“可能还想记住”的过去状态的数量;更新门将允许我们控制新状态中有多少个是旧状态的副本。

image.png

我们来看一下门控循环单元的数学表达。对于给定的时间步$t$,假设输入是一个小批量 $X_t \in \mathbb{R}^{n \times h}$ (样本个数$n$,输入个数$d$),上一个时间步的隐状态是 $H_{t−1} \in \mathbb{R}^{n \times h}$ (隐藏单元个数$h$)。那么,重置门$R_t\in \mathbb{R}^{n \times h}$和 更新门$Z_t∈\mathbb{R}^{n \times h}$的计算如下所示:

$$
R_t = \sigma(X_t W_{xr} + H_{t-1} W_{hr} + b_r) = \sigma(W_{r} \cdot[H_{t-1}, X_{t}] + b_{r})
$$

$$
Z_t = \sigma(X_t W_{xz} + H_{t-1} W_{hz} + b_z) = \sigma(W_{z} \cdot[H_{t-1}, X_{t}] + b_{z})
$$

其中 $W_{xr}, W_{xz} \in \mathbb{R}^{d \times h}$ 和 $W_{hr}, W_{hz} \in \mathbb{R}^{h \times h}$ 是权重参数,$b_r, b_z \in \mathbb{R}^{1 \times h}$ 是偏置参数。请注意,在求和过程中会触发广播机制。我们使用 $\texttt{sigmoid}$ 函数将输入值转换到区间 $(0, 1)$

候选隐状态

接下来,让我们将重置 $\mathbf{R}_t$ 与常规隐状态更新机制集成,得到在时间步 $t$ 的候选隐状态(candidate hidden state) $\tilde{\mathbf{H}}_t \in \mathbb{R}^{n \times h}$:

$$
\tilde{\mathbf{H}}t = \tanh(\mathbf{X}t \mathbf{W}{zh} + (\mathbf{R}t \odot \mathbf{H}{t-1}) \mathbf{W}{hh} + \mathbf{b}h) = \tanh(W{h} \cdot [R_{t} \cdot H_{t-1 }, X_{t}]+b_{h})
$$

其中 $\mathbf{W}{zh} \in \mathbb{R}^{d \times h}$ 和 $\mathbf{W}{hh} \in \mathbb{R}^{h \times h}$ 是权重参数,$\mathbf{b}_h \in \mathbb{R}^{1 \times h}$ 是偏置项,符号 $\odot$ 是 Hadamard 积(按元素乘积)运算符。在这里,我们使用 $\tanh$ 非线性激活函数来确保候选隐状态中的值保持在区间 $(-1, 1)$ 中。

$\mathbf{R}t \odot \mathbf{H}{t-1}$ 的元素相乘可以减少以往状态的影响。每当重置门 $\mathbf{R}_t$ 中的项接近 1 时,我们恢复一个普通的循环神经网络。对于重置门 $\mathbf{R}_t$ 中所有接近 0 的项,候选隐状态是以 $\mathbf{X}_t$ 作为输入的多层感知机的结果。因此,任何预先存在的隐状态都会被重置为默认值。

image.png|475

隐状态

上述的计算结果只是候选隐状态,我们仍然需要结合更新门 $\mathbf{Z}_t$ 的效果。这一步确定新的隐状态 $\mathbf{H}t \in \mathbb{R}^{n \times h}$ 在多大程度上来自旧的状态 $\mathbf{H}{t-1}$ 和新的候选状态 $\tilde{\mathbf{H}}_t$。更新门 $\mathbf{Z}t$ 仅需要在 $\mathbf{H}{t-1}$ 和 $\tilde{\mathbf{H}}_t$ 之间进行按元素的凸组合就可以实现这个目标。这就得出了门控循环单元的最终更新公式:

$$
\mathbf{H}_t = \mathbf{Z}t \odot \mathbf{H}{t-1} + (1 - \mathbf{Z}_t) \odot \tilde{\mathbf{H}}_t
$$

每当更新门 $\mathbf{Z}_t$ 接近 1 时,模型就倾向只保留旧状态。此时,来自 $\mathbf{X}_t$ 的信息基本上被忽略,从而有效地跳过了依赖链中的时间步 $t$。相反,当 $\mathbf{Z}_t$ 接近 0 时,新的隐状态 $\mathbf{H}_t$ 就会接近候选隐状态 $\tilde{\mathbf{H}}_t$。

这些设计可以帮助我们处理循环神经网络的梯度消失问题,并更好地捕捉时间步距离很长的序列历史依赖关系。例如,如果整个子序列的所有时间步的更新门都接近于 1,则无论序列的长度如何,在序列起始时间步的旧隐状态都将很容易保留并传递到序列末。

image.png|500

总之,门控循环单元具有以下显著特征:

  • 重置门有助于捕获序列中的短期依赖关系,控制当前输入和前一隐藏状态的结合方式
  • 更新门有助于捕获序列中的长期依赖关系,决定了前一时刻隐藏状态中的信息保留多少

[!question] 为什么RNN中通常喜欢用 tanh 作为激活函数?

  • 与其他激活函数(如ReLU)相比,tanh在梯度计算和数值稳定性方面较为稳定。尽管ReLU在某些任务上表现优越(特别是在避免梯度消失的问题上),但其输出不对称,且在某些情况下会导致“梯度爆炸”或“死神经元”(对于负输入始终输出0)。相比之下,tanh更平滑,且避免了ReLU中可能遇到的一些数值不稳定问题。
  • tanh的输出范围是 [-1, 1],它是一个对称的激活函数。这意味着它可以处理负值和正值,这对于在RNN中捕捉和传递信息非常重要。相对而言,sigmoid函数的输出范围是 [0, 1],这可能会限制信息的传递,因为它不能表示负数。

Energy-based Out-of-distribution Detection

Energy-based Out-of-distribution Detection(NeurIPS 2020)

motivation:
使用softmax置信度分数会导致模型对OOD data的预测有较高的置信度(这与softmax的特性有关,也有深度神经网络训练的特性有关),这显然是不合理的。同时,有研究表明通过深度生成模型估计得到的密度函数对于OOD data的检测并不可靠。基于此,作者提出了energy score。

idea:
基于energy的模型将每个输入映射为一个标量,这个标量对于见过的数据(ID data)较低,对于未见过的数据(OOD data)较高。
一、使用energy score的一些优点:可以直接根据分类模型推导得到,而不依赖密度估计;可以解决模型对OOD data的预测过度自信的问题;使用方便,是一个无参数度量。
二、作者提出了一个训练框架,能够利用分布内数据和辅助数据集数据,使得ID data和OOD data的energy score有一个较为明显的差距。
三、基于energy的fine tune model不仅可以提高OOD data的检测效果,对ID data进行分类的准确率也不会因此下降。

同样使用后处理 #post-hoc

能量函数

基于能量的模型(EBM)的本质是建立一个函数$E(\mathbf{x}):R^D \to R$,将输入空间的每个点x映射到一个称为能量的单一非概率标量。能量值的集合可以通过吉布斯分布转化为概率密度$p(\mathbf{x})$:
image.png
其中分母称为配分函数,它在$y$上边缘化,$T$是温度参数。

由上式的分母部分可以推出,给定数据点$x \in R^D$的亥姆霍兹自由能$E(\mathbf{ x})$可以表示为对数配分函数的负值:
image.png
image.png

综述:基于能量的模型 - yearn的文章 - 知乎
LeCun 的Lessons:yann.lecun.com/exdb/publis/pdf/lecun-06.pdf
补充:ICLR2020的论文:解读 Your Classifier is Secretly an Energy Based Model and You Should Treat it Like One-CSDN博客

基于能量的模型与现代机器学习,尤其是判别模型有着内在的联系。为了看到这一点,我们考虑一个判别神经分类器$f(\mathbf{x}):R^D\to R^K$,它将输入$x \in R^D$映射到K个称为logits的实数值。这些logits用于使用softmax函数推导分类分布:
image.png
softmax:
image.png

通过连接Eq.1和Eq.3,我们可以将给定输入$(\mathbf{x},y)$的能量定义为$E(\mathbf{x},y)= f_{y}(\mathbf{x})$。更重要的是,在不改变神经网络$f_{y}(\mathbf{x})$的参数化的情况下,我们可以用softmax激活的分母来表示$x \to R^D$上的自由能函数$E(x; f)$:
image.png

image.png
论文尝试在分类模型上接入energy函数,通过energy进行OOD检测。energy较小的为ID数据,energy较大的为OOD数据。当负能量评分大于阈值时,OOD检测器将该输入分类为OOD。

实际上,通过负对数似然(negative log-likelihood,NLL))损失训练的模型本身就倾向于拉低ID数据的energy,负对数似然损失可表示为:
image.png
定义energy函数 $E(x,y) = -f_{y}(x)$并将$\log$里面的分数展开,NLL损失可转换为:
image.png
从损失值越低越好的优化角度看,公式6的第一项倾向于拉低目标类别$y$的energy,而公式6第二项从形式来看相当于输入数据的free energy。第二项导致整体损失函数倾向于拉低目标类别$y$的energy,同时拉高其它标签的energy,可以从梯度的角度进行解释:
image.png|404

上述式子是对两项的梯度进行整合,分为目标类别相关的梯度和非目标相关的梯度。可以看到,目标类别相关的梯度是倾向于更小的energy,而非目标类别相关的梯度由于前面有负号,所以是倾向于更大的energy。另外,由于energy近似为$-f_y(x)=E(x,y)$,通常都是目标类别的值比较大,所以NLL损失整体倾向于拉低ID数据的energy。

使用 energy 进行OOD

分布外检测是一个二元分类问题,它依赖于一个分数来区分分布内和分布外的例子。评分函数应产生可区分分布内和分布外的值。一个自然的选择是使用数据$p(\mathbf{x})$的密度函数,并考虑具有低可能性的示例是OOD。可以通过诉诸基于能量的模型来获得判别模型的密度函数:
image.png
归一化密度函数$Z$(分母)(相对于x)可能难以计算,甚至在输入空间上可靠地估计。

为了减轻这一问题,我们的关键观察结果是,缺乏标准化根本不会影响OOD检测。具有较高出现概率的数据点相当于具有较低能量。要看到这一点,我们可以采取对数化方程:
image.png

image.png
正(分布内)样本具有更高的分数
能量分数本质上是非概率性的,可以通过 logsumexp 方便地计算
我们的方法不需要显式估计密度Z,因为Z与样本无关,并且不影响整体能量分数分布。

Energy Score与Softmax的关系:
image.png
可见,直接优化softmax等价于同时优化energy score和fmax

从上述式子可以看出,softmax置信度的对数实际上是free energy的特例,先将每个energy减去最大的energy进行偏移(shift),再进行free energy的计算,导致置信度与输入的概率密度不匹配。随着训练的进行,通常$f^{max}(x)$会变高,而$E(x;f)$则变低,所以softmax是有偏评价函数,置信度也不适用于OOD检测。

对比:
image.png
因此,与密度 p(x) 很好地对齐的能量得分不同,softmax 置信度得分不太能够可靠地区分分布内和分布外的示例。 为了通过一个真实的示例进行说明,图 2 显示了 SVHN 数据集 (OOD) 中的一个示例和分布内数据 CIFAR-10 中的另一个示例。 虽然它们的 softmax 置信度分数几乎相同(1.0 与 0.99),但负能量分数更容易区分(11.19 与 7.11)。 因此,在原始 Logit 空间(能量得分)而不是移动 Logit 空间(softmax 得分)中工作可以为每个样本产生更多有用的信息。 我们在 4.2 节的实验结果中表明,对于 OOD 检测,能量得分是比 softmax 得分更好的指标。
image.png
左边是softmax,右边的是energy。发现softmax得到的置信度几乎相等,但是energy得到的差值会大一些,提供了更多信息。

进行训练

虽然能量得分对于预训练的神经网络很有用,但虽然能量得分对于预训练的神经网络很有用,但分布内和分布外之间的能量差距可能并不总是对于分类来说是最佳的。 因此,我们还提出了一个能量有限(energy-bounded)的学习目标,其中神经网络经过微调,通过将较低的能量分配给分布内数据,将较高的能量分配给 OOD 数据来显式地创建能量间隙。 学习过程在对比塑造能量表面方面提供了更大的灵活性,从而产生更可区分的分布内和分布外数据。 具体来说,我们的基于能量的分类器是使用以下目标进行训练的:
image.png

其中 $F(x)$ 是分类模型的 softmax 输出,$D^{train}_{in}$ 是分布内训练数据。 总体训练目标结合了标准交叉熵损失以及以能量定义的正则化损失:

image.png

其中 $D^{\text{train}}_{\text{out}}$ 是未标记的辅助 OOD 训练数据。特别是,我们使用两个平方 Hinge 损失项以及独立的边界超参数 $m_{\text{in}}$ 和 $m_{\text{out}}$ 对能量进行正则化。

一方面,模型会惩罚产生能量高于 $m_{\text{in}}$ 的分布内样本;另一方面,模型会惩罚能量低于 $m_{\text{out}}$ 的分布外样本。换句话说,损失函数惩罚能量为 $E(x) \in [m_{\text{in}}, m_{\text{out}}]$ 的样本。模型微调后,下游 OOD 检测流程与 3.1 节的描述一致。

实验

分布内数据集

我们使用 SVHN [28]、CIFAR-10 [18] 和 CIFAR-100 [18] 数据集作为分布内数据。 我们使用标准分割,并分别用 $D_{train}^{in}$ 和 $D_{test}^{in}$ 表示训练集和测试集。

ID数据集包含CIFA-10、CIFAR-100,并且分割训练集和测试集。OOD测试数据集包含Textures、SVHN、Places365、LSUN-Crop、LSUN_Resize和iSUN。辅助用的OOD数据集则采用80 Million Tiny Images,去掉CIFAR里面出现的类别

分布外数据集

对于 OOD 测试数据集 Dtest out ,我们使用六个常见基准:Textures [5]、SVHN [28]、Places365 [49]、LSUN-Crop [46]、LSUN-Resize [46] 和 iSUN[45]。 所有图像的像素值通过 z 归一化进行归一化,其中参数取决于网络类型。 对于辅助异常数据集,我们使用 8000 万张微小图像 [38],这是从网络上抓取的大规模、多样化的数据集。 我们删除了该数据集中出现在 CIFAR-10 和 CIFAR-100 中的所有示例。

评估指标

我们测量以下指标:
(1)当分布内示例的真阳性率为95%时,OOD示例的误报率(FPR95);
(2) AUROC;
(3) 精确率-召回率曲线下面积 (AUPR)。

训练细节

image.png

训练结果

与softmax和OE

image.png

与其他OOD

image.png

能量微调是否会影响神经网络的分类精度?

可以提高

image.png

关于温度缩放

image.png

应用前提

数据与预想的任务不直接相关
image.png

做法

借助预训练模型泛化到我们自己的数据集上

当数据集较小时:
冻结前面的层,只训练最后一层全连接的分类层,实现微调(fine-tuning)

数据集较大时:
多往前训练几层

image.png

卷积层不会动

用冻结的权重进行特征抽取

存在4种情况

CS231n里面的举例:

image.png

数据集小,数据相似

替换最后的全连接层
image.png

数据集小,数据不太一样

放弃全连接层和最后部分提取高阶特征的卷积层,重新设计全连接层

image.png

数据集大,数据相似

不进行冻结,权重基于预训练模型,再进一步训练

image.png

数据量大,数据集不大相同

可以所有层在预训练模型权重上训练(同上)

经典的预训练模型

image.png

但是预训练模型不是万能的,He 2018 使用预训练模型与随机初始化模型进行对比,发现几轮后效果差不多,只是预训练模型可以加速收敛

image.png

[!ques] 数据集不够大的处理思路

  1. 找一个类似的大数据集训练模型
  2. 对模型进行迁移学习和微调泛化到小数据集上
    深度学习框架提供了大量预训练模型库
    image.png

迁移学习的细节

卷积神经网络提取特征的思路:

  • 逐步细化,一开始提取边缘,后面提取部件,逐渐复杂
    image.png

我们认为提取的特征是通用的,可以进行互相替换的。于是提出可以把前面的层进行冻结,只训练后面的全连接层

例子:皮肤癌数据集

基于Inception-v3

image.png

混淆矩阵

image.png

sensitivity(ReCall): 得了病的有多少被检测出病
specificity: 健康的人有多少被检测出健康

image.png
prisition:诊断为得病的人有多少真的得病

可视化

哪些容易被误分类

image.png

saliency map表示病灶区域(梯度敏感区)
image.png

多分类混淆矩阵
image.png

如何设计迁移学习

用一半数据训练A模型,再用另外一半数据训练B模型

image.png

冻结B模型前3层:B3B,不冻结:B3B+
冻结A模型前3层,在B模型上测试:A3B,不冻结:A3B+

结果:
image.png

卷积层层与层之间会存在联合适应性,如果冻结了某个层但其他层不冻结可能会破坏耦合

image.png

另一种讲法

李宏毅ML2021中介绍:
image.png

Model Fine-tuning

  • 任务描述
    • Target data:$(x^t, y^t)$ 非常少 (#Oneshot)
    • Source data: $(x^s,y^s)$ 非常大
  • 举例,speaker adaptation:
    • Target: 某个人物的audio data
    • Source: 非常多人的audio data

Idea: 先在source data上训练,然后再到Target data做fine-tune

eg. 拿欧洲语言做中文语言的transfer
image.png|525

[!question] 怎么判断两个数据集像不像
一种想法是,先训练 Task1,然后 Task2,它的每个hidden layer都会去接前面Net1某一个hidden layer的output。这样即使非常不像,Task1不会被影响,Task2借用Task1的参数,但可以把这些参数直接设成0,这样也不会影响自己的Performance
image.png

Domain-adversarial training

Target data没有标注,Source data有标注
这两个不是match的

但可以把source data当成training data,把target data当成testing data来处理

image.png

重新回到CNN

image.png

绿色的部分是作为特征抽取的,以MNIST为例,抽取特征后进行t-SNE降维,可以很明显看到数据被投影成了9个类,但是把MNIST-M输入后,数据并没有很好的表征。

这是因为domain不同产生的影响。于是,能不能去除这种影响?即,能不能让红色和蓝色进行均匀混合?

image.png

于是任务转化为训练一个domain classifier 和label predictor,既能够骗过domain classifier,同时还可以让predicter正常预测

三个网络的目标有所区别:

  • feature extractor:最大化分类准确度,最小化领域分类准确率(需要骗过domain classifier)
  • Label predictor: 最大化分类准确率
  • Domain classifier:最大化领域分类准确率
    image.png

[!question] 怎么骗过domain?
feature extractor每次都对domain传来的梯度乘-1,即始终往domain需要的相反方向走,让domain迷惑
不太好训练
需要让domain classifer不断训练,避免让它传0
image.png
image.png


image.png

zero-shot learning

与上面的类似,但有不一样的是,source data和target data的任务是不一样的

source data从来没有出现过target data的内容

语音识别常见
解决思路是不去辨认一段声音属于什么word,而是辨认属于哪个phoneme
建立phoneme和对应的表,查表即可

image.png

对于CV,可以建一个database,通过总结每个class的attributes的特点来判断
在training时候,建立class与attributes的对应
testing时,根据网络提取的attributes的特点查表,得到对应的class,找到最接近的
感觉CLIP的思想与这个类似

把图片用 $f$ 映射到一个特征空间,attributes通过 $g$ 映射到另一个特征空间,使得$f(x)$和$g(x)$越接近越好
image.png

[!question] 如果没有database?
使用word2vec,把attributes用word2vec代替
image.png

损失函数

需要同时考虑到:

  • 同一个配对,越接近越好
  • 不同的配对,越远离越好

因此,这里的loss不能用原来的MSE,需要进行改正:

$$
f^*,g^* = arg \min_{f,g} \sum_{n} max(0, k - f(x^n) \cdot g(y^n)+\max_{m\neq n} f(x^n)g(y^m))
$$

image.png

  • 混合word2vec
    image.png

对不同语言丢到embedding后,表达相同意思的句子经投影的会聚集在一起

self-taught learning

source data unlabeled
target data labeled

与半监督学习不同,这里的 unlabeled data、source data与target data比较远

0%