AI 基础笔记
来自人工智能基础课程,仅作留档。
概率论小知识
正态分布
定义两个变量的协方差
因此对于两列分布
最大似然估计:
假设一些变量服从某个参数位置的分布
考虑一些数据点
频率学派
那么想要找到的
用 log 可以增加精度。
由于整个模型系统可能会非常复杂,数学上求解
贝叶斯学派
回顾贝叶斯公式
带入例子,得到
这假定了模型
一个例子是扔硬币,可以认为硬币本身服从某种分布(例如硬币大致是公平的),那么就可以加入这种假设来适当“修正”先验概率、
信息论小知识
如果别人告诉你某件不太可能发生的事发生了,那么这个信息量比较高(排除了更多的可能)。
同时两件独立事件信息量会相加,因此自信息的一种合法刻画就是
KL - 散度(KL-divergence)
误差可以看做某种度量(距离),对于两组概率分布
这相当于用
有一种改进的 JS 散度:
交叉熵(cross entropy)
这个不知道有啥用(好像确实挺多人用的)
下节课讲怎么炼丹。
Python 小知识
pip install 包
conda 创建环境(venv 也可以),环境之间独立,可以采用不同版本
服务器 + vscode remote ssh
numpy 非常牛(非常快)
有浅拷贝,创建新副本需要 copy
炼丹
数据 -> 知识
任务:
- 有监督学习:分类、回归(有标签)
- 无监督学习:聚类、密度估计、降维(无标签)
- 半监督学习(部分有标签)
- 弱监督学习(有标签,但需要的标签不存在)
- 强化学习(另一个领域,主要关注于环境和决策,用途包括博弈论等)
经验:数据集 -> 测试集
不能过拟合、能够将数据集特征泛化到测试集数据。
表现:衡量一个模型的表现如何,一些常见的 loss:
- 二分类:
\#\{f(X)\neq Y\} - 回归
\sum (f(X)-Y)^2 - 密度
\sum-\log P_f(Y)
最后要优化 loss 最小,即
想要通用的训练方法来解决类似(甚至是所有)的机器学习问题。
线性回归分类问题
最典中典的问题。
线性模型:
这个东西的可解释性很好,而且很简单,但是这个东西有比较大的缺陷和局限。
给定数据
人工计算:假设使用均方差
然后求一下偏导,就可以手动算出来一个式子
梯度下降:直接算一个东西出来不一定好弄,而且数据太多的话求逆
梯度下降
初始获得一个解
有的时候数据太少,导致之前例子里的矩阵不可逆,那么可以引入一些外部信息作为假设(例如模型的参数
MAP(贝叶斯学派):求
如果假设参数服从高斯分布:损失函数体现成
假设服从拉普拉斯分布:变为
两个分布都有其用途,比如加入这种正则化项会使得最后参数的大小比较小,这个时候可以发现那些参数是比较有用的,那些是没用的(系数非常小,甚至为 0),用告诉分布这可以提取特征。
广义线性模型:
逻辑回归
线性回归-预测连续值
逻辑回归-分类问题。
step function:
需要根据网络输出的一个概率给出一个结果,
这个东西是这么来的:
那么这里就可以做一个分类器(Logistic Regression)
sigmiod 引入了非线性,在感知机(线性组合)后边接一个就可以转成
对于分类任务,就会有一堆数据
先手取个 log 增加精度,然后这个东西实际上就是最小化
这类问题用均方差的话很多时候斜率是 0,不太好搞,但用交叉熵就比较好(ppt 上有图)。
对于图像识别问题(经典分类问题),是一个过去非常有挑战性的问题,需要一些额外的工具。
神经网络就是把很多层这样的东西叠起来,必须要引入非线性,但先不讲。
最近邻分类器
之前是需要人为标注、有参数的。
无参方法:数据中每加入一个数据点,和之前的数据点算一个距离,看看和原来哪个最接近,认为和对应数据同一个类别。
比如直接把像素点相减然后算一个距离(加起来或者之类的)。
当然也不一定要是最近的点,也可以从
超参数:不是和训练相关的,比如之前
现在有一个已知的训练集,上面这个东西选
交叉验证:整个训练集分成若干份,每次取出一份为验证集,取一个平均比取单个更有代表性。
聚类——无监督模型
k-means 聚类。
随机 k 个初始分类点,然后不断迭代,对于每次迭代,先找每个数据点最近的分类点,划分一下类,然后计算中心点,用中心点更新每个类分类的分类点,然后重新找最近的点划分类,以此类推。这个东西初始点对整个算法的影响其实很大,不够好,同时可以构造一些数据导致算法收敛很慢。另外异常值也会对最终影响很大,总之就是很不牛。
神经网络基础
单个神经元:输入一堆参数,线性组合一下然后套一个激活函数。
可以用 pytorch 上 gpu。
一个神经元相当于
图片和卷积
图片编码-编码每个像素,对像素的编码决定信息量,同时像素太少就会太糊。图像就表为二维矩阵。
灰度直方图:对每个灰度统计一下亮度=它的有几个像素,可以提现整体亮度的趋势。
太亮/太暗 -> 人看不清楚。可以把最暗、最亮的拉到灰度轴两端,做归一化。
黑白图片相当于 int 或 float 的矩阵,彩色图片就相当于是 RGB 三个颜色的矩阵
局部增强:对局部进行一些操作,相当于卷积一个东西,即
这个东西很有用,比如可以做傅里叶变换,过滤掉一些频率的东西。同样的道理还可以提取一些特征,比如想查看是不是存在某种图案,那么可以卷积一个对应的函数(比如长得像想找的东西的函数),那么得到的加强点就是对应特征的位置。
例如:平均化就是弄一堆 1/9 这相当于过滤到了高频信号;锐化就是弄一堆 -1 和一个 8,这里和为 0 可以过滤掉频率比较低的部分,留下锐利的部分(这在某种意义下相当于差分,是一个边缘提取)。高斯(正态分布)和平均化差不多,也可以用中间值(中位数),效果也和平均化差不太多(一个应用是雪花噪声)。
卷积神经网络
全连接层在图片比较小的时候还行(MNist 中的 2828=784,隐藏层大约每层几百个神经元),但如果图片太大那就寄了,比如 1K 1K * 3,这个矩阵存都存不下。
人眼实际上是辨别某些图片的整体特征,而不是同时考虑所有东西,因此可能可以不用全连接层。那么可以搞某种稀疏链接,而且可以复用,那就卷积吧!
1D 卷积是一般的卷积,2D 卷积就相当于给一个卷积矩阵。大概有几个参数(stride 隔几个做一次,padding 越界怎么算)。这么搞可以把图片搞小一点,提取了一些特征图而不需要原图的全部信息。如果搞一堆卷积层的话就可以抽取一些特征的特征,弄出一些比较抽象的东西。
有一些乱搞比如在卷积的东西里面塞一些洞,让整个东西可以看到更多东西。
池化算法
越往后走,越需要更多的卷积宽度(输出更多的特征),这个会导致整个东西越来越大,pooling 就是让长宽都减少一些,就是进行一个特征的聚合(本质上似乎和卷积也没有什么特别的区别(?))
可以用不同尺寸的池化算法然后再搞,弄到一块搞到后边,反正就是纯瞎搞,看着怎么有道理怎么搞。
分层表示学习
怎么训练一个 CNN 呢?首先需要很多层卷积,因为需要得到更多信息才能够进行一些操作。那到底学到了啥捏?可以看一看卷积对什么样的输入反应最大,这样就可以看看卷积到底筛选了个什么玩意,有一定希望能够明白到底学了个啥。事实上这个网络并不总是靠谱,可能高出一些专门的攻击(如攻击 AlphaGo 感受范围比较小,或者攻击一些图像识别算法)。
一些辉煌的历史:AlexNet 将 CNN 用在图像识别,整了几个 CNN 然后接全连接层,搞成 1000 分类,薄纱传统机器学习。后来又搞了个 VGG16。
现在用的比较多的是 3 3 的卷积核(之前很喜欢用 7 7),事实上套几层之后都差不多。
很多都喜欢先在 ImageNet 上训练一个多分类模型,然后把最后的全连接层弄掉,只留下前面的一堆 CNN 层,结果得到了一个很好的通用特征提取器,非常厉害,这个就是所谓预训练模型,这样就可以搞来干别的了。
关于梯度消失问题:卷积层搞太多容易梯度小时,根本没法训练,于是就引入了 ResNet(残差卷积网络),就相当于是把一层的结果作为两层后的输入,这样的好处是保留了梯度,每层的梯度直接传回之前两层,这样的单位成为一个残差快(residual block)。
大家发现这个东西太好用了,现在没人搞计算机视觉了(?)
卷积怎么跑得快捏?一般的卷积复杂度就是枚举每个东西。
SqueezeNet:现在没人用了,搞一个 1 * 1 的卷积层压缩特征层数,然后再扩大一下
MobileNet:分层卷积,不把多张图搞到一块了,而是把每个特征图弄成一个 2D 的卷积,然后再搞一个 1 1 k 的东西把不同特征图之间的东西混起来,这样对于每个位置的计算量 t n m k 就变成了 n m + t * w,这叫深度可分离卷积。
ShuffleNet:把图片先分割一下,然后分开做,在一些地方 shuffle 一下,把特征给混起来,这样也可以减少计算量。
反卷积:多弄点 padding 或者塞点 0,保证信息没有损失就可以了。
一些其他的算法包括把图变大然后在搞(resize convlution)
一些训练小技巧:
首先感受野要覆盖整个图。另外可以使用数据增强(比如调整一下亮度、左右翻转,这个可以用 dataloader 和 dataset 搞)或者试试正则化,因为数据很小而且网络很深,很容易
CNN 这个东西很擅长提取图片当中的特征,因此在计算机视觉当中有很多应用。
CNN 用途
这个不同于分类问题,是要在图片中把东西识别出来(框起来)。
一个著名的数据集是 Pascal VOC,分为 20 类和大约 11k 个照片,27k 个框框。反正之后也搞了一堆数据集,现在更大了。
这个任务主要是看交并比(Intersection over Union),框框画的越接近肯定越好,一般认为当 IoU > 0.5 的时候物体被成功检测到。
平均精确度(Average Precision,AP):计算精度和召回率。
精确度 = 预测对的阳性 / 预测的阳性;召回率 = 预测对的阳性 / 真正的阳性。
不同的领域对这个东西的要求是不同的。
通常把这个东西画成 召回率-准确度 图,就可以得到一个 2 维的图,理想情况下最好的模型应该两个值都是 1,所以肯定是左下方面积越大越好,这个东西就叫 AP。通常把不同类 AP 分开算(水论文)
目标检测算法:R-CNN
用选择性搜索算法(Selective Search,这是个非神经网络算法)提取候选区域,然后将区域适当拉伸处理成给定的大小,然后扔到 VGG(的预训练模型)当中分类,之后通过回归来获得框框的位置(这里用到了非极大值抑制用以移除重叠的边界)。
当然这个很好,但是也有点不太好:首先是比较慢,其次拉伸操作可能会影响分类问题的准确性,而且每个都拿 VGG 算一遍也很慢,最后这个东西不是端到端训练(很多步)。
之后就搞出了一个 SPP Net。SPP Net 主要的改进在于先整一堆卷积层,然后再在提取的特征图上进行搜索找出区域,之后用一个金字塔池化方法。
然后又搞了 Fast R-CNN 和 Faster R-CNN,去掉了选择性搜索,改用区域提议网络(Region Proposal Network,RPN),用神经网络搜索候选区域,这样就成功搞出了一个端到端模型(整个东西是一大个模型,梯度可以从最后到最前传播,可以同时优化整个网络,不需要优化每一步了),感觉有点现代人工智能那味了。
目标检测算法:YOLO:
输出两个东西,一个是 7 7 的东西,表示图上对应范围里是什么东西,另外还处理出物品的长宽,合起来就可以知道物品的位置了!最后会输出一个 7 7 * 30 的特征图,每个位置是一个大小为 30 的向量,分别输出分类结果、对应的长宽还有置信度一类的东西,这样就可以把最后的框画出来。
这个东西也有一些问题,比如小物体跟别识别不出来。
反正后来又有很多人搞了很多东西。
图像分割
驻点分类任务:把照片上属于不同物品的部分分成不同的颜色(标签),当然这个也有不同的目标,比如语义分割或者实例分割(把同类的实例分开)。就是像素级的分类问题,最后有几类就输出几层 0/1,相当于每一个像素内部 softmax 一下得到概率分布。
这个要用到反卷积的一个操作,搞出高级特征之后用反卷积网络还原回来。问题是最后会得到一个比较高级的特征,但是深度很大的话就会损失很多很小的细节,在最后小张量上面肯定不可能很好地分割。解决方式就是使用 Skip Connection,把正向卷积过程当中每层的特征扔到解码器对称的位置上去,这样就可以保证反卷积可以保留原来的小特征。
像素级的交叉熵:面积较大的物体对损失函数的权重较大,分割小物体性能较差。Dice 系数:可以看做是可以求导的 IoU,
那怎么换成实例分割捏?加上前面的框框就行了。
multitask learning:多个(类似)任务同时训练,可以提升网络性能,总之就是后来搞了一大堆。
当然还有各种乱七八糟的技巧,比如加权突出边缘之类的。
人脸识别
首先找到人脸,对准然后识别。
人脸识别:给定一张图片,与已知的人脸库进行比较,从而确定人脸对应的身份。这个问题也有两类,即是否封闭,所有可能识别的人脸都出现在数据集当中。如果用人脸数据库的话更新就很麻烦,所以基本上还是用的是开集,输入的人脸并不一定在数据集当中,即数据集和数据库分开。
就是希望有一个固定的模型,新添加人的时候使用单张图片进行参考。
怎么训练的?利用 CNN 的特征提取能力训练一个提取人脸特征的东西,然后得到一个特征向量,不同的人比较特征向量。那么这个模型就要求一个人的照片提取出来的特征向量差别不大。最后就要求最小化一个人不同的距离,最大化不同人的距离,这个可以用类似均方差之类的东西弄。现在已经解决了!可喜可贺。
人脸认证:给定量张图像,验证是不是属于同一个人
姿态估计
提取运动关节位置。
有两种实现,一种是自顶向下,先把每个人分出来然后再对每个人做,这个好处是之前目标检测的技术已经比较牛了,但是要对每个人分别估计运动状态,人太多了就不好办了。
另一种是自底向上,首先检测所有关键点,然后分给不同的人,这个好在效率比较高,但是分给不同的人比较困难。
另一个思路是把姿态估计弄成目标检测,直接用目标检测算法检测关节的形态,每个关节连线画成一个框。
其他应用
人员重识别(不同摄像头追踪同一个人)
深度估计(用两张图片才有视差)
风格迁移(图 + 图 = 图)
超分辨率(图像分辨率增强)
图到图转换翻译。
接下来要讲无监督/非对称的图像翻译。
生成对抗网络(GAN)
监督学习 -> 对抗学习,实现目标由分类变成生成内容。
生成式模型
给一个描述,渲染/构造出一个图片。
不同于传统的图像计算学(依赖先验知识),生成式模型是由数据驱动的。
就是希望获得一个图片(或其他内容)的概率分布,通过已知的数据学习这个分布。这个东西有几个特点:
- 生成:通过训练出来的概率分布生成新东西
- 密度估计:通过训练出来的概率分布判断一个东西和数据当中的东西是不是一类
- 无监督学习:根据无标注的数据集学习
回顾一下判别式模型和生成式模型的区别:
判别式模型:对于一堆数据点
生成式模型:对于每个标签
朴素的 GAN
有两个东西对抗,一个生成器 G 和一个判别器 D。G 的任务是根据输入的随机向量生成一张图,让这张图尽量欺骗 D,是它判别为真的图;D 的任务是一个二分类任务,希望所有数据集当中的真图和 G 生成的图分开。
两个损失函数(优化目标)是相反的。但是由于这个东西可以串成一个大网络,G 可以获得 D 到底是长什么样,针对性地学习,这样生成器和判别器的能力都不断提升,最后 G 就具备了图像的生成能力,即将随机变量的分布(比如若干独立正态分布)映射到数据空间中的分布。
这实际上是一个 mini-max 博弈,可以证明如果两个东西都优化到了最优解那生成器 G 就会生成真实的数据概率分布,而且 D 完全分不出来。这个东西可以得到一个额外的结果,就是控制输入给 G 的噪声逐渐变化,就可以采样出从一个类别过渡到另一个类别的图的分布,很有意思。
当然这个实际效果不好,cifar10根本跑不出来能看的东西。
DCGAN: Deep convolution GAN
先对输入的噪声 z(100 维)投影+reshape一下,得到一大堆 4 4 1024 的东西,之后一路反卷积最后得到 3 64 64 的照片,这个效果就很好了。
然后有一些炼丹小技巧,使用跨步卷积、调一调训练的超参数之类的。
然后这个因为是把上述东西当做 G 塞到一个 GAN 里面,当然也可以有可视化的图渐变。当然这个实际上是把输入的噪声 z 当做特性,所以甚至可以把几张图对应的噪音 z 做一个线性操作然后就可以得到有对应特征的图。眼镜男 - 男 + 女 = 眼镜女。大神啊!
变分自编码器
另外有个东西叫 VAE(variational autoencoder,变分自编码器)。这个玩意有一个编码器 E,图像 X 经由 E 编码成 Z,然后有一个解码器 G,把 Z 解码成 X',然后这个这个东西的优化目标就是 L_2(X,X'),即均方误差。这样就可以获得一个图像和一个向量的双向对应(E + G),由于想要生成图片得符合 Z 的分布,可以给 Z 加一个 KL 散度限制它接近正态分布,同样地还是同时训整个网络,优化目标就是两个东西加起来。
GAN 只能把一个概率分布映射到图片,但 VAE 能有一个接近双向的映射。VAE 好就好在它可以把图变成编码,因此可以方便地求两个图的平均值。
所以说更好的 GAN 应该还有编码器。
GAN 的损失函数 vs 自编码器的损失函数(均方误差)
均方误差不太牛,问题在于细小物体可能直接消失,因为小物体在最终的均方误差当中贡献很小,只要整体大面上可以就均方误差很小,因此 VAE 很难学会细节的东西,比较一坨,比如会把人的耳朵搞没。但是 GAN 就没问题,因为优化目标相反就可以有一个对抗的过程,都通过去的知识不断比较学习,相当于是自适应的损失函数。
所以 GAN 很快就能生成很多很高清的东西了,VAE 比较拉。
后来还有扩散模型和视频生成的 sora 之类的,当然是比较复杂了。
更牛的 GAN
回顾一下,GAN 的目标就是找到
现在 GAN 的目标就是找一个类似编码器的东西。
一个尝试是除了噪声以外还给 G 输入一个分类向量 c,c 是 one-hot 的,表示要生成哪一类的图。然后 D 除了分辨真假以外还要做一个分类任务,输出一个 softmax 的东西表示猜测的 c。
D 的损失函数就是,对于 data 中的东西要预测是真的,并且分类尽量准确;对于 z 生成的东西,要预测是假的,并且分类对应的位置尽量是 0。G 的损失函数就是首先让 D 认为图是真的,并且尽量分到 c 中那一类当中。这样最后的结果就是 G 学会了怎么生成骗过 D 的真假判别和类型判别的,即真的而且是对应类别。这样已经是学会了类别。
之后还想用文本、图片+文本 生成图片。文本到图像的生成:另一个多模态生成问题,GAN 刚还是多模态的(要有噪声)。
为了训这个东西,每张图都有若干句话描述它,这样每个图片都会有匹配的句子和(其他)不匹配的句子。
之前的判别器是一个输出类别,但是现在没得输出了,另外需要一个文本编码器。
判别器 D 是这样工作的:可以获得文本编码器的编码和图片,首先要判断图是不是真的,然后要判断文本和图是不是匹配。那么数据集就包括若干图和它们匹配/不匹配的句子,可以喂给 D。对于前端的 G,也有一个文本编码器编码文本,和噪声一起喂到 G 当中,G 的优化目标就是想欺骗判别器,让图真并且让图和文本匹配。需要注意两个文本编码器应该是一样的。
这样就可以文生图了!皆大欢喜。但是还是想要让 GAN 有一个编码器。最简单的方法是给一张图然后找到离他最近的噪声 z,这样就可以梯度下降了!真是炼丹之炼丹啊。
编码器
无监督转换:回忆条件生成的 GAN(给出一个 one-hot 的 c),当噪声不变 c 修改的时候,除了 c 控制的特征以外其他的应该差不多。现在把 G 控制住,作为预训练模型,然后加一个编码器 E,直接把 G 输出的图 X 重新编码回 Z。这样甚至可以直接变换 c 控制的特征,保持其他的不便。
当然梦想很美好,现实很骨感。当图片太大了或者更复杂的图片(特征),就根本学不会了,虽然 E 已经做得很好了,但还是不行。这个原因是 E 只看过假图,只看过真图,真图和假图的分布本身不是完全重合的,因为 G 不可能训得很完美,然后就会导致输入真图的时候 z 就不一定是好的了,因为有可能压根不在概率分布里,这样 z 是不准确的。
同样可以把整个网络反过来,X -> E -> Z -> G -> X,这是由于 G 可能根本就没法生成出 X,G 根本没法学习。
这样直接暴力搞就肯定不行了,只能在一些比较小或者特征比较接近的数据集上表现比较好,根本原因在于 G 不可能完全学会了真图的分布。
BiGAN
现在就是想要找到 X 和 Z 的联合分布。那么就需要同时训 G 和 E。具体地,E 接受真图 X,输出预测编码 Z',G 接受编码(噪声)Z,输出假图 X',判别器 D 接受 X 和 Z,然后想要把上述两种情况分开,G 和 E 的目标都是欺骗 D 使得它分不出来。
最后反正就会让 E 和 G 互逆(如果是最好情况下),但是实际上炼丹根本练不出来,因为压缩率太高了,Z 维数太小,所以根本不现实。
所以其实可能不需要把特征变成一个特别小的向量。
CoGAN
学习两个(语义相似)领域的联合分布。比如说男女图片,X_A 和 X_B。
首先弄两个个 GAN 让 G_A 学习女性的照片,G_B 生成男性的照片,然后 G_A 和 G_B 前面几层的权重共享,靠近 Z 的是高维特征,因此这样可能能够提取出一些公共的特征;更远离 Z 的可能是比较细节的特征。这样的话生成的图也差不多。同时编码器 D_A 和 D_B 的后几层权重也共享,这样就会有一些高维特征的公共判断。
这样确实能够搞出来大体差不多,然后特定控制的特征不同。但是这个还是不能解决编码器的问题。
CycleGAN
上边东西的问题是提取成高维特征之后信息太少了。现在要搞一个 G_A2B 和 G_B2A,这两个都由一个编码器 E 和一个生成器 G 构成,然后 G_A2B 和真实的 X_B 对抗,由 D_B 分辨,G_B2A 和真实的 X_A 对抗,由 D_A 分辨。如果就这样的话那生成任意一个像 B 当中的东西就可以了,解决方法是把 X_A 经由 G_A2B 生成的 X_B' 重新用 G_B2A 生成 X_A',然后搞一个 X_A 和 X_A' 的误差。G_B2A 同理。
这样的好处是要求 G_A2B 尽量保留原图的特征,这样 G_B2A 才能生成出像原图的东西。
一个应用是分割图转换成街景图,这样以前做图像识别的数据集就能拿来用了,这个东西效果最好的是 CycleGAN,因为之前其实都没有要求生成的图和原图尽量长得一样。
当然这个也有一定问题,比如说如果数据集有点偏差的话最后输出的特征(比如色调)可能会有点区别。一个针对性的方法是要求 X_A 和经过 G_B2A 之后的 X_A' 之后要尽量一样,现在色调就弄好了。
不出意外这个也有问题。比如马转斑马就很好,但是斑马转马就不行了(有纹路),因为如果不保留的话就只能瞎画纹路了。所以说这个会导致特征互相串,特征都被保留起来了。
然后还有一个更好地东西,就是 ACL-GAN,通过重新设计损失函数要求前后差不多就行了,这样就可以去掉一些特征了,皆大欢喜。
文修图
就是 图 + 文 = 修改的图。
这个东西和之前的文生图也差不太多,G 给输入的的图片先 Encode,加上任意一个不符合特征的句子(经过文本编码器),然后要让新的图像和句子匹配,后半部分的判别器 D 和之前一样,要分辨是真的假的还是和是不是符合句子。
这其实也是个弱监督学习,因为并没有图片修改之后长什么样。
RNN
跑去考试了,待补。
Attention 和 Transformer
RNN 可以上下文,但代价大、长时效果差,而且不能并行。
Transformer 能够同时把整个句子(序列)放进去,可以比较高效地并行。
Attention 原理
人类视觉注意力:只有一个焦点,忽略无关信息,可以空间、特征选择性地关注信息。这个比较省能量,可以借鉴到神经网络当中。
这个就叫 self-attention
- 非自主性提示:键(Key),值(Value)
- 自主性提示:查询(Query)
大概就是对于当前的一个字(token),去看句子当中每个位置哪个和当前的相关,这样就可以得到一个权重的矩阵,表示当前每个词对应的相关性,然后再把已经提取出来的特征相乘,就能得到这句话的意思(大概)。
先把每个 token 搞一个词嵌入然后写成矩阵 Q,之后另外搞一个特征的玩意 K,搞一个
搞完了之后给每个词 softmax 以下就可以得到一个概率分布,之后再搞一个线性变换加权然后输出。
多头注意力
可以影流之主搞 h 个 self-attention,把输入的向量也分 h 份,这样每个头可以包括不同方面的注意力,最后放一起搞一搞输出。
Transformer
整体包括编码器(Encoder)和解码器(Decoder)。
位置编码:句子 = 词 + 顺序,词嵌入可以用 Embedding 序列搞,顺序需要位置嵌入,这就是位置嵌入,要搞一个编码位置的玩意。经常用正弦/余弦函数(为什么要分开搞?)
Encoder:
词嵌入 + 位置嵌入 -> (带残差)多头注意力 -> 归一化 -> 带残差的全连接层。
多个编码器可以套起来。
Decoder:
总体来说,decoder 会不停地输入已经生成的东西,第一次输入一个 BOS 占位符之类的东西,之后喂到多头注意力之后并上 encoder 得到的信息(encoder 只做一次,之后不变),然后获取下一个词的输出。
首先,输入的词嵌入和位置嵌入会先喂到一个“带掩码”的多头注意力。生成当前词的时候要把之后位置的东西搞掉,避免虚空注意到之后的东西,就是给之前注意力最后 softmax 的地方上三角加一个 -inf 就可以了。
然后和 encoder 得到的东西作为 K 和 V,当前的作为 Q,搞出一个东西来。这样 Q 就包含了当前生成器的状态,经过多头注意力可以“注意到”句子当中对当前位置比较必要的一些特征。
NLP 预训练
让无标签数据上学习通用语言表示,预训练之后把最后几层换掉接上。
比较常见的预训练模型:GPT、BERT
GPT 只用了解码器 Decoder,只通过左侧的上下文来预测当前词,通过一些无标签文本来训练下一个 token 的生成概率,训练很方便!训练就是预测下一个 token + 一些附加任务(比如分类判断情感之类的)。
怎么用这个预训练模型捏?首先得在后边搞一个全连接层,喂给 decoder 的时候搞一些不同的标记,然后 transformer 就可以干不同的事了,真神奇!
BERT 则是编码器 Encoder,处理句子之间的关系,以此喂一个句子进去,训练就是人工挖掉一些东西(比如 15% 用于预测,其中 80% 替换成特殊标签,10% 替换称错的词,另外 10% 不动),然后完形填空,这样不仅能够完成句子,还能识别错的词。这个东西的主要作用是 NSP(Next Sentence Prediction),预测下一个句子。
这个实际上不是直接生成一句话,而是判断两个句子是不是连着的(有上下文关系),这样就可以用之前很多 CNN 和 GAN 的训练方法方法故技重施了。
这个也可以用一些刚刚 GPT 的方法用,比如塞一堆分隔符之类的,然后后边接点乱七八糟的东西,这样可以干不同的事。
一点小历史
2017 年 Transformer 提出:典中典之 Attention is All You Need。
最开始大家都用 BERT,因为 BERT 迁移性很好,但是后来 GPT 搞得很好,因为知识已经放在了大模型的参数当中,用生成式的方法解决问题通常可以对问题本身有更好的理解(?)
当然现在从 GPT 1 到 GPT 4 一直在 Scaling Law,即参数提升知识能力也会提升。