论文阅读:Empowering Large Language Model for Sequential Recommendation via Multimodal Embeddings and Semantic IDs

基本信息 论文标题:Empowering Large Language Model for Sequential Recommendation via Multimodal Embeddings and Semantic IDs 作者单位:香港城市大学&腾讯 论文链接:https://arxiv.org/pdf/2509.02017 来源:CIKM 2025 Motivation:论文要解决的问题是什么 LLM4SR的基本范式如下,即用LLM直接来做搜推的范式(这种方式在学术界常见,但在工业界不常见)。由于LLM的输入词表范围是有限的(通常比较小),因此其token emb dim通常比较大,比如2048或者4096;而搜推场景的item量级很大,而且在不断更新,因此工业界经典的id-based的搜推模型的item emb dim通常比较小,比如64或128。经典的id-based的搜推模型能比较好地学习到搜推场景的协同信号,为了让LLM模型也能感知这种信息,LLM4SR范式通常会先预训练一个id-based的经典搜推模型,然后将其中的item id emb通过下图的Linear Projection的映射层,映射到LLM token emb的空间,让LLM也能感知搜推的协同信号。 上述LLM4SR范式存在两个问题: 维度坍缩:id-based训出来的id emb dim比较小(如64),LLM token emb dim比较大(如4096),在由id emb通过Linear Projection映射到toen emb的过程中,虽然64映射到4096空间了,但扩维后的矩阵存在低秩问题,即还是只利用了4096中的64维的空间。 论文中,作者分两种情况进行了分析,如果Linear Projection只是一个线性层的话,通过公式推导能得出上述结论;如果Linear Projection包含非线性变换,作者通过实验分析也发现了维度坍缩的现象。 灾难遗忘:除了使用id-based模型产出的id emb,LLM4SR也常用多模态模型产出item emb表征,然后转换成semantic id输入到LLM4SR中。在这种情况下,产出的semantic id通过会遗忘多模态item emb的信息,导致下游LLM4SR的效果不佳。 论文中,作者用公式9来衡量semantic id保留pretrain多模态emb的信息量。具体来说,如果行为流中的商品序列是{A,B,C,D},target item是E。使用pretrain多模态emb能计算出E和A~D的相似度,例如相似度<E,A> > <E,B>。如果将pretrain多模态emb转换成semantic id,然后由semantic id恢复出新的A~E的emb之后,再计算E和A~D的相似度,如果仍然有<E,A> > <E,B>,则认为一致(concordant),否则不一致(disconcordant)。这个分析方法挺好的,通过这个指标能估算出转换成semantic id之后,仍然保留原有pretrain多模态emb对搜推场景的序关系的保留程度。 作者发现,转换成semantic id之后,信息只保留了37.14%;进一步,如果semantic id是在下游任务中端到端训练的,则信息只保留了5.5%,也就是说94.5%的pretrain emb的序的信息都丢掉了,也就是灾难遗忘。 Semantic id构建方法 3套emb来源,一套id-based经典搜推模型产出的包含协同信号的emb,另外两套是LLM2CLIP产出的多模态文本和图片emb。作者提到传统CLIP对长文本处理能力较弱,所以升级到LLM2CLIP,能更好地处理长文本。 Semantic id构建方法是经典的RQ-VAE的方法,但有如下两个改进点: 将emb的重构loss由MSE升级成MMD (maximum mean discrepancy),MSE是计算原始emb和重构emb的欧式距离的误差,而MMD是计算两个分布的diff,实验表明能MMD比MSE能保留更多的pretrain多模态emb信息(即上述公式9),保留44.36% 对量化后的emb做了对齐,因为LLM2CLIP本身进行了图文模态的对齐,所以文中只新增了id emb分别和文本、图片模态的对齐 此外,还有一点论文没提但可能和常规RQ-VAE不同之处,就是原始emb在进行RQ-VAE之前,有一个Encoder升维的操作,在重构loss前对应有一个Decoder降维的操作,而semantic id量化恢复emb是Decoder之前的那个。这一升一降,估计也有助于缓解维度坍缩。 ...

October 4, 2025 · 1 min

公告

博客数据恢复中,敬请期待! 测试图片: 测试代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 // Necessary header files for input output functions #include <iostream> using namespace std; // main() function: where the execution of // C++ program begins int main() { // This statement prints "Hello World" cout << "Hello World"; return 0; } 测试数学公式: This is an inline \(a^*=x-b^*\) equation. ...

August 15, 2025 · 1 min

【论文速读】End-to-End Differentiable Learning of Protein Structure

