赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
笔者是一个医学生,纯纯的计算机白痴。因为OpenAI近期的活跃表现,对人工智能产生了兴趣。咨询了学习计算机科学的同学,了解到神经网络是人工智能较为重要的一块,所以抱着试一试的心态想要自学相关内容。以下是目前自学后的总结,主要是当给自己留个“努力过”的证明,如果有大佬看到了本文,还希望能多多批判,帮助笔者进步。
因为本人并未系统学过计算机科学,所以许多观点都是东拼西凑,再加上自己的理解得来的,所以接下来的话大概率是错误的,还望指正。
在我看来,在计算机诞生以前,人类解决问题的常用套路是:提出问题→数学建模→解决问题。
提出问题和解决问题不必多说,关键在于中间的“数学建模”这一步。
所谓建模,就是把现实生活中的问题通过一定的方式转化为数学语言能够描述的问题。虽然每年都有专门的建模比赛,但其实建模本身在我们的日常生活中处处可见,只不过有些建模用得过于频繁,以至于我们会把其当作理所当然的事情。
比如在菜市场买菜,我要买半斤土豆。双方先把钱定下来,然后买方微信支付,卖方交货。这其中,就蕴含了一个数学建模的过程:
而模型中“通过数字”这一步,也就是我们所说的“一斤土豆五块,半斤土豆二块五”。只不过这样的模型我们从小就在用,所以我们倒不觉得有什么稀奇。
可是要知道,土豆本身是没有什么“几块几斤”这个说法的,这个是我们人类为了贸易的便利而人为设定的东西,所以这样一种建模的思想是值得我们重视的。
以上买土豆的例子有一个特点,就是计算量小。但人类社会在发展,问题的数量与复杂程度都在增加,这个时候,仅仅凭借人类自身的计算能力就很难解决了。
于是计算机出现了。
我们知道,计算机的发明本身是服务于战争的。战争时间紧迫,要在短时间内处理计算出足够多的数据来推断敌方状态,这就是计算机满足的需求。后来战争结束,计算机进入民用市场,虽然服务的内容有所变化,但本质上仍是“高效计算”。
也就是说,当有了计算机后,人类解决问题的套路变为:提出问题→数学建模→计算机→解决问题。
换言之,有了计算机,我们可以把许多庞大复杂的数学问题交给计算机去解决,而所谓编程,就是在数学模型与计算机之间建构一座桥梁,使计算机能够为我们服务。
遵循这个思路,我自学神经网络时,会把重点更多地放在数学建模这一步。当然,适当了解计算机编程也十分有必要,但能力有限,在本篇总结中,我会只从数学建模这一个角度去阐述我的自学成果。
我主要自学了两个板块:图像识别与自然语言处理。因此,对应提出的问题就是:
不考虑细节,给出的大致模型是:
而神经网络,就是负责第2步中的“一系列运算”。
那么在分析第2步前,先把第1步和第3步弄清楚是很有必要的。
数字与图像的相互映射很容易理解。我们可以把一张矩形的图分解为许多正方形,这样一来,每个正方形都只有一种颜色,而不同的颜色可以用不同的数字来表示,于是,一张矩形图片就可以用许多排列整齐的数字来表示。反过来,我们也可以把许多排列整齐的数字转化为肉眼可辨识的图片。而这其中的正方形与正方形里面的数字,就是我们所说的“像素”。
数字与自然语言之间的相互映射则相对抽象。因为文字形式本身的唯一特点就是“差异”,所以要用数字表示文字,最容易想到的就是类比身份证,用一连串长度相同的数组来表示各个文字。比如,“我姓陈,不姓王”这句话中,一共有6个字,但2个“姓”是同一个字,所以有5种字,那么就用长度为5的数组去表示各个文字:
就像人有身份证一样,每个文字也有其对应的数组(或者说,向量)。然后反过来,又可以根据数组来反推出对应的文字。
但这里有一个问题:图像用数字表示不难理解,因为对于一个特定的“小正方形”而言,其颜色强度是确定的,因此,可以把不同强度的颜色用不同的数字来准确表示。
然而,文字呢?文字的含义如何通过数字来表示?
比如,“吃”和“饭”两个字经常搭配使用,那么,按理来说,当我们用数字去表示这两个文字时,数字就应该突显出对应的规律,而不只是许多个毫无规律的数字搭配在一起。
所以,在给文字配备“身份证”时,我们需要额外的设计。
首先,在设计前,我们要接受一个假设:某个字词的含义由它周围的字词决定。
这和我们做英文阅读题时很像。做阅读题时,不是有那种根据上下文猜测对应表粗单词的含义的题型吗?其实就是这个假设的很好的映证。
不妨再具体地举一个例子:有两句话,一句是“我吃饭”,另一句是“我恰饭”。那么,即使我们不知道“吃”和“恰”是什么意思,但根据他们两个上下文都是“我”和“饭”,不难推断出,“吃”和“恰”的含义应该是差不多的。
“某个字词的含义由它周围的字词决定”,我们把这个假设命名为分布式假设(distributional hypothesis)
好,既然接受了分布式假设,我们来看如何根据这个假设为文字配备身份证。
现在,我们选定一篇文章,文章里有许多文字,对吧?我们把这些文字一个一个拎出来,单独观察每个文字左右有些什么文字。
比如,在“别阻拦我吃饭喝汤”这句话中,我们拎出“吃”这个字,发现其左边有“别阻拦我”,右边有“饭喝汤”。然后,为了统一和方便,我们需要决定留下左右多少范围内的文字。简单起见,我们定为1,也就是说,我们只看拎出的文字的左边1个文字和右边1个文字,也就是“我”和“饭”。
一篇文章不止有这一句话吧?也许在下一句中,又有“别让我吃面”,于是在拎出“吃”时,又有左右的“我”和“面”,这样一来,我们目前手中的数据就是:对于“吃”这个字而言,身边出现了2次“我”,1次“饭”,1次“面”。以此类推,我们可以得到文章中所有文字的“身边数据”。
接着,我们用矩阵表示出这些数据:
别 | 阻 | 拦 | 我 | 吃 | 饭 | 喝 | 汤 | 让 | 面 | |
---|---|---|---|---|---|---|---|---|---|---|
别 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
阻 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
拦 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
我 | 0 | 0 | 1 | 0 | 2 | 0 | 0 | 0 | 1 | 0 |
吃 | 0 | 0 | 0 | 2 | 0 | 1 | 0 | 0 | 0 | 1 |
饭 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
喝 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
汤 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
让 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
面 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
横着看,比如“我”这一行,我们发现其周围没有“别”、“阻”等,但有“吃”和“让”,这就是这个矩阵蕴含的信息。
于是,我们就根据这个矩阵为每个文字分配身份证,比如“我”这个字,就是横着把数字搬过来即可:
其他文字同理。
这样做怎么就能体现出文字的含义了?为了证明这些“身份证”的价值,我们不妨根据身份证来测量文字间的相关性,然后看看数字运算出的结果是否符合我们的认知规律。
怎么计算呢?用向量。
高中我们学过二维向量,当两个二维向量相乘时,会有一个值,我们把这个值先后除以两个二维向量的长度,就得到了两个二维向量之间的夹角余弦值。这个余弦值越大,说明夹角越小,两个向量的方向越接近;余弦值越小,说明夹角越大,两个向量的方向越背离。
我们把这个逻辑运用在文字的身份证中。
事实上,每个身份证,都可以看作一个向量,只不过不是二维的,而是多维的,维数虽然上升,但背后的性质依旧相通。选定两个身份证,我们算出它们之间的夹角余弦值,余弦值越接近1,说明夹角越接近0,两个身份证的相关性越强,反之就越弱。
比如,我们选定“面”,算其他字与“面”的相似度,并排列如下:
我 - 0.816
饭 - 0.707
别 - 0.0
阻 - 0.0
拦 - 0.0
吃 - 0.0
喝 - 0.0
汤 - 0.0
让 - 0.0
可以看到,“我”和“饭”与“面”的相似度较高,也比较符合我们的认知规律,说明这种身份证配法还不错。
但问题也随之而来了,按理说同样作为食物的“饭”才应该和“面”最为匹配,怎么“我”反而跑到前面去了?可见,这种身份证还有一定的局限性。
我们先分析这种局限性的来源。不难理解,因为“我”在两句话中出现的频率实在太高了,即使它和“面”真正的相似度没有“饭”强,但奈何出现次数多,单纯从个数的统计角度看,便造成了高于“饭”的假象。
为了修正这个假象,我们需要对身份证做出进一步的修改。简单说,就是在原有矩阵基础上除以字词总数量,这样就对冲了因为数量带来的优势。当然,后续还有诸如降维这样的操作,因为不是重点,就不一一赘述了(其实是我能力不够……)。
以上这种身份证配备方式虽然有效表达了文字,但仍旧存在两个问题:
一个是统计工作量太大,必须得对给定的文字库一次性全统计完;
另一个是难以深层次地表达文字间的一些逻辑关系,比如:“面”-“长条形”=“馒头”-“方块形”,人很容易就能理解,但用以上统计得来的文字身份证,就不好说了。
于是,为了解决这两个问题,新的身份证分配模型又被设计出来。至于怎么设计出来,这里先暂按不表。
还记得数学建模的3个步骤吗?之前说的都是第1步而第3步,接下来说明第2步,也是最为核心的一步。
当我们把一头一尾的数字都确定下来后,接下来要做的,就是确定一套运算体系,能够把“头部”的数字映射到“尾部”。
如何确定这套运算体系?以前是基本都靠人脑设计,但现在人脑只需要宏观地调控战略方向,更多具体微观的战术则交给计算机自己解决。
我们以一个具体的例子来理解两者的差别。
比如我现在有25张猫和25张狗图片,总共映射成了50组数据;此外,我把“猫”这个标签映射为[1,0],把“狗”这个标签映射为[0,1];现在要做的是,确定一套运算体系,能够把每一组数据都映射为[1,0]或[0,1],并且要保证映射的正确性。
如果是人为设计,可能就是人自己想一些具体的公式:比如对于一组数据,先求平均,再求方差等等。然后再这样不断推演下去,从而不断向[1,0]或[0,1]靠近。
但如果是计算机的话,就是人把数据全部丢给计算机自己去“啃”,让计算机自己摸索出一套运算体系来完成映射。
而后者,交给计算机“啃”的这样一种思路,就是深度学习,即“神经网络”。
别急,让我们停下来,再次好好确认神经网络的地位。
我们要先提出问题,再是数学建模,然后交给计算机,最后解决问题。
而建模过程中要先用数字表达出问题,再想办法确定数字之间的运算体系,而神经网络负责的,就是让计算机自己能够根据数据“啃”出这样一套计算体系。
那么神经网络究竟是什么?它是如何能够让计算机自己就能够“啃”出运算体系的?这是接下来的重点。
还是先不考虑细节,粗略地看,神经网络其实是一种正向传播与反向传播相结合的机制。
什么是“正向传播”?就是把输入的数据传递成想要得到的数据的过程。
什么是“反向传播”?就是根据已知的正确数据与算出来的数据相对比,把彼此的差异再沿着传递过来的路径传回去,让路径根据这个差异调整自身,使得自身能更好地运算输入的数据。
也就是说,神经网络要做的,是根据正确答案与自己算出来的答案间的差异,不断优化数字的运算体系,直到算出来的答案能和正确答案一样。
从哲学的角度来看,这种设计思路和人的学习模式十分相似,例如我学会使用筷子,其实就是不断试错,不断调整手的姿势,直到能挑上食物为止。
好,以上是粗略地俯瞰整个神经网络。接下来的问题是,神经网络具体长什么样子?它是怎么做到这样一种“试错”然后“优化”的过程的?
神经网络,顾名思义,就是像人的神经一样的网络。人的神经是什么样的?许多个神经元细胞相互连接,前一个神经元的信息可以传递给后面许多个神经元。而人的神经是如何帮助我们学习,试错的?其实是神经元细胞内化学物质的作用。
简单来讲,信息需要载体,对吧?神经元细胞内的信息载体是什么?是各种化学物质。这些化学物质在神经元细胞内发生各种变化,神经元细胞会对这些变化有一定的识别能力,会根据变化的程度来控制信息的传递。
神经网络参考了人的神经,也是设计了许多个类似于神经元细胞的“节点”,这些节点之间相互联系,前面的节点将传来的信息向后传。
人的神经网络中的信息载体是化学物质,那计算机中的神经网路的信息载体是什么?
没错,就是数字。
也就是说,每个节点会根据前面节点传来的数字,向后传递出新的数字,依次传递下去。
这样说似乎有点感觉了,但还是很空洞,所以,需要有一个具体的案例来帮助我们理解神经网络的具体过程。
即,我们需要“计算图”出场了。
我们先把一“头”一“尾”的数字定下来:
神经网络如何将“头”运算为“尾”?计算图如下:
整个计算图有3列,我们从左往右地看:
具体来看数字的流动过程:
那么,上文表粗的“一定的方式”,具体来说是怎样的一种方式?
很简单,就是加权求和。
也就是每个输入的数字乘上一个比例,然后再加在一起。
比如,5个输入数字转化为中间节点a1的方式是:
237 × 0.1 + 125 × 0.2 + 32 × 0.3 + 78 × 0.4 + 96 × 0.5 = a 1 237×0.1+125×0.2+32×0.3+78×0.4+96×0.5=a1 237×0.1+125×0.2+32×0.3+78×0.4+96×0.5=a1
然而,为了运算的完备性,除了加权求和,我们还需要额外再单独加上一个数字,比如:
237 × 0.1 + 125 × 0.2 + 32 × 0.3 + 78 × 0.4 + 96 × 0.5 + 100 = a 1 ( = 237.5 ) 237×0.1+125×0.2+32×0.3+78×0.4+96×0.5+100=a1(=237.5) 237×0.1+125×0.2+32×0.3+78×0.4+96×0.5+100=a1(=237.5)
然后再以另外一种特定的“加权求和再加数字”方式得到a2和a3。
那么得到了a1,a2,a3,同理就可以得到y1,y2。
对吗?
不觉得差点什么?
还记得人脑的神经元是如何工作的吗?是不是说的前一个神经元传来信息,神经元根据这个信息的强弱来传出新的信息?
那好,上文提到的“加权求和再加数字”相当于人脑神经元的哪一步?
没错,仅仅是前一个神经元传来信息这一步。
我们还需要对传来的信息做进一步处理才行,也就是所谓的“根据强弱来传出新的信息”。
怎么个“根据”法?还是求助于数学公式。
比如sigmoid函数:
还记得5个输入数字传递给a1的是多少吗?是237.5。针对这个237.5,a1会利用sigmoid函数把这个237.5转化为新的数字,可以从图中看出,十分接近1,根据公式得到的结果也是如此。也就是说,a1虽然得到的是237.5,但它传递出去的数字会变为1。
当然,这里可用的数学公式有很多,就不一一展开了。
总之,我们要把握的原则就是:
所以关键的地方在哪里?其实是“加权求和再加数字”和“根据强弱来传出新的信息”这两步,对吧?
我们把“加权求和再加数字”这一步骤中的权重和数字拎出来,叫做“参数”,把“根据强弱来传出新的信息”这一步骤的函数拎出来,叫做“激活函数”。
还记得我说神经网络是“正向”和“反向”的结合吗?以上都是“正向”,也就是说都只是尝试,“反向”如何实现?也就是说“试错”并“优化”这一步如何通过神经网络做到?
我们先要想清楚,“试错”和“优化”在数学上的体现是什么。
“试错”,就是把算出来的答案和真正的答案相对比,差的越多,错误越严重。
“优化”,就是要让这种错误越来越不严重。
具体到神经网络是什么呢?
其实就是先前说的“参数”。
即,“反向”就是通过比照算出的结果和真正的结果,通过一定的方式来修改参数,使得参数能够更好地服务于数字,使输入数字得到的输出数字越来越接近真正的输出数字。
又来了,一定的方式……
没错,依旧是数学方法。
比如梯度下降法,就是求导算出各个参数对误差的影响程度,然后根据这个影响程度去修改参数。如果求导后表明当前参数的增大会引起误差的增大,那么我就按照一定的比例减少当前参数的大小,反过来就增加当前参数的大小。至于具体如何求导,又如何把误差沿着网络结构反向传回去,这不在本文的范文内(也不在笔者的能力范围内……)。
同样的,这里可用的数学方法也有很多,也不一一展开了,还是把握原则即可。
而以上,就是神经网络的基本结构。
先停住,我们再回过头来好好看看神经网络是怎么一回事:
还记得上文所提到的“人宏观地决定战略方向,而计算机负责微观的战术”吗?如果神经网络的参数都是由计算机自己算出来的,那还有人什么事?换个问法,人能决定神经网络的哪些部分?
其实有很多,比如神经网络整个框架与流程的设计,可别以为神经网络就只有上文给出的那一种“列列相排”的模式,花样多着呢。各种各样的架构对应处理不同的数字映射体系,这个是计算机解决不了的,只能靠人来。
即便限定到同一种框架与流程,神经网络内部的许多东西也需要人来调整,比如需要多少列节点?每一列又需要多少个节点?节点内部的激活函数应该选哪一种?输入的数字是否需哟做一些预先处理?怎么做?反向优化参数的时候选什么数学方法?要训练多少次?每次训练多少数据?怎么评价模型的好坏?……
诸如此类的许多因素都得由人来拍板,人的智慧也就体现在这儿。
老规矩,因为本文是要从数学建模的角度去总结笔者学习神经网络的结果,所以更多地会去看不同架构,而具体的超参数和其他因素,就不涉足了。
其实就是最初举的那个例子,一列一列排着节点,前一列的节点一起通过加权求和再加数字的方法传给下一列的节点
这个名词听到的频率很高啊,属于是未见其结构,先问其名声了。其实就是在原有的全连接层上做出了改进。
具体怎么改进呢?这得和“非卷积神经网络”对比来看才清楚。
还是假设有一张图片,图片是一个正方形,可以被分解为28×28个小的正方形(像素)。
现在初始的图片映射为数字是怎样的?是一个28×28的矩阵,对吧?
好,我们如何处理这个矩阵呢?
一种常见的思路是,把这个28×28的矩阵拉成一个长条,即784个数字,然后再把这784个数字填入到对应的全连接层中,经过一系列加权求和再相加,激活函数,映射为最终想要的输出数字。
但这样做有一个问题,就是数字太多怎么办?28×28还好,如果是上万级的像素量呢?
还有,如此简单粗暴地把一张本来有意义排列的矩阵拉成一条,很难不怀疑会损失许多信息。
就像人眼看图片,往往也是根据整张图片来判断的吧。没有谁会挨个从上往下,从左往右把每个像素都看一遍,然后得到结果的。
于是,仿照人的思维模式,我们不把图像矩阵拉成长条,而是直接加权求和。
怎么直接加权求和?既然输入的数字就是矩阵,那我同样把对应的参数排列成矩阵不就好了吗?
这就是所谓的“卷积”(数学上和信息学上的卷积我未能明确理解,所以这里还需要看到的大佬指教),即通过排列成特殊形状的参数来处理原有的图像矩阵,得到新的矩阵,然后又继续处理下去,直到合适的时候,再拉成长条,交给全连接层。
这个设计很有意思。
先看模型的目的,目的是输入一个标签,让神经网络能够根据标签输出对应的图片。
比如我输入的是“狗”的标签[0,1],那么神经网络能根据这些数字运算出一组像素矩阵,画出来应该是狗。
怎么做到呢?
最基本的想法应该是将一头(标签)一尾(图片的像素矩阵)的数据定好,然后交给计算机“啃”,对吧?
但这样做有一个问题,就是大概率只能生成已知的图案。
但我既然都有了图案,干嘛还大费周章地要生成个一模一样的呢?
如果可以,当然是要生成一个符合要求,但又不完全一样的图案,对吧?
所以单纯地“标签-结果”的模式走不通。
怎么办呢?
很简单,让两个神经网络互“卷”。
具体说,一个神经网络(甲)负责识别图像,另一个神经网络(乙)负责生成图像,然后我们要让甲不断识别出乙的错误,同时要让乙不断努力升级好能够骗过甲。
就这样让甲和乙内部不断竞争(当然,前提是甲原本就是是训练好了能够识别猫狗差异的),直到双方都很难再做出进步,这个时候,乙往往就能生出许多逼真的图片了。
这里要填坑了,之前在总结文字映射为数字时,不是说仅靠统计来给文字分配身份证的方法不可取吗?那怎样才能更好地分配身份证呢?
利用神经网络。
等等,如果思路清晰的话,你会立刻意识到问题所在。神经网络要做的不是确定一套运算体系,然后这套运算体系把输入的数字映射为输出的数字吗?既然现在文字连身份证都还没有,输入的数字也就没有,怎么能使用神经网络呢?这不等于让一个人自己把自己举起来吗?
是的,这里的思路十分巧妙,可以说是“过河拆桥”,也可以说是“曲线救国”。
究竟怎么个拆法,怎么个救法呢?
我们先给每个文字一个临时身份证,比如独热向量(也就是上文那种很多个0与一个1构成的向量),这是输入的数字。
那输出的数字是什么呢?我们的目标是得到文字的真正身份证,应该如何做到呢?
先把文字的真正身份证放下不管,我们把目标定为输出文字的后面的文字。
还记得“分布式假设”吗?一个文字的含义由其周围的文字确定,反过来,原则上也可以根据周围的文字来得到对应文字的含义。
也就是说,给出前面几个文字,应该是可以推理得出后面的文字的。
而我们输入的正是前面几个文字的身份证,目标是得到后面的文字。
然后就是使用神经网络去正向传播,反向优化了。
好,优化完毕,我们得到了一个模型,可以根据前文预测后文了。
那文字的身份证呢?
就在优化完毕的这个模型中。
还记得神经网络优化的是什么吗?是参数,对吧?
既然得到的这个模型可以通过这些参数来根据前文推测出后文,我们有理由认为,这些参数,很大程度上,是包含了每个文字的含义的。
也就是说,我们看似是要训练出能够预测后面数字的模型,实际上不过是要取出训练后的参数,拿来作为文字的真正身份证。这也就是我所说的“曲线救国”。
而临时身份证(独热向量)呢?肯定就不要了嘛,也就是所谓的“过河拆桥”。
而这样一套模式,将文字转为参数形成的向量,也就是word2vec(word to vector)。
这套框架主要针对具有顺序意义的信息,比如文字,音频等。
因为信息传递的顺序具有意义,所以不能再想以前的网络结构那样,只是单纯地把数字向下一列传递了。
那除了往下一列传递,还能往哪儿传递?
往自己传递。
也就是说,对于一个节点,它会接收两部分信息,一部分是常规的输入数字,也就是文字的身份证,另一部分则是前一时刻的相同节点传给自己的数字。
然后该节点又会处理这两部分数字,生成新的数字。新生成的数字不仅会作为输出的数字,还会传递给下一时刻的该节点。
这样一种“自己喂给自己数据”的模式就是所谓的“循环”。
也是因为不仅接收了本来就要的输入数字,还接收了前一时刻处理后的数字,所以这样一种模式能够体现数据顺序的意义。
简单的循环神经网络依靠前一时刻传递来的数字理解数据顺序的意义,但问题是当这种迭代的次数过多,数字处理会出现一定的问题。
具体来说,是在反向传播时,求导算出来的梯度会因为次数过多而无法被利用(过低或过高)。
因此,参考这种“循环”的思路,除了原本输入的数字和前一时刻算出的数字,再引入第三份数字。
新引入的第三份数字就是来调节内部的运算过程,具体怎么运算暂时不必考虑,把握大的方向即可。
而新引入的第三份数字被称为“记忆单元”,这第三份数字只会在节点自身的循环之间传递,不会被当作输出数据向下一列输出。
道理和长短期记忆一样,都是为了解决简单的循环神经网络在反向传播时遇到的梯度消失和梯度爆炸。
和长短期记忆不同的是,这个模型并没有引入新的第三份数字,而是通过巧妙的运算设计,把前一时刻传递过来的数字用成了既能承担记忆,又能承担输出的模样。
也就是一份数字当两份数字用。
还是和之前一样,我们首先要从宏观上明确注意力机制要干什么。
简单说,注意力机制是用来优化seq2seq的。
什么是seq2seq?
顾名思义,sequence to sequence,将一组具有顺序意义的数字转化为另一组具有顺序意义的数字。
怎么做呢?
就像生成对抗网络一样,让两个神经网络互卷,我们这里也使用两个循环神经网络(准确讲,是长短期记忆或门控循环单元)。
这就是最基本的seq2seq。
那么这种seq2seq有什么问题呢?
问题在于编码出来的新数字。
起初设计的seq2seq,无论输入的数字有多少,因为每次都会迭代新生成的数字,所以最后编码出来的数字只会是最后一次迭代出来的结果。也就是所,编码出来的数字形状(向量长度)是固定的。
这当然不好,尤其是迭代次数太多时,5万个文字最后被压缩成10个数字?怎么想都知道会损失太多信息。
那么注意力机制如何优化seq2seq呢?
其实就是在每次迭代时,不要把迭代前的数字丢了,而是随着迭代专门保存进一个空间,迭代了多少次,这个空间就有多少组数字,然后把空间内的数字当作编码的成果。
这样一来,就可以根据输入的数字长度来调整编码后的信息了。
接着,在原有的循环圣经网络基础上,再加上一层结构——Attention,这层结构专门就是利用这个新生成的空间内的数字,挑选出当前处理的数字,运算。
其实仅仅是这样会感觉很奇怪,就这样一个挑选运算的过程为什么要大费周章地专门命名一个注意力机制?
因为“选择”这个行为在建模时本身就很不容易。
倒不是说不好建模,而是说要考虑到后续反向优化,在对“选择”建模时,必须要考虑到能否微分的问题。
当然,牛人总是牛的,轻松把这个问题解决了(具体怎么解决的,还是那句话,不在本文范围内)。可虽然轻松,但毕竟也是个重量级想法,所以需要单独拎出来命名。
再回顾一下之前的注意力机制:在原有的循环神经网络上再加上一层Attention,帮助运算,避免“乱锅炖”的处理。
而循环神经网络有一个天生的问题:因为必须要不断迭代,这样一个线性的过程只能在CPU(处理线性问题)上运算,不能在GPU(处理并行问题)上运算,速度会慢很多。
于是,一种解决的思路是用Attention代替循环神经网络,也就是说,整个网络框架里,就只有Attention和一些基础的全连接层,不仅比先前的简洁,而且事实证明效果也更好。
这样一种模式被命名为转换器,Transformer,GPT中的T就是这个。
总之,笔者着重从数学建模的角度总结了自学神经网络的结果,后续有能力的话还会从代码实现的角度来再做总结。
还望各位大佬指教批评!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。