从24年底DeepSeek出圈之后,连村里的奶奶都知道了,未来如果不知道人工智能,会不会和现在的文盲一样了呢,作为初学者,这里记录下自己的学习过程。
1.机器学习和深度学习
机器学习(ML)是训练计算机程序或者系统在没有明确指令的情况喜爱执行任务的科学,计算机系统使用机器学习算法来处理大量的数据、识别数据模式并预测位置或者新场景的准确结果。深度学习是机器学习的一个子集,使用特定的算法结构,称之为神经网络,以人脑为模型。深度学习方法试图自动执行通常需要人类智能的更复杂的任务。比如你可以使用深度学习来描述图像、翻译文档或者将声音转录成文本。
深度学习使用人工智能和机器学习(AI/ML)帮助数据科学家收集、分析和解析大量数据。深度学习(也称为深度神经学习或深度神经网络)会让计算机通过观察,学习、模仿人类获取知识的方式。
AI的核心目标是通过机器学习、深度学习等技术,让计算机能够从数据中学习,并自主地进行推理和决策。根据AI的能力范围和智能化程度,可以将人工智能分为ANI、AGI和ASI三个等级:
ANI(弱人工智能)主要被编程以执行单一任务,它通常只能针对特定领域或任务展现出类似人类智能的能力。例如,手机地图导航、网购产品推荐等都是ANI的典型应用。
AGI(通用人工智能)则是在不特定编码知识与应用区域的情况下,应对多种甚至泛化问题的人工智能技术。它拥有推理、计划、解决问题、抽象思考、快速学习和从经验中学习的能力。AGI更像是无所不能的计算机,能够像人类一样应对多种任务和环境。
ASI(超人工智能)相较AGI,不仅要求具备人类某些能力,还要能够独立思考并解决问题。ASI不仅在智能化程度上超越了AGI,还在应用范围上有所扩展,能够应对更加复杂和多样化的任务。
人工智能包括自然语言处理(NLP)、计算机视觉(CV)、机器学习、深度学习、数据挖掘、机器人技术等分支。这些分支在处理不同类型的数据和任务时各有优势。
自然语言处理(NLP)主要关注于自然语言的理解和生成,计算机视觉(CV)则关注于图像和视频的识别和理解,机器学习和深度学习则通过训练数据来让计算机自主地进行决策和预测,数据挖掘则从大量数据中挖掘出有用的信息,机器人技术则利用AI技术来构建能够执行各种任务的自动化系统。
上述是关于AI的经典论述,在介绍什么是 Transformer 之前,需要很多的准备工作。
2.什么是神经网络
一起皆函数functions.最简单的线性函数就是
既,有个输入x,经过函数变化得到输出y. 既输入域x -> f(x) -> y输出域。如果给出
很容易就得到 这样的关系,但是如果给出的是
这个是不是就不容易一眼看出来了,怎么办可以直接放入到坐标轴中。发下有个类似在直线附近“波动”的,大致画一条直线这个就是拟合的过程,那如果是这种的就发现需要一个非线性函数进行拟合了,那如果把线性函数变成非线性函数呢,给线性函数增加一个激活函数,比如平方,正弦,e的指数 。
这就是激活函数,因为实际应用中,线性关系关系太少了,常用的激活函数比如
上面介绍的就是一个变量,实际输入可能很多,此时从一维变成多维。
这样就是将线性函数加一个激活函数->非线性函数。将上面作为一个整体,可以再次进行激活变换
把这里的每个小圈圈叫做神经元,左边的是输入层,右边的是输出层。继续增加激活函数。那中间的这一层就不早是最终的输出层了,而是存在于某个很复杂的函数变换中,对于输入输出而言,我们看不到这一层,因此把这一层叫隐藏层。
而右侧的图中这一大片神经元互相连接形成的网络结构称为神经网络。
回顾下,目前有两个输入变量,
构成了输入层。按照如下步骤
- 先进行一次线性变换,
- 再进行一次激活函数,
得到了隐藏层
- 把a当成一个输入变量,继续进行一次线性变换和激活函数
就计算出了最终的输出
我们再整体看下,有输入,
接着得到隐藏层
,最后得到输出
.整体上就像一个信号从做到右传播了过去,这就是神经网络的前向传播。
3.向量积和范数
为什么要突然插入这个呢,因为这个是神经网络参数非常重要的基础部分。
线性代数中非常有用的一个运算符就是范数,非正式的说,向量的范数是表示一个向量有多大呢,这里的大小
不涉及维度,而是分量的大小。在线性代数中,向量范数是将向量映射到标量的函数
.给定任意向量
.向量范数需要满足一定的条件和属性,即:
- 如果按照常数因子
缩放向量的所有元素,其范数也会按照相同常量因子的绝对值进行缩放,即
- 满足三角不等式
- 范数是非负的
所以这里给出范数和
范数
4.如何计算神经网络参数
现在我们再次接着什么是神经网络的章节。给出一组数据,并给出一个拟合函数,获取和
的关系
这样我们很容易得出右侧拟合的不好,那如何定义拟合的不好呢?
函数值我们使用,预测值使用
表示。那真实值和预测值之间的误差就是
。为了评估所有值的误差,将所有误差相加。
这样就能反映预测数据和真实数据之间的总的差异,也就可以反映当前的这份线性函数与真实数据的拟合度了,那上面这个函数我们叫他损失函数 。初中数学我们就知道,处理绝对值非常不方便撒,需要各种分类讨论,因此改成平方的形式,这样的好处就是
- 取消绝对值
- 方法较大误差的影响
这就是均方误差。
均方误差只是损失函数的一种计算或者说是定义的一种类型。那这个函数就是关于和
的二元一次函数
求函数的最小值,就是求导数为0的坐标的值,
最后求解得到
这个是一个二次函数,求其导数为0的地方。
因为这个是关于和
的一个函数,如何求解呢,最简单的办法就是去尝试呢,有鱼没鱼先撒两网。
我们假设作为起始值,现在就是找一个更优的
和
,看看是否
更小呢。
比如变化了一点,看看
函数变化了多少,调整
从5增加到6,计算损失函数为9,那说明这个变化的方向是对的,因为我们要求的是损失函数的最小值。再尝试把
增加1,发现
,发现损失函数增加了2,那说明
的增加会让误差变大,这次方向是错的,那就反过来将
往小的方向调整 。
所以最终就是微调或者
对损失函数的影响,然后每次把参数向着让损失函数变小的那个方向进行微调,直到让损失函数足够小,具体如何调整呢,
变化一点,使得损失函数变化多少,这其实就是
的偏导.
我们要做的就是让和
不断地往
小的方向去寻找。即
我们要做的就是让和
不断的往偏导数的反方向去变化。变化的快慢再增加一个参数,叫学习率
这些偏导数构成的向量就叫做梯度
而不断地变化和
,让损失函数逐渐变小的过程,进而求出最终的
和
,这个过程就叫做梯度下降。那现在如何求解偏导数呢?
首先我们根据的值求出
的值,这里随便选择一个激活函数 。比如使用
然后再根据a的值计算出输出层,这个
前文提到是预测值
然后再根据和真实值
计算出损失函数。这里损失函数就使用均方误差了。
由于只有一个输出数据,所以把求和符号简化下。这个神经网络中一共有四个参数,分别是
这四个参数需要通过梯度下降的方式逐步求解。关键的问题就是求解对它们的偏导数,以
为例。偏导数也是导数,导数就是自变量的微变对因变量的影响是多大,就是
变化一点对
变化影响。
所以就是变化一点导致
变化了多少,
变化了一点导致
变化了多少,
变换一点导致
变化了多少。
将上面的相乘就知道了变化导致
变化了多少。
这种偏导数的求解方式就叫做链式法则。 由于我们求导的或者说求解偏导的过程是从右侧向左侧依次求导。再计算前一层的偏导数,比如这里先求解是
这里是先对 求解偏导,这个求解依次之后,下次对求解
就可以再次复用了。通样对于求解
的偏导也是如此,这样求解过程就是从右向左一点点点的传播过来,这个过程我们形象的称之为反向传播。根据前向传播根据输入x计算出输出y,然后再通过反向传播根据计算出损失函数关于每个参数的梯度,然后每个参数都向着梯度的反方向变化一点点,这就构成了神经网络的一次训练。神经网络经过多轮训练,直到损失函数足够小。
5.训练神经网络为什么这么难
是不是觉得只要样本数据足够多,就可以训练出好结果呢,原则是这样的,但是实际使用受限于资源,成本,样本数的限制,无法做到足够多的。我们先看看
黑色表示拟合的数据,这个就是训练的曲线拟合的更好,但是是不是“感觉”有种过犹不及的感觉呢。 绿色点是预测值,发现右边的不如左侧的,这种就是在训练数据上表现的很好,但是在没有见过的数据上表现很糟糕的现象就叫过拟合。在没有见过的数据上的表现能力叫泛化能力。
所以并不是模型越大越好。所以说简化模型的复杂度在某些场景是有效果的,当然增加训练数据量也是有效果的。数据量足够充足,原本复杂的模型也会变得相对简单了,但是很多情况下无法收集更多的样本数据,那就可以在原有的数据中“创造”更多的数据。
比如要识别上述图像中的内容,只有几幅照片数据量偏少,此时可以对图像记性旋转、翻转、裁剪、加噪声等操作,创造出更多的训练样本。
这个就是数据增强。这样不仅能增加了训练数据,还能让模型不因输入的一点点小的变化而对结果产生很大的波动。这就是增强了模型的鲁棒性。刚刚是从数据和模型本身入手来防止过拟合,那有无可能从训练过程入手阻止过拟合的发生呢,其实训练过程就是不断调整参数的过程。
只要不让参数过分的向着过拟合的方向发展就可以了。
所以有个简单方法就是在损失函数中把参数本身的值加上去。
这样在参数往大的方向调整时候,如果让损失函数减少的没有那么多,导致新的损失函数反而是变大的,那么此时参数调整的方向就是不合适的,因此这样就一定程度上抑制了参数的野蛮增长。前面的章节提到了关于绝对值的处理和替代方案,这个就是所谓的范数。
还有一种方式。我们的目的是为了防止模型过度依赖某几个参数。这里还是先从示例入手。
假设这是一只小队,中间有一个很牛逼的人物 ,有这个人在总会觉得这支队伍的整体战斗力很强,其实是某个人很强。比如某次这个任务休假了,此时这支队伍可能就无法胜任较为困难的人物了,因为核心不在。这种就是典型的过度依赖少量参数的表现。那怎么办呢?可以在训练过程中每次都随机丢弃部分参数
这样就避免了在某些关键参数上过度依赖的风险。这种方法叫DropOut.除了上面的,还会遇到比如
-
梯度消失,也是就是网络越深,梯度反向传播时会越来越小,导致参数更新困难
-
梯度爆炸,也就是梯度数值越来越大,参数的调整幅度失去了控制
-
收敛速度过慢,也就是陷入了具有最优或者来回震荡
-
计算开销过大,也是就是数据规模量太庞大了,每次完整的前向传播和反向传播非常耗时
每个问题人民都想了各种办法来解决,比如用
-
梯度裁剪,用来放置梯度的更新过大
-
残差网络,用合理的网络结构来防止深层网络的梯度衰减
-
权重初始化和归一化,让梯度分布更平滑
-
动量法,RMSProp,Adam等自适应优化器来加速收敛,减少震荡
-
mini-batch把巨量的训练数据,分割成几个小批次,降低单次计算开销
6.搞不明白的矩阵和CNN
如果有多个,这么写就太麻烦了。这样写下去就太麻烦了。此时需要转换成矩阵,表示第一个神经元的第二个参数。我们用矩阵表示 :
对应的就是
但是这样没有体现神经元的层,那我们就抽象下 。
都使用来表示,输入层使用
表示,第一层使用
表示。所以第一层就是
第二次就是
用表示第几层,最后的通用公式就是这样的
这样每一层的神经元都是上一层的函数。对于每个神经元都和前一层的所有神经元相连接的情景,我们称之为全连接层(FC)
全连接好不好呢,因为数据足够丰富,但是实际使用也有很大的问题,假设一个的图像。展开后输入给输入层的就是900个神经元,假如下一层的神经元是1000,这个全连接层的总参数量就是90万,这太大了。
而且这仅仅是把图像平铺展开,还没有体现出像素之间的空间联系,图片稍微动一下,可能所有神经元都和原来的完全不同,但从图片整体上看,可能仅仅是平移或者变暗,这就是不能很好的理解图像的局部模式,那怎么办呢?
比如随便取一个3*3的矩阵,然后选择一个矩阵。把每个对应位置的值相乘
46*0+75*(-1)+82*0并求和,最终得到一个值就是250。
这样最终把这种运算方式,遍历划过原图像的每个地方,得出的数值形成一个新的图像,这种方式叫做卷积运算。刚才这个固定的矩阵就叫做卷积核。卷积核处理图像后可以达到一定的效果,比如模糊效果,浮雕效果,轮廓效果,锐化效果等,那在神经网络中,卷积核的值是未知的,是和参数一样被训练出来的。
这个矩阵称之为卷积核。
这样就不用画圈了。
除了卷积层外,通常还有池化层,作用是对卷积层后的特征图像进行降维,减少计算量,同时保留主要特征,这里的卷积层,池化层都可以有多个。
这种适用于图像识别领域的实际网络结构就叫做卷积神经网络CNN,CNN只能处理静态图片,但是如果要处理视频,时间序列,文本,语音等动态数据,就需要使用另一种神经网络结构
7.从RNN到Transformer
给你几个字,让你识别下一个字;给几句话让你识别出褒义还是贬义.
如果把这些设计成神经网络的函数
要想把这些文字作为输入参数,首先需要把这些文字变成计算机能识别的数字,这个过程就是编码
有两种极端的方式可以进行编码,一种是只用一个数字标识来代表每个词,比如1代表我,2代表你,3代表他
这样你的词表有多大,数字范围就有多大,这样缺点太明显了,维度太低了,相当于一个一维的向量;另一个极端的方式就是准备一个超级大的向量
这种维度太高了,而且都是稀疏,都是正交的找不到词和词之间的相关性,所以维度太高了不行,维度太低了也不行,所以那我们就搞一个不大不小(维度不高不低)的矩阵。这个就是词嵌入,通过词嵌入的方式得到词向量维度不高也不低 。
每个位置依然可以理解为某一个特征,只不过这个是训练出来的,不是我们人定的,所以特征是什么,可能我们人类无法完全理解,为什么这种方式可以表示词和词之间语义上的相关性呢?可以用两个向量的点积或者余弦相似度
来表示向量之间的相关性,进而表示两个词语之间的相关性,这就将自然语言之间的联系转化为了可以用数学公式计算出来的方式,同时一些数学上的计算结果,也能反映出一些现实中很神奇的解释,比如一个训练好的词嵌入矩阵,可能会使得桌子-椅子=鼠标-键盘。把所有词向量组成的一个大矩阵,就叫做嵌入矩阵 。
其中的每一列就表示的是词向量,这个不是我们人类给每个词赋值形成的,通过深度学习的方法训练出来的,词向量的空间维度非常高,这个叫做潜空间。
现在我们输入一句,输出每个词的褒贬性。通过词嵌入,把每个词变成一个300维的词向量,那么输入端就有1500个神经元。
这样行不行呢?当然可以,但是有两个问题
-
输入层太大了,而且会随着一句话中词语数量的多少而变化,是变长的,不确定的
-
另一个是无法体现词语的先后顺序,仅仅是把它们非常生硬的平铺展开了一个非常大的向量一股脑的送到了输入层,这就像之前说的图像识别领域,把一张图片的所有像素点展开成一个大向量,一股脑的送到输入层一个道理。这样既增加了神经元的个数,又不能很好的抽象出特征和关联
在CNN中是通过卷积操作提取了图像的特征
在自然语言处理领域,通过什么办法既能解决词语之间的先后顺序问题,又能降低输入层的参数量呢?。首先使用经典的神经网络,不要输入一句话而是输入一个词,输出就是这个词是褒义还是贬义,第二个词语也是如此
我们使用表示第几个词。这样就有了顺序关系.
参考最开始的简单模型,但是第二词的计算没有让第一个词参与进来。
我们让第一个词进行非线性变换后,先输出到一个隐藏状态H1,再经过一次非线性变换得到输出Y1,接着让h1和第二词x2一起参与运算,。。。这样就把所有的一句话中的词语囊括进来了。但是这里的w就要进行区分了,有的是针对词向量的,有专门针对隐藏状态的
矩阵,以及最终计算输出结果的
矩阵,对于偏置项b也是如此
把上面这个图简化下,这就是循环神经网络RNN。这个图也有右侧的画法。
这个RNN模型就具备了理解词和词之间的先后顺序的能力,就可以解决判断一句话中各个单词的褒贬词性,给出一句话不断生成下一个字,以及翻译等多种自然语言处理的工作了。
我们接着展开看看
-
第一个词
和权重矩阵
。得到第一个词的隐藏矩阵
并准备往后传
-
和权重矩阵
相乘得到第一个词的输出结果
-
接着计算第二个词词
,同样和要和权重矩阵,但是这个时候需要主要需要将第一个词的隐藏状态
加到输入向量中,拼接起来。
-
同时权重矩阵也增加一个
计算出第二个词的隐藏状态
并准备继续往后传
和经典神经网络相比,就是多了一个前一时刻的隐藏状态
当然这个RNN还有两个问题
-
信息随着时间部的增多而逐渐丢失,无法捕捉长期依赖,而有的语句恰恰是在很远的地方起到了关键作用
-
RNN必须按照顺序处理,每个时间部依赖上一个时间部的隐藏状态的计算结果,无法并行计算
为了解决这些问题,人们使用GRU和LSTM改进了传统的RNN
是否有一种彻底抛弃这种顺序计算,直接一眼把全部信息尽收眼底的新方案呢,那就是Transformer
8.Transformer
用神经网络做一个翻译任务。
先用词嵌入的方式把每个词转换成一个词向量,假设向量维度就是6。
如果把每个字都丢入到一个全连接神经网络中,那每个词都没有上下文信息,且长度只能一一对应。不太行,如果用循环神经网络RNN又面临串行计算,而且如果句子太长,也会导致长期依赖困难的问题,也不太行。
那怎么办呢?
首先给每个字一个位置编码,表示这个词出现在整个句子中的位置,具体怎么计算再说
把位置编码加入到原来的词向量中。
现在这个词就有了位置信息,但是此时每个词还没有其他词的上下文信息,也就是注意不到其他词语的存在,那怎么办呢?接着看,首先使用一个矩阵和第一个词向量相乘得到一个维度不变的
向量,这个
矩阵是可以通过训练过程学习得到的一组权重值,同理再用一个
矩阵和第一个词向量相乘得到
向量,再用一个
矩阵得到
向量.接着对其他词向量也和相同的
矩阵
矩阵
矩阵相乘
依次类似再和其他矩阵相乘
实际使用GPU运算的时候,是使用拼接而成的大矩阵做乘法
现在原来的词向量已经变成了QKV矩阵,接着我们让矩阵和
做点积
这表示在第一个词的视角里,第一个词和第二词的相似度是多少,同理
拿到这些相似度的系数后,再和向量相乘再相加得到
这个
就是表示在第一个词的视角下,按照和他相似度大小,按照权重把每个词的向量都加到了一起。这就把全部上下文的信息都包含在第一个词当中了。同理可得其他几个词也按照这种方式,那么此时每个词都把其他词的词向量按照和自己的相似度权重加到了自己的词向量中
这里的就是计算的中间过程了,我们从全局视角看
现在就是把最初输入的词向量经过一些处理,变成了一组新的词向量。不一样的是这组新的词向量中每一个都是包含了位置信息和其他词的上下文信息的一组新的词向量。这就是注意力机制Attention做的事情。
我们再进一步优化下,有的时候一个词和另一个词可能从不同的视角看是不一样的,对于注意力机制来说,如果只通过一种方式来计算一次相关性,灵活性会大大降低。所以我们做些改进。之前我们是每个词计算一组
现在我们在这个QKV基础上,再经过两个权重矩阵变换变成两组QKV,给每个词两个学习机会。学习到不同的要计算相似度的QKV,来增加语言的灵活性。这里的每组qkv称为一个头head.
接下来在每个头里面的q、k、v仍然经过刚刚的注意力层的运算。得到a向量.
然后把两个a向量拼接起来,得到了和刚才一样的结构
就得到了和刚刚一样的结构
对于刚刚的注意力Attention注意力机制,就叫做多头注意力Multi-Head Attention
这就是多(两)头注意力矩阵。这就是Transformer。
对照下Transformer经典架构图。
-
第一步就是把输入的内容通过词嵌入的方式转换成词向量矩阵
- 第二步加入位置信息,其实就是再加一个形状一样的矩阵
-
经过多头注意力的处理,输出的矩阵维度和输入没有变化,给每个词向量增加了上下文信息
-
添加残差网络和归一化处理,是为了解决梯度消失,并且让分布更加稳定而做的优化
再看看细节部分
如果是部分多头的单头注意力,那么就先让q和k相乘,得到一个相似度系数的矩阵
然后再和v相乘,最终得到了一个包含上下文信息的词向量矩阵
当然还有中间的缩放,掩码和一层softmax处理
接着看看右边的多头注意力情况 qkv分别经过线性变换拆分拆分成多组,相当于给了多次机会学习到不同的相似度关系,依次经过注意力机制运算后,把运算结果拼接concat起来,接着做一次线性变换。
训练这个神经网络的过程就是
- 首先输入要翻译的文本, “I love you baby”
- 然后经过词嵌入Input Enbedding,引入位置编码Positional Encoding
- 经过多头注意力机制、残差归一化处理
- 接着送入一个全连接神经网络,再经过残差和归一化处理
- 结果送入解码器的一个多头注意力机制的两个输入中作为KV矩阵
- 再看右边解码器的部分,输出是翻译后的文本“我爱你宝贝”,同样经过词嵌入、引入位置编码
- 经过多头注意力机制、进行残差和归一化处理
- 送入上面输入的一个多头注意力的一个输入中作为Q矩阵和刚才从编码器送入的KV矩阵再经过多头注意力、残差和归一化
- 接着再全连接和神经网络,残差和归一化。最后在经过一层线性变化的神经网络,投射到词表向量中,最后用softmax层转化为概率,这就代表的预测的下一个词在词表中的概率分布。我们取概率最高的
这里再补充一点,真正推理翻译的时候,是一个一个词进行翻译的
比如翻译到“我”,下一个词应该是“爱”,所以输出我的时候是看不到后面的词的
这就需要掩码把后面的词遮挡住,以便训练的时候模拟真实推理场景时的过程。比如输入是I love you baby,输出只有一个词“我”的时候,经过这个神经网络,最后上方输出的词表概率分布,我们想要的结果就是“爱”字的概率最大,如果训练的时候有偏差,那么计算损失函数,再反向传播调整Transformer结构中的各种权重矩阵,直到学习好为止。
上述学习笔记内容来源于视频 和部分自己的理解。