Knowledge Mining
Last updated on May 12, 2024 pm
Embedding
编码:文字的数字化
Embedding这个词直译为中文是:嵌入,这是让人摸不着头脑的两个字。啥是嵌入?嵌入了啥?跟自然语言又有啥关系?
嵌入的体现形式是一组具有固定长度的数组(向量),接下来我们将探讨它的本质以及它在计算机理解自然语言的过程中所扮演的角色。
要解答以上问题,不妨先思考:让计算机理解自然语言,我们需要做什么?
计算的基础是数,而自然语言是文字,因此很容易想到要做的第一步是让文字数字化 —— 编码。要设计编码的方法,需要思考的问题是:哪些性质是编码规则必须要满足的?
有一条是显然可以给出的:
性质一:每一个词具有唯一的量化值,不同词需要具有不同的量化值
背后的逻辑不言自明:一词多数,或多词一数,都会增加计算机理解语言的难度,这种难度就如同多音字或多义词给人类造成的困难,尽管智慧让我们可以克服这些障碍,但对计算机来说,为它降低一些难度显然是必要的。
满足性质一的方法非常容易设计,例如:首先穷举出人类所有的文字或词组 —— 这个集合必定是有限集,例如汉字有10万个,字母有26个,英语单词数小于100万个。由于是有限集,我们可以给每一个词分配一个固定的数字。
很显然,这一方法存在一个很大的问题:数的值与词的义是割裂的。
可以通过一个简单的例子来思考:在英语中,a和an是完全同质的词,而a和abnormal则是差异极大的词。如果按照上述编码方式,可能会有以下赋数方式:a=1,abnormal=2,an=100,这个时候我们会发现a和abnormal似乎在数值上更加靠近,而a和an这两个同质的词却隔得非常远。因此,需要添加一条规则来确保数字化后的数值与词义之间具有关联:
性质二:词义相近的词需要有“相近”的量化值,词义不相近的词量化值需要尽量“远离”
这一性质很容易理解,如果近义词具有相近的量化值,那么意思相近的句子编码后相关性也更大,即同义的句子在序列特征上会更加接近,这将有利于计算机而言更高效地理解共性、区分特性;反之则会给计算机制造非常多的困难,难以捕捉同质内容之间的共性,就意味着模型需要更多的参数才能描述同等的信息量,学习过程自然就会更加困难。
基于语义的编码
OpenAI的Jack Rae在Standford的分享中提到了一个很深刻的理解语言模型的视角:语言模型就是一个压缩器。
所有的压缩,大抵都能被概括在以下框架内:提取共性,保留个性,过滤噪声。带着这个视角去看,就更容易认识到性质二的必要性。不同词所编码的数值,是否基于词义本身的相似性形成高区分度的聚类,会直接影响到语言模型对于输入数据的压缩效率。
对于神经网络模型,词的量化值可以全部是整数,但是语言模型的输出则不一定是整数。例如当模型输出1.5,词表只定义了1和2,这时该如何处理呢?
我们会希望1和2都可以,甚至3也不会太离谱,因此1和2所代表的词在词义上最好有某种共性,而不是像"a"和"abandon"一样,几乎找不到词义上的关联。当相近的词聚集到一起,推断出有效输出的概率就会更高。
但是新的问题又出现了(或许应该说本来就存在,只是刚被发现):词义具有多维性。例如A和B词义相似,B和C词义相似,但并不意味着A和C词义也相近。
当用一个标量来表示一个词时,词和词之间的关系只能基于两个标量间的差值得到,从而只有“远”和“近”两种状态,但实际情况是两个词只在某些维度上接近。如“Love”和“Passion”接近的地方是:情感浓度,二者都表示存在强烈的情感,但是在情感色彩方面(消极or积极),“Love”是积极的,“passion”具有更加中性的色彩,于是同样具有浓烈情感的“Rage”也与“Passion”相近,但是“Rage”的情感色彩却是消极的。
于是我们需要一个多维的数字形态,即使用向量 —— 对于每一个词,我们可以表达为一组数,而非一个数。这样一来,就可以在不同的维度上定义远近(距离),词与词之间复杂的关系便能在这一高维的空间中得到更详细的表达。这,就是Embedding!“嵌入”这个名字其实并不贴切,不妨可以叫它“词义向量”,其所处的空间可以称为“词义空间”。
编码器的设计
目前为止,我们已经找到了可以用于表达词义的数字化形式 —— 向量,也知道了一个好的编码方式应当满足的性质。如何设计一套方法,来完成我们所期望的编码,就成了最后的问题。
一个比较容易想到的方法是,令词义的不同维度和向量的不同维度进行关联。例如,对词义的维度进行全面的拆分:名词、动词、形容词、数量特征、颜色特征、人物、主动、被动、情感色彩、情感强度、空间特征等等,只要维度的数量足够多,一定可以把词义所包含的信息全都囊括在内。一旦我们给出每一个维度的定义,就可以给出每个词在相应维度上的数值,从而完成词的向量化,并且完美地符合以上给出的两点性质。但这个看似可行的设计,并不具备可实现性。
首先要能够囊括所有词义的不同维度,需要的维度数量必然极高,而要对词义进行这么精细的切分,本身就非常困难,其次即使切分成功了,要将每个词不同维度的意义赋予有效的数值,哪怕是资深的语言学家恐怕也会感到棘手。今天大家所熟知的语言模型中,并没有一个是用这一方式对词进行向量化的。但是这个思想方案却是有意义的,词义向量的不同维度之于计算机,就如同上面我们列举的维度 —— 词性、数量、时间、空间等等之于人类。
纯构建的方式是不可行的,但今天我们已经知道了一套有效的解决办法:神经网络加大数据,暴力出奇迹。这套范式的起源是:Word2Vec。语言模型基于词义向量,而词义向量真正开始有效,正是从Word2Vec模型开始的。
Word2Vec的关键是:一个词的意义,可以被它所出现的上下文定义。换一种说法:上下文相似的词在词义上也存在一定的相似性。Word2Vec 的两类做法分别是:
中心词 --> 神经网络 --> 上下文
上下文 --> 神经网络 --> 中心词
这个方法当然不是终点,它的局限性是明显的,但开创性已经足够了。本质上,Word2Vec并没有尝试去理解句子的语义。因此对于完全相同的上下文,不同的中心词的词义相似性是容易捕捉的。当词义向量的聚类逐渐形成,由近义词构成的上下文,也一定程度上能够标记词义相近的中心词。但人类的语言结构非常复杂,当相同语义通过不同句式、语态、修辞进行表达时,某些近义词对的关系可能无法设别。
浅谈GPT
GPT(Generative Pre-Training Language Models)是一个有能力理解句子的模型。如果说此前讨论的Word2Vec这类构建词义向量的模型是教计算机“认字”的过程,那么GPT模型的训练,则是“认字”+“背书”的过程。老师最后只考书背的好不好,但为了把书背好,GPT也被动地强化了其认字的能力。
GPT推理的核心是Transformer,Transformer的核心是Attention机制,Attention机制是什么?
一言以蔽之:计算词义向量之间的“距离”后,对距离近的词注入更多的注意力,而收到高注意力的词义则获得更高的激活值,当预测完成后,通过反向传播算法,特定的激活帮助了最终的预测,对应词之间关联将被强化,反之则被弱化,也即:通过计算注意力分数和对值进行加权求和来产生关注的输出,模型便是通过这一方式学到了词之间的关系。
本文作者的理解我觉得有一定的道理:Attention机制之所以重要和好用,原因之一是可以有效帮助词义向量(Embedding)聚类。
GPT的例子想想其实很有趣,一般的工程思维是将大的问题拆分成多个小问题然后逐个解决,但对与计算机处理问题而言有所不同。正如刚开始提出的问题:让计算机理解自然语言,我们需要做什么?然后分析:计算的基础是数,而自然语言是文字,因此第一步是让文字数字化。这其实是走了这样一条解决问题的路径:先将文字数字化后,再考虑理解句子。有趣的是,对词进行向量化编码的最好方法,是直接训练一个理解句子的语言模型。这就像为了让婴儿学会走路,我们直接从跑步开始训练。人类会摔跤会受伤,但机器不会 —— 至少在Embodied \(^{[1]}\) 之前不会,因此人类自身为了降低代价所建立的步骤化学习过程或许并不适合人工智能。其实不难发现,深度学习中许多好的解决方案往往都是一步到位的。
[1] 在深度学习领域,"Embodied"通常指的是将模型嵌入到具有物理实体的环境中进行学习和交互。在传统深度学习中,模型通常是在静态数据集上进行训练和测试的,而不考虑模型在真实环境中的交互。然而,在一些应用领域(机器人学、自动驾驶等),模型需要在真实环境中进行学习和决策。在这种情况下,"Embodied"深度学习侧重于将模型放置在与环境交互的设置中,通过感知环境、采取行动并与环境进行反馈交互来学习。这样做的目的是使模型更加适应现实世界的复杂性和不确定性,从而能够更好地应对复杂的任务和场景。这种方法可以带来更加鲁棒和智能的系统,因为模型需要考虑到环境的动态变化,并根据实时反馈进行决策和调整,可以更好地理解和解决现实世界中的问题。
感受野
感受野(Receptive Field)定义:卷积神经网络每一层输出的Feature Map上的像素点映射回输入图像上的区域大小,即卷积神经网络能看到的输入图像的区域。
感受野的大小
输入图片在经过不同的卷积层时,卷积核能看到的图像结构是不一样的。当经过较浅的卷积层作用后,生成的图像(更准确的说应该是特征图)中每个像素点只是对原图像局部信息的一个特征提取(卷积的作用:通过卷积核提取图像的特征,卷积核的大小决定了对图像局部加权的范围),图像的细节信息丰富,但是图像的上下文信息很少,我们将其称之为图像的感受野小。反之,图像经过深层的卷积层作用之后,图像能看到的原图像的范围更大,但同时细节信息缺失(这很容易理解:看得更多更广了,自然会忽视掉部分细节),我们将其称之为图像的感受野大。
大感受野的作用
一般任务要求感受野越大越好,比如图像分类中最后的卷积层感受野要比输入图像的尺寸大。理论上,网络越深、感受野越大,性能越好。
密集预测任务(Dense Prediction,源自semanitc image segmentation,图像语义分割的目标是将图像的每个像素所属类别进行标注。因为是预测图像中的每个像素,这个任务通常被称为密集预测)要求输出像素的感受野足够大,确保做出决策时没有忽略重要信息,网络深度也要够深。
目标检测任务中设置Anchor(先验框、锚点、prior bounding box,是提前在图像上预设好的不同大小、不同长宽比的框,使得模型更容易学习目标的位置、大小和其中的特征)要严格对应感受野,Anchor的太大或者偏离目标太多都会严重影响检测性能。
增大感受野的方法
主要的方法是增加网络的深度。
Pooling(池化)。对数据降维,减小网络参数,提升计算效率,同时增加感受野,但是会造成分辨率降低,损失图像的细节信息。
Dilated conv(空洞卷积)。可以解决池化操作增加感受野后图像信息缺失的问题。
图(a)是普通卷积的运算看到的感受野大小,卷积后的每个像素能看到的卷积前图片的区域为3x3。图(b)可以当成使用卷积核为7x7进行的卷积运算,但其中只有标记为红色的9个点参与计算(dilated为2),能看到的感受野范围是7x7大小。同理图(c)可以当成是使用卷积核为15x15进行卷积运算,但其中只有标记为红色的9个点参与计算(dilated为4),能看到的感受野范围是15x15大小。
空洞卷积与普通卷积相比,增加了感受野,但是不会增加需要训练的参数量,因为增加的感受野范围内的其他像素点是选择性跳过的,卷积层能看到,只是不需要参与卷积运算而已(并不是增加padding,填充像素0的操作)。
模型梯度和优化器梯度
模型梯度和优化器梯度是深度学习中的两个重要概念,它们在训练过程中起着关键作用。
模型梯度
定义:
在机器学习和深度学习中,模型梯度是指损失函数相对于模型参数(如权重和偏置)的导数。这个导数指示了如果改变参数,损失函数会如何变化。
作用:
模型梯度是优化过程中的关键因素,它指出了损失函数下降最快的方向,即函数值增大最快的方向的反方向。在反向传播过程中,通过链式法则计算得到的梯度,用于指导参数的更新,以便减少损失值。
理解:
梯度是一个计算图中的张量(Tensor)的属性。当你进行前向传播时,PyTorch会构建一个计算图,图中的节点是张量,边是从输入张量到输出张量的操作(运算关系)。
当你调用.backward()方法进行梯度反向传播时,PyTorch会自动计算图中所有具有requires_grad=True属性的张量的梯度,并将这些梯度存储在各自张量的.grad属性中。
模型梯度指的是模型参数(通常是神经网络的权重和偏置)在训练过程中通过反向传播计算出的梯度。这个梯度反映了模型参数在当前值下,损失函数变化最快的方向。模型梯度由.backward()方法梯度反向传播
这意味着每个模型参数张量都有一个与之关联的梯度张量,该梯度张量表示的是损失函数关于该参数的导数,即模型梯度。
优化器梯度
定义:
优化器梯度通常指的是优化算法中使用的梯度信息,它不仅仅是当前批次数据的梯度,还可能包括之前批次的梯度信息,以及学习率、动量等超参数。
作用:
优化器在反向传播过程中,指引损失函数(目标函数)的各个参数往正确的方向更新合适的大小(使用模型梯度信息来决定参数更新的方向和步长),使得更新后的各个参数让损失函数值不断逼近全局最小。不同的优化器有不同的策略来利用历史梯度信息,例如SGD优化器使用当前批次的梯度直接更新模型参数,而像Adam这样的优化器则结合了一阶动量(指数加权平均梯度)和二阶动量(指数加权平均梯度平方)来调整更新的步长和方向。
理解:
优化器(即优化算法)是用来求取模型的最优解的一个独立的对象,它保存了模型参数的引用以及当前的学习率和其他超参数。优化器需要知道前向传播过程中哪些参数是可训练的(即哪些张量具有requires_grad=True属性)。优化器不计算梯度,它只是梯度的更新者,他决定了以什么样的形式更新参数。
优化器梯度指的是优化器根据模型参数的梯度来更新这些参数的规则和状态。优化器通常有自己的状态,比如学习率、动量等,它会根据模型参数的梯度来调整模型参数的值,以便在下一次迭代中得到更小的损失值。常见的优化器有SGD、SGDM、Adagrad、RMSProp和Adam等。
当你创建一个优化器实例时,你将模型的参数传递给它,例如:optimizer = torch.optim.SGD(model.parameters(), lr=0.01)。优化器对象通常保存在它自己的内存空间中,它维护了当前的参数状态(比如动量项在torch.optim.SGD的情况下)和更新规则。当你调用optimizer.step()时,优化器就会根据存储的梯度来更新它所保存的参数。
二者的关系
梯度存在于模型的参数(即张量)中,而优化器则以一个单独的实体存在,维护着参数的更新规则和状态。在每次训练迭代中,优化器都会使用参数的.grad属性来更新其值。
总的来说,模型梯度是损失函数对模型参数的导数,而优化器梯度则是优化器根据模型梯度和其他信息(如历史梯度、学习率等)计算出的用于更新模型参数的信息。两者紧密相连,共同作用于模型训练过程中的参数更新。
在训练循环中,通常会先清除上一步迭代中计算的梯度(使用.zero_grad()方法),然后进行前向传播和反向传播计算新的梯度,最后由优化器根据这些梯度来更新模型参数。这个过程会在整个训练过程中重复进行,直到模型收敛或达到预定的迭代次数。
深入理解ResNet
参考文章:https://zhuanlan.zhihu.com/p/101332297
引言
残差神经网络(ResNet)是由微软研究院的何恺明、张祥雨、任少卿、孙剑等人提出的。ResNet在2015年的ILSVRC(ImageNet Large Scale Visual Recognition Challenge)中取得了冠军。
残差神经网络的主要贡献是发现了“退化现象(Degradation)”,并针对退化现象发明了 “快捷连接(Shortcut connection)”,极大的消除了深度过大的神经网络训练困难的问题。神经网络的“深度”首次突破了100层、最大的神经网络甚至超过了1000层。
在2012年的ILSVRC挑战赛中,AlexNet取得了冠军,并且大幅度领先于第二名,由此引发了对AlexNet广泛研究,并让大家树立了一个观念:网络越深则准确率越高。随着VGGNet、Inception v1、Inception v2等相继出现,这个观点被不断验证和强化,得到越来越多学者的认可。那么问题来了:它真的正确吗?
它是正确的,至少在理论上是正确的。
退化现象
假设一个层数较少的神经网络已经达到了较高准确率,我们可以在这个神经网络之后,拼接一段恒等变换的网络层,这些恒等变换的网络层对输入数据不做任何转换,直接返回 y = x,就能得到一个深度较大的神经网络,并且这个深度较大的神经网络的准确率等于拼接之前的神经网络准确率,准确率没有理由降低(毕竟只做了恒等变换,没有进行任何别的数据层面的操作)。
层数较多的神经网络,可由较浅的神经网络和恒等变换网络拼接而成,如下图所示:
通过实验,ResNet随着网络层的不断加深,模型的准确率先是提高,直到达到最大值(准确率饱和),然后随着网络深度的继续增加,模型准确率毫无征兆的出现大幅度降低。这个现象与“越深的网络准确率越高”的理念显然是矛盾的。ResNet团队把这一现象称为“Degradation”,即退化。
ResNet团队把退化现象归因为深层神经网络难以实现“恒等变换(y=x)”。这乍一看让人难以置信:能够模拟任何函数的深层神经网络,竟然无法实现恒等变换这么简单的映射?
让我们来追溯深度学习的起源。与传统的机器学习相比,深度学习的关键在于:网络层数更深、非线性转换(激活函数)、自动特征提取和特征转换。其中,非线性转换将数据映射到高维空间以便于更好的完成“数据分类”。随着网络深度的不断增大,所引入的激活函数也越来越多,数据被映射到更加离散(维度更高)的空间,此时已难以让数据回到原点(恒等变换)。或者说,神经网络将这些数据映射回原点所需要的计算量,已经远远超过我们所能承受的(硬件受限)。
退化现象让我们对非线性转换进行反思,非线性转换确实极大的提高了数据分类能力,但是随着网络的深度不断加大,我们在非线性转换方面已经走的太远,已然无法实现线性转换。显然,在神经网络中增加线性转换分支成为很好的选择,于是ResNet团队在ResNet模块中增加了快捷连接分支,在线性转换和非线性转换之间寻求一个平衡。
至于快捷连接(Shortcut connection),我就不过多赘述了,之前的文章中也有提及。我在此之前只是不加思考的阅读各种论文、资料(可能看了转头又忘了),从未想过在现在来看很基础的ResNet里面还有这么有趣且严谨的分析过程,给我了很大的启发。所谓科研,或者进行别的学习和研究,甚至于阅读书籍,都需要带着问题和审视的头脑,多问问为什么。十万个为什么不只是少儿读物,应是求知求学的最基本要素。引用毛泽东领袖的话就是:所谓学问,就要既学又问,学和问是不能分开的。书此以自省。
大模型时代
预训练
在很多的论文中都使用了“预训练”这个东西。为什么要预训练呢?下面就来揭开它的面纱。
很多机器学习模型都需要依托带标签的数据集做训练,此话怎讲?举个例子,让机器去学习和让小孩去学习是类似的。比如小孩辨别猫或狗,无非是父母每次看到一只猫或一条狗,告诉小孩这是猫/狗,小孩不断记忆猫狗的特征,久而久之,小孩见到一只新猫/狗,不用父母告诉TA,也能知道是猫还是狗。
机器也是一样的,给1000张猫的图片告诉机器是猫,机器不断记忆猫的特征,等给它第1001张不标注是猫的图片的时候,机器能立马认出来是猫,而前面这1000张猫的图片就是训练机器的过程,且通过已知样本不断校准机器的判断能力、不断迭代降低误差(误差 = 真实结果与实验结果的差距)。
但是我们身边存在大量没有标注的数据,例如文本、图片、代码等等,标注这些数据需要花费大量的人力和时间,标注的速度远远不及数据产生的速度,所以带有标签的数据往往只占有总数据集很小的一部分。而如果手头任务的训练集数据量较少的话,那现阶段好用的CNN比如Resnet、Densenet、Inception等网络结构层数很深(几百万上千万甚至上亿的参数量),当训练数据少则很难很好地训练这么复杂的网络,但如果先把好用的这些大模型的大量参数通过大的训练集合比如ImageNet预训练好(大规模图像数据集ImageNet有超过1000万的图像和1000类物体的标注),即直接用ImageNet初始化大模型的大部分参数。接下来再通过手头上少的可怜的数据去Fine-tuning(即微调参数),以更适合解决当前的任务,那事情就顺理成章了。
Transformer
关于Transformer的理解,可以看这篇文章:Transformer通俗笔记。
作者用了通俗易懂的文字详细解读了Transformer的知识,令人受益匪浅。文章涉及大量的知识点,包括但不限于:向量化(Onehot->Embedding)、神经网络语言模型NNLM(Neural Network Language Model)、Encoder and Decoder、Attention、Multi-Head Attention、预训练(双层双向LSTM)+特征融合的模式ELMO(Embedding from Language Models)、预训练+微调(Fine-tuning)的模式迁移学习、GPT与BERT。
Transformer的时空复杂度可以参考此文:FlashAttention。在现代GPU中,计算速度已经远超过显存访问的速度,Transformer中的大部分计算操作的瓶颈是显存访问。所以,减少对HBM(High Bandwidth Memory,高带宽存储器,一款CPU/GPU内存芯片,即“RAM”)的读写次数,有效利用更高速的SRAM来进行计算是非常重要的,而对于性能受限于内存带宽的操作,进行加速的常用方式就是kernel融合。也就是说,要避免反复执行“从HBM中读取输入数据,SRAM执行计算,最后将计算结果写入到HBM中”,将多个操作融合成一个操作,减少读写HBM的次数,是降低计算耗时的重点优化目标。尽量把计算过程都在SRAM中进行,但SRAM内存不够大,因此需要进行分块计算。这是针对Transformer中注意力机制的二次复杂度\(O(N^2)\)分析,以提高计算效率的一种方法,其中涉及很多硬件相关的技术,我没有看明白,先放在这吧,等日后有机会再攻略。
Mamba
参考文章:一文通透想颠覆Transformer的Mamba:从SSM、HiPPO、S4到Mamba。
Mamba与RNN颇有相似之处。RNN中的隐藏状态会随着时间的推移而忘记靠前面的信息,且RNN具有非线性的激活函数如tanh,无法写成卷积的形式,没法并行训练。Mamba最早提出是用来解决NLP问题的,它处理长程信息的能力优于RNN,并且计算复杂度低于Transformer。Mamba是一种状态空间模型SSM(State Space Model),利用了选择性扫描算法(Selective scan algorithm)、硬件感知算法(Hardware-aware algorithm)、HiPPO以及Flash Attention等技术。
Mamba建立在更现代的适用于深度学习的结构化SSM(简称S6)基础上,相当于S4模块的改进,解决了S4参数固定导致的无法对输入进行针对性推理的问题。Transformer的注意力机制虽然有显著效果但效率不算很高,毕竟其需要显式地存储整个上下文(storing the entire context,也就是KV缓存),直接导致训练和推理消耗算力很大。Transformer就像人类每写一个字之前,都把前面的所有字和输入都复习一遍,所以写的慢。RNN的推理和训练效率高,但性能容易受到对上下文压缩程度的限制,容易忘掉更前面的内容。而SSM的问题在于其中的矩阵A、B、C始终是不变的,无法针对不同的输入针对性的推理。Mamba的解决办法是,相比SSM压缩所有历史记录(HiPPO技术,通过将看到的所有输入信息压缩/投影为系数向量,产生隐藏状态来记忆历史),Mamba设计了一个简单的选择机制,通过“参数化SSM的输入”,让模型对信息有选择性处理,以便关注或忽略特定的输入。这样一来,模型能够过滤掉与问题无关的信息,并且可以长期记住与问题相关的信息。
总的来说,这篇文章通过RNN的不足引入状态空间模型SSM,继而逐步解读S4、S6(Mamba)的相关理论知识,循序渐进,是了解Mamba的绝佳之作!