深度学习基础
这是一篇讲述深度学习的文章,参考课程为李宏毅动手学习深度学习2021、2022版
简介
深度学习本质上有三步,首先是定义一个model,实际上是一个函数.之后是定义这个函数的好坏,第三部是找到最好的函数
回归(regression)
回归指的是根据一个向量输出一个数值,主要作用是做一个对连续值的预测 回归任务与分类任务是相对应的,就想连续与离散一样. 这个翻译导致我一直没明白他是干什么的 :(
model
这里的模型是一个线性模型, 可以表示为$y = b + W\cdot X$ 这里的$W X$指的是向量 这些输入的X叫做特征,W 是权重,b 指的是偏置(bias)
判断函数好坏
- 首先我们需要训练数据, 即一些(x, y)的值对
- 定义一个loss function, 其实就是一个描述预测与目标偏差的函数 $L(f) = L(w, b)$ 可以使用差的平方和, $L(w, b) = \sum_{i=1}^{n} (f(x_i) - y_i)^2$
找到最好的函数
找到最好的函数,就是找到最好的$w, b$ 使得$L(w, b)$最小. 这里可以使用梯度下降法(gradient descent), 也就是说,我们不断的调整$w, b$使得$L(w, b)$最小
梯度下降的公式为: $w = w - \alpha \frac{\partial L}{\partial w}$, 这里的$\alpha$是学习率, 是一个超参数, 用来控制每次调整的大小.实质上就是在函数的某一点, 沿着梯度的反方向走一步, 使得函数值减小. (梯度在二维的理解就是斜率)
这样存在一个问题,就是会陷入局部最优解, 但是线性回归是一个凸函数, 所以不存在局部最优解, 只有全局最优解
- 如果是两个参数呢, 比如上面的$w, b$呢? 这个时候就是偏导数了, 也就是说, 梯度下降的公式变成了 $w = w - \alpha \frac{\partial L}{\partial w}$, $b = b - \alpha \frac{\partial L}{\partial b}$ 即分别对$w, b$求偏导数, 然后分别更新$w, b$
反复经过这个步骤,就可以找到最好的$w, b$ 使得$L(w, b)$最小
提高model复杂度
一次函数可能无法很好的契合预测,那么可以引入新的二次预测函数, 也就是说, $y = b + W\cdot X + W_2 \cdot X^2$, 这样训练后的model对于测试集的损失会更小 很容易的想到,是不是多项式越复杂,结果越好呢? 这个时候就会引入一个新的概念, 过拟合(overfitting), 过拟合指的是模型在训练集上表现很好, 但是在测试集上表现很差. 我们会发现在参数增大到一定程度后,反而会使得模型在测试集上表现很差.
重新设计model
在增大输入数据时,观察到这样一个现象, 即数据分布不能用简单的多项式函数表示 这张图表示,函数受到一个额外的变量影响, 在这张图里是宝可梦的物种.如果物种为A,就契合一个多项式,为B就契合另一个多项式. 但是要怎么实现这样的线性模型呢,这就需要$\delta$函数, 即冲激函数,即满足特定条件的时候输出1,否则输出0. 公式可以表示为 $ y = b_1 \cdot \delta(x_s = A) + w_1 \cdot \delta(x_s = A)x + b_2 \cdot \delta(x_s = B) + w_2 \cdot \delta(x_s = B)x$ 不过这样还是没能解决过拟合的问题,这时候我们就需要引入一个新的概念, 正则化(regularization),
正则化
正则化就是在原本的损失函数后面加上一项, 即$L(w, b) = \sum_{i=1}^{n} (f(x_i) - y_i)^2 + \lambda \sum_{i=1}^{n} w_i^2$, 这里的$\lambda$是一个超参数, 用来控制正则化的强度. 这样就可以避免过拟合的问题.
- 观察到, 后面加的这一项越小,损失值越小,那么为什么我们要期望函数的参数值都很小呢?
这是因为参数值小代表这函数的光滑性, 也就是随输入变化而变化的值会更小, 即对输入不敏感, 也就是更具有泛化性. 这也是为什么在正则项里没有bias, 因为bias是用来调整函数的整体位置的, 不影响函数的光滑性
分类问题
回归就是将预测的值划定为几个离散的类
从regression问题出发
容易想到的是,可以通过regression的预测结果与哪个分类的值更相近作为划分类的手段. 但是这样存在一个问题 以0 和1作为两个分类的代表值, 那么对于regression来说, 可能会存在一些可能远远偏离1的点, 比如说1000. 那么对于regression来说,这些会被视为错误节点, 但是对于分类来说, 这些点是可以被接受的. 这就是分类与回归的区别, 分类是一个离散的值, 而回归是一个连续的值
逻辑回归
使用sigmoid函数来将预测值映射到0-1之间, 也就是$y = \frac{1}{1 + e^{-z}}$, 这里的$z = b + W\cdot X$ 这个函数的图像是一个S型的曲线, 也就是sigmoid函数, 这个函数的值域是(0, 1), 也就是可以用来表示概率. 也就是$P(y=1|x) = \frac{1}{1 + e^{-z}}$, 这里的$P(y=1|x)$表示在给定$x$的情况下, $y=1$的概率. 也就是如果$P(y=1|x) > 0.5$, 那么就认为$x$属于类1, 否则属于类0
损失函数
逻辑回归通过sigmod函数将预测值转换为概率值, 也就是$P(y_i|x_i) = \frac{1}{1 + e^{-z}}$, 这里的$z = b + W\cdot X$. 也就是我们可以将sigmoid函数的输出值作为分类的概率值. 也就是如果$P(y=1|x) > 0.5$, 那么就认为$x$属于类1, 否则属于类0
假设数据服从伯努利分布, 则单个样本的似然函数为$P(y_i | x_i) = P(y_i=1 | x_i)^{y_i} \cdot P(y_i=0 | x_i)^{1-y_i} = P(y_i=1 | x_i)^{y_i} \cdot (1-P(y_i=1 | x_i))^{1-y_i}$,为了方便优化,取负对数也就是$L(w, b) = -\sum_{i=1}^{n} [y_i \log(P(y_i | x_i)) + (1-y_i) \log(1-P(y_i | x_i))]$, 这正是 二元交叉熵损失(BCE Loss)。因此,最小化交叉熵损失等价于 最大化似然函数,使得模型预测的概率分布最接近真实分布。 |
多分类问题
对于多分类问题, 也就是有多个类, 那么可以使用softmax函数来将预测值映射到0-1之间, 也就是$P(y_i|x_i) = \frac{e^{z_i}}{\sum_{j=1}^{k} e^{z_j}}$, 这里的$z_i = b + W\cdot X$, $k$是分类的数量. 对于x,以三分类为例,会输出三个y分别代表x属于这三类的概率. softmax的作用就是将他们之间的差距放大. 举例来说,原本的z值为[1, 2, 3], 那么经过softmax函数后,会变成[0.09003057, 0.66524096, 0.24472847], 也就是将最大的值放大了, 其他的值缩小了. 也就是如果$P(y=1|x) > P(y=2|x)$, 那么就认为$x$属于类1, 否则属于类2
多分类的损失函数
这里的损失函数上少一个负号
逻辑回归的缺陷以及引入神经网络
逻辑回归做分类可能会遇到这种问题, 比如说,我们有一个数据集, 但是这个数据集是线性不可分的, 也就是无法用一条直线将数据分开. 这时候就需要引入神经网络了. 举个例子, 如果按照左图直接划分是无法将红蓝直接划分开的, 所以我们对两个维度分别做变换得到右图就是线性可分的了,那么问题是这种变换应该怎么找呢? 就需要使用深度学习让机器帮忙寻找了
CNN (影像识别)
输入
模型的输入是一张图片, 一般来说是一个三维张量, 也就是一个矩阵, 这里的三维指的是宽高和通道数, 通道数一般是3, 也就是RGB三个通道. 也就是输入的图片是一个$H \times W \times C$的张量. 在输入的时候将他reshape一个一维向量作为输入,后面采用上面的多分类器进行分类. 看似很美好, 实则有个问题就是参数量过于巨大, 也就是$H \times W \times C \times K$, 这里的$K$是分类的数量. 也就是如果图片的大小为$1000 \times 1000$,分类为1000, 那么参数量就是$1000 \times 1000 \times 3 \times 1000$, 这时候就需要引入卷积了
卷积
卷积的本质就是一个滑动窗口, 也就是在图片上滑动一个窗口, 然后将窗口内的值与权重相乘, 然后求和, 也就是$y = b + W \cdot X$, 这里的$W$是一个小的矩阵, 也就是卷积核, $X$是一个小的矩阵, 也就是窗口内的值. 这样就不需要想fnn那样一个一个像素看而是可以一次观察一整个窗口. 如果觉得这样还是会有较多参数如何进一步简化呢?
共享权重
对于每一个窗口, 都会有一些神经单元对其负责, 即线性层里面的节点. 对于两个不同区域的窗口, 可以共享他们的权重. 这并不代表这两个的输出会是相同的, 因为他们具有不同的输入
同时具备这两个特性的神经层就是卷积层, 具有卷积层的神经网络叫卷积神经网络(CNN)
这个权重就是我们熟知的卷积核, 在对整张图像进行运算后,会根据filter的个数输出相应的feature map, 也就是特征图. 如果filter有64个,即有64组参数,那么结果就是一个64通道的图. 在之后进行卷积的时候, 卷积就必须是3* 3* 64* out了
维度说明
卷积核的维度为$H \times W \times C_{in} \times C_{out}$, 这里的$H$和$W$是卷积核的大小, $C_{in}$是输入的通道数, $C_{out}$是输出的通道数. 在计算的时候,针对每个输出维度,提取他的三维卷积核,$H \times W \times C_{in}$的大小, 对于每个输入维度$C_in$,与对应的输入图像的$H \times W$的大小进行2维卷积,将所有的输出相加,得到一个$C_{out}$的输出维度。最终输出的大小为$H_{out} \times W_{out} \times C_{out}$, 这里的$H_{out}$和$W_{out}$是输出的宽高, 也就是经过卷积后的大小. 也就是$H_{out} = \frac{H - H_{kernel} + 2 \cdot padding}{stride} + 1$, $W_{out} = \frac{W - W_{kernel} + 2 \cdot padding}{stride} + 1$, 这里的$padding$是填充的大小, $stride$是步长. 卷积核$W_{i,j}$代表从通道i到输出j的对应卷积核(滤波器系数)
池化
观察到一张图能提取的信息与其等比例缩小后的图是十分相似的, 也就是如果将一张图缩小到1/2, 那么提取的信息是不会有太大变化的. 这时候引入池化层, 也就是对特征图进行降维. 将特征图的宽高缩小, 但是通道数不变. 这样就可以减少参数量了. 池化层有很多种, 比如说最大池化, 平均池化等. 最大池化就是取窗口内最大的值, 平均池化就是取窗口内的平均值. 这里的窗口大小一般是2 * 2或者3 * 3, 步长一般是2. 也就是每次滑动2个像素.
空间变换层(spatial transformer layer)/数据增强
由于CNN的学习能力不具有缩放性与旋转性,即旋转后的图片就不能正确识别了,这个层就是解决这个问题的。
平移旋转
解决办法就是将某一层的输入图像想某个方向偏移几格,这可以通过一个普通的线性层来实现,如图所示。 这里只需要将系数在指定的地方置1,其余是0即可。依此类推,旋转也是可以实现的。
缩放
对特征矩阵使用仿射变换,比如放大就可以使用如下公式 \(\left[ \begin{matrix} x' \\ y' \end{matrix} \right] = \left[ \begin{matrix} 2 & 0\\ 0 & 2 \end{matrix} \right] \cdot \left[ \begin{matrix} x \\ y \end{matrix} \right]\)
总的来说,可以通过六个参数就可以描述这个层,除了前面的4个,还有后面的额外2的偏置参数
如何进行梯度下降呢
因为这个函数明显不连续,在每个点的梯度都是0,因此在进行这个方法的时候,需要进行双线性插值(interpolation),即对于中间的非整数节点,将其按照曼哈段距离作为权重来用四周的整数节点表示 此时就可以进行梯度下降了,为什么呢? 按照原本策略,描述变换的6个参数有微小变化时,最终结果没有改变,比如从0.6到0.61最后都是取值到1。但是按照插值策略,这个值是由四周的值加权表示的,如果与四周的距离有些微变化,那么自身的值也会有些微变化,即变成可微的。
具体应用
不止可以放在卷积层前面,也可以放在后面,甚至可以同一个位置放两个
RNN
RNN最大的一个特点就是,可以考虑前面的输入。他会将上一次输入的结果与当前输入一起输入给模型。 可以看出,每一次传递的都是隐藏层的输出。如果模型深度比较大,即存在多个隐藏层,那么就会传递多个值。当然也存在将模型输出结果作为下一次的输入的做法。
Bidirecitional RNN
对相反方向做一个RNN,之后将两个方向的隐藏层的值共同作为输入。这样的好处是不仅可以获取前面输入的信息,还能获取后续输入的信息。
long short-term memory (LSTM)
这个模型多了几个控制信号
形式化的表示如下: 其中左侧的方格代表一个记忆单元。那么这四个输入是怎么得到的呢
对于每一次输入x,分别对其乘以4个矩阵,得到4个向量,作为一个memory cell的四个输入,之后做对应的运算得到输出$y^t$,并更新$c^t$
实际操作中,每一层的输入不止取决于$x^t$,还有前一次的输出$y^{t-1}$以及上一轮存储的结果$c^{t-1}$,称之为peephole
训练
同样也是采用梯度下降法,使用的是反向传播的进阶版本(BPTT)。考虑了时间的影响。
梯度消失,爆炸
由于rnn需要经历许多次的循环,最终的梯度会呈指数增长。举个例子: 假设对于一个神经元的输入是1,后续的输入都是0.那么存储的结果就是input的权重w*1,经过1000次输入后,存储的结果就是$w^{1000}$,那么w大于1和小于1就会导致梯度极大和梯度趋于0。那么训练所需的lr就是极小与极大,导致模型无法训练出来。使用LSTM可以解决这一问题,因为LSTM的输入与记忆单元是相加操作,这就避免了乘积导致的梯度爆炸的问题。目前说使用RNN,默认就是使用LSTM。
自注意力机制
前面的模型的输入输出都可以看做一个向量,可是如果遇到输入是多个向量,且各个向量长度不同,则明显无法用前面的模型解决。举例来说,在语言处理里面,每次输入的句子长度不同,则转化后的向量长度也不同。
对于输出则有多种可能:
- 输出数目与输入相同,比如输入4段语音,返回4段标签
- 只有一个输出标签描述所有输入,比如对一段评价进行整体分析,返回positive还是negative
- 第三种是不知道要输出多少,要由机器自由决定,又叫seq2seq任务,例如翻译任务。 下面介绍第一种类型
sequence labeling(输入输出标签一样)
首先可以想到的是对于每一个输入都得到一个输出,但是这样存在一个问题,就是没有把输入之间的联系考虑进去,比如这个例子,第二个单词与第四个单词分开分析就是一个意思,实际在整体来看一个是动词一个是名词
解决办法是使用一个windows,将每一个输入改为包括前后2个输入的一个windows,这样就获取到上下文信息了。
self-attention
对于上面的windows方法,仍然不能考虑整个输入间的联系。进一步,将每个全连接层的输入改为整体考虑整个sequence后产生的输入,这个考虑的过程就是自注意力。这个步骤可以重复多次。
具体运作方式
自注意力层会有n个输入,n个输出。输出的每一个结果都是综合考虑所有输出所产生的。 具体步骤:
- 对一个输入$a_1$,找到与其相关的所有输入。每一个向量与其相关的程度用$\alpha$表示。
- $\alpha$的计算:
- 通过第一种方式计算$\alpha$,对于所有$\alpha$做一个softmax
- 最后将每个输入乘以$W^v$得到的结果,乘以$\alpha$作为权重,求和就得到了一个输出
实际上,这4个输出是并行计算的,而不是一个一个计算的。在计算q,k的时候,将所有a合并为一个矩阵,最后同时计算所有的q,k,v。整个过程中需要学习的参数只有$W^q, W^k, W^v$
multi-head attention
为了让模型可以学习到不同的联系,使用多个自注意力层,每个层的q,k,v的参数都不一样。每个层的输出会被拼接起来,然后通过一个线性层得到最终的输出。即上图中的qkv都会变为x个,每一份独立计算,最后会生成x个b。最后将所有的b拼接起来,通过一个矩阵得到最终输出。
位置编码(positional encoding)
由于自注意力层是并行计算的,因此无法获取到输入的顺序信息。为了解决这个问题,使用位置编码来表示每个输入的位置。位置编码可以是一个向量,表示每个输入的位置。这个向量可以通过正弦和余弦函数来生成。具体来说,对于第$i$个位置的编码,可以表示为: \(PE(i, 2j) = \sin\left(\frac{i}{10000^{\frac{2j}{d}}}\right)\) \(PE(i, 2j+1) = \cos\left(\frac{i}{10000^{\frac{2j}{d}}}\right)\) 最后将这个PE与输入的向量相加,得到最终的输入向量。这样就可以获取到输入的顺序信息了。
self-attention for speech recognition
在语音识别中,输入是一个音频信号的特征向量序列,输出是一个文本序列。由于音频信号的特征向量序列长度不固定,因此需要使用自注意力机制来处理。与前面的不同,由于语音信号会转换为数量很大的输入向量,因此自注意机制的观察范围将从全部降低到前后几个。
字嵌入
字嵌入是将一个字转换为一个向量的过程。这个向量可以表示这个字的语义信息。字嵌入可以通过训练得到,也可以通过预训练模型得到。常用的预训练模型有Word2Vec,GloVe等。
prediction-based
预测式的字嵌入是通过预测一个字在上下文中的概率来得到的。具体来说,对于一个字$w_i$,他会得到一个训练后的矩阵,里面是对出现在这个词后所有词汇预测的概率。两个相似的词后面跟的词汇也会相似,因此最后生成出来的向量也会相似。
batch_normalization
为什么需要BN
首先,一个简单的神经网络的训练目标是尽可能的降低损失函数的值。用一个图像来表示 就是左上图。我们在训练神经网络的过程中,目的就是让损失函数的值尽可能的接近0。也就是让图像中的点尽可能的接近中心。不过图中w1与w2的梯度是不同的,w2的梯度比w1大很多,因此采用固定大小的学习率很难训练出来。因此这里要探究为什么会出现这种梯度不均匀的情况。 从下图的公式可以看出,损失函数的值e是由输入x简介间接决定的。如果x1比较小 ,w1的改变对最终的e的改变也比较小,反应到图像上就是梯度比较小。x2反之。因此为了减小这种由输入参数大小差距过大导致梯度不均匀的情况,就需要BN了。
feature normalization
一个简单的归一化方法:对于输入的多个向量,针对每个维度求平均值,之后所有向量的该维度的值都减去这个平均值,再除以标准差即可。
讲完了归一化,前面还有一个batch需要讨论。由于数据量通常比较大,因此每次做归一化都是针对一个batch进行处理,比如一次对64个数据归一化
ps: batch normalization是横向做均值,而layer normalization是纵向的对于单个向量求均值
batchnorm2d
我们发现,做完归一化的某一维度的均值一定是0,方差是1。这样其实会对网络做出限制,为了打破这一限制,我们在后面再加上一层,对其加上偏移参数用于网络训练。 $\gamma$与$\beta$初始化为 1 和 0,防止又一次产生前面归一化要解决的问题。
batch normalization - TESTING
在推理的时候,输入数据可能不足一个batch,这时候ptorch的处理是使用moving average。即使用当前数据的均值与前面数据的均值组合当做当前sample的均值
seq2seq model
我们前面的模型大多是固定输入,固定输出的,而seq2seq model的输入输出长度是不固定的,比如翻译模型。
seq2seq model 模型结构
Encoder
简单来说,就是根据一个输入向量输出一个向量。Encoder里面包含许多个block,每一个block的结构如右下 首先是加入位置编码,之后是经过一个多头注意力层,之后是残差链接与归一化,再经过一个全连接与归一化,就完成了一个block
Decoder AT(autoregressive)
- decoder的输入:与encoder的输入不同,decoder的输入是逐个输出的,比如首先会输入一个起始向量,假设输出一个“机”,第二个输入就是“机”,输出“器”。第三个输入就是“器”等等
- 结构:
实际上与encoder的不同点只有第一层自注意力机制与额外的一层自注意力机制
- masked attention: decoder的自注意力层与普通的区别在于,他的输入是逐个输入的,即当前的元素只能看见前面输入的元素,后面的元素是不可见的。因此在 这一步中,将修改为下图
- 结束符:由于我们无法确定输出的长度,因此机器自己判断。添加一个end字符,在机器输出这个字符之后,就停止输出
- NAT encoder:与AT encoder一次输入一个不同的是,他是同时输入多个begining单词,同时输出所有结果。一个难题是,输出的长度没法确定,因此可以额外设置一个classifier用于推断输出的长度。这个NAT的好处在于可以并行化,并且可控输出长度。
- cross attention:这一部分用于将encoder与decoder相连。将decoder产生的q与encoder输入的k做交叉处理
train
损失函数
与分类问题类似,采用交叉熵损失函数,将得到的输出与预计的结果作为函数的输入,得到最终的损失值
teacher focing
意思是,在训练的时候,会给decoder看正确答案,即同时给他输入输出,例如告诉他在输入‘机器学’的时候应该输出‘习’。
exposure biase
指的是训练的时候,decoder看到的输入是正确的,但是在测试的时候,他的输入是自身输出的,可能使错的
scheduled sampling :简单来说就是在训练的时候就不要全给模型正确的输入
generative adversarial network (GAN 生成式对抗神经网络)
什么是generator
普通的model,有一个输入x,输出y。generator在这之上加入一个输入z,这个输入z是一个分布采样得来的。那么根据不同的采样,输出y也是一个范围。
为什么需要generator
我们之前的机器的预测任务是有标准答案的,比如翻译任务。但是有些任务是没有单一标准答案的,比如视频预测,要预测的一个人可能向左走也可能向右走。当这两种情况同时存在训练集里面,机器会输出向左与向右两个人。为了应对这种情况,我们加入一个几率(噪声),让机器的输出具有随机性,这样他就知道既有概率向左也有概率向右。当我们的任务需要一定创造力的时候,就尤为需要这一点。想象让ai写诗但是每次都生成一样的诗,显然不符合我们的预期。
Discriminator
在生成器生成内容之后,需要一个模型判别生成的效果。discriminator也是一个神经网络,可以根据输入给出评分。
GAN基本原理
generator生成内容,discriminator进行打分,generator根据这个评分更新自己的模型,而discriminator根据生成的图片与目标图片的关系更新评价模型。
训练算法
- 固定生成器,训练分辨器:将生成器产生的图片与目标图片做为训练数据,可以按分类或回归问题训练分辨器分辨这两种图片
- 固定分辨器,训练生成器:将这两个模型接起来,之后固定分辨器的参数,训练生成器。将最终得分视作loss,用梯度上升训练模型。
- 之后就是反复训练。
自监督学习
监督学习与自监督学习
我们前面的模型都是监督学习,即给定一个输入,模型产生一个输出。我们会根据他的输出结果与我们原有的label做对比进而改进模型。 而自监督学习就是在我们没有label的情况下让机器自己学习。自监督学习是无监督学习的一种特殊方法。
masking input
将输入的文字随机覆盖掉,可以换成一个特殊字符或者随机换成某个文字。这么做的用处在于可以用来将已有资料做训练。以bert为例: 他是transformer里面的一个encoder,我们将输入中的某个文字mask后,训练他的输出要与原本mask的值相同,或分类为同一类。有种背诵古文时,盖住下句留上句来自我背诵的感觉。
做完这个训练后,模型被训练为可以做填空题,但是神奇的是它可以被拿去做别的任务。 这个训练bert的过程就是pre-train
GLUE general language understand evaluation
一个自然语言处理方面的评价标准
如何使用bert,即预训练模型
假设需要一个对语句进行正面评价与负面评价的分类任务。 这里面只有分类用的线性层的参数是随机初始化的,而bert的参数是预训练好的。
这里并不完全是自监督学习,因为预训练部分可以不需要标注资料,但是最后分类训练还是需要标注资料才能训练的。
如何预训练seq2seq模型
显然与bert不同的是,还需要对decoder做预训练。预训练的方法是将输入的数据弄乱,训练他输出是弄乱前的顺序。
为什么bert可以工作
针对一个向量中的每个值,他经过bert的输出结果是根据上下文的几个值得出的。实际上是一个deep版本的word embedding
多语言bert
即使用多种语言的预训练bert。神奇的是,这个预训练的模型使用英文资料集训练,却会学会中文的问题。 一个实验可以解释这个问题,实验者将所有的中文embedding向量减去英文的之后获得一个向量x。之后输入一个英文问题,之后将这个问题转化的embedding加上x,最终机器回答的结果变为中文了。这个实验说明机器实际可以理解语言之间的差异,我猜测可能是在某个维度上对不同语言进行了区分。
GPT
与bert的不同在于,bert做的是填空题,而GPT是续写题或者预测题,即会根据输入预测下一个单词。 GPT更像一个transformer的decoder的架构,共同点是都无法看到后面的东西,只能获取前面的信息。
GPT-3的进步(few-shot learning)
bert等预训练模型虽然是训练过的,但是实际要用到具体的任务时,还是需要当前任务的资料来做fine-tune。GPT-3的目标就是简化这一步骤,通过一些提示词来代替fine-tune。
自编码器 auto encoder
- 介绍:自编码技术实际是自监督的一种形式,都不需要标注数据。他的训练方式为训练解码器的输出与编码器的输入一致。
- 用处:可以将编码器的输出embedding向量作为下游任务的输入。因为输入图片本身是一个高维向量,而经过编码器后会被压缩为低维向量
- 好处:AE的核心思想是将输入数据压缩到一个低维的“潜在空间”
工作原理
为什么auto encoder的训练方式可行呢,为什么中间部分可以用低维向量表示输入的高维图片。比如输入图片是$55$的,但是在encoder之后变成$22$的,却也可以在解码器后还原出原有图像。原因在于输入图像虽然是$5*5$的,但是实际可行的变换却不足25种。
特征解耦
encoder针对一个输入,比如说一段声音信号或者图片等,输出都是一个向量。特征解耦的目的就是尝试将这个向量拆开,得到负责每个特征部分的向量,比如让某个维度对应声音信号中的某个人的声音。 一个应用就是语音转换,比如想做一个变声器,只需要在encoder之后将代表声音特征的部分提取出来,替换到另一个人的encoder相应结果的部分,就会实现变声的效果。
RL 强化学习
- 监督学习:提供正确答案,让机器按照答案学习
- 强化学习:不知道正确答案,但是借由与环境的互动,机器知道当前输出结果是好是坏
RL的基本结构
- 每一次的行为:deep RL的推理部分与神经网络类似,都是一个经过一个神经网络。在RL里被称之为policy network。输出的结果是一个分类任务的结果,会给出所有行动对应的概率。
- 评分:每一次行动都会产生一个评分(reward),当一场游戏结束后,总的评分(return)就是每次评分的和。可以将这个return的负值看做loss
- 优化:训练network的参数,使得return的值越大越好
由于reward和env是无法训练的黑盒子,所以还不能按照正常训练神经网络的方式计算。不过这个结构和GAN十分相似,把actor视为generator,env与reward视为discriminator。在训练的时候,都是固定后者训练前者,来使得discriminator的输出更大。不同点在于GAN的discriminator是可以训练的,但是RL里面的是不能修改的。
policy gradient
如何训练policy network? rl的资料收集在for循环中,也就是每次循环都要重新收集材料。因为在上一次收集的材料可能不适合下一次循环。以游戏为例,上一帧可能射击比较好,下一帧可能移动比较好。如果用相同的材料,就无法train到想要的结果。
资料收集
训练actor的资料最初是没有的,首先需要使用一个初始化后的actor与env交互,获取各种${S,a}$对,之后对每一对${S,a}$给出一个reward值。
- exploration:在数据收集阶段需要一定随机性,可能越随机越好
- critic:给定actor$\theta$,根据当前环境S,使用行为a时所获得多少奖励
- value function:函数$V^\theta(s)$,对指定actor输入环境s,得到折扣累计奖励。
就是说,并非单纯的将后续所有操作的reward求和,而是离当前操作越远,就对于整体的return影响越小。
如何训练value function
- 蒙特卡洛方法:
就是训练当前函数的结果与目标值相同
- temporal-difference approach:不需要看完整个游戏就可以拿到训练资料。 之前方法的G需要一直游玩玩整场游戏,得到所有reward值,再乘因子后加起来。而这个方法的训练不需要用到G。
观察到连续两次的结果$V^\theta(s_t)$与$V^\theta(s_{t+1})$之间存在类似于数列递推的联系,因此可以对两者求差来进行训练,如下图所示。
神经网络压缩
神经网络太过于巨大,要想在一些终端之类的有算力,内存限制的设备上运行,需要对其进行压缩。
网络剪枝
核心概念就是,许多参数在修建掉之后对整个推理的影响不大,所以这部分就是找到这些参数,然后去掉他们。工作流程如下 实际上就是每次减去一点,然后微调减小影响,不断循环这个过程。 修建的基本单元分为两种,一个是神经元,一个是参数。
- 参数为基本单位:缺点就是让神经网络的结构变得不再整齐。比如当前层的节点每一个都是链接后面n个节点,但是剪去一个参数后,就会存在一个节点后续链接n-1个节点,要写出这个程序会变得很复杂。所以在实际上不会剪掉这个参数,而是把它置零。
- 神经元为基本单位:不存在上述问题。
为什么不直接训练小的网络而是要剪枝
原因是大的网络比较好train
知识蒸馏
一个大的模型和小的模型。大的模型叫老师模型,小的叫学生模型。 训练的过程为:让小模型学习大模型的输出。比如老师模型输出一张手写数字的概率分布,那么对同样的输入,学生模型的学习结果就是老师模型的相应输出。
为什么不直接训练小的模型呢? 往往结果没有从大的模型学过来的结果好
ensemble上的应用
ensemble指的是利用多个模型的输出结果,综合起来作为输出,可以用投票的方法也可以用平均值的方法。通常这样的效果是非常好的,不过在实际应用中没法同时推理这么多模型,那么就把 ensemble的输出看做是老师模型的输出,让我们的模型学习这个结果。
修改softmax
通过参数T可以使得最终结果的分布更加平缓,这样学生模型能学到更多的信息,比如某两个输出结果可能是比较相似的。如果不加这个参数,就相当于只学习了正确答案,却没有学习到结果之间的参数。
参数量化
- 用比较少的空间存储一个参数。
- 权重分群:对所有参数按照给定好的大小分群,比如设定分作4群,之后将参数大小相近的分为一个群,并将一个群中所有参数用一个统一的值取代。这样所有的参数可以用2个bit存储了(00 01 10 11)
- 在上一步基础上,加上哈夫曼编码
架构设计
针对CNN的优化
- depthwise convolution: 原本的卷积核中包含out_channel个filter,每个filter又包含in_channel个矩阵。这个优化就是让filter的个数等于in_channel,且每个只包含一个矩阵。实际运算上,让一个filter负责一个输入的channel,即输入输出的通道一样。这个算法很符合对CNN的误解:)
- pointwise convolution: 上个优化的缺点是,通道之间没有交互,完全独立,这样就不能识别通道间的特征。在这个优化里,filter的数目上与寻常无样,但是kernel size(filter)的大小固定为1
- 使用这两种方法代替原有的卷积层,会发现参数量大致变为$\frac{1}{k*k}$,k为kernel size。这个优化是一个用层数换参数的策略,由下图可以看到,原本结果矩阵的红框部分来自于左侧相应红框区域,使用新策略后生成的红框部分也是来自同样的区域。
其他架构设计
mobile net,squeeze net……
动态计算
指的是网络可以调整他需要的计算量
动态深度
模型根据情况决定要在哪层隐藏层就输出结果,这样就实现调整深度的效果。一个训练思路是将所有输出层的cross entropy加起来作为损失来训练网络