首先放出本文的Hightlights: 蛋白质三级结构预测一般分为两种方法,一种是基于模板的预测方法(Template-Based Modeling, TBM),另一种是从头测序方法(Free Modeling, FM)。TBM方法目前已经能达到比较好的预测精度,但并不是所有蛋白都有同源模板,当模板蛋白和目标蛋白的相似性低于某个阈值时,TBM方法的性能就会比较差。而传统的FM方法,需要过多的人工特征,使得整个流程非常复杂。 作者在一次报告中,将传统的蛋白质结构预测算法(上图)比作10年前的图像识别算法(下图),虽然10年前的图像识别算法也能达到比较好的性能,但需要很多人工设计的特征,比如SIFT特征等,不够简洁漂亮。随着深度学习的兴起,现在图像识别不再需要人工设计特征,只要搭建好神经网络,输入原始图片即可完成识别和分类,性能比之前的人工方法还要好。所以,作者也希望能提出一个简洁、纯深度学习的模型来预测蛋白质的三级结构。 本文的模型(Recurrent Geometric Networks, RGN)从宏观上来说就如博客开篇的图片所示,非常的简洁漂亮,输入是蛋白质的一维序列,经过神经网络,输出是每个氨基酸残基的三个扭转角,然后再通过三维重构,得到蛋白质的笛卡尔坐标。 更具体来说,RGN包括三个部分,分别是模型预测、三维重构和误差反向传播,下面分别介绍这三个部分。 模型预测是上图的左下角部分,即输入是蛋白质序列,输出是每个氨基酸残基的三个扭转角。因为每个氨基酸对应三个扭转角输出,每个氨基酸和其上下文的氨基酸有关联,所以使用双向LSTM最合适不过了。Bi-LSTM没什么好讲的,关键讲讲其模型的输入和输出。输入部分,作者把每个氨基酸编码成一个41维的向量,如上图所示,其中包括20维氨基酸的one-hot向量(因为只有20种氨基酸)、20维PSSM位置向量和1维具体的位置信息。其中的PSSM位置向量可以理解为这个位置上的不同氨基酸的概率分布,由于有20种氨基酸,所以PSSM向量维度也是20。网上没有找到氨基酸的PSSM向量示例,找到一个DNA的,如下图,每个位置上,字母越大表示出现该核苷酸的概率越大,换成氨基酸是类似的道理。所以整个网络的输入,除了PSSM矩阵,没有任何人工设计的特征,已经很优雅了。 https://davetang.org/muse/2013/10/01/position-weight-matrix/ Bi-LSTM的输出是三个扭转角,但并不是三个实数这么简单。作者首先把整个拉氏图平面聚类,比如聚类成m=60个点,然后就把输出离散化成60类的分类问题。分类输出采用Softmax归一化,这样就会得到60类的概率分布,如RGN网络图最右边的子图所示。60类的概率分布再通过加权平均的方式得到最终的三个扭转角的实数值。我很好奇为什么需要经过一个离散再加权平均的方法,Bi-LSTM直接回归输出三个扭转角的实数不是更省事吗? 预测得到三个扭转角之后,进入RGN的第二个阶段,就是三维重构,在RGN网络图的左上角。三维重构说起来也简单,就是根据每个氨基酸残基的三个扭转角,重构出蛋白质的三维结构。由于常规的蛋白质三维结构坐标系是笛卡尔坐标系(直角坐标系),所以需要把扭转角坐标转换为笛卡尔坐标,以便于求解误差。这个部分作者没有细说,因为是另一篇论文:Parallelized Natural Extension Reference Frame: Parallelized Conversion from Internal to Cartesian Coordinates。 最后就是怎样求解误差以及误差反向传播了。这个也比较有意思,想想看,对于一条长为L的蛋白质序列,给定预测的三维结构和真实的三维结构,怎样计算它们之间的误差。不能直接对应坐标相减,因为有可能两个坐标系的坐标原点不一样。作者的方法是这样的:对于预测结构,求每两个氨基酸的距离差,就是\(\tilde{d}_{j,k}\);对于真实结构,也做类似的操作。这样做的好处是抹掉了坐标原点的影响,用两点之间的相对距离来表示三维结构。然后,对真实的\(\tilde{d}_{j,k}^{(exp)}\)和预测的\(\tilde{d}_{j,k}^{(pred)}\)再求二范数\(||D||_2\),最后除以长度进行归一化,就得到了误差dRMSD。 上述dRMSD误差相比于之前领域内常用的TMscore,好处就是可微分,可自动求导,可梯度下降了;另外,如上所述,dRMSD不要求预测结构和真实结构进行对齐;但是有一点是dRMSD对size敏感,而且不能识别镜面对称这种错误结构,比如左手和右手的结构是镜面对称的,如果真实结构是左手,但模型预测成了右手,dRMSD是检测不到这种错误的。 模型介绍完毕,训练和测试数据集来自CASP竞赛。作者把每一届CASP比赛的数据集作为测试集,从CASP7~CASP12;每一届比赛之前公布的所有PDB数据集(seq, structure)作为对应测试集的训练集。其中,CASP11分出一部分作为验证集,用来优化网络超参数。 测试结果如Table 1所示,可以看到,在没有模板的FM类别中,本文的RGN预测误差是最小的;在有模板的TBM类别中,RGN的性能几乎垫底,当然这里参与评测的都是当届比赛中Top-5的模型,所以RGN和这5个模型比是垫底,但差距是很小的。 另外,作者提到,在TBM类别的数据集中,CASP的参赛模型比较依赖模板的质量。具体来说,对于真实的结构,如果模板结构和真实结构误差很小(y轴),则模型的预测结构和真实结构的误差也很小(x轴),这两个变量成一定的线性相关关系(第一行)。而对于本文的RGN,则没有这种相关关系,说明RGN一视同仁,不会受模板质量的影响,因为RGN是纯深度学习的模型,根本就没有用到模板。 在预测速度上,RGN虽然需要训练几周甚至上月的时间,但预测速度是毫秒级别的,是评测的几个模型中最快的。快速的RGN能使一些新的应用成为可能,比如药物发现、蛋白质设计等。 最后,总结一下本文的主要工作、创新点和局限性: 三个特点: torsional angles,局部信息 geometric units ,全局信息 dRMSD,局部+全局 创新点: 简洁,Model replaces structure prediction pipelines with one mathematical function 另辟蹊径,纯deeplearning,不依赖structural templates、co-evolutionary information、energy model等,本文预测融合了本文方法和领域知识的新模型有望解决蛋白质结构预测问题 局限性: 依赖PSSM矩阵 本文作者来自哈佛医学院系统药理学实验室,文章只有作者一个人,很了不起了。哈佛医学院的另一个教授评价作者:“AlQuraishi 研究的特点在于,一名埋头在哈佛医学院和波士顿生物医学社区丰富研究生态系统中的研究人员,居然能够在计算机科学最热门的领域里抗衡谷歌等巨头。——Peter Sorger”,太棒了,我也想做这样的研究。 ...

August 30, 2019 · 1 min

CS224N(2.12)Convolutional Networks for NLP

今天我们介绍如何使用CNN解决NLP问题。截止目前,我们学习了很多RNN模型来解决NLP问题,由于NLP是序列的问题,使用RNN这种循环神经网络是很符合直觉的,而且也取得了不错的效果。但是,由于RNN速度较慢,而且梯度消失问题比较严重,人们就想借用CV领域的CNN,看是否能解决NLP的问题。 我们在之前的博客中已经详细介绍过卷积神经网络CNN,这里不再详细介绍。下面我们以一篇paper中使用CNN对句子进行情感分类为例,简要介绍下怎样将CNN应用到NLP中。 上图是一个非常简单的CNN网络,用来对影评进行情感分类,输入是一个长度为7的句子,我们把每个词用长度为5的词向量来表示,则对于输入来说,得到了一个7×5的矩阵,这不就相当于一张图片了吗,后续操作就很像CV了。第二步,需要对输入“图片“进行卷积操作,请注意,虽然输入可以看做图片,但其本质上是“一维”的句子,所以我们设计卷积核大小时,卷积核的宽度要固定为5,保证卷积核能对完整的词向量进行操作。这里共设计了3个不同大小的卷积核,每种大小有2个卷积核,共6个卷积核。卷积操作完成之后得到了6个特征图,对每个特征图取max pooling再拼接起来,得到一个长为6的向量,这就是用CNN对句子抽取的特征向量。最后再接一个softmax进行二分类。 除了上图展示的CNN操作外,还有一些CNN操作有可能会用到: 卷积操作的stride=k,每k行一个group进行卷积,默认卷积操作是k=1 卷积操作的dilation=k,跨k行进行卷积,默认卷积操作是k=1 padding,上图卷积操作之后,feature map相比于输入维度变小了,如果要想保持维度不变,可对输入进行padding max/avg pooling over time,上图的max pooling即为max pooling over time,即对整个句子所有时间步的feature取max k-max pooling,对整个句子的所有时间步的feature取top-k的max值,同时保持feature的相对顺序不变,上述max pooling相当于1-max pooling local max pooling,stride=k,对每k个feature取max,这个和CV里默认的max pooling是一样的,CV里就是画一个框取max dropout=p,对于每个连接,随机以概率p丢弃,属于一种正则化技术,能有效增加模型的鲁棒性 skip connections,之前讲过很多次了,直连线路,没有中间商赚差价 batch normalization,对每次卷积操作的输出进行z-score标准化,使得均值为0,标准差为1,能有效增加模型的鲁棒性 卷积核大小为1×1的卷积,相当于卷积前后的feature map的全连接,但又比全连接的参数少,因为一个卷积核的参数是共享的 最后,给出我们目前所学的工具箱: 词袋模型:对于一个句子,简单的把所有词的词向量进行平均,也能取得不错的baseline效果 基于滑动窗口的模型:对于POS、NER等不需要很长的上下文信息的问题来说,效果不错 CNN:对分类问题效果很好,容易在GPU上并行,所以效率很高 RNN:对于NLP问题来说,符合认知,对分类问题效果不是很好(如果只用最后一个隐状态的话),加上Attention性能提升明显,特别适合序列标注、语言模型等序列问题

August 5, 2019 · 1 min

CS224N(2.7)Question Answering

这节课的内容比较简单,是问答系统(Question Answering, QA)的入门介绍。 QA简介 首先,为什么需要QA?目前各大搜索引擎对于一个查询,给出的都是一个结果列表。但是很多查询是一个问题,答案也往往比较确定,比如“现任美国总统是谁?”,此时,返回一堆结果列表就显得太过啰嗦了,尤其是在手机等移动设备上搜索时,简单的给出回答也许会更好一些。另一方面,智能手机上的助手如Siri、Google Now之类的,用户期望的也是简洁的答案,而不是一堆网页列表。 QA系统的组成主要有两个部分,一部分是根据问题检索到相关的文档,这部分是传统的信息检索的内容;另一部分是对检索到的文档进行阅读理解,抽取出能回答问题的答案,这部分就是本文要介绍的QA系统。 QA的历史可追溯到上世纪七十年代,但真正取得突破性进展也就是最近几年。2015/2016年,几个大规模QA标注数据集的发表,极大的推动了这个领域的发展。这其中比较有名的数据集是斯坦福大学发布的Stanford Question Answering Dataset (SQuAD)。 SQuAD数据集的每一个样例包含一段描述P,一个问题Q,以及对Q的人工标注答案A。为了使数据集更加鲁棒,对于每个问题,都给出了三个人工标注答案。每个答案都是描述P中的一小段文字,称为一个span。所以,问题相对来说比较简单,答案可以直接从描述中提取sub-sequence得到。 QA系统的评价指标有两个,一个是确定性匹配Exact match,即对于每个问题,模型给出的回答如果和3个答案中的任意一个完全匹配,则加1分,否则不加分。另一个是F1指标,使用词袋模型(不考虑词的顺序),对于每个问题,模型给出的回答和3个答案中的每一个计算F1,这个问题的F1是3个F1的最大值,最终得分是所有问题的F1打分的均值。Exact match和F1都不考虑标点符号和冠词。相对来说,F1比Exact match更可靠和鲁棒一些。 经过两年的两三年的刷榜,SQuAD数据集的最好性能已经超越了人类的性能,为了增加数据集的难度,斯坦福后续推出升级版本SQuAD 2.0。 由于1.1版本的问题都有答案,所以QA系统变成了一个排序系统,只需要把Answer列表中排名第一的结果输出就好了。2.0在1.1的基础上,增加了没有答案的问题,可以理解为假问题,对系统造成干扰。此时就要求系统判断这个问题能否从描述P中获得答案,如果没有答案的话,就不输出任何回答<No Answer>。对于没有答案的问题,如果系统没有输出答案,得1分,否则输出任何答案都得0分。 SQuAD数据集的局限性: 回答都是span-based类型的,没有yes/no、计数、why等的问答。 由于构造问题q的时候,已知了描述P,那么q和P的描述会很像,无论是用词还是语法。而搜索引擎面临的真实情况往往是,q根本不知道P是什么,有可能q和P的描述在行文及用词上有很大差别。 描述P比较简单,因为答案是一个span,所以模型把q和P匹配,找到可能的答案位置就行。实际的复杂场景有可能要综合好几个句子的信息,还要理解不同的指代关系等才能得出最终答案。 虽然SQuAD数据集还有不少局限性,但由于其是一个well-targeted、well-structured、clean dataset,在QA发展初期,还是为促进QA发展立下了汗马功劳。 Stanford Attentive Reader 下面介绍一下Chris Manning组针对SQuAD数据集开发的QA系统——Stanford Attentive Reader。该系统目前虽然不是最好性能,但它包含QA的基本模块,可以作为QA的一个baseline模型。 首先模型对问题q进行表征的方法如下,输入是q中每个词的词向量,然后使用一个Bi-LSTM提取句子特征,由于是双向的LSTM,所以模型把正向和反向的LSTM的最后一个隐状态拼接起来,作为对整个句子的表征。 由于SQuAD数据集的回答都是描述P中的一个span,那么,模型只需要预测出这个span在P中的起始位置和终止位置即可,具体方法如下图所示。其实也很简单,上一步我们得到的句子的表征向量q,下一步,我们对描述P也使用Bi-LSTM,得到描述P中每个词的表征向量\(\tilde p_i\)。然后,使用两次Attention,用q查询集合\(P=[\tilde p_1,…,\tilde p_n]\),得到答案span的起始位置\(\alpha_i\)和终止位置\(\alpha’_i\)。另外,由于\(q\)和\(\tilde p_i\)的维度可能不一样,又或者为了提升模型性能,在计算Attention score的时候,不是简单的向量点积,而是采用了线性变换的方法,增加了参数\(W\)。 后来,Chris Manning组又推出了升级版本Stanford Attentive Reader++,主要包括两个方面。首先,对表征问题的网络进行了改进,\(q\)不仅包含Bi-LSTM的两个尾结点的隐状态,而是包含整个问题所有隐状态的加权平均,而且网络层数增加到了3层。其次,对描述P的表征方面,原来的输入只包含词向量,现在还包含语言特征(如POS、NER的标签)、词频、以及近义词的相似度等。改进版模型性能提升了不少。 另一个比较流行的QA系统是BiDAF,如下图所示,这里不再详细介绍。它的特点一方面输入不仅包含词向量,还包含字符级别的特征。另一大创新是在Attention Flow Layer,相对于Stanford Attentive Reader,BiDAF的Attention是双向的,不但包含q对P的Attention,还包含P对q的Attention。

August 4, 2019 · 1 min

CS224N(1.31)Translation, Seq2Seq, Attention

今天介绍另一个NLP任务——机器翻译,以及神经网络机器翻译模型seq2seq和一个改进技巧attention。 机器翻译最早可追溯至1950s,由于冷战的需要,美国开始研制由俄语到英语的翻译机器。当时的机器翻译很简单,就是自动从词典中把对应的词逐个翻译出来。 后来在1990s~2010s,统计机器翻译(Statistical Machine Translation, SMT)大行其道。假设源语言是法语\(x\),目标语言是英语\(y\),机器翻译的目标就是寻找\(y\),使得\(P(y|x)\)最大,也就是下图的公式。进一步,通过贝叶斯公式可拆分成两个概率的乘积:其中\(P(y)\)就是之前介绍过的语言模型,最简单的可以用n-gram的方法;\(P(x|y)\)是由目标语言到源语言的翻译模型。为什么要把\(P(y|x)\)的求解变成\(P(x|y)*P(y)\)?逐个击破的意思,\(P(x|y)\)专注于翻译模型,翻译好局部的短语或者单词;而\(P(y)\)就是之前学习的语言模型,用来学习整个句子\(y\)的概率,专注于翻译出来的句子从整体上看起来更加通顺、符合语法与逻辑。所以问题就转化为怎样求解\(P(x|y)\)。 SMT进一步把\(P(x|y)\)分解成\(P(x,a|y)\),其中\(a\)表示一个对齐alignment,可以认为是两种语言之间单词和单词或短语和短语的一个对齐关系。如下图所示是一个英语和法语的alignment。对齐本身就很复杂,存在1对1,1对多,多对1,多对多等情况,所以\(P(x,a|y)\)的求解在给定\(y\)的情况下,不但要考虑对齐方案\(a\)的情况\(P(a|y)\),还需要考虑对齐之后词与词的翻译情况\(P(x|a,y)\),可能的情况非常多。 那么,SMT怎样找到\(\arg max_y\)呢?穷举所有情况是不可能的,启发式搜索是可行的。形象描述就是在搜索过程中,对概率较低的路径进行剪枝,只保留概率较大的翻译情况。如下图的搜索树,对于概率较低的路径就不往下搜索了。 总之,统计机器翻译非常复杂,有很多的子模块,需要很多的人工干预和特征工程。 2014年,seq2seq模型横空出世,神经网络机器翻译(Neural Machine Translation, NMT)方兴未艾。seq2seq顾名思义,就是从序列到序列的模型,因为机器翻译的源语言和目标语言都是seq。 seq2seq的NMT如下图所示,它由两个RNN组成,左边的红色部分称为Encoder RNN,它负责对源语言进行编码(Encode);右边的绿色部分称为Decoder RNN,它负责对目标语言进行解码(Decode)。首先,Encoder RNN可以是任意一个RNN,比如朴素RNN、LSTM或者GRU。Encoder RNN负责对源语言进行编码,学习源语言的隐含特征。Encoder RNN的最后一个神经元的隐状态作为Decoder RNN的初始隐状态。Decoder RNN是一个条件语言模型,一方面它是一个语言模型,即用来生成目标语言的;另一方面,它的初始隐状态是基于Encoder RNN的输出,所以称Decoder RNN是条件语言模型。Decoder RNN在预测的时候,需要把上一个神经元的输出作为下一个神经元的输入,不断的预测下一个词,直到预测输出了结束标志符<END>,预测结束。Encoder RNN的输入是源语言的word embeding,Decoder RNN的输入是目标语言的word embeding。 seq2seq是一个很强大的模型,不但可以用来做机器翻译,还可以用来做很多NLP任务,比如自动摘要、对话系统等。 seq2seq作为一个条件语言模型,形式化来说,它直接对\(P(y|x)\)进行建模,在生成\(y\)的过程中,始终有\(x\)作为条件,正如下图的条件概率所示。 上面介绍了seq2seq的预测过程,seq2seq的训练过程如下图所示。训练的时候,我们同时需要源语言和翻译好的目标语言,分别作为Encoder RNN和Deocder RNN的输入。对于Encoder RNN没什么好说的。Decoder RNN在训练阶段,每一个时间步的输入是提供的正确翻译词,输出是预测的下一个时间步的词的概率分布,比如在\(t=4\),预测输出是\(\hat y_4\),而正确答案是“with”,根据交叉熵损失函数,\(J_4=-\log P(“with”)\)。总的损失函数就是所有时间步的损失均值。 seq2seq的训练过程是end2end的,即把Encoder RNN和Decoder RNN作为一个整体进行训练,不会像SMT一样有很多的子模块单独训练。当然seq2seq也可以单独对encoder和deconder进行训练优化,再组合,但是这个效果不一定会比整体优化encoder和deconder更好。 上上张图介绍的seq2seq的预测过程,实际上是一个贪心的预测过程,即在Decoder RNN的每一步都贪心选择\(\hat y_t\)概率最大的那个词。但是贪心只能保证每一步是最优的,无法保证预测出来的句子整体是最优的。特别是如果在\(t\)时刻贪心选择的词不是全局最优,会导致\(t\)时刻往后的所有预测词都是错误的,没有回头路了。但是如果每个时间步都穷举所有可能的情况的话,时间复杂度\(O(V^T)\)又太高了。 Beam search搜索策略是贪心策略和穷举策略的一个折中方案,它在预测的每一步,都保留Top-k高概率的词,作为下一个时间步的输入。k称为beam size,k越大,得到更好结果的可能性更大,但计算消耗也越大。请注意,这里的Top-k高概率不仅仅指当前时刻的\(\hat y_t\)的最高概率,而是截止目前这条路径上的累计概率之和,如下图的公式所示。 举例如下,假设\(k=2\),第一个时间步保留Top-2的词为”he”和”I”,他们分别作为下一个时间步的输入。”he”输入预测输出前两名是”hit”和”struck”,则”hit”这条路的累加概率是”he”的概率加上”hit”的概率=-1.7,类似的可以算出其他几个词对应路径的概率打分。最后在这4条路上保留\(k=2\)条路,所以”hit”和”was”对应路径保留,作为下一个时间步的输入;”struck”和”got”对应路径被剪枝。 最终的搜索树如下图所示,可以看到在每个时间步都只保留了\(k=2\)个节点往下继续搜索。最后”pie”对应的路径打分最高,通过回溯法得到概率最高的翻译句子。请注意,beam search作为一种剪枝策略,并不能保证得到全局最优解,但它能以较大的概率得到全局最优解,同时相比于穷举搜索极大的提高了搜索效率。 在beam search的过程中,不同路径预测输出结束标志符<END>的时间点可能不一样,有些路径可能提前结束了,称为完全路径,暂时把这些完全路径放一边,其他路径接着beam search。beam search的停止条件有很多种,可以设置一个最大的搜索时间步数,也可以设置收集到的最多的完全路径数。 当beam search结束时,需要从n条完全路径中选一个打分最高的路径作为最终结果。由于不同路径的长度不一样,而beam search打分是累加项,累加越多打分越低,所以需要用长度对打分进行归一化,如下图所示。那么,为什么不在beam search的过程中就直接用下面的归一化打分来比较呢?因为在树搜索的过程中,每一时刻比较的两条路径的长度是一样的,即分母是一样的,所以归一化打分和非归一化打分的大小关系是一样的,即在beam search的过程中就没必要对打分进行归一化了。 ...

August 2, 2019 · 1 min

CS224N(1.29)Vanishing Gradients, Fancy RNNs

梯度消失 今天介绍RNN的梯度消失问题以及为了解决这个问题引出的RNN变种,如LSTM何GRU。 在上一篇博客中,通过公式推导,我们已经解释了RNN为什么容易产生梯度消失或梯度爆炸的问题,核心问题就是RNN在不同时间步使用共享参数\(W\),导致\(t+n\)时刻的损失对\(t\)时刻的参数的偏导数存在\(W\)的指数形式,一旦\(W\)很小或很大就会导致梯度消失或梯度爆炸的问题。下图形象的显示了梯度消失的问题,即梯度不断反传,梯度不断变小(箭头不断变小)。 梯度消失会带来哪些问题呢?一个很明显的问题就是参数更新更多的受到临近词的影响,那些和当前时刻\(t\)较远的词对当前的参数更新影响很小。如下图所示,\(h^{(1)}\)对\(J^{(2)}(\theta)\)的影响就比对\(J^{(4)}(\theta)\)的影响大。久而久之,因为梯度消失,我们就不知道\(t\)时刻是真的对\(t+n\)时刻没影响还是因为梯度消失导致我们没学习到这种影响。 下图是一个更形象的例子,假设我们需要预测句子The writer of the books下一个单词,由于梯度消失,books对下一个词的影响比writer对下一个词的影响更大,导致模型错误的预测成了are,但这显然是不对的。 类似的,如果梯度爆炸,则根据梯度下降的更新公式,参数会一瞬间更新非常大,导致网络震荡,甚至出现Inf或NaN的情况。 梯度爆炸一个比较好的解决方法是梯度裁剪,即如果发现梯度的范数大于某个阈值,则以一定的比例缩小梯度的范数,但不改变其方向。如下下图所示,左子图是没有梯度裁剪的情况,由于RNN的梯度爆炸问题,导致快接近局部极小值时,梯度很大,参数突然爬上悬崖,然后又飞到右边一个随机的区域,miss掉了中间的局部极小值。右子图是增加了梯度裁剪之后,更新步伐变小,参数稳定在局部极小值附近。 总的来说,梯度爆炸相对好解决,但梯度消失就没那么简单了。在RNN中,每个时刻\(t\),都改写了前一个时刻的隐状态,而由于梯度消失问题,长距离以前的状态对当前时刻的影响又很小,所以导致无法建模长距离依赖关系。那么,如果把每个时刻的状态单独保存起来,是否能解决长距离依赖问题呢? LSTM LSTM就是这样一个思路,请大家结合如下两幅图来理解: (下图)首先,从宏观上来说,LSTM的隐层神经元不仅包含隐状态\(h_t\),还专门开辟了一个cell来保存过去的“记忆”\(c_t\),LSTM希望用\(c_t\)来传递很久以前的信息,以达到长距离依赖的目的。所以LSTM隐层神经元的输入是上一时刻的隐状态\(h_{t-1}\)和记忆\(c_{t-1}\),输出是当前时刻的隐状态\(h_t\)和希望传递给下一个时刻的记忆\(c_t\)。 (上图)每个时刻\(t\),为了调控遗忘哪些记忆,写入哪些新记忆,LSTM设置了两个门,分别是遗忘门\(f^{(t)}\)和写入门\(i^{(t)}\)。它们都是上一时刻的隐状态\(h^{(t-1)}\)和当前时刻的输入\(x^{(t)}\)的函数。\(f^{(t)}\)控制遗忘哪些记忆,即\(f^{(t)}\circ c^{(t-1)}\);\(i^{(t)}\)控制写入哪些新记忆,即\(i^{(t)}\circ \tilde c^{(t)}\),其中\(\tilde c^{(t)}\)即为期望写入的新记忆,它也是\(h^{(t-1)}\)和\(x^{(t)}\)的函数。最终,新时刻\(t\)的记忆就是这两部分的组合,请看上图\(c^{(t)}\)表达式。 (上图)输出门\(o^{(t)}\)控制哪些记忆需要输出到下一个隐状态\(h^{(t)}\),\(o^{(t)}\)自己又是\(h^{(t-1)}\)和\(x^{(t)}\)的函数。 大家结合上图的公式和下图的示意图就不难理解了。 LSTM解决梯度消失最直接的方法就是,遗忘门选择不遗忘,每一时刻的\(f^{(t)}\)都选择记住前一时刻的记忆\(c^{(t-1)}\),然后直接传递给下一时刻。那么,所有前\(t-1\)时刻的记忆都会被完整的传递给第\(t\)时刻,从而对\(t\)时刻的输出产生影响。 而朴素RNN无法保存前期状态的原因就是因为朴素RNN把之前时间步的信息都一股脑存储在隐状态\(h^{(t)}\)中了,隐状态\(h^{(t)}\)成为了整个网络的瓶颈,一旦出现梯度消失,则很久以前的信息对当前时刻的影响就微乎其微了。LSTM的关键就是开辟了一个新的cell来存储记忆,这个新的cell相当于记忆的一条捷径,时刻\(t\)除了可以像常规RNN一样通过\(h^{(t-1)}\)来获取很久以前的信息,还可以通过cell存储的记忆\(c^{(t-1)}\)来便捷地获取到很久以前的信息,所以隐状态\(h^{(t)}\)不再成为整个网络的瓶颈,有新的cell来分担。 需要提醒的是,虽然LSTM开辟新的cell来存储记忆,但这个记忆也会受到连续梯度相乘的影响,所以依然存在梯度消失或梯度爆炸的问题,但从实际效果来看,LSTM性能很不错,也很鲁棒。 GRU 另一种能缓解RNN梯度消失的网络——GRU。为了简化LSTM,GRU又没有cell了,但依然保留了门来控制信息的传递。首先看下图最后一个公式,当前时刻的隐状态\(h^{(t)}\)等于上一时刻的隐状态\(h^{(t-1)}\)和新写入的隐状态\(\tilde h^{(t)}\)的加权平均,通过更新门\(u^{(t)}\)来控制它们之间的比例,\(u^{(t)}\)是上一时刻的隐状态\(h^{(t-1)}\)和当前时刻的输入\(x^{(t)}\)的函数。新写入的隐状态\(\tilde h^{(t)}\)又通过一个重置门\(r^{(t)}\)来控制,类似的,\(r^{(t)}\)也是\(h^{(t-1)}\)和\(x^{(t)}\)的函数。 个人觉得,GRU中的更新门\(u^{(t)}\)类似于LSTM中的输出门\(o^{(t)}\);GRU中的重置门\(r^{(t)}\)类似于LSTM中的遗忘门\(f^{(t)}\)和写入门\(i^{(t)}\)的组合;GRU中新写入的隐状态\(\tilde h^{(t)}\)类似于LSTM中的细胞记忆\(c^{(t)}\)。所以,可以把GRU看作LSTM的简化版本。 直观来说,GRU和LSTM类似,解决梯度消失的策略就是新增\(u^{(t)}\)来控制\(h^{(t-1)}\)和\(\tilde h^{(t)}\)的比例,如果\(u^{(t)}=0\),则\(h^{(t)}=h^{(t-1)}\),即\(t\)时刻的隐状态和上一时刻的隐状态相同,虽然这肯定效果不好,但至少说明GRU是有能力保留之前的隐状态的。 GRU和LSTM的性能差不多,但GRU参数更少,更简单,所以训练效率更高。但是,如果数据的依赖特别长且数据量很大的话,LSTM的效果可能会稍微好一点,毕竟参数量更多。所以默认推荐使用LSTM。 其他缓解梯度消失的策略 由于链式法则,或者所选非线性激活函数的原因,不仅仅RNN,所有神经网络都存在梯度消失或者梯度爆炸的问题,比如全连接网络和CNN。一些通用解决方法如下: ResNet。因为梯度是在传递的过程中逐渐减小并消失的,如果跨越好几层直接进行连接,天然能保持远距离信息。个人理解,这就相当于买家和卖家直接相连,没有中间商赚差价\(\mathcal F(x)\),买到的价格最接近卖出的价格\(x\)。能一定程度上减弱梯度消失的问题。 更激进的是DenseNet,把跨越多层之间的很多神经元都连起来,也就是说有更多的线路没有中间商赚差价,进一步减弱梯度消失问题。 HighwayNet。借鉴了LSTM和GRU的思路,不是像ResNet一样直接新增一条直连线路\(x\),而是搞一个平衡因子\(u\),卖家到买家的价格由\(u\)进行调和平均:\(u*\mathcal F(x)+(1-u)*x\),用\(u\)来控制多少走中间商,多少走直连线路。 虽然所有神经网络都存在梯度消失的问题,但RNN的这个问题更严重,因为它连乘的是相同的权重矩阵W,而且RNN针对的是序列问题,往往更深。 双向RNN 假设我们在对句子进行情感分类,如下图所示。对于terribly这个词,常规RNN,terribly的梯度只能看到左边的信息,看不到右边的信息,因为网络是从左到右的。单独看terribly或者从左往右看,在没有看到exciting时,可能认为terribly是贬义词,但是如果跟右边的exciting结合的话,则意思变为强烈的褒义词,所以有必要同时考虑左边和右边的信息。 双向RNN包含两个RNN,一个从左往右,一个从右往左,两个RNN的参数是独立的。最后把两个RNN的输出拼接起来作为整体输出。那么,对于terribly这个词,它的梯度能同时看到左边和右边的信息。 由于双向RNN对于某个时刻\(t\),既需要知道\(t\)时刻前的信息(Forward RNN),又需要知道\(t\)时刻之后的信息(Backward RNN),所以双向RNN无法用于学习语言模型,因为语言模型只知道时刻\(t\)之前的信息,下一时刻的词需要模型来预测。对于包含完整序列的NLP问题,双向RNN应该是默认选择,它通常比单向RNN效果更好。 多层RNN 前面展示的RNN从时间\(t\)的维度上来说可以认为是多层的,但是RNN还可以从另一个维度来增加层数。如下图所示,将上一层(RNN layer 1)的输出作为下一层(RNN layer 2)的输入,不断堆叠下去,变成一个多层RNN。通常来说,深度越大,性能越好,如果梯度下降能训练好的话。 RNN的层数通常不会很深,不会像CNN一样,达到上百层,RNN通常2层,最多也就8层。一方面是RNN的梯度消失问题比较严重,另一方面是RNN训练的时候是串行的,不易并行化,导致网络太深的话训练很花时间。 ...

August 1, 2019 · 1 min

CS224N(1.24)Language Models and RNNs

今天要介绍一个新的NLP任务——语言模型(Language Modeling, LM),以及用来训练语言模型的一类新的神经网络——循环神经网络(Recurrent Neural Networks, RNNs)。 语言模型就是预测一个句子中下一个词的概率分布。如下图所示,假设给定一个句子前缀是the students opened their,语言模型预测这个句子片段下一个词是books、laptops、exams、minds或者其他任意一个词的概率。形式化表示就是计算概率 $$\begin{eqnarray}P(x^{(t+1)}|x^{(t)},…,x^{(1)})\tag{1}\end{eqnarray}$$\(x^{(t+1)}\)表示第\(t+1\)个位置(时刻)的词是\(x\),\(x\)可以是词典\(V\)中的任意一个词。 既然语言模型在给定前t个词之后可以预测第t+1个词的概率,那么预测到第t+1个词之后,又可以递归的根据前t+1个词预测第t+2个词,如此不断的进行下去,就可以预测一整个句子的概率了。所以,也可以把语言模型看做一个可以计算一个句子出现的概率的系统,形式化表示就是如果一个句子是\(x^{(1)},…,x^{(T)}\) ,那么语言模型可以计算句子概率 $$\begin{eqnarray}P(x^{(1)},…,x^{(T)})& = & P(x^{(1)})\times P(x^{(2)}|x^{(1)})\times…\times P(x^{(T)}|x^{(T-1)},…,x^{(1)}) \tag{2}\\& = & \prod_{t=1}^T P(x^{(t)}|x^{(t-1)},…,x^{(1)})\tag{3}\end{eqnarray}$$可以看到(3)式连乘的项就是(1)式,所以这两个定义的内涵是一样的。 那么语言模型有什么用呢?它的用处可大了,比如现在的输入法会根据前一个输入的词预测下一个将要输入的词,此所谓智能输入法;比如在百度或谷歌搜索时,输入前几个关键词,搜索引擎会自动预测接下来可能的几个词;比如网上有很多智能AI会自动生成新闻、诗歌;还比如用在语音识别、机器翻译、问答系统等等。可以说语言模型是很多NLP任务的基础模块,具有非常重要的作用。 在前-深度学习时代,人们使用n-gram方法来学习语言模型。对于一个句子,n-gram表示句子中连续的n个词,比如还是上图的例子,n-gram对于n=1,2,3,4的结果是: 1-grams (unigrams): “the”, “students”, “opened”, “their” 2-grams (bigrams): “the students”, “students opened”, “opened their” 3-grams (trigrams): “the students opened”, “students opened their” 4-grams: “the students opened their” n-gram方法有一个前提假设,即假设每个词出现的概率只和前n-1个词有关,比如2-gram对于每个词出现的概率只和前面一个词有关,和更前面的词以及后面的词都没有关系,所以我们有如下图的assumption。又这是一个条件概率,展开之后得到如下除法的形式。n-gram的计算方法就是,统计语料库中出现\(x^{(t)},…,x^{(t-n+2)}\)的次数(分母),以及在这个基础上再接一个词\(x^{(t+1)}\)的次数\(x^{(t+1)},x^{(t)},…,x^{(t-n+2)}\)(分子),用后者除以前者来近视这个条件概率。 举个例子,假设完整的句子是as the proctor started the clock, the students opened their,需要预测下一个词的概率分布。对于4-gram方法,则只有students opened their对下一个词有影响,前面的词都没有影响。然后我们统计训练集语料库中发现,分母students opened their出现1000次,其后接books即students opened their books出现了400次,所以P(books|students opened their)=400/1000=0.4。类似的,可以算出下一个词为exams的概率是0.1。所以4-gram方法认为下一个词是books的概率更大。 ...

July 31, 2019 · 2 min

CS224N(1.22)Dependency Parsing

Dependency Parsing是指对句子进行语法分析并画出句子成分的依赖关系,比如对于句子“She saw the video lecture”,首先可以分析出主语、谓语、宾语等句子成分;其次可以分析出依赖关系,比如saw依赖于She等。这就是句法分析。完成句法分析的算法被称为句法分析器parser,一个parser的性能可以用UAS和LAS来衡量,UAS就是parse出来的依赖关系对比正确依赖关系的正确率,LAS就是句子成分分析的正确率。 那么,为什么需要句法分析呢?因为:(i)了解句子结构能更好的理解句子的含义;(ii)人们在交流的时候,通过组合简单的句子成分来表达复杂的含义;(iii)我们需要知道句子中成分之间的依赖关系,以此来正确解读句子的含义。 其实说到底就是为了更正确的理解句子含义。比如对于句子“San Jose cops kill man with knife”这个句子就有歧义,with knife到底是修饰man还是修饰kill,句子的意思大不相同。如果新闻小编学过NLP的话,大概不会写出这种歧义的句子。 句法分析有很多算法,本世纪初当机器学习兴起后,Nivre等人提出了基于转移的句法分析器。该算法维护一个堆栈stack,用来存放已经分析过的词,以及一个buffer,用来存放还未分析的词。初始时,stack只有一个额外添加的[root]节点,buffer保存了完整的句子。然后,对于buffer中的每一个词,有三种操作,分别是:(i)shift,将buffer中的一个词压入stack;(ii)left arc,对于stack中的词,如果栈的第二个元素是栈顶元素的依赖项,则把第二个元素出栈;(iii)right arc,对于stack中的词,如果栈顶元素是栈的第二个元素的依赖项,则把栈顶元素出栈。如此循环,直到buffer为空以及stack中只剩下[root]。 对于上述算法,核心问题是,对于stack+buffer的不同状态,应该选择shift、left arc和right arc中的哪个操作呢?对于本世纪初的研究者来说,他们选择了机器学习方法。很简单嘛,每一个stack+buffer的状态相当于输入,3种操作相当于输出,把这个问题建模成分类问题不就行了吗。于是Nivre等人对每一个stack+buffer的状态,人工抽取出很多的特征,然后使用logistic或者svm进行分类。但是,当时的特征设计都是0/1状态的,特征向量很稀疏;特征又多,抽取特征很花时间。 当神经网络火了之后,人们自然想到了用神经网络替代logistic或svm,提出了新的句法分析器,该课程老师所在团队就是这么干的。他们对于每一个stack+buffer的状态,抽取出words、POS tags和arc labels三种不同类型的特征,都用词向量来表示。然后输入只有一个隐层的全连接网络,效果立马超过了之前所有人工设计的特征和方法。基于这个工作,后续又有很多改进版本。 https://nlp.stanford.edu/pubs/emnlp2014-depparser.pdf 好了,上述就是这节课的主要内容,由于本人对句法分析不太感兴趣,没有亲自做作业,大家可以参考别人的解答。

July 29, 2019 · 1 min

CS224N(1.15 & 1.17)Backpropagation

这篇博客把1.15和1.17两次课内容合并到一起,因为两次课的内容都是BP及公式推导,和之前的Neural Networks and Deep Learning(二)BP网络内容基本相同,这里不再赘述。下面主要列一些需要注意的知识点。 使用神经网络进行表示学习,不用输入的x直接预测输出,而是加一个中间层(图中橙色神经元),让中间层对输入层做一定的变换,然后中间层负责预测输出是什么。那么中间层能学到输入层的特征,相当于表示学习,自动学习特征。对于word2vec,中间层就是词向量。 命名实体识别(Named Entity Recognition, NER),任务是把一个句子中的一些实体词识别出来,比如下图中识别出地点LOC、机构ORG和人名PER等。通常采用的方法是把需要判断类型的词及其周围的几个词的词向量拼接起来,输入到神经网络进行分类。但是由于一个句子中真正的实体词较少,而很多其他词Others会很多,导致样本不均衡,此时需要进行采样,具体方法可以搜索怎样处理NER样本不均衡的问题。 我们知道词向量其实是NLP实际任务中的副产品,任何一个NLP任务都可以得到词向量。这就存在一个问题,当我们在实现一个具体的NLP任务时,是使用预训练的词向量,还是根据实际任务现场训练一个词向量呢?建议是,如果有可用的预训练词向量,则最好使用预训练词向量。因为预训练的词向量通常在很大规模的数据集上进行过训练,词向量的质量还不错,而某个具体的NLP任务的样本数可能不太多,导致训练得到的词向量还没人家预训练的好。所以,如果实际任务的数据量较小,则用预训练的词向量;否则,可以尝试一下根据实际任务fine tune词向量。 这节课的核心就是不断使用链式法则对BP算法求导,然后反向传播。在反向传播的过程中,可以利用上游计算好的梯度,增量式的更新下游的梯度,如下图所示,就是公式[downstream gradient] = [upstream gradient] × [local gradient]。这个在之前介绍BP网络的时候也提到过,其实就是那篇博客的(BP2)公式,误差对\(w\)的偏导可以通过误差对\(b\)的偏导乘以神经元输出得到。 当有多个输入的时候,也是一样,只不过local gradients变为了多个分支。 很有意思的是老师总结到:加法相当于把上游的梯度分发给下游;max相当于路由;乘法相当于开关。听老师讲下面的实例会有切身的体会。 当然,现在的流行的神经网络框架都帮我们完成了自动求导,我们只需要把local gradient定义好,框架会自动帮我们进行反向传播。需要定义的就两点,一个是正向经过该神经元,output=forward(intput);另一个是反向经过该神经元时,input_gradient=backward(output_gradient)。下面第二个图是一个很简单的例子,定义了forward和backward两个操作。 最后,简要介绍了6个注意事项: 使用正则化避免过拟合 使用python的向量和矩阵运行,而不是for循环,前者相比于后者有~10x加速 目前流行的非线性激活函数是ReLU,Sigmoid和tanh比较少用了 参数(权重)初始化,初始值最好是随机的很小的值,有一些专门的策略,如Xavier sgd优化器效果还不错,不过目前流行的优化器是Adam 学习率最好是10的倍数,而且可以成10倍的放大或缩小;一些fancy的优化器会对设定的学习率进行逐步缩减(比如Adam),所以对于这些优化器,一开始的学习率可以设大一点,比如0.1 最后是本周作业,包含两部分内容,一部分是手动求导,编辑公式太麻烦了,我就写在了纸上,大家可以参考这位仁兄的解答。另一部分是根据手动推导的梯度公式,补充word2vec算法中的求解梯度的算法以及sgd更新公式,如果是第一次接触这方面内容,可以参考这位仁兄的实现。 但是,根据上一篇博客的介绍,word2vec除了可以根据作业中的极大似然的方法求解,还可以用3层全连接网络来实现,相比于极大似然更简洁也更容易理解,具体可以参考这篇博客以及这篇具体实现。

July 29, 2019 · 1 min