import torch
from transformers import BertModel, BertTokenizer
# 这里我们调用bert-base模型,同时模型的词典经过小写处理
model_name = 'bert-base-uncased'
# 读取模型对应的tokenizer
tokenizer = BertTokenizer.from_pretrained(model_name)
# 载入模型
model = BertModel.from_pretrained(model_name)
# 输入文本
input_text = "Here is some text to encode"
# 通过tokenizer把文本变成 token_id
input_ids = tokenizer.encode(input_text, add_special_tokens=True)
# input_ids: [101, 2182, 2003, 2070, 3793, 2000, 4372, 16044, 102]
input_ids = torch.tensor([input_ids])
# 获得BERT模型最后一个隐层结果
# 对文本的每一个token生成768维的向量,如果是二分类任务,我们接下来
# 就可以把第一个token也就是[CLS]的768维向量,接一个linear层,预测出分类的logits,或者根据标签进行训练。
with torch.no_grad():
last_hidden_states = model(input_ids)[0] # Models outputs are now tuples
""" tensor([[[-0.0549, 0.1053, -0.1065, ..., -0.3550, 0.0686, 0.6506],
[-0.5759, -0.3650, -0.1383, ..., -0.6782, 0.2092, -0.1639],
[-0.1641, -0.5597, 0.0150, ..., -0.1603, -0.1346, 0.6216],
...,
[ 0.2448, 0.1254, 0.1587, ..., -0.2749, -0.1163, 0.8809],
[ 0.0481, 0.4950, -0.2827, ..., -0.6097, -0.1212, 0.2527],
[ 0.9046, 0.2137, -0.5897, ..., 0.3040, -0.6172, -0.1950]]])
shape: (1, 9, 768)
"""
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect()
时。将触发三次握手。
第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
发送完毕后,客户端进入 SYN_SEND
状态。
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD
状态。
第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED
状态,当服务器端接收到这个包时,也进入 ESTABLISHED
状态,TCP 握手结束。
三次握手的过程的示意图如下:
TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close()
操作即可产生挥手操作。
第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1
状态。
第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2
状态,等待服务器端关闭连接。
第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK
状态,等待来自客户端的最后一个ACK。
第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT
状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED
状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED
状态。
四次挥手的示意图如下:
随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。**随机森林的随机性体现在每颗树的训练样本是随机的,树中每个节点的分裂属性集合也是随机选择确定的。**有了这2个随机的保证,随机森林就不会产生过拟合的现象了。
随机森林是用一种随机的方式建立的一个森林,森林是由很多棵决策树组成的,每棵树所分配的训练样本是随机的,树中每个节点的分裂属性集合也是随机选择确定的。
简述xgboost的推导过程
lstm和rnn的区别
对nlp的理解是多少
手撕代码(1)反转链表 (2)快速排序 (3)用神经网络搭建一个LR
对pytorch和keras了解多少
二者都是集成学习算法,都是将多个弱学习器组合成强学习器的方法。
Bagging:从原始数据集中每一轮有放回地抽取训练集,训练得到k个弱学习器,将这k个弱学习器以投票的方式得到最终的分类结果。
Boosting:每一轮根据上一轮的分类结果动态调整每个样本在分类器中的权重,训练得到k个弱分类器,他们都有各自的权重,通过加权组合的方式得到最终的分类结果。
存在。我们可以使用无监督学习的某些指标或人为地去评估模型性能,以此来判断是否过拟合。
将原始数据集划分为k个子集,将其中一个子集作为验证集,其余k-1个子集作为训练集,如此训练和验证一轮称为一次交叉验证。交叉验证重复k次,每个子集都做一次验证集,得到k个模型,加权平均k个模型的结果作为评估整体模型的依据。
k越大,不一定效果越好,而且越大的k会加大训练时间;在选择k时,需要考虑最小化数据集之间的方差,比如对于2分类任务,采用2折交叉验证,即将原始数据集对半分,若此时训练集中都是A类别,验证集中都是B类别,则交叉验证效果会非常差。
准确率 = TP / (TP + FP),召回率 = TP / (TP + FN),其中TP表示将正例正确分类为正例的数量,FP表示将负例错误分类为正例的数量,FN表示将正例错误分类为负例的数量。
准确率可以理解为在所有分类为正例的样品中,分类正确的样本所占比例;召回率可以理解为在所有原始数据集中的正例样品中,正确挑出的正例样本的比例。
因此若增大阈值t,更多不确定(分类概率较小)的样本将会被分为负例,剩余确定(分类概率较大)的样本所占比例将会增大(或不变),即准确率会增大(或不变);若增大阈值t,则可能将部分不确定(分类概率较小)的正例样品误分类为负例,即召回率会减小(或不变)。
A.增加网络层数,总能减小训练集错误率
B.减小网络层数,总能减小测试集错误率
C.增加网络层数,可能增加测试集错误率
C。增加神经网络层数,确实可能提高模型的泛化性能,但不能绝对地说更深的网络能带来更小的错误率,还是要根据实际应用来判断,比如会导致过拟合等问题,因此只能选C。
L1范数:向量中各个元素绝对值之和
L2范数:向量中各个元素平方和的开二次方根
Lp范数:向量中各个元素绝对值的p次方和的开p次方根
输入数据本身存在nan值,或者梯度爆炸了(可以降低学习率、或者设置梯度的阈值)
减小图像尺寸即数据降维,缓解过拟合,保持一定程度的旋转和平移不变性。
sigmoid,relu,tanh,非线性化
防止过拟合。每次训练,都对每个神经网络单元,按一定概率临时丢弃。
很有可能是梯度消失了,它表示神经网络迭代更新时,有些权值不更新的现象。
改变激活函数,改变权值的初始化等。
可以扩充数据集,对数据重新采样,改变评价指标等。
神经网络在反向传播过程中要不断地传播梯度,而当网络层数加深时,梯度在逐层传播过程中会逐渐衰减,导致无法对前面网络层的权重进行有效的调整。 残差网络中, 加入了short connections 为梯度带来了一个直接向前面层的传播通道,缓解了梯度的减小问题。
(1) 防止梯度消失 ( sigmoid的导数只有在0附近的时候有比较好的激活性,在正负饱和区的梯度都接近于0)
(2) ReLU的输出具有稀疏性
(3) ReLU函数简单计算速度快
空洞卷积也叫扩张卷积,在保持参数个数不变的情况下增大了卷积核的感受野,同时它可以保证输出的特征映射(feature map)的大小保持不变。一个扩张率为2的3×3卷积核,感受野与5×5的卷积核相同,但参数数量仅为9个。
在卷积神经网络中,感受野 (receptive field)的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小。
模型复杂度过低,不能很好的拟合所有的数据
增加模型复杂度,如采用高阶模型(预测)或者引入更多特征(分类)等
Mobilenet(https://arxiv.org/abs/1704.04861)
Shufflenet(https://arxiv.org/abs/1707.01083)
Xception(https://arxiv.org/abs/1610.02357)
使用im2col的方法将划窗卷积转为两个大的矩阵相乘,见下图:
一般做法是将缺失的标签设置特殊标志,在计算梯度的时候忽略。
(1)Gaussian 满足mean=0,std=1的高斯分布x∼N(mean, )
(2)Xavier 满足x∼U(−a,+a)x∼U(−a,+a)的均匀分布, 其中 a = sqrt(3/n)
(3)MSRA 满足x∼N(0, )x∼N(0,)的高斯分布,其中σ = sqrt(2/n)
(4)Uniform 满足min=0,max=1的均匀分布。x∼U(min,max)x∼U(min,max)
等等
深度学习中的注意力机制从本质上讲和人类的选择性视觉注意力机制类似,核心目标是从大量信息中有选择地筛选出少量重要信息并聚焦到这些重要信息上,忽略大多不重要的信息。目前在神经机器翻译(Neural Machine Translation)、图像理解(Image caption)等场景都有广泛应用。
MaxPooling能保证卷积神经网络在一定范围内平移特征能得到同样的激励,具有平移不变形。
所谓的权值共享就是说,用一个卷积核去卷积一张图,这张图每个位置是被同样数值的卷积核操作的,权重是一样的,也就是参数共享。
(1)模型蒸馏技术(https://arxiv.org/abs/1503.02531)
(2)利用AutoML进行网络结构的优化,可将网络计算复杂度作为约束条件之一,得到更优的结构。(https://arxiv.org/abs/1807.11626)
在反向传播算法计算每一层的误差项的时候,需要乘以本层激活函数的导数值,如果导数值接近于0,则多次乘积之后误差项会趋向于0,而参数的梯度值通过误差项计算,这会导致参数的梯度值接近于0,无法用梯度下降法来有效的更新参数的值。
改进激活函数,选用更不容易饱和的函数,如ReLU函数。
欧氏距离,交叉熵,对比损失,合页损失
30.对于多分类问题,为什么神经网络一般使用交叉熵而不用欧氏距离损失?
交叉熵在一般情况下更容易收敛到一个更好的解。
通道降维,保证卷积神经网络可以接受任何尺寸的输入数据
不能,每次迭代时目标函数不一样
使得迭代之后的值在上次值的邻域内,保证可以忽略泰勒展开中的二次及二次以上的项
利用之前迭代时的梯度值,减小震荡
用多个小卷积核串联可以有大卷积核同样的能力,而且参数更少,另外有更多次的激活函数作用,增强非线性
对输入图像用多个不同尺寸的卷积核、池化操作进行同时处理,然后将输出结果按照通道拼接起来
反卷积即转置卷积,正向传播时乘以卷积核的转置矩阵,反向传播时乘以卷积核矩阵
由卷积输出结果近似重构输入数据,上采样
在数据送入神经网络的某一层进行处理之前,对数据做归一化。按照训练样本的批量进行处理,先减掉这批样本的均值,然后除以标准差,然后进行缩放和平移。缩放和平移参数同训练得到。预测时使用训练时确定的这些值来计算
核函数将数据映射到更高维的空间后处理,但不用做这种显式映射,而是先对两个样本向量做内积,然后用核函数映射。这等价于先进行映射,然后再做内积。
过拟合指在训练集上表现的很好,但在测试集上表现很差,推广泛化能力差。产生过拟合的原因是训练样本的抽样误差,训练时拟合了这种误差。增加训练样本,尤其是样本的代表性;正则化
非线性,几乎处处可到,单调
梯度为0,Hessian矩阵不定的点,不是极值点
不收敛,收敛太慢,泛化能力差。调整网络结构,调整样本,调整学习率,调整参数初始化策略
多个二分类器组合。1对1方案,1对剩余方案,多类损失函数
层次聚类,k均值算法,DBSCAN算法,OPTICS算法,谱聚类
随机选择K个样本作为类中心,将样本随机划分成K个子集然后计算类中心
EM算法用于求解带有隐变量的最大似然估计问题。由于有隐变量的存在,无法直接用最大似然估计求得对数似然函数极大值的公式解。此时通过jensen不等式构造对数似然函数的下界函数,然后优化下界函数,再用估计出的参数值构造新的下界函数,反复迭代直至收敛到局部极小值点
一面50分钟
二面55分钟
一面50分钟
二面30分钟
劝退
一面75分钟
二面45分钟
三面hr
一面50分钟
二面30分钟
聊实习
一面60分钟
二面60分钟
三面60分钟
经理面
一面20分钟
二面60分钟
一面40分钟
分类模型(又称分类器,或诊断)将实例映射到特定类。ROC分析的是二元分类模型,也就是输出结果只有两种类别的模型,例如:(阳性/阴性) (有病/没病) (垃圾邮件/非垃圾邮件) (敌军/非敌军)。
当讯号侦测(或变量测量)的结果是连续值时,类与类的边界必须用阈值来界定。举例来说,用血压值来检测一个人是否有高血压,测出的血压值是连续的实数(从0~200都有可能),以收缩压140/舒张压90为阈值,阈值以上便诊断为有高血压,阈值未满者诊断为无高血压。二元分类模型的个案预测有四种结局:
真阳性(TP):诊断为有,实际上也有高血压。
伪阳性(FP):诊断为有,实际却没有高血压。
真阴性(TN):诊断为没有,实际上也没有高血压。
伪阴性(FN):诊断为没有,实际却有高血压。
这四种结局可以画成2 × 2的混淆矩阵
ROC空间
ROC空间将伪阳性率(FPR)定义为 X 轴,真阳性率(TPR)定义为 Y 轴。
给定二元分类模型和它的阈值,就能从所有样本的(阳性/阴性)真实值和预测值计算出(X=FPR, Y=TPR) 座标点。
从 (0, 0) 到 (1,1) 的对角线将ROC空间划分为左上/右下两个区域,在这条线的以上的点代表了一个好的分类结果(胜过随机分类),而在这条线以下的点代表了差的分类结果(劣于随机分类)。
完美的预测是在左上角的点,在ROC空间座标 (0,1)点,X=0 代表着没有伪阳性,Y=1 代表着没有伪阴性(所有的阳性都是真阳性);也就是说,不管分类器输出结果是阳性或阴性,都是100%正确。一个随机的预测会得到位于从 (0, 0) 到 (1, 1) 对角线(也叫无识别率线)上的一个点;最直观的随机预测的例子就是抛硬币。
让我们来看在实际有100个阳性和100个阴性的案例时,四种预测方法(可能是四种分类器,或是同一分类器的四种阈值设定)的结果差异:
1。自我介绍
2。然后直接问了下研二实习导师同意了吗
3。然后让介绍项目,平安车险的一个比赛
4。对Y值聚类是什么思路具体介绍一下,kmeans了解吗,自己实现的吗,K值取多少怎么确定的,kmeans的特征?(这里其实没太懂,可能是问kmeans用的什么聚类?我说可能是密度聚类,调用的sklearn)
5。为什么想到用AUC做评价指标,AUC应该是做二分类的吧,讲一下AUC和ROC(前一天晚上准备看,结果忘了,路上太热了也没看)
6。说一下lightgbm吧,讲一下GBDT,和决策树的区别。
7。比赛的数据是怎么个方式,线上平台是怎么操作,用什么处理的数据,对数据进行过清洗吗。
8。我看你简历上写了深度学习,有做过什么项目吗。(讲了一个课程作业)
9。用了gensim的词向量模型,有一个score函数,说了一下这个函数是干嘛的,他说他印象中没这个东西。然后说了另外一个LSTM的模型,让我把整个数据处理、模型训练、测试、损失函数讲一下。我一开始一会让我讲LSTM,开始画LSTM的图,然后说这个当成个黑盒子就行,你讲一下整个流程。这个作业一共花的时间不到一周,所以有点忘了,也没写到简历里面,顺口说的,讲的不是很好,当时傻了说最后是一个sigmoid,他愣了一下,最后他说最后应该个是softmax吧,我说对对对。
10。然后问我用keras做的还是tf。然后问还有没有别的项目,没了,做一个算法题。
11。一个贼他妈简单的归并排序,提醒了我三次,说排序、nlogn的排序、归并排序你学过吗。(考研的时候学过)你写一写吧(我好像忘了)。面试官好像无语了,然后让我就写一个n方的吧。
12。最后问我有什么想问的,我说那边现在在做什么,实习生平时做什么。他又问了我有没有用c++写过大项目,因为那边目前有个项目要用c++。
13。然后问了我为啥转专业,我想了想是不是应该说我热爱编程,热爱数学,热爱计算机,还是算了,然后说本科工科很苦逼,深山老林发电厂,计算机钱多。面试官笑了笑,就完了。
上面就是我暂时能想到的一些点,也是自己在面试的过程中不断碰壁遇到的一些问题,然后整理下来的。对于基础知识这一块,可能会有很多同学问机器学习和深度学习之间如何权衡,其实我想说的是看你自己想找什么工作,我给自己的定位是深度学习与NLP,所以面试之前只看了SVM,然后在所有面试中也只有个别的面试官会问到机器学习的东西。怎么说呢,我的看法是,要学,要懂,但是次要,你只需要在整个面试过程中不断地展现自己在深度学习上的造诣,不给面试官留下时间去问机器学习就好。当然,如果你有足够的时间去准备,看看是最好的,毕竟你所有的准备都可能在面试中给自己增光添彩,按照自己的时间精力去分配就好。
这部分会按照面试时间的先后顺序大概说一下,先大体上说一下,拿到的offer有竹简智能-对话方向、阿里小蜜-对话方向、阿里新零售-NLP算法、滴滴AILab-对话方向、美团点评AI平台-对话方向、百度NLP部分-NLP算法、百度度秘事业部-对话方向、搜狗-机器翻译。跪了的有微信搜一搜看一看(面到了HR,现在还没给消息,暂时当他是跪了吧)、京东AILab-对话方向(跪的有点不知所措,虽然我也并不想去这里)。微软亚研(上周刚一面,就当是跪了吧,希望是一波毒奶)。怎么说呢,面的公司有点多,整个过程很累,但是由于offer的时间线原因,几个想要去的offer都是到最后才拿到,所以面了比较久。整体上感觉面试还算比较轻松,主要原因是找的实习大部分跟自己做的方向很match,所以整体上能够发挥出自己所学的东西,所以面试的结果也都还挺好的。下面就各自介绍一下:
一、2018.3.8 竹简智能 算法实习生
算法题:股票买卖获最大利润
一面:先简单介绍了一下Memory Network的相关知识,然后结合key-value MemNN模型介绍了一下自己做的基于KB知识库的问答系统,主要讲了以下其模型和工作原理。然后接下来聊了聊seq2seq模型,并主要介绍了一下attention机制,让写了下attention的公式,怎样计算得分和权重,说了下soft attention和hard attention的区别。然后聊了下tensorflow里面seq2seq的借口,吐了吐槽也介绍了自己实现的模型里面的一些细节和方法。
二面:主要针对我的京东实习和文本分类方面的问题进行提问,先问我都用过那些模型实现文本分类,当时卡克了只说出来了两个,尴尬==****(fasttext TextCNN RCNN HAN DMN EntityNetwork charCNN charRNN)。需要在总结一下各个模型的优缺点****。然后问了我觉得现在文本分类中还有哪些没有解决的问题,我想了会说样本不平衡问题(应该进行下采样来解决,他问我还有什么办法,我说这块没有尝试过只是在网上见到过一些介绍),和多类别分类问题(这里引入了知乎竞赛),多标签分类确实是一个很难的问题,面试官让我写损失函数,我当时由于紧张和时间久远也没有回答上来,算是整个面试过程中唯一回答的不好的问题吧。
三面:技术总监,到没有聊什么技术,拿着简历随便问了点项目和实习相关的东西,然后主要聊了公司的一些情况之类的,表达了对我很满意想让我留下来然后协调了一下实习时间之类的,算是发了口头offer。后面HR打电话问我的意向的时候拒了。
二、2018.3.13 阿里智能服务部–阿里小蜜 算法实习生
一面:面试官很亲和,上来主要是简历面,可以说是面面俱到,基本上简历上的东西都被问了个遍,而且还会眼神的考察一些基础知识,比如说介绍一下某些模型的细节、原理等等,稍微扩展了一下简历之外的东西看看知识的了解情况吧,比如说问了我句子相似度、传统方法做文本分类、SVM、word2vec等几个并没有出现在我简历中的知识点。然后也有几个开放性的问题,比如说我在京东的实习,如果让我采取方案的话我会使用什么方案,fasttext、CNN、RNN的优缺点各是什么等等,也都简单的聊了一下,感觉整体上来讲面试的效果还算可以,基本上问题的回答上来了。面试官也没有深究细节,点到为止。最后问了我关于实习地点在杭州是否可以,可是我还有别的选择吗==#
二面 2018.3.31 今天终于接到了二面的电话,记得是一个阳光明媚的中午_,面试大概持续了半个小时,先让我讲了一下attention的原理,接着讲了一下seq2seq的缺点,如何改进;如何实现再已知答案的情况下进行答案生成。然后问如何加速预测速度(其实这两个问题我也不是很清楚,只是很模糊的打了一下);接下来聊了一下京东的实习情况,为什么fasttext速度很快,然后问了下如果现在在做会采用什么样的方案;说一说RNN和LSTM的区别和原理;说一下自己的未来规划;感觉整个面试更偏向于理解,而不会是非在意细节,更不会具体到公式,但是还是会比较关注优模型化和性能方面。整体来讲,还不错??
三面 2018.4.7 一周后接到了三面电话,面试官应该很忙,毕竟清明节面试,而且感觉还有很多个人要面试的样子。面试大概持续了半个小时,上来让我讲一下最近做的对话系统的项目,我已开始说了一下模型的细节,面试官打断了我说相听一下具体的实现细节,不要讲论文的模型,然后我就把自己实现seq2seq时遇到的deepcopy和beam_search两个问题以及解决方案大概讲了一下,面试官到没有提什么问题,只是问了一下最后的真实效果,以及怎么评价之类的问题。然后就问了一下能不能去杭州实习,三面就结束了。
四面 2018.5.2 有过了快一个月才收到4面电话,直接是HR面,先是自我介绍,然后问了一下基本情况,发论文学习成绩之类的,然后问现在都有什么offer了,如何选择云云,20分钟左右让我等通知。
2018.5.3,今天有个小蜜部门的工程师加我微信,说我的面试通过了,口头发了offer,说后面会有后续的offer流程。
三、2018.3.30 阿里零售通 算法实习生
今天是阿里校招北邮行,貌似可以当场面试,所以就抱着试一试的心态去看看,本来想着去找智能服务部问一下自己简历的情况,结果智能服务部的人没去,却被零售通的人拉过去面试了一会。很轻松,负责人大概聊了一会就让我去二面,貌似是HR,也很随意,主要是他在讲他们部门,我基本上没说什么,然后他就说让他们部门总监给我三面,下午收到电话,面了50分钟左右。整体感觉上他们的算法部门应该是刚成立不久,挺缺人的,主要做推荐和物流这块,面试应该问题不大。但是我还是更想去智能服务部那边,毕竟方向更对口,所以跟他们说需要在考虑靠考虑。
4.3号又接到了零售通HR的电话,表示他们那边已经同意给我发offer,如果我也接受的话就把阿里小蜜的校招流程停掉转到他们那里去,在接受一轮交叉面试就可以了。我跟HR沟通了一下,说希望在考虑一下(因为我感觉阿里小蜜的人肯定会在清明节给我面试电话,所以想在等一下)。然后面试官就说那就等清明节结束之后让我给他一个回复。
2018.4.10 虽然小蜜那边的面试还没结束,offer也不一定能拿到,但一狠心还是把零售通的offer给拒了。
四、2018.3.15 滴滴AILab 自然语言处理实习生(对话方向)
整个面试过程只有一面,面试官把我接上来之后先让我介绍一下自己之前做过的一个项目,我就说了一下使用seq2seq实现对话系统的模型,接着讲了讲模型的缺点以及使用MMI的改进方案(这里自己当时没说好,感觉自己把自己绕进去了==),然后介绍完整个项目的细节之后,面试官提出了一个问题,说Attention机制的计算细节和公式是怎样的,然后我就介绍了一下公式的计算方法,然后说了一下改进的方案等。面试官就没有再问相关问题,感觉他好像也不是特别懂的样子,然后就说出一道算法题目做做吧。题目是有两个有序的集合,集合的每个元素都是一段范围,求其交集,例如集合{[4,8],[9,13]}和{[6,12]}的交集为{[6,8],[9,12]}。然后我就开始做,先写了个暴力解法,然后面试官让我想想有没有什么改进可以把时间复杂度改善。想了几分钟,说了一下自己的大致思路,其实并没有想到方案==不过交流的过程中得到一个很重要的信息就是这些范围是排序而且互相之间不会重合。所以这里也是给大家提个醒,一定要先把题目搞清楚再开始做题,不然很可能像我这样吧。然后搞清楚之后题目就很简单了,写一个循环就可以了,时间复杂度是O(N+M),然后就结束了,面试官让我问几个问题,然后又问了我关于实习时间的问题,就让我走了。整个面试时间持续了一个小时多一点,算法和编程差不多各占一半吧。
3.16号收到了offer,后来拒掉了
五、2018.3.16 腾讯搜一搜看一看 算法岗实习生
一面是个比较年轻的人,感觉挺厉害的,很关注算法效果、性能等方面,话语之间透露出一种刁刁的味道。上来看了看我的简历,让我讲一讲对话系统方面的工作。照常讲模型推公式,说完之后,面试官问了我关于MMI模型第一个改进目标函数中P(T)是如何计算的,我说每个词的联合概率分布乘积,当时他面露疑问,我还没反应过来是什么意思,到后面有说到这个问题才明白,原来他的意思是P(T)应该是单纯语言模型学习出来的结果,而按照我的说法,P(T)是在输入的基础上进行计算的,不得不说,面试官的水平很好,完全没接触过的东西竟然能一阵见血的指出我的纰漏,这个地方之前确实没怎么注意过,回来查了一下,计算P(T)的时候确实应该直接输入一个全零的初始化状态,这样才是一个语言模型学习到的概率。然后又接着问了文本分类的东西,我主要讲了一下TextCNN,TextRNN的模型,然后接下来讲了一下知乎竞赛的东西,感觉这块介绍的还算可以,然后又聊了下相关的一些问题。对了,这个面试官十分关注数据集的问题,比如我介绍到的movieQA数据集是一个什么形式,有多少QA对等等,还有知乎竞赛用到的数据集有大概多少个文本,数量是多大,但是平时有没有关注过这些问题,所以基本上没有答上来==接下来面试官出了一道K个有序链表的合并问题,手撕代码。
二面是个年纪比较大的程序员,整体感觉他不是很懂深度学习,机器学习应该是个高段位选手。主要问了我文本分类和论文方面的东西,到没有问出什么很有难度的问题。最后说让我讲一下底层优化方面的知识,我说是优化算法还是类似于tensorflow底层算法优化,他说前者,然后我就吧啦吧啦讲了一堆SGD,动量,AdaGrad,RMS,Adam之类的。然后问我会不会C++,我说不常用但是能读懂程序,他应该是想问我道算法题,但是他又不会java之类的??没搞懂,问了一句之后就说第一个面试官已经问完算法题了是吗,那我就不问了,然后就走了,说去找三面面试官,但是过了一会又说今天面试先结束,不知道是不是挂了还是大家已经下班了==
两面基本都是持续一个小时多一点,没有特别的压迫感和难度,基本都能答上来。但是我同学也是面的这个部门,说上来就给了5道算法题让做,然后全程面试官各种懂,问各种问题。我,也是一脸懵逼,同一个部门面试差别这么大的嘛,反正先等消息吧还是。
2018.3.21 二面,前两天收到了复试的通知,貌似是面试委员会面试,后面再有一个HR面试就结束了,然后开开心心去面试。到了之后发现短信和邮件中没有面试官联系方式(因为经过初面之后简历直接交给总部开始走校招流程,所以总部的电话也打不通,总之就是联系不上,也怪我一开始没有注意到联系方式这件事情了),连楼都进不去,无奈之下联系了初面的面试官,跟他说明了情况,最后又被他接到了一面的地方让我等一会他问一下情况,过了一会说要再加一轮技术面,我不知道具体的情况是什么,反正当时心态是崩了的,该参加的面试没参加还要临时再加一轮技术面试什么鬼。
然后面试官就来了,上来就让推导word2vec反向传播,讲实话我上周刚推完还给实验室的同学讲了一遍,奈何当时的情况下自己一紧张怎么推都感觉是错的,唉很尴尬,卡了很久最后算是勉强退了出来,不过面试官又让我写Embedding矩阵的梯度,这块之前也没在意过,只是知道更新当前单词对应的词向量即可,最后也没写上来其梯度公式,面试官让我回来再想想。然后开始问简历,他可能没接触过问答和对话系统,也没问我相关经历,一直针对文本分类这块再问,虽然也都算答上来了,但总感觉少点什么,一种说不上来的感觉。最后问我要是现在在做京东实习的工作我会怎么做,感觉也答得不是很好,然后问我FastText,CNN,RNN的区别,我感觉说的还不错,但是面试官好像还不是很满意==,最后送我出去的时候说还是要好好把基础打扎实。
等了很久吧,我一度以为已经挂了,结果4月18号收到了一次面试,貌似是因为之前提前批已经结束了,而我的面试流程也随之终止,所以一直拖到校招才又开始面。先电话面了一轮,很水,基本上就是问简历,然后第二天去HR面,这个过程自己表现得有点嚣张了貌似,具体不详说,反正估计是把HR惹到了,然后应该也是挂了~~
六、2018.3.20 美团点评 AI平台 算法实习生面试
一面面试官应该是搞后台开发的吧,深度学习一点不懂,上来就开始专业歧视,问我通信工程的会不会编程==,然后让我自己介绍,我说要讲模型的细节吗,他说不用,我看是讲了你也不懂吧,然后又说,你会数据结构吗,你们通信工程应该不学吧,你补这方面知识了吗?我++,你是猴子派来的逗比吧,然而我已经对他失望了,并不想理他。然后他貌似也不知道问什么了,开始看我的简历,又用电脑看我的专栏文章,说你对这个领域还挺了解的是吗,我说是啊,然后他就问我如果给你一个新的领域你该怎么上手,当时心里就想这个面试官真是没话找话,于是我啪啪啪又是一顿吹比。然后他竟然问,Redis你懂吗,让你学你怎么学,当时我就觉得聊不下去了。随便说了两句,然后他有看了看电脑我以为要出道编程题,结果他就直接走了,走了,了。
二面是部门老大,基本上不能算是面试吧,大概聊了一下,也没有算法题什么的,然后就互相问了几个问题,然后就结束了,面试官表达了想要我的意愿,说之后应该会有HR联系我之类的。这个人貌似挺厉害的,MSRA+Facebook的工作经历,今年刚回国开始成立美团的这个部门,直接给CEO汇报。
整个面试刨去等待应该不到40分钟吧,这可能是我面过的最水的一次面试了,可能是因为部门刚成立,二面人也说了,一切都是刚起步。回来之后就接到了offer,但是对这边并无好感,所以就拒了,后来那个leader又给我打电话表达了想让我过去的意愿,顺带diss了一下我面试的其他公司,虽然感觉他很有诚意,我去了之后应该也会被重视,但还是拒绝了,因为实习还是想找一个比较稳定成熟的部门多学点东西。
七、2018.4.17 百度自然语言处理部算法实习生
这个是在官网投的简历,到了那才发现自己好像投递错了,投成了校招==捞我简历的组是做query理解的,怎么说呢,整体感觉这个任务比较简单,基本用不上什么深度学习的技术,甚至面试过程中面试官一直在劝退我学深度学习,还是简单说一下面试过程吧。
一面,日常介绍了一下自己以前的工作,面试官更关注于文本分类这部分的工作,简单问了一下。然后就开始劝退了,说你是遇到什么任务都会使用深度学习模型吗,我说也用过机器学习的方法,比如VSM向量空间模型,但是比对结果发现深度学习的效果更好。然后就问我如果现在让我负责一个项目,主要是判断一个句子是否为问句,让我设计一套方案,并且给出所需要的时间,准确度要达到95%以上。然后我就扯了一堆,分词,词性标注,训练模型之类的。他说你怎么保证95%的准确率呢,我说二分类很简单,稍微调下参数应该就可以。考虑到面试官对深度学习的厌恶,我又补充说也可以使用机器学习的方法去做,比如说句法解析等技术,甚至网上应该已经有现成的问句识别的方案可以使用之类的。然后面试官就说,其实是一个比较简单的任务,用很简单的技术就可以达到95%,没必要上深度学习模型之类的。然后又说深度学习的缺点,什么端到端不可控,在很多任务里面有些特例是解决不了的,我说可以加bad case,他说有些情况加不完,比如机器翻译里面balabala,然后我就说,据我所知很多大公司的机器翻译用的完全是深度学习模型,他一时语塞,我也并不想给他面子。然后就说那你设计一个框架吧,会有很多任务,每次回调用其中的一个或几个,然后返回结果。其实没太高明白他想问什么,我随便说了下,什么传参啊,并行化啊之类的。然后他就说需要考虑可扩展性,比如说方便的新增模型之类的,后来闹了半天才知道他是想问继承和接口方面的问题,自己也没有打的很好。然后出了一个字符串反转的编程题。
二面,应该是他们小组的leader,上来还是一波自我介绍和聊项目,然后又进入了一波日常劝退,我心里就想你们这个组是有毒吧,说让我好好了解一下NLP原本的东西,这个倒是有些道理,可奈何时间精力有限啊。然后接下来就可以说是很逗了,感觉是一波深度学习基础知识点考查,dropout、正则化、过拟合、CNN、bagging和boosting的区别、优化算法通通问了一遍。然后出了一道二叉搜索树删除一个节点的编程题。接下来问问题,这个过程里面给我的感受就是,他们本身query这个任务偏简单,所以用一些简单的工程上的手段就可以解决,不需要上深度学习模型,然后就是搜索需要的时间反应很短,深度学习速度往往跟不上,所以就,嗯,怎么说呢,跟自己方向不太搭吧。
三面,应该不是他们组而是整个自然语言处理部的领导,但万万没想到是个小女生,我本以为他是HR。还是范范的聊了一下项目,然后他告诉我说他们整个部门是在做对话,我当时真的是听得一脸懵逼,怎么就直接从query理解跳到了对话了,然后说了一堆,我其实还是主要关注我去了之后干什么,但是他全程不给我明确的回复,一直在回避,然后我就直接问,我来了是不是跟前两面的面试官在同一个组,做同样的事情,然后他还是在回避,说这个会根据每个组的实际需求安排。然后面试就结束了
2018.4.23 今天收到了三面面试官的电话通知,拿到了他们部门的offer。后来考虑了两天还是拒掉了。
八、2018.4.23 百度度秘部门 对话系统算法实习生
前两天因为对NLP部门的岗位不是很满意所以又投了度秘,今天面试了一下,总共面了四面,四个半小时,可以说是很吐血了,全程问了很多开放性问题,我也尽量的回忆一下,复个盘==
一面,上来写了一道判断树B是否为树A的子树,一个坑是树不一定是二叉树,需要自己定义树的结构,其实就是剑指offer上题目的变种。写完之后开始问项目,主要关注于seq2seq做对话这个项目,我讲了一下attention、怎么做多轮、怎么解决类似于“I don’t know”等等几个问题,然后面试官就开始问一些开放性的问题,比如他们在做任务型的多轮对话,让我去设计这样一个系统,应该包含哪些模块,内各模块的功能,如何判断一句话是否跟上一句话处在同一个场景下,如何消歧等等,自己也是胡乱的说,有的没的都在扯。最后又问了下LR、SVM、极大似然估计等相关的一些问题。
二面,面试官好像主要是看到我之前做过知乎的看山杯竞赛,好像他也做过,然后比较感兴趣就过来聊了一下,我就把当时用过的一些模型还有两个主要的创新点介绍了一下,他闻了一下目标函数怎么选、多标签分类的特点、CNN如何做Padding、dropout具体的实现方法等问题。
三面,面试官是我将来的leader,感觉面试官很注重对损失函数的理解,整个面试过程中就一直在问各种损失函数。这个面试官主要针对我简历中京东的实习开始,但是又完全跟京东实习没有关系,而是单纯地提了一个问题,让我去建模,如何设计目标函数,并且把一些商家的信息添加到目标函数中进行惩罚。这个地方还是自己的短板吧,感觉自己想了很久最后在面试官的提示下也算是做出来了,然后面试官又问我SVM和LR的损失函数分别是什么,让我用tensorflow实现一个SVM,我想了一会感觉不会,他说那你实现一个LR吧,我大概写了一下。然后面试官又提出了一个问题,有一堆半监督的样本,即50%有类别ABC等,50%的样本没有类别,现在要使用tensorflow实现一个模型,去实现两个任务,第一个是首先要区分该样本是否为标记样本,可以理解为一个二分类,然后如果是有标注的样本的话在求出其类别。然后自己也是硬着头皮瞎写了一堆。最后应该就是写到算法题,一个无序数组找到其最大值和最小值,我卡了很久,因为不可能直接遍历一遍,这样太简单了,但是有想不到O(logn)的解决方法,也不可能使用排序,然后问了下面试官,他说先两两比较,然后我说这样仍然是O(N)啊,他说那肯定啊,但是总的比较次数降低了。
四面,四面面试官是临时拉过来帮忙面试的,好像之前的面试官有事,然后他全程就各种开放性问题,感觉更偏底层的NLP处理的技术一点,有很多小问题自己也没答到点子上。然后就是三道编程题,第一道是100亿个数中寻找最大的10000个,剑指offer原题,借助堆排序进行做,分析了一下时间复杂度。然后是对100亿个数做排序,但是内存只有4G,这道题没思路,面试官说是外排序,没接触过就过了,最后一个是字符串转整型,自己实现一下。
第二天收到了offer,如果不出意外应该回去度秘实习吧先。
总结一下这个找工作的过程,因为自己平时积累的比较多,所以整个面试还相对来说比较轻松。然后就是想说一下对话系统这个方向,各大公司都有再发力,个人也认为这将是未来一段时间内深度学习在NLP领域的一个爆发点,而且很多创业公司已经在吃这块蛋糕,李纪为大神也拿到了风投建立了自己的公司。但不得不说,这里面还是有很多待解决的问题,如何做到理解是很重要的一块。深度学习在当前对话系统中也只是占一部分,端到端更是还没有到应用的程度,特别是在多轮对话和任务导向的对话系统中。单说公司的话,百度的度秘、阿里的小蜜、微软的小冰应该算是做得比较不错的,度秘侧重于智能家居,旨在做一个操作系统,小蜜主要在智能客服领域发力,在电商领域有着很大的应用场景,小冰现在不是很清楚,只知道技术应该挺吊的;接下来向京东、美团、滴滴,也都有在做,不断地投入很多精力搞这一块,但整体的效果应该比不上前面两个;再就是小的创业公司,都会找一个自己的着力点,比如个人助手等,但如何生存下去、如何盈利还是一个问题。(以上均为个人看法==不喜勿喷)。
另一种方法:XGBoost在寻找splitpoint的时候,不会枚举所有的特征值,而会对特征值进行聚合统计,按照特征值的密度分布,构造直方图计算特征值分布的面积,然后划分分布形成若干个bucket(桶),每个bucket的面积相同,将bucket边界上的特征值作为split
point的候选,遍历所有的候选分裂点来找到最佳分裂点。
上图近似算法公式的解释:将特征k的特征值进行排序,计算特征值分布,rk(z)表示的是对于特征k而言,其特征值小于z的权重之和占总权重的比例,代表了这些特征值的重要程度,我们按照这个比例计算公式,将特征值分成若干个bucket,每个bucket的比例相同,选取这几类特征值的边界作为划分候选点,构成候选集;选择候选集的条件是要使得相邻的两个候选分裂节点差值小于某个阈值
传统GBDT以CART作为基分类器,xgboost还支持线性分类器,这个时候xgboost相当于带L1和L2正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)。
作者:JayLou娄杰
链接:https://zhuanlan.zhihu.com/p/57153934
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1、word2vec和tf-idf 相似度计算时的区别?
word2vec 1、稠密的 低维度的 2、表达出相似度; 3、表达能力强;4、泛化能力强;
2、word2vec和NNLM对比有什么区别?(word2vec vs NNLM)
1)其本质都可以看作是语言模型;
2)词向量只不过NNLM一个产物,word2vec虽然其本质也是语言模型,但是其专注于词向量本身,因此做了许多优化来提高计算效率:
3、 word2vec负采样有什么作用?
负采样这个点引入word2vec非常巧妙,两个作用,1.加速了模型计算,2.保证了模型训练的效果,一个是模型每次只需要更新采样的词的权重,不用更新所有的权重,那样会很慢,第二,中心词其实只跟它周围的词有关系,位置离着很远的词没有关系,也没必要同时训练更新,作者这点非常聪明。
4、word2vec和fastText对比有什么区别?(word2vec vs fastText)
1)都可以无监督学习词向量, fastText训练词向量时会考虑subword;
2)fastText还可以进行有监督学习进行文本分类,其主要特点:
5、glove和word2vec、 LSA对比有什么区别?(word2vec vs glove vs LSA)
1)glove vs LSA
2)word2vec vs LSA
3)word2vec vs glove
6、 elmo、GPT、bert三者之间有什么区别?(elmo vs GPT vs bert)
之前介绍词向量均是静态的词向量,无法解决一次多义等问题。下面介绍三种elmo、GPT、bert词向量,它们都是基于语言模型的动态词向量。下面从几个方面对这三者进行对比:
(1)特征提取器:elmo采用LSTM进行提取,GPT和bert则采用Transformer进行提取。很多任务表明Transformer特征提取能力强于LSTM,elmo采用1层静态向量+2层LSTM,多层提取能力有限,而GPT和bert中的Transformer可采用多层,并行计算能力强。
(2)单/双向语言模型:
7、LSTM和GRU的区别?
样本选择上:
Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
样例权重:
Bagging:使用均匀取样,每个样例的权重相等
Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。
预测函数:
Bagging:所有预测函数的权重相等。
Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
并行计算:
Bagging:各个预测函数可以并行生成
Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮
欢迎大家来到预训练语言模型的专题系列分享,本篇推送是该专题系列的第三篇。在前两篇推送[萌芽时代],[风起云涌]中,我们分享了该领域的奠基文章以及声名鹊起却生不逢时的ELMo模型,本期我们带来的文章将会让大家了解文本分类的一些通用技巧,希望大家看完后炼丹技术都能更上一层楼!
同时感谢清华大学自然语言处理实验室整理的体系图,我们将沿此脉络前行,探索预训练语言模型的前沿技术,本期的第一篇文章处于图中绿色框内,另一篇为课外阅读。红色框内的论文在前几期中介绍,大家有兴趣的可以前去一看。
前几期介绍的大多是模型或结构,而这篇文章由 Jeremy Howard 和 Sebastian Ruder 发表于2018年,介绍的是文本分类中语言模型的通用训练技巧。其中的一些技巧,吴老师和我在kaggle 的jigsaw 文本分类比赛中也有应用,并在比赛中拿到了金牌。在未来的推送中,可能还会有详细介绍。
这篇文章认为,目前语言模型在finetune时经常会过拟合到小数据集上,而且容易导致灾难性遗忘。相比于CV模型,NLP模型层数较少,所以需要更多的训练技巧来使其表现更好。而他们在本文中提出了fine-tuning 语言模型的关键技术 ULMFiT,可以大大地提高六个文本分类任务的效果,并且用更少的数据训练就可以达到相当的效果,加强了泛化能力。
首先介绍下ULMFiT的总体框架。之前的很多论文提出的都是预训练 + finetune 两个阶段的训练,而本文提出使用三阶段训练。
文章认为上述第二个阶段很有必要。因为无论通用的语料多样性多么好,都和你目标任务的数据分布有区别。而且在比较小的特定任务数据上finetune语言模型可以很快得到收敛,成本较低。同时,这样finetune以后,即使对比较小的数据集,语言模型也能变得比较鲁棒。
ULMFiT的总体框架(来自论文)
其次,在ELMo,GPT的介绍中我们都提到过,语言模型的不同层其实能够捕捉不同级别的语义特征,比如ELMo底层LSTM更多捕捉语法和词层面的特征,而上层LSTM更多捕捉整句话的语言的特征。既然是不同类型的信息,就应该区分地去进行参数的finetune,所以文章提出了discriminative fine-tuning,即对不同的层使用不同的学习率去学习。因为越靠近最下层Embedding层,模型参数就会含有更多通用信息,不应随任务目标发生很大变化。所以为了降低灾难性遗忘的可能,越下层,就会用更小的学习率来学习,而上层为了让模型能够更快地学习到目标任务的独有信息,会用相对大的学习率。一般层之间的学习率会等比地变化,在这篇文章里,这个比值为2.6, 即上一层参数学习率为下一层的2.6倍。
再者,为了让语言模型能更好地学习到特定任务相关的特征,文章使用了Slanted triangular learning rates (SLTR),让模型在训练初期快速收敛到一个合适的参数区域,接着再进行细致地优化。在现在看来这就是一种warmup策略。warmup已经在神经网络模型中被广泛应用了,huggingface的transformers也有现成的函数来对warmupscheduler进行控制。
SLTR示意图(来自论文)
最后,在目标任务的直接优化过程中,文章提出了几种辅助训练技巧,其中这些我认为比较简单通用。
文章接下来的篇幅从各方面比较了文中技巧对任务的提升,我们可以大致看一下。其中,full 是指优化整个模型,last指只优化最后一层,discr指discriminative fine-tuning, sltr指slanted triangular learning rates,cos指cosine annealing schedule。可以看到,文中提到的几个技术都对误差率的下降有明显的效果。
不同策略下验证错误率(来自论文)
这篇文章的贡献是深远的,它提出了预训练语言模型比较通用的训练方法和技术。这篇文章虽然早于GPT和BERT发表,但是它的框架完全可以在后来的强大模型中提供帮助,让我们NLP的炼丹之旅轻松又愉快!
本篇文章是由复旦计算机系的多位作者发表的。讨论如何在文本分类任务中对BERT模型进行finetune。虽然这篇文章不在体系图,但与第一篇文章在内容上比较相关,而且我们在kaggle比赛中也应用到了,所以一起在这里介绍。我们长话短说,直接来总结一下这篇文章的几个贡献点和有用的技巧。
第一个贡献是,框架相比于上篇文章进行了微调。在通过任务相关数据进行语言模型finetune后,多加了一步可选的stage: 把BERT在领域内相关的其他任务上进行多任务的训练,我认为这是对于ULMFiT的补充。
BERT finetune框架(来自论文)
第二个贡献是对长文本的处理,我们在之后BERT文章中将会介绍,BERT模型能一次处理的最长文本长度为512,有时我们为了降低模型运行时间和占用空间,有可能将这个长度变得更短,这时候就可能要对文本进行截断。文章的结论就是最好的截断方式既不是截头,也不是截尾,应该头尾都截一部分保留最重要信息。
长文本不同处理方式的错误率(来自论文)
第三个贡献是在任务上详细分析了BERT的不同层****对文本分类任务的效果。具体做法是,在某一层后直接接分类器进行分类。单层中,以最后一层的效果最好,因为文本分类是更贴近语言层面的任务。而在文章尝试的其他几种选择中,把最后四层concat或者max pooling效果最好。
不同层向量用以分类的错误率(来自论文)
第四个贡献其实是借鉴discriminative fine-tuning,进行层间学习率的下降。越接近底层,含有的通用信息越多,越不应该随着特定任务进行大规模的参数改变,否则有灾难性遗忘风险。在他们的尝试中,学习率2e-5,层间学习率变化因数0.95对BERT来说比较合适的。
不同学习率设置的分类错误率(来自论文)
总之,这篇文章进行了很多完备的实验,来提出和验证了在文本分类任务上,BERT的较好的finetune策略及其效果。文章验证了 : 1) 对于文本分类,BERT的最高层的效果最好 2) 使用合适的层间学习率下降策略,BERT能够克服灾难性遗忘的问题 3) 任务相关或领域内相关数据的语言模型finetune可以大大提升效果 4) 相关的多任务学习也对特定任务有提升效果 5) BERT只需少量的特定数据就可以预训练以提升任务。文章对我们训练BERT模型有很好的指导意义,以后再也不用担心炸炉啦!
本期的论文就给大家分享到这里,感谢大家的阅读和支持,下期我们会给大家带来预训练语言模型其他的论文阅读分享,敬请大家期待!
欢迎关注晴天1号,这里有很多最新最热的论文阅读分享,有问题或建议可以在公众号下留言。
Universal Language Model Fine-tuning for Text Classification (2018)
https://www.aclweb.org/anthology/P18-1031.pdf
How to Fine-Tune BERT for Text Classification(2019)
https://arxiv.org/pdf/1905.05583.pdf
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
https://arxiv.org/pdf/1810.04805.pdf
谢清华大学自然语言处理实验室对预训练语言模型架构的梳理,我们将沿此脉络前行,探索预训练语言模型的前沿技术,红色框为前期脚印,绿色框为本期介绍,欢迎大家留言讨论交流。
本期将要介绍的就是在NLP领域无人不知,无人不晓的预训练语言模型BERT了,由Google AI在2018年底推出,刚出现就刷新了一大批榜单,甚至在一些任务上超过了人类的表现,令人惊艳。谷歌团队成员Thang Luong在推特上表示,BERT模型开启了NLP的新时代。就其效果、易用性、通用性各方面来说,在当时不愧称为预训练语言模型的王者,压服众多的模型。让我们花十分钟一起,跟着论文来体会BERT的设计思路和重点。
文章在一开始概括了当时的两种不同的预训练语言模型的策略,feature-based 策略及 fine-tuning 策略。
BERT使用的是后者,因为这种策略需要改变的参数量较少,迁移也较为简单。同时他们指出,现在限制这种策略性能的主要问题是。如GPT这种模型,它预训练时使用了标准语言模型的目标,导致它只能是单向的。在Transformer层中,每个token在self attention 时都只能关注其之前的token,会严重损害在一些任务上如问答上的效果,在之前的不少论文中都佐证了这个观点。所以,使模型能够学习一个文本双向的信息是非常关键的一点。
BERT如此受大家推崇的原因之一当然是其强劲的性能,但另外突出的是其易用性和通用性。BERT的预训练和下游特定任务的训练,在模型上的差别仅仅是顶层的output layer ,而且可以在很多任务上通用。
在前面的介绍也讲到,作者认为无论是单向的生成式语言模型,还是独立的left-to-right和right-to-left的进行拼接都不如真正的深层双向联合训练。但以标准的语言模型目标,没办法实现双向的训练,因为模型在预测某个单词时,会间接地在多层的上下文中看见“自己”,导致泄露。
BERT提供的解决方案就是Mask LM 任务,它会随机mask掉一定比例的token,让它在训练的时候不在输入中出现,并把它们作为目标来训练,这样就可以防止泄露,mask的方式是把token替换成一个固定的token [MASK]。在实际使用的过程中,这会带来一个问题,因为MLM任务是语言模型的训练任务,也就是说[MASK] 这种token只会在语言模型训练时有,在下游模型的fine-tuning时是不会出现的,这就会导致预训练和fine-tuning的数据分布不匹配。为了弥补这个问题,这15%应该被mask掉的token有80%的可能被替换成[MASK],有10%的可能被替换成另外一个随机的token,另有10%的可能会维持原样不变。这样做,可以让Transformer的encoder无法去知道哪个token是要被预测的,也不知道哪个词被替换成随机词了,使它不得不对每一个token都形成一个较好的向量表示,没法取巧。
BERT模型细节:
我一直认为BERT论文中的这张图画得非常好,将三种模型的结构描绘得十分清楚,我们从右到左再来重温一下,如果对细节想要进一步了解,建议回顾前几期的推送。
ELMo模型的核心组件是LSTM。最下方的Embedding层为字向量;中间是两层LSTM,分别有独立的left-to-right 和 right-to-left 的双向网络;双向LSTM的输出在最上方连接,形成包含上下文语义的向量表示。
GPT模型的核心组件首次使用了Transformer。最下方的Embedding层为token embedding与position embedding 相加,token embedding的vocab为BPE算法所得;中间为12层的Transformer,语言模型目标为标准的单向条件概率,没有双向的语义能力。
BERT模型的核心组件是Transformer。最下方的Embedding为token embedding、segment embedding和position embedding 相加。token embedding的vocab为30000个左右词的Wordpiece embedding;中间的Transformer层取决于两个模型的尺度;因为MLM任务,所以BERT能够捕捉双向的语义特征。
BERT的输入也与GPT类似都用了[CLS]和[SEP],相比之下在预训练和finetune都做了规范化和处理,以应对不同的任务。句子开头的token为[CLS],结尾的token为[SEP]。如果输入仅有一句话,那规范化后的tokens是[CLS] [Sentence1] [SEP],如果为两句话,那么规范后的tokens是 [CLS] [Sentence1] [SEP] [Sentence2] [SEP] 。另外,BERT模型还需要输入segment_id,以标识token的每一个位置是属于第一句话还是第二句话的,第一句话的位置上segment_id都是0,第二句话的位置都是1。具体的细节,下一期我打算结合hugging face的transformers的代码来进行进一步的分享。
BERT预训练所用的数据更大了,包含BookCorpus(800M words)和English Wikipedia(2500M words)
接下来,文章对BERT模型中对性能产生影响的各个因素进行了对比试验。
首先是预训练任务的影响。LTR指的是Left-to-Right,可以看出最大的收益来源于Transformer替代了BiLSTM,其次是MLM任务带来的双向深层训练,再其次是NSP任务带来的收益。
各预训练任务带来的影响
接着是模型尺度的影响,可以很明显的在图中看出,总体来说是越大的模型会获得越好的效果。
模型尺度带来的影响
最后,如果把BERT当作feature-based模型来用,不同层的向量表征所影响的效果,可以看到最好的是最后四层concat起来的结果,其实我们在[文本分类训练技巧] 一文中,专门就这个进行过讨论,有兴趣可以移驾一看。
不得不说,BERT的来到在2018年底给NLP的格局带来了巨大的变化,它让人们对NLP的前景充满了信心和期待,机器在NLP领域真的有了超越人类的可能,令人振奋。但BERT预训练的代价可不小,文中写道,模型batch size为256:(256 sequences * 512 tokens = 128,000 tokens/batch),总共大概在33亿左右的单词上训练了40个epoch。BERT-base在4 Cloud TPUs (16 TPU chips total)上,BERT-large在 16 Cloud TPUs (64 TPU chips total),都训练了大概4天左右才训练完毕。
这么多算力的消耗说实话也让人大吃一惊,换成普通的GPU时间简直是令人绝望的数字。不过下游的任务的预训练和特定任务训练就很快了。对于一般的开发者来说,只要下载在通用语料上预训练的模型,接着进行时间上可接受的下游训练即可,这也就是预训练语言模型给我们带来的魅力!
本期的论文就给大家分享到这里,感谢大家的阅读和支持,下期我们大概率会给大家带来实打实的huggingface transformers上相关代码分析,敬请大家期待!
欢迎关注朴素人工智能,这里有很多最新最热的论文阅读分享,有问题或建议可以在公众号下留言。
前期回顾:[萌芽时代]、[风起云涌]、[文本分类通用技巧] 、[GPT家族]
感谢清华大学自然语言处理实验室对预训练语言模型架构的梳理,我们将沿此脉络前行,探索预训练语言模型的前沿技术,红色框为前期脚印,绿色框为本期介绍,欢迎大家留言讨论交流。
本期将要介绍的就是在NLP领域无人不知,无人不晓的预训练语言模型BERT了,由Google AI在2018年底推出,刚出现就刷新了一大批榜单,甚至在一些任务上超过了人类的表现,令人惊艳。谷歌团队成员Thang Luong在推特上表示,BERT模型开启了NLP的新时代。就其效果、易用性、通用性各方面来说,在当时不愧称为预训练语言模型的王者,压服众多的模型。让我们花十分钟一起,跟着论文来体会BERT的设计思路和重点。
文章在一开始概括了当时的两种不同的预训练语言模型的策略,feature-based 策略及 fine-tuning 策略。
BERT使用的是后者,因为这种策略需要改变的参数量较少,迁移也较为简单。同时他们指出,现在限制这种策略性能的主要问题是。如GPT这种模型,它预训练时使用了标准语言模型的目标,导致它只能是单向的。在Transformer层中,每个token在self attention 时都只能关注其之前的token,会严重损害在一些任务上如问答上的效果,在之前的不少论文中都佐证了这个观点。所以,使模型能够学习一个文本双向的信息是非常关键的一点。
BERT如此受大家推崇的原因之一当然是其强劲的性能,但另外突出的是其易用性和通用性。BERT的预训练和下游特定任务的训练,在模型上的差别仅仅是顶层的output layer ,而且可以在很多任务上通用。
在前面的介绍也讲到,作者认为无论是单向的生成式语言模型,还是独立的left-to-right和right-to-left的进行拼接都不如真正的深层双向联合训练。但以标准的语言模型目标,没办法实现双向的训练,因为模型在预测某个单词时,会间接地在多层的上下文中看见“自己”,导致泄露。
BERT提供的解决方案就是Mask LM 任务,它会随机mask掉一定比例的token,让它在训练的时候不在输入中出现,并把它们作为目标来训练,这样就可以防止泄露,mask的方式是把token替换成一个固定的token [MASK]。在实际使用的过程中,这会带来一个问题,因为MLM任务是语言模型的训练任务,也就是说[MASK] 这种token只会在语言模型训练时有,在下游模型的fine-tuning时是不会出现的,这就会导致预训练和fine-tuning的数据分布不匹配。为了弥补这个问题,这15%应该被mask掉的token有80%的可能被替换成[MASK],有10%的可能被替换成另外一个随机的token,另有10%的可能会维持原样不变。这样做,可以让Transformer的encoder无法去知道哪个token是要被预测的,也不知道哪个词被替换成随机词了,使它不得不对每一个token都形成一个较好的向量表示,没法取巧。
Next Sentence Prediction (NSP)
很多任务,包括问答、自然语言推断等是基于理解两句句子之间关系的,不能直接被语言模型所建模,所以BERT还有另外一个二分类任务NSP来捕捉句子间的关系。在构造这个任务的数据集时,会有50%的概率,提供正样本,即某句句子和其下一句句子的组合,50%的概率在语料中选择任意一句句子构成负样本。这个任务相较MLM来说还是相当简单的。
BERT模型细节:
我一直认为BERT论文中的这张图画得非常好,将三种模型的结构描绘得十分清楚,我们从右到左再来重温一下,如果对细节想要进一步了解,建议回顾前几期的推送。
ELMo模型的核心组件是LSTM。最下方的Embedding层为字向量;中间是两层LSTM,分别有独立的left-to-right 和 right-to-left 的双向网络;双向LSTM的输出在最上方连接,形成包含上下文语义的向量表示。
GPT模型的核心组件首次使用了Transformer。最下方的Embedding层为token embedding与position embedding 相加,token embedding的vocab为BPE算法所得;中间为12层的Transformer,语言模型目标为标准的单向条件概率,没有双向的语义能力。
BERT模型的核心组件是Transformer。最下方的Embedding为token embedding、segment embedding和position embedding 相加。token embedding的vocab为30000个左右词的Wordpiece embedding;中间的Transformer层取决于两个模型的尺度;因为MLM任务,所以BERT能够捕捉双向的语义特征。
BERT的输入也与GPT类似都用了[CLS]和[SEP],相比之下在预训练和finetune都做了规范化和处理,以应对不同的任务。句子开头的token为[CLS],结尾的token为[SEP]。如果输入仅有一句话,那规范化后的tokens是[CLS] [Sentence1] [SEP],如果为两句话,那么规范后的tokens是 [CLS] [Sentence1] [SEP] [Sentence2] [SEP] 。另外,BERT模型还需要输入segment_id,以标识token的每一个位置是属于第一句话还是第二句话的,第一句话的位置上segment_id都是0,第二句话的位置都是1。具体的细节,下一期我打算结合hugging face的transformers的代码来进行进一步的分享。
BERT预训练所用的数据更大了,包含BookCorpus(800M words)和English Wikipedia(2500M words)
接下来,文章对BERT模型中对性能产生影响的各个因素进行了对比试验。
首先是预训练任务的影响。LTR指的是Left-to-Right,可以看出最大的收益来源于Transformer替代了BiLSTM,其次是MLM任务带来的双向深层训练,再其次是NSP任务带来的收益。
各预训练任务带来的影响
接着是模型尺度的影响,可以很明显的在图中看出,总体来说是越大的模型会获得越好的效果。
模型尺度带来的影响
最后,如果把BERT当作feature-based模型来用,不同层的向量表征所影响的效果,可以看到最好的是最后四层concat起来的结果,其实我们在[文本分类训练技巧] 一文中,专门就这个进行过讨论,有兴趣可以移驾一看。
不同层向量选择对feature-base模型带来的影响
不得不说,BERT的来到在2018年底给NLP的格局带来了巨大的变化,它让人们对NLP的前景充满了信心和期待,机器在NLP领域真的有了超越人类的可能,令人振奋。但BERT预训练的代价可不小,文中写道,模型batch size为256:(256 sequences * 512 tokens = 128,000 tokens/batch),总共大概在33亿左右的单词上训练了40个epoch。BERT-base在4 Cloud TPUs (16 TPU chips total)上,BERT-large在 16 Cloud TPUs (64 TPU chips total),都训练了大概4天左右才训练完毕。
这么多算力的消耗说实话也让人大吃一惊,换成普通的GPU时间简直是令人绝望的数字。不过下游的任务的预训练和特定任务训练就很快了。对于一般的开发者来说,只要下载在通用语料上预训练的模型,接着进行时间上可接受的下游训练即可,这也就是预训练语言模型给我们带来的魅力!
本期的论文就给大家分享到这里,感谢大家的阅读和支持,下期我们大概率会给大家带来实打实的huggingface transformers上相关代码分析,敬请大家期待!
欢迎关注朴素人工智能,这里有很多最新最热的论文阅读分享,有问题或建议可以在公众号下留言。
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
https://arxiv.org/pdf/1810.04805.pdf
本文将通过细节剖析以及代码相结合的方式,来一步步解析Attention is all you need这篇文章。
这篇文章的下载地址为:https://arxiv.org/abs/1706.03762
本文边讲细节边配合代码实战,代码地址为:https://github.com/princewen/tensorflow_practice/tree/master/basic/Basic-Transformer-Demo
数据地址为:https://pan.baidu.com/s/14XfprCqjmBKde9NmNZeCNg密码:lfwu
好了,废话不多说,我们进入正题!我们从简单到复杂,一步步介绍该模型的结构!
模型的整体框架如下:
整体架构看似复杂,其实就是一个Seq2Seq结构,简化一下,就是这样的:
Encoder的输出和decoder的结合如下,即最后一个encoder的输出将和每一层的decoder进行结合:
好了,我们主要关注的是每一层Encoder和每一层Decoder的内部结构。如下图所示:
可以看到,Encoder的每一层有两个操作,分别是Self-Attention和Feed Forward;而Decoder的每一层有三个操作,分别是Self-Attention、Encoder-Decoder Attention以及Feed Forward操作。这里的Self-Attention和Encoder-Decoder Attention都是用的是Multi-Head Attention机制,这也是我们本文重点讲解的地方。
在介绍之前,我们先介绍下我们的数据,经过处理之后,数据如下:
很简单,上面部分是我们的x,也就是encoder的输入,下面部分是y,也就是decoder的输入,这是一个机器翻译的数据,x中的每一个id代表一个语言中的单词id,y中的每一个id代表另一种语言中的单词id。后面为0的部分是填充部分,代表这个句子的长度没有达到我们设置的最大长度,进行补齐。
给定我们的输入数据,我们首先要转换成对应的embedding,由于我们后面要在计算attention时屏蔽掉填充的部分,所以这里我们对于填充的部分的embedding直接赋予0值。Embedding的函数如下:
在本文中,Embedding操作不是普通的Embedding而是加入了位置信息的Embedding,我们称之为Position Embedding。因为在本文的模型中,已经没有了循环神经网络这样的结构,因此序列信息已经无法捕捉。但是序列信息非常重要,代表着全局的结构,因此必须将序列的分词相对或者绝对position信息利用起来。位置信息的计算公式如下:
其中pos代表的是第几个词,i代表embedding中的第几维。这部分的代码如下,对于padding的部分,我们还是使用全0处理。
所以对于输入,我们调用上面两个函数,并将结果相加就能得到最终Position Embedding的结果:
3、Multi-Head Attention
3.1 Attention简单回顾
Attention其实就是计算一种相关程度,看下面的例子:
Attention通常可以进行如下描述,表示为将query(Q)和key-value pairs映射到输出上,其中query、每个key、每个value都是向量,输出是V中所有values的加权,其中权重是由Query和每个key计算出来的,计算方法分为三步:
1)计算比较Q和K的相似度,用f来表示:
2)将得到的相似度进行softmax归一化:
3)针对计算出来的权重,对所有的values进行加权求和,得到Attention向量:
计算相似度的方法有以下4种:
在本文中,我们计算相似度的方式是第一种,本文提出的Attention机制称为Multi-Head Attention,不过在这之前,我们要先介绍它的简单版本Scaled Dot-Product Attention。
计算Attention首先要有query,key和value。我们前面提到了,Encoder的attention是self-attention,Decoder里面的attention首先是self-attention,然后是encoder-decoder attention。这里的两种attention是针对query和key-value来说的,对于self-attention来说,计算得到query和key-value的过程都是使用的同样的输入,因为要算自己跟自己的attention嘛;而对encoder-decoder attention来说,query的计算使用的是decoder的输入,而key-value的计算使用的是encoder的输出,因为我们要计算decoder的输入跟encoder里面每一个的相似度嘛。
因此本文下面对于attention的讲解,都是基于self-attention来说的,如果是encoder-decoder attention,只要改一下输入即可,其余过程都是一样的。
3.2 Scaled Dot-Product Attention
Scaled Dot-Product Attention的图示如下:
接下来,我们对上述过程进行一步步的拆解:
First Step-得到embedding
给定我们的输入数据,我们首先要转换成对应的position embedding,效果图如下,绿色部分代表填充部分,全0值:
得到Embedding的过程我们上文中已经介绍过了,这里不再赘述。
Second Step-得到Q,K,V
计算Attention首先要有Query,Key和Value,我们通过一个线性变换来得到三者。我们的输入是position embedding,过程如下:
代码也很简单,下面的代码中,如果是self-attention的话,query和key-value输入的embedding是一样的。padding的部分由于都是0,结果中该部分还是0,所以仍然用绿色表示.
Third-Step-计算相似度
接下来就是计算相似度了,我们之前说过了,本文中使用的是点乘的方式,所以将Q和K进行点乘即可,过程如下:
文中对于相似度还除以了dk的平方根,这里dk是key的embedding长度。
这一部分的代码如下:
你可能注意到了,这样做其实是得到了一个注意力的矩阵,每一行都是一个query和所有key的相似性,对self-attention来说,其效果如下:
不过我们还没有进行softmax归一化操作,因为我们还需要进行一些处理。
Forth-Step-增加mask
刚刚得到的注意力矩阵,我们还需要做一下处理,主要有:
query和key有些部分是填充的,这些需要用mask屏蔽,一个简单的方法就是赋予一个很小很小的值或者直接变为0值。
对于decoder的来说,我们是不能看到未来的信息的,所以对于decoder的输入,我们只能计算它和它之前输入的信息的相似度。
我们首先对key中填充的部分进行屏蔽,我们之前介绍了,在进行embedding时,填充的部分的embedding 直接设置为全0,所以我们直接根据这个来进行屏蔽,即对embedding的向量所有维度相加得到一个标量,如果标量是0,那就代表是填充的部分,否则不是:
这部分的代码如下:
经过这一步处理,效果如下,我们下图中用深灰色代表屏蔽掉的部分:
接下来的操作只针对Decoder的self-attention来说,我们首先得到一个下三角矩阵,这个矩阵主对角线以及下方的部分是1,其余部分是0,然后根据1或者0来选择使用output还是很小的数进行填充:
得到的效果如下图所示:
接下来,我们对query的部分进行屏蔽,与屏蔽key的思路大致相同,不过我们这里不是用很小的值替换了,而是直接把填充的部分变为0:
经过这一步,Encoder和Decoder得到的最终的相似度矩阵如下,上边是Encoder的结果,下边是Decoder的结果:
接下来,我们就可以进行softmax操作了:
Fifth-Step-得到最终结果
得到了Attention的相似度矩阵,我们就可以和Value进行相乘,得到经过attention加权的结果:
这一部分是一个简单的矩阵相乘运算,代码如下:
不过这并不是最终的结果,这里文中还加入了残差网络的结构,即将最终的结果和queries的输入进行相加:
所以一个完整的Scaled Dot-Product Attention的代码如下:
3.3 Multi-Head Attention
Multi-Head Attention就是把Scaled Dot-Product Attention的过程做H次,然后把输出合起来。论文中,它的结构图如下:
这部分的示意图如下所示,我们重复做3次相似的操作,得到每一个的结果矩阵,随后将结果矩阵进行拼接,再经过一次的线性操作,得到最终的结果:
Scaled Dot-Product Attention可以看作是只有一个Head的Multi-Head Attention,这部分的代码跟Scaled Dot-Product Attention大同小异,我们直接贴出:
在进行了Attention操作之后,encoder和decoder中的每一层都包含了一个全连接前向网络,对每个position的向量分别进行相同的操作,包括两个线性变换和一个ReLU激活输出:
代码如下:
Encoder有N(默认是6)层,每层包括两个sub-layers:
1 )第一个sub-layer是multi-head self-attention mechanism,用来计算输入的self-attention;
2 )第二个sub-layer是简单的全连接网络。
每一个sub-layer都模拟了残差网络的结构,其网络示意图如下:
根据我们刚才定义的函数,其完整的代码如下:
Decoder有N(默认是6)层,每层包括三个sub-layers:
1 )第一个是Masked multi-head self-attention,也是计算输入的self-attention,但是因为是生成过程,因此在时刻 i 的时候,大于 i 的时刻都没有结果,只有小于 i 的时刻有结果,因此需要做Mask.
2 )第二个sub-layer是对encoder的输入进行attention计算,这里仍然是multi-head的attention结构,只不过输入的分别是decoder的输入和encoder的输出。
3 )第三个sub-layer是全连接网络,与Encoder相同。
其网络示意图如下:
其代码如下:
decoder的输出会经过一层全联接网络和softmax得到最终的结果,示意图如下:
这样,一个完整的Transformer Architecture我们就介绍完了,对于文中写的不清楚或者不到位的地方,欢迎各位留言指正!
1、原文:https://arxiv.org/abs/1706.03762
2、https://mp.weixin.qq.com/s/RLxWevVWHXgX-UcoxDS70w
3、https://github.com/princewen/tensorflow_practice/tree/master/basic/Basic-Transformer-Demo
NLP领域的现状以及AI工程师面临的严峻挑战
在过去几年时间里,NLP领域取得了飞速的发展,这也推动了NLP在产业中的持续落地,以及行业对相关人才的需求。 虽然,NLP的崛起滞后CV多年,但目前的势头还是势不可挡。
但这里我们要面对的现实是,行业上90%以上的NLP工程师是“不合格的”。在过去几个月时间里,我们其实也面试过数百名已经在从事NLP的工程师,但明显发现绝大部分对技术深度和宽度的理解是比较薄弱的,大多还是只停留在调用现有工具比如BERT、XLNet等阶段。
我们一直坚信AI人才的最大壁垒是创造力,能够持续为变化的业务带来更多的价值。但创造的前提一定是对一个领域的深度理解和广度认知,以及不断对一个事物的追问比如不断问自己为什么。
为什么在这个问题上使用Adam,而不是GD或者Adagrad? 对于特定的业务场景,我应该如何把领域知识考虑进去, 用先验,还是用限制条件? 对于拼车场景,设计了一套优化目标,但好像是离散优化问题,应该如何解决? 对于二分类,我应该选择交叉熵还是Hinge Loss?BERT模型太大了,而且效果发现不那么好比如next sentence prediction, 能不能改一改? 为什么CRF要不HMM在不少NLP问题上效果更好? 文本生成效果不太好,如何改造Beam Search让效果更好呢?训练主题模型效率太慢了,如果改造吉布斯采样在分布式环境下运行呢? 数据样本里的标签中有一些依赖关系,能不能把这些信息也加入到目标函数里呢?
另外,有必要保持对前沿技术的敏感性,但事实上,很多人还是由于各种原因很难做到这一点。基于上述的目的,贪心学院一直坚持跑在技术的最前线,帮助大家不断地成长。
为什么选择贪心学院的高端NLP?
首先,全网不可能找得到另外一门系统性的训练营具备如此的深度和广度,这里包括国外的课程,所以从内容的角度来讲是非常稀缺的内容。
其次,即便网络上的资源非常多,学习是需要成本的,而且越有深度的内容越难找到好的学习资源。如果一门课程帮助你清晰地梳理知识体系,而且把有深度的知识点脉络讲清楚,这就是节省最大的成本。
另外,作为一家专注在AI领域的教育科技公司,教研团队的实力在同行业可以算是非常顶尖的,这里不乏顶会的最佳论文作者、ALBERT的作者等。
最后,我们这一期的NLP高阶训练营(第七期)在原有的基础上做了大量的升级,融合了更多前沿的内容,而且在部分内容上加深了难度。
为AI从业者/研究生/研究员专门定制
全网唯一《NLP自然语言处理高阶训练营》
对课程有意向的同学
添加课程顾问小姐姐微信
报名、课程咨询
02部分项目作业
课程设计**紧密围绕学术界最新进展以及工业界的需求,涵盖了所有核心知识点,并且结合了大量实战项目,**培养学员的动手能力,解决问题能力。
03直播授课,现场推导演示
**区别于劣质的PPT讲解,导师全程现场推导,**让你在学习中有清晰的思路,深刻的理解算法模型背后推导的每个细节。更重要的是可以清晰地看到各种模型之间的关系!帮助你打通六脉!
▲源自:CRF与Log-Linear模型讲解
▲源自:CRF与Log-Linear模型讲解
▲源自:Convex Optimization 讲解
▲源自:Convergence Analysis 讲解
不管你在学习过程中遇到多少阻碍,你都可以通过以下4种方式解决:
1、直接在线问导师;
2、记录到共享文档中,每日固定时间的直播答疑;
3、学习社群中全职助教,随时提问答疑
4、共同的问题在Review Session里面做讲解
注:每次答疑,班主任都会进行记录,以便学员实时查阅。
04每周课程安排
采用直播的授课方式,一周4-5次的直播教学, 包括2次的main lectures, 1-2次的discussion session (讲解某一个实战、必备基础、案例或者技术上的延伸), 1次的paper reading session (每周会assign一篇必备论文,并且直播解读)。教学模式上也参考了美国顶级院校的教学体系。以下为其中一周的课程安排,供参考。
05你的必备挑战
1.编写一些技术类文章
通过在知乎上发表相关技术文章进行自我成果检验,同时也是一种思想碰撞的方式,导师会对发表的每一篇文章写一个详细的评语。万一不小心成为一个大V了呢?虽然写文章的过程万分痛苦,学习群里半夜哀嚎遍野,但看一看抓着头发写出来的文章结果还是非常喜人的!看着自己收获的点赞数,大家都默默地感谢起导师们的无情!
这种满满的成就感,让大家一篇接一篇写了下去!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KlMduBRr-1603024781977)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
个个都立刻变身成了知乎大牛~
2.Project项目 & 日常作业
**除了文章,算法工程师的立命根本–项目代码,**导师更是不会放过的。每次在Gitlab上布置的作业,导师们都会带领助教团队会予以详细的批改和反馈。并逼着你不断的优化!
06 课程研发团队
贪心学院联合来至Google、亚马逊、微软等AI企业11位AI科学家对课程内容进行不断的打磨细化,课程基础部分涵盖了该AI技术邻域从业者必备的所有核心知识点,同时在课程深度上加入了**最新的学术研究及工业界的最新进展相关的教学,**确保学员学到国内外企业中热门AI知识技能。
▲部分课程研发导师简介
这两天群里更是捷报连连。我们前三期项目的已经有多名学员被一线AI企业录取,还有通过二面、三面等待着offer。相信未来几周我们将会受到更多的好消息!
随便截了几个学员反馈。
我确定了我们的魔鬼训练营没有误人子弟,我们的课程真的帮助到大家实质的技能提升或帮助大家拿到offer。
这次我们迎来了第七期NLP的招生,千万不要觉得这是一个对标其他线上课程的普通的训练营。由于内容的专业性以及深度,在过去吸引了大量的全球顶级名府的学员,**这里不乏来自斯坦福、UCSD、USC、哥大、HKUST、爱丁堡等世界名府的学生;**在这里,你不仅可以享受到通往顶尖人才的快乐、也可以结识志同道合的AI从业者以及未来的科学家。
本文结构如下:
所谓摘要,就是对给定的单个或者多个文档进行梗概,即在保证能够反映原文档的重要内容的情况下,尽可能地保持简明扼要。质量良好的文摘能够在信息检索过程中发挥重要的作用,比如利用文摘代替原文档参与索引,可以有效缩短检索的时间,同时也能减少检索结果中的冗余信息,提高用户体验。随着信息爆炸时代的到来,自动文摘逐渐成为自然语言处理领域的一项重要的研究课题。
按照摘要面向的文档类型,可以将其分为单文档摘要和多文档摘要。根据需要产生摘要的文档长度,可以将摘要分为长文摘要、短文摘要。按照摘要的生成方法,可以将它分为抽取式摘要和生成式摘要。抽取式摘要是通过抽取拼接源文档中的关键句子来生成摘要的,生成式摘要则是系统根据文档表达的重要内容,自行组织语言,对源文档进行概括。后者是比较常见的划分方式,因为抽取式摘要和生成式摘要在生成过程中有较大的区别。本文后续对摘要生成方法的分类,也是根据这种方式进行划分。
摘要的评估可以参照下图:
其中:
外在评价就是从摘要所服务的下游任务的效果(如检索中的召回率,文本分类中的F1分数值)对摘要进行评价。
抽取式方法从原文中选取关键句组成摘要。这种方法天然的在语法、句法上错误率低,保证了一定的效果。传统的抽取式摘要方法使用图方法、聚类等方式完成无监督摘要。当下流行的有监督摘要的方法,一种是先提取词语、句子级别的各类特征,比如句子的长度、位置、句子中的词语的TF-IDF值等等,然后利用机器学习的算法对句子进行抽取。或者是基于神经网络的抽取式摘要往往将问题建模为序列标注和句子排序两类任务。下面我们将简单介绍这些算法:
一般来说,作者常常会在标题和文章开始就表明主题,因此最简单的方法就是抽取文章中的前几句作为摘要。Lead-3即抽取文章的前三句作为文章的摘要。Lead-3 方法虽然简单直接,但却是非常有效的方法。
TextRank 算法仿照 PageRank,将句子作为节点,使用句子间相似度,构造无向有权边。使用边上的权值迭代更新节点值,最后选取 N 个得分最高的节点,作为摘要。
将文章中的句子视为一个点,按照聚类的方式完成摘要。首先将句子转化为向量表示(这一过程不同的论文做法可能不同),再使用 K 均值聚类和 Mean-Shift 聚类进行句子聚类,得到 K个类别。最后从每个类别中,选择距离质心最近的句子,得到 K 个句子,作为最终摘要。
抽取式摘要可以建模为序列标注任务进行处理,其核心想法是:为原文中的每一个句子打一个二分类标签(0 或 1),0 代表该句不属于摘要,1 代表该句属于摘要。最终摘要由所有标签为 1 的句子构成。将抽取式摘要建模成序列标注问题后,就可以应用序列标注中的方法来进行句子标注了。比如BiLSTM、BiLSTM+CRF等等。
该模型的一个问题是,模型的训练需要监督数据,现有数据集往往没有对应的句子级别的标签,因此需要通过启发式规则进行获取。具体方法为:首先选取原文中与标准摘要计算 ROUGE 得分最高的一句话加入候选集合,接着继续从原文中进行选择,保证选出的摘要集合 ROUGE 得分增加,直至无法满足该条件。得到的候选摘要集合对应的句子设为 1 标签,其余为 0 标签。
除此之外,当下最新的论文还有基于深度学习还有强化学习对句子进行打分的方法:
1.SWAP-NET : Extractive Summarization with SWAP-NET: Sentences and Words from Alternating Pointer Networks
2.NN-SE : [Neural summarization by extracting sentences and words
3.BANDITSUM :BANDITSUM: Extractive Summarization as a Contextual Bandit
4.SummaRuNNer: A recurrent neural network based sequence model for extractive summarization of documents
5.Refrech: Ranking sentences for extractive summarization with reinforcement learning
6.DQN: Deep reinforcement learning for extractive document summarization:
7.RNES w/o coherence :Learning to Extract Coherent Summary via Deep Reinforcement Learning
抽取式摘要在语法、句法上有一定的保证,但是也面临了一定的问题,例如:内容选择错误、连贯性差、灵活性差等问题。生成式摘要允许摘要中包含新的词语或短语,灵活性高,随着近几年神经网络模型的发展,序列到序列(Seq2Seq)模型被广泛的用于生成式摘要任务,并取得不错的效果。
但是简单的Seq2seq直接应用到摘要生成会有一些问题,比如重复生成、信息冗余,无法处理未登录词,关键信息丢失,可读性差等等。相对应的改进主要有以下几类:
毫无疑问,文本摘要最核心的问题是确定关键信息,在生成摘要的时候,要将这些关键信息融入进去,同时要尽量避免出现重复、可读性差、这些问题。 关于文本摘要未来的方向,可以考虑从以下几个方面入手:
ALBERT作为BERT的一个变体,在保持性能的基础上,大大减少了模型的参数,使得实用变得更加方便,是经典的BERT变体之一。
考虑下面给出的句子。作为人类,当我们遇到“apple”这个词时,我们可以:
NLP最新发展的基本前提是赋予机器学习这些表示的能力。
2018年,谷歌发布了BERT,试图基于一些新的想法来学习这个表示:
语言建模包括预测单词的上下文,作为一种学习表示的方法。传统上,这包括到当给出前面的单词时预测句子中的下一个单词。
相反,BERT使用了一个掩码语言模型目标,在这个模型中,我们在文档中随机地对单词进行掩码,并试图根据周围的上下文来预测它们。
“下一个句子预测”的目的是检测两个句子是否连贯。
为此,训练数据中的连续句被用作一个正样本。对于负样本,取一个句子,然后在另一个文档中随机抽取一个句子放在它的旁边。在这个任务中,BERT模型被训练来识别两个句子是否可以同时出现。
为了解决上述两项任务,BERT使用了多层Transformer模块作为编码器。单词向量被传递到各个层,以捕获其含义,并为基本模型生成大小为768的向量。
Jay Alammar有一篇非常好的文章:
http://jalammar.github.io/bert/,更深入地阐述了Transformer的内部机制。
BERT发布后,在排行榜上产生了许多NLP任务的最新成果。但是,模型非常大,导致了一些问题。“ALBERT”论文将这些问题分为两类:
1、内存限制和通信开销:
考虑一个包含一个输入节点、两个隐藏节点和一个输出节点的简单神经网络。即使是这样一个简单的神经网络,由于每个节点的权重和偏差,也会有7个参数需要学习。
BERT-large模型是一个复杂的模型,它有24个隐含层,在前馈网络和注意头中有很多节点,所以有3.4亿个参数。如果你想在BERT的基础上进行改进,你需要大量的计算资源的需求来从零开始进行训练并在其上进行迭代。
这些计算需求主要涉及gpu和TPUs,但是这些设备有内存限制。所以,模型的大小是有限制的。
分布式训练是解决这个问题的一种流行方法。我们以BERT-large上的数据并行性为例,其中训练数据被分到两台机器上。模型在两台机器上对数据块进行训练。如图所示,你可以注意到在梯度同步过程中要传输的大量参数,这会减慢训练过程。同样的瓶颈也适用于模型的并行性,即我们在不同的机器上存储模型的不同部分。
2、模型退化
最近在NLP研究社区的趋势是使用越来越大的模型,以获得在排行榜上的最先进的性能。ALBERT 的研究表明,这可能会导致收益退化。
在论文中,作者做了一个有趣的实验。
如果更大的模型可以带来更好的性能,为什么不将最大的BERT模型(BERT-large)的隐含层单元增加一倍,从1024个单元增加到2048个单元呢?
他们称之为“BERT-xlarge”。令人惊讶的是,无论是在语言建模任务还是在阅读理解测试(RACE)中,这个更大的模型的表现都不如BERT-large模型。
从原文给出的图中,我们可以看到性能是如何下降的。BERT-xlarge的性能比BERT-large差,尽管它更大并且有更多的参数。
ALBERT在BERT 的基础上提出了一些新颖的想法来解决这些问题:
1、跨层参数共享
BERT-large模型有24层,而它的基础版本有12层。随着层数的增加,参数的数量呈指数增长。
为了解决这个问题,ALBERT使用了跨层参数共享的概念。为了说明这一点,让我们看一下12层的BERT-base模型的例子。我们只学习第一个块的参数,并在剩下的11个层中重用该块,而不是为12个层中每个层都学习不同的参数。
我们可以只共享feed-forward层的参数,只共享注意力参数,也可以共享整个块的参数。论文对整个块的参数进行了共享。
与BERT-base的1.1亿个参数相比,ALBERT模型只有3100万个参数,而使用相同的层数和768个隐藏单元。当嵌入尺寸为128时,对精度的影响很小。精度的主要下降是由于feed-forward层的参数共享。共享注意力参数的影响是最小的。
跨层参数策略对性能的影响
2、句子顺序预测 (SOP)
BERT引入了一个叫做“下一个句子预测”的二分类损失。这是专门为提高使用句子对,如“自然语言推断”的下游任务的性能而创建的。基本流程为:
像ROBERTA和XLNET这样的论文已经阐明了NSP的无效性,并且发现它对下游任务的影响是不可靠的。在取消NSP任务之后,多个任务的性能都得到了提高。
因此,ALBERT提出了另一个任务**“句子顺序预测”**。关键思想是:
这使得模型能学习到更细粒度的关于段落级的一致性的区别。
ALBERT推测NSP是无效的,因为与掩码语言建模相比,它并不是一项困难的任务。在单个任务中,它混合了主题预测和连贯性预测。主题预测部分很容易学习,因为它与掩码语言建模的损失有重叠。因此,即使NSP没有学习连贯性预测,它也会给出更高的分数。
SOP提高了下游多句编码任务(SQUAD 1.1, 2.0, MNLI, SST-2, RACE)的性能。
在这里我们可以看到,在SOP任务上,一个经过NSP训练的模型给出的分数只比随机基线略好一点,但是经过SOP训练的模型可以非常有效地解决NSP任务。这就证明SOP能带来更好的学习表现。
3、嵌入参数分解
在BERT中,使用的embeddings(word piece embeddings)大小被链接到transformer块的隐藏层大小。Word piece embeddings使用了大小为30,000的词汇表的独热编码表示。这些被直接投射到隐藏层的隐藏空间。
假设我们有一个大小为30K的词汇表,大小为E=768的word-piece embedding和大小为H=768的隐含层。如果我们增加了块中的隐藏单元尺寸,那么我们还需要为每个嵌入添加一个新的维度。这个问题在XLNET和ROBERTA中也很普遍。
ALBERT通过将大的词汇表嵌入矩阵分解成两个小的矩阵来解决这个问题。这将隐藏层的大小与词汇表嵌入的大小分开。这允许我们在不显著增加词汇表嵌入的参数大小的情况下增加隐藏的大小。
我们将独热编码向量投影到E=100的低维嵌入空间,然后将这个嵌入空间投影到隐含层空间H=768。
比BERT-large模型缩小了18x的参数
训练加速1.7x
在GLUE, RACE和SQUAD得到SOTA结果:
ALBERT标志着构建语言模型的重要一步,该模型不仅达到了SOTA,而且对现实世界的应用也是可行的。
# 首先下载这个数据集到../data路径下,然后解压至../data/aclImdb路径下。
# 本函数已保存在d2lzh包中方便以后使用
# sha1就是对文件内容二进制流进行一种数学运算后得到的一串16进制字符,这一串16进制字符可以用来检查原文件有无被修改;把你得到的文件用同样的方法,如MD5,进行校验运算后得到的一串16进制字符,如与原提供者的不同,说明你得到的文件与原文件不同,已经被修改,通常叫数字签名。
什么是sha1校验值
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。 SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。
SHA1算法描述
在SHA1算法中,我们必须把原始消息(字符串,文件等)转换成位字符串。SHA1算法只接受位作为输入。假设我们对字符串“abc”产生消息摘要。首先,我们将它转换成位字符串如下: 01100001 01100010 01100011 ――――――――――――― ‘a’=97 ‘b’=98 ‘c’=99 这个位字符串的长度为24。下面我们需要5个步骤来计算消息摘要MAC。
SHA1值改变怎么办?只要保证下载后的sha1值和发布的相符即可放心刻录。删除某一文件肯定会导致哈希值不同的。删除与否对刻盘不影响的。删除ei.cfg的目的其实很单纯:为了实现windows7多版本选择性安装。
再解:sha1值是针对文件完整性的,只要里面1字节的内容被改变,就会不一样~
import collections
import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.contrib import text
from mxnet.gluon import data as gdata, loss as gloss, nn, rnn, utils as gutils
import os
import random
import tarfile
def download_imdb(data_dir='../data'):
url = ('http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz')
sha1 = '01ada507287d82875905620988597833ad4e0903'
fname = gutils.download(url, data_dir, sha1_hash=sha1)
with tarfile.open(fname, 'r') as f:
f.extractall(data_dir) # 解压全部文件!
download_imdb()
# 读取训练数据集和测试数据集。每个样本是一条评论及其对应的标签:1表示“正面”,0表示“负面”。
def read_imdb(folder='train'): # 本函数已保存在d2lzh包中方便以后使用
data = []
for label in ['pos', 'neg']:
folder_name = os.path.join('../data/aclImdb/', folder, label) # 在其后面加入标签数据
for file in os.listdir(folder_name):
with open(os.path.join(folder_name, file), 'rb') as f:
review = f.read().decode('utf-8').replace('\n', '').lower()
data.append([review, 1 if label == 'pos' else 0])
random.shuffle(data)
return data
train_data, test_data = read_imdb('train'), read_imdb('test')
# 我们需要对每条评论做分词,从而得到分好词的评论。这里定义的get_tokenized_imdb函数使用最简单的方法:基于空格进行分词。
def get_tokenized_imdb(data): # 本函数已保存在d2lzh包中方便以后使用
def tokenizer(text):
return [tok.lower() for tok in text.split(' ')]
return [tokenizer(review) for review, _ in data]
# 现在,我们可以根据分好词的训练数据集来创建词典了。我们在这里过滤掉了出现次数少于5的词。
def get_vocab_imdb(data): # 本函数已保存在d2lzh包中方便以后使用
tokenized_data = get_tokenized_imdb(data)
counter = collections.Counter([tk for st in tokenized_data for tk in st])
return text.vocab.Vocabulary(counter, min_freq=5,
reserved_tokens=['' ])
vocab = get_vocab_imdb(train_data)
'# words in vocab:', len(vocab)
('# words in vocab:', 46152)
# 因为每条评论长度不一致所以不能直接组合成小批量,我们定义preprocess_imdb函数对每条评论进行分词,并通过词典转换成词索引,然后通过截断或者补“”(padding)符号来将每条评论长度固定成500。
def preprocess_imdb(data, vocab): # 本函数已保存在d2lzh包中方便以后使用
max_l = 500 # 将每条评论通过截断或者补'',使得长度变成500
def pad(x): # 截断补齐
return x[:max_l] if len(x) > max_l else x + [
vocab.token_to_idx['' ]] * (max_l - len(x))
tokenized_data = get_tokenized_imdb(data)
features = nd.array([pad(vocab.to_indices(x)) for x in tokenized_data])
labels = nd.array([score for _, score in data])
return features, labels
# 现在,我们创建数据迭代器。每次迭代将返回一个小批量的数据。
batch_size = 64
train_set = gdata.ArrayDataset(*preprocess_imdb(train_data, vocab))
test_set = gdata.ArrayDataset(*preprocess_imdb(test_data, vocab))
train_iter = gdata.DataLoader(train_set, batch_size, shuffle=True)
test_iter = gdata.DataLoader(test_set, batch_size)
for X, y in train_iter:
print('X', X.shape, 'y', y.shape)
break
'#batches:', len(train_iter)
X (64, 500) y (64,)
Out[8]:
('#batches:', 391)
# 在这个模型中,每个词先通过嵌入层得到特征向量。然后,我们使用双向循环神经网络对特征序列进一步编码得到序列信息。最后,我们将编码的序列信息通过全连接层变换为输出。具体来说,我们可以将双向长短期记忆在最初时间步和最终时间步的隐藏状态连结,作为特征序列的表征传递给输出层分类。在下面实现的BiRNN类中,Embedding实例即嵌入层,LSTM实例即为序列编码的隐藏层,Dense实例即生成分类结果的输出层。
class BiRNN(nn.Block):
def __init__(self, vocab, embed_size, num_hiddens, num_layers, **kwargs):
super(BiRNN, self).__init__(**kwargs)
self.embedding = nn.Embedding(len(vocab), embed_size)
# bidirectional设为True即得到双向循环神经网络
self.encoder = rnn.LSTM(num_hiddens, num_layers=num_layers,
bidirectional=True, input_size=embed_size)
self.decoder = nn.Dense(2)
def forward(self, inputs):
# inputs的形状是(批量大小, 词数),因为LSTM需要将序列作为第一维,所以将输入转置后
# 再提取词特征,输出形状为(词数, 批量大小, 词向量维度)
embeddings = self.embedding(inputs.T)
# rnn.LSTM只传入输入embeddings,因此只返回最后一层的隐藏层在各时间步的隐藏状态。
# outputs形状是(词数, 批量大小, 2 * 隐藏单元个数)
outputs = self.encoder(embeddings)
# 连结初始时间步和最终时间步的隐藏状态作为全连接层输入。它的形状为
# (批量大小, 4 * 隐藏单元个数)。
encoding = nd.concat(outputs[0], outputs[-1])
outs = self.decoder(encoding)
return outs
embed_size, num_hiddens, num_layers, ctx = 100, 100, 2, d2l.try_all_gpus()
net = BiRNN(vocab, embed_size, num_hiddens, num_layers)
net.initialize(init.Xavier(), ctx=ctx)
# 由于情感分类的训练数据集并不是很大,为应对过拟合,我们将直接使用在更大规模语料上预训练的词向量作为每个词的特征向量。这里,我们为词典vocab中的每个词加载100维的GloVe词向量。
glove_embedding = text.embedding.create(
'glove', pretrained_file_name='glove.6B.100d.txt', vocabulary=vocab)
# 然后,我们将用这些词向量作为评论中每个词的特征向量。注意,预训练词向量的维度需要与创建的模型中的嵌入层输出大小embed_size一致。此外,在训练中我们不再更新这些词向量。
net.embedding.weight.set_data(glove_embedding.idx_to_vec)
net.embedding.collect_params().setattr('grad_req', 'null')
# 训练模型
lr, num_epochs = 0.01, 5
trainer = gluon.Trainer(net.collect_params(), 'adam', {
'learning_rate': lr})
loss = gloss.SoftmaxCrossEntropyLoss()
d2l.train(train_iter, test_iter, net, loss, trainer, ctx, num_epochs)
training on [gpu(0), gpu(1)]
epoch 1, loss 0.5677, train acc 0.687, test acc 0.812, time 41.6 sec
epoch 2, loss 0.3931, train acc 0.826, test acc 0.842, time 42.5 sec
epoch 3, loss 0.3466, train acc 0.853, test acc 0.851, time 44.0 sec
epoch 4, loss 0.3091, train acc 0.868, test acc 0.853, time 42.0 sec
epoch 5, loss 0.2844, train acc 0.882, test acc 0.853, time 41.3 se
# 本函数已保存在d2lzh包中方便以后使用
def predict_sentiment(net, vocab, sentence):
sentence = nd.array(vocab.to_indices(sentence), ctx=d2l.try_gpu())
label = nd.argmax(net(sentence.reshape((1, -1))), axis=1)
return 'positive' if label.asscalar() == 1 else 'negative'
# 下面使用训练好的模型对两个简单句子的情感进行分类。
predict_sentiment(net, vocab, ['this', 'movie', 'is', 'so', 'great'])
Out[15]:'positive'
predict_sentiment(net, vocab, ['this', 'movie', 'is', 'so', 'bad'])
Out[16]:'negative'
# 增加迭代周期。训练后的模型能在训练和测试数据集上得到怎样的准确率?再调节其他超参数试试?
# 使用更大的预训练词向量,如300维的GloVe词向量,能否提升分类准确率?
# 使用spaCy分词工具,能否提升分类准确率?你需要安装spaCy(pip install spacy),并且安装英文包(python -m spacy download en)。在代码中,先导入spaCy(import spacy)。然后加载spaCy英文包(spacy_en = spacy.load('en'))。最后定义函数def tokenizer(text): return [tok.text for tok in spacy_en.tokenizer(text)]并替换原来的基于空格分词的tokenizer函数。需要注意的是,GloVe词向量对于名词词组的存储方式是用“-”连接各个单词,例如,词组“new york”在GloVe词向量中的表示为“new-york”,而使用spaCy分词之后“new york”的存储可能是“new york”。
# Python reload(sys) NameError: name 'reload' is not defined
对于 Python 2.X:
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
# python3默认是用utf-8编码,无法直接用reload
# pip在2020年1月1日已经不支持python2了!所以python2.7用不了pip!
# 激活python2.7环境
conda create -n shaofeng_27 python=2.7
conda list
conda activate shaofeng_27
# 下一次重新登录时,依旧会默认是python3.6.9,只需要conda activate shaofeng_27激活下2才能进入到python2.7!
# 下一次重新登录时,jupyter需要重新激活下python3.6.9,只需要conda activate py36激活下才能进入到原来的python装好库的环境!
服务器切换到指定工作目录:
ctrl+d 从python退回命令行终端
cd
/home/shaofeng2/Projects/URun.ResearchPrototype.Lite/Projects/AutomaticWriting/sr1c/Alg/Sum_Bandit/
pip install https://download.pytorch.org/whl/cu90/torch-1.1.0-cp36-cp36m-win_amd64.whl -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
# 同一级目录下的文件用 ./data/。。。当前目录
# 看清楚readme!
导读
深度学习视觉领域的增强方法可以很大程度上提高模型的表现,并减少数据的依赖,而NLP上做数据增强不像在图像上那么方便,但还是有一些方法的。
与计算机视觉中使用图像进行数据增强不同,NLP中文本数据增强是非常罕见的。这是因为图像的一些简单操作,如将图像旋转或将其转换为灰度,并不会改变其语义。语义不变变换的存在使增强成为计算机视觉研究中的一个重要工具。
我很好奇是否有人尝试开发NLP的增强技术,并研究了现有的文献。在这篇文章中,我将分享我对当前用于增加文本数据的方法的发现。
这种方法试图在不改变句子主旨的情况下替换文本中的单词。
例如,你可以用三个最相似的单词来替换句子中的单词,并得到文本的三个变体。
使用像Gensim这样的包来访问预先训练好的字向量和获取最近的邻居是很容易的。例如,这里我们通过训练推特上的单词向量找到了单词“awesome”的同义词。
# pip install gensim
import gensim.downloader as api
model = api.load('glove-twitter-25')
model.most_similar('awesome', topn=5)
你会得到5个最相似的单词和余弦相似度。
[('amazing', 0.9687871932983398),
('best', 0.9600659608840942),
('fun', 0.9331520795822144),
('fantastic', 0.9313924312591553),
('perfect', 0.9243415594100952)]
因此,我们可以使用mask预测来生成文本的变体。与之前的方法相比,生成的文本在语法上更加连贯,因为模型在进行预测时考虑了上下文。
使用开源库这很容易实现,如Hugging Face的transformers。你可以将你想要替换的token设置为并生成预测。
from transformers import pipeline
nlp = pipeline('fill-mask')
nlp('This is cool')
[{'score': 0.515411913394928,
'sequence': ' This is pretty cool',
'token': 1256},
{'score': 0.1166248694062233,
'sequence': ' This is really cool',
'token': 269},
{'score': 0.07387523353099823,
'sequence': ' This is super cool',
'token': 2422},
{'score': 0.04272908344864845,
'sequence': ' This is kinda cool',
'token': 24282},
{'score': 0.034715913236141205,
'sequence': ' This is very cool',
'token': 182}]
然而,这种方法的一个问题是,决定要屏蔽文本的哪一部分并不是一件小事。你必须使用启发式的方法来决定掩码,否则生成的文本将不保留原句的含义。
要替换的单词是从整个文档中TF-IDF分数较低的整个词汇表中选择的。你可以参考原文中的实现:
https://github.com/googresearch/uda/blob/master/text/augmentation/word_level_augment.py。
在这种方法中,我们利用机器翻译来解释文本,同时重新训练含义。Xie et al.使用这种方法来扩充未标注的文本,并在IMDB数据集中学习一个只有20个有标注样本的半监督模型。该方法优于之前的先进模型,该模型训练了25,000个有标注的样本。
反向翻译过程如下:
你还可以同时使用不同的语言运行反向翻译以生成更多的变体。如下图所示,我们将一个英语句子翻译成三种目标语言:法语、汉语、意大利语,然后再将其翻译回英语。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yWqoWEe-1603024781999)(A Visual Survey of Data Augmentation in NLP.assets/nlp-aug-backtranslation-multi.png)]
这项技术也被用在了的Kaggle上的“Toxic Comment Classification Challenge”的第一名解决方案中。获胜者将其用于训练数据增强和测试期间,在测试期间,对英语句子的预测概率以及使用三种语言(法语、德语、西班牙语)的反向翻译进行平均,以得到最终的预测。
对于反向翻译的实现,可以使用TextBlob。或者,你也可以使用Google Sheets,并按照此处给出的说明:
https://amitness.com/2020/02/backtransling-ingooglesheets/,免费申请谷歌翻译。
这些是使用正则表达式的简单的模式匹配的转换,由Claude Coulombe在他的论文中介绍。
在本文中,他给出了一个将动词形式由简写转化为完整形式或者反过来的例子。我们可以通过这个来生成增强型文本。
既然转换不应该改变句子的意思,我们可以看到,在扩展模棱两可的动词形式时,这可能会失败,比如:
为了解决这一问题,本文提出允许模糊收缩,但跳过模糊展开。
你可以在这里找到英语缩略语的列表:
https://en.wikipedia.org/wiki/wiki/wikipedia%3alist_of_english_contractions。
这些方法的思想是在文本中加入噪声,使所训练的模型对扰动具有鲁棒性。
这项技术是由Luque在他的关于TASS 2019情绪分析的论文中提出的。这项技术的灵感来自于遗传学中发生的染色体交叉操作。
该方法将tweets分为两部分,两个具有相同极性的随机推文(即正面/负面)进行交换。这个方法的假设是,即使结果是不符合语法和语义的,新文本仍将保留情感的极性。
这一技术对准确性没有影响,但有助于论文中极少数类的F1分数,如tweets较少的中性类。
这项技术已经在Coulombe的论文中使用。其思想是解析和生成原始句子的依赖关系树,使用规则对其进行转换,并生成改写后的句子。
例如,一个不改变句子意思的转换是句子从主动语态到被动语态的转换,反之亦然。
要使用上述所有方法,可以使用名为nlpaug的python库:
https://github.com/makcedward/nlpaug。它提供了一个简单且一致的API来应用这些技术。
我从文献综述中得出的结论是,这些增强方法中有许多是非常特定于任务的,它们对性能的影响仅针对某些特定用例进行了研究。系统地比较这些方法并分析它们对许多任务的性能的影响将是一项有趣的研究。
英文原文:
https://amitness.com/2020/05/data-augmentation-for-nlp/
NLP:自然语言处理(NLP)是信息时代最重要的技术之一。理解复杂的语言也是人工智能的重要组成部分。而自google在2018年10月底公布BERT在11项nlp任务中的卓越表后,BERT(Bidirectional Encoder Representation from Transformers)就成为NLP一枝独秀,本文将为大家层层剖析bert。
NLP常见的任务主要有:中文自动分词、句法分析、自动摘要、问答系统、文本分类、指代消解、情感分析等。
我们会从one-hot、word embedding、rnn、seq2seq、transformer一步步逼近bert,这些是我们理解bert的基础。
Word Embedding
首先我们需要对文本进行编码,使之成为计算机可以读懂的语言,在编码时,我们期望句子之间保持词语间的相似行,词的向量表示是进行机器学习和深度学习的基础。
word embedding的一个基本思路就是,我们把一个词映射到语义空间的一个点,把一个词映射到低维的稠密空间,这样的映射使得语义上比较相似的词,他在语义空间的距离也比较近,如果两个词的关系不是很接近,那么在语义空间中向量也会比较远。
如上图英语和西班牙语映射到语义空间,语义相同的数字他们在语义空间分布的位置是相同的
在句子的空间结构上我们期望获取更底层的之间的关系比如:
king和queen之间的关系相比与man与woman的关系大体应该相同的,那么他们通过矩阵运算,维持住这种关系
Paris 和France之间的关系相比与Berlin与German的关系大体应该相同的,那么他们通过矩阵运算,维持住这种关系
简单回顾一下word embedding,对于nlp来说,我们输入的是一个个离散的符号,对于神经网络来说,它处理的都是向量或者矩阵。所以第一步,我们需要把一个词编码成向量。最简单的就是one-hot的表示方法。如下图所示:
one-hot encoding 编码
通常我们有很多的词,那只在出现的位置显示会,那么势必会存在一些问题
两个词语义上无法正确表示,我们更希望低维的相似的比较接近,语义相近的词距离比较近,语义不想近的词,距离也比较远。
解决的办法就是word enbedding,是一种维位稠密的表示。
Neural Network Language Model(神经网络语言模型)
我们都知道word2vec,glove。其实更早之前的神经网络语言模型里出现。已经有比较早的一个词向量了。语言模型是nlp的一个基本任务,是给定一个句子w,包括k个词,我们需要计算这个句子的概率。使用分解成条件概率乘积的形式。变成条件概率的计算。
传统的方法,统计的n-gram的,词频统计的形式,出现的多,概率就高,出现少概率就低。
神经网络语言模型架构如上图:
将每个词向量拼接成句子矩阵。每一列都是一个词, 如北京、上海、 天津比较近,大致相同一块区域,所以当预测时,可以给出大概相同的概率,不仅仅与预料中统计结果有关系。矩阵相乘就可以提取出这个词,但是为了提取一个词,我们要进行一次矩阵运算,这个比较低效,所以比较成熟的框架都提供了查表的方法,他的效率更高。
因为上下文环境很相似,会共享类似的context,在问我要去 (__)概率会比较大。这也是神经网络语言模型的一个好处。我们通过神经网络语言模型得到一个词向量。当然我们也可以用其他的任务来做,一样得到词向量,比如句法分析,但是那些任务大部分是有监督的学习,需要大量的标注信息。
语言模型是非监督的,资料获取不需要很大的成本。
word2vec和神经网络语言模型不同,直接来学习这个词向量,使用的基本假设是分布式假设,如果两个词的上下文时相似的,那么他们语义也是相似的。
word2vec分为cbow(根据context预测中心词)和skip-gram(根据中心词预测context)两种。
我们可以通过word2vec或者 glove这种模型在大量的未标注的语料上学习,我们可以学习到比较好的向量表示,可以学习到词语之间的一些关系。比如男性和女性的关系距离,时态的关系,学到这种关系之后我们就可以把它作为特征用于后续的任务,从而提高模型的泛化能力。
但是同时存在一些问题比如:
RNN/LSTM/GRU
那么这种上下文的语义可以通过RNN/LSTM/GRU来解决,RNN与普通深度学习不同的是,RNN是一种序列的模型,会有一定的记忆单元,能够记住之前的历史信息,从而可以建模这种上下文相关的一些语义。RNN中的记忆单元可以记住当前词之前的信息。
RR可以解决,理论上我们希望学到很长的关系,但是由于梯度消失的问题,所以长时依赖不能很好的训练。
其实lstm可以解决RNN长时依赖梯度消失的问题。
seq2seq
对于翻译,我们不可能要求英语第一个词一定对应法语的第一个词,不能要求长度一样,对于这样一个rnn不能解决这一问题。我们使用两个rnn拼接成seq2seq来解决。
比如经典的翻译例子法语到英语的翻译,由encoder编码到语义空间和decoder根据语义空间解码翻译成一个个的英语句子。
encoder把要翻译的句子,映射到了整个语义空间,decoder根据语义空间再逐一翻译出来,但是句子长度有时会截断。有一个问题,我们需要一个固定长度的context向量来编码所有语义,这个是很困难的,要记住每一个细节是不可能的。用一个向量记住整个语义是很困难的。
这时候我们引入了attention机制。
可以理解为context只记住了一个大概的提取信息,一种方法是做内积,内积大就关注大,这里可以理解为一种提取的方式,当提取到相关内容,再与具体的ecoder位置计算,得到更精细的内容。
pay attention 做内积。越大越相近 约重要,后续的attention、transformer都是对seq2seq的一个改进,通过这种可以解决word embbeing没有上下文的一个问题。
加上attention机制,我们就取得了很大的成绩,但是仍然存在一个问题,
顺序依赖,如下图:t依赖t-1,t-1依赖t-2,串行的,很难并行的计算,持续的依赖的关系,通常很慢,无法并行:
Contextual Word Embedding
要解决RNN的问题,就引入了contextual word embedding。
attention是需要两个句子的,我们很多时候只有一个句子,这就需要self-attention。提取信息的时候、编码时self-atenntion是自驱动的,self-attention关注的词的前后整个上下文。
self-attention最早是transformer的一部分。transformer是怎么解决这一问题的?
transformer:
本质也是一个encoder与decoder的过程,最起初时6个encoder与6个decoder堆叠起来,如果是LSTM的话,通常很难训练的很深,不能很好的并行
每一层结构都是相同的,我们拿出一层进行解析,每一层有self-attention和feed-forward,decoder还有普通的attention输入来自encoder,和seq-2seq一样,我在翻译某一个词的时候会考虑到encoder的输出,来做一个普通的attention
如下图例子给定两个词 thinking和machies,首先通过word embedding把它变成向量,通过self-attention,把它变成一个向量,这里的sefl-attention时考虑上下文的。然后再接全连接层,计算z1的时候我要依赖x1、x2、x3整个序列的,才能算z1,z2也一样,我算r1的时候时不需要z2的,只要有z1我就可以算r1.只要有z2就能算r2,这个是比较大的一个区别,这样就可以并行计算。
我们来看看self-attention具体是怎么计算的
假设只有两个词,映射成长度只有四的向量,接下来使用三个变换矩阵wqwkwv,分别把每个向量变换成三个向量 q1k1v1q2k2v2这里是与设映的向量相乘得到的
得到向量之后就可以进行编码了,考虑上下文,如上文提到的bank同时有多个语义,编码这个词的时候要考虑到其他的词,具体的计算是q1k1做内积 q2k2做内积得到score,内积越大,表示约相似,softmax进行变成概率。花0.88的概率注意Thinking,0.12注意macheins这个词
就可以计算z1了,z1=0.88v1+0.12z2
z2的计算也是类似的,
q表示为了编码自己去查询其他的词,k表示被查询,v表示这个词的真正语义,经过变换就变成真正的包含上下文的信息,普通attention可以理解为self-attention的一个特例,
普通attention的对比:
实际中是多个head, 即多个attention(多组qkv),通过训练学习出来的。不同attention关注不同的信息,指代消解 上下位关系,多个head,原始论文中有8个,每个attention得到一个三维的矩阵。
将8个3维的拼成24维,信息太多 经过24 *4进行压缩成4维。
位置编码:
self-attention是不考虑位置关系的,两个句子中北京,初始映射是一样的,由于上下文一样,qkv也是一样的,最终得到的向量也是一样的。这样一个句子中调换位置,其实attention的向量是一样的。实际是不一样的,一个是出发城市,一个是到达城市。
引入位置编码,绝对位置编码,每个位置一个 Embedding
每个位置一个embedding,同样句子,多了个词 就又不一样了,编码就又不一样了
tranformer原始论文使用相对位置编码,后面的bert open gpt使用的是简单绝对位置编码:
大家可以尝试bert换一下相对位置会不会更好:
transformer 中 encoder 的完整结构,加上了残差连接和 layerNorm
decoder加上了普通的attention,最后一刻的输出,会输入
transformer的decoder不能利用未知的信息,即单向信息流问题。
transformer 解决的问题:
可以并行计算,训练的很深,到后来的open gpt可以到12层 bert的16、24层
单向信息流的问题:至少在encoder的时候考虑前面和后面的信息,所以可以取得很好的效果,
transformer解决了普通word embedding 没有上下文的问题,但是解决这个问题,需要大量的标注信息样本。
如何解决transformer的问题,就引入了elmo
elmo:无监督的考虑上下文的学习。
一个个的预测的语言模型:
双向的lstm,每个向量2n,是一种特征提取的方法,考虑的上下文的,编码完,就定住了,
elmo:将上下文当作特征,但是无监督的语料和我们真实的语料还是有区别的,不一定的符合我们特定的任务,是一种双向的特征提取。
openai gpt就做了一个改进,也是通过transformer学习出来一个语言模型,不是固定的,通过任务 finetuning,用transfomer代替elmo的lstm。
openai gpt其实就是缺少了encoder的transformer。当然也没了encoder与decoder之间的attention。
openAI gpt虽然可以进行fine-tuning,但是有些特殊任务与pretraining输入有出入,单个句子与两个句子不一致的情况,很难解决,还有就是decoder只能看到前面的信息。
bert
bert从这几方面做了改进:
bert为什么更好呢?
bert的输入是两个句子,分割符sep,cls表示开始,对输入的两个句子,使用位置编码, segment embeding 根据这个可以知道 该词属于哪个句子,学习会更加简单。可以很清楚知道第一句子需要编码什么信息,第二个句子可以编码什么信息。
单向信息流的问题,换一个任务来处理这个问题
单向信息流问题:mask ml 有点类似与完形填空,根据上下文信息猜其中信息,计算出最大概率,随机丢掉15%的词来bert来进行预测,考虑前后双向的信息,怎么搞两个句子?
-50%概率抽连续句子 正样本1
这样学习到两个句子的关系,可以预测句子关系,在一些问答场景下很重要。
finetuning:
单个句子的任务,我们拿第一个cls向量,上面接一些全连接层,做一个分类,标注的数据 fine-tuningbert参数也包括全连接的一个参数,为什么选择第一个?
bert任务还是预测这个词,预测的时候会参考其他的词,如eat本身还是吃的语义,直接根据eat去分类,显然是不可以的,cls没有太多其他词的语义,所以它的语义完全来自其他的语义 来自整个句子,编码了整个句子的语义,用它做可以,当然也可以得出所有结果进行拼接后,再来进行预测。
注意:
bert的实际应用比较简单,不过多赘述内容,推荐简单的demo样例:
https://www.jianshu.com/p/3d0bb34c488a
使用不同的方式来使用BERT模型。
在NLP中不断的研究产生了各种各样的预训练模型。对于各种任务,例如文本分类、无监督主题建模和问题回答等,不断的在刷新业界最佳。其中,最伟大的发现之一是在神经网络结构中采用了注意力机制。这种技术是所有称为transformers的网络的基础。他们应用注意力机制来提取关于给定单词上下文的信息,然后将其编码到一个学习到的向量中。
作为数据科学家,我们可以调用很多transformers架构,并使用它们对我们的任务进行预测或微调。在这篇文章中,我们喜欢读经典的BERT,但是同样的推理也适用于其他所有的transformer结构。我们使用了siamese结构,这是一个双路BERT,用于多文本输入的分类。
我们从Kaggle上收集数据集。新闻类别数据集:
https://www.kaggle.com/rmisra/news-category-dataset包含从HuffPost上获得的2012年至2018年的约20万条新闻标题。我们需要根据两种不同的文本来源对新闻文章进行分类:标题和简介。我们总共有40多种不同类型的新闻。为了简单起见,考虑到工作流的计算时间,我们只使用了8个类的一个子组。
我们不应用任何预处理和数据清洗,我们让BERT表演所有的魔法。我们的工作框架是Tensorflow与Huggingface的transformer库。更详细地说,我们使用了原始的Bert模型transformer,它的输出就是原始的隐藏状态,没有任何特定的头。它可以像Tensorflow模型的子类一样访问,并且可以很容易地在我们的网络架构中进行调优。
作为第一个竞争者,我们引入了单个BERT的结构。它只接收一个文本输入,这是两个文本源拼接的结果。这是正常操作:任何模型都可以接收拼接起来的特征作为输入。对于transformers,这个过程将输入与特殊tokens结合起来。
BERT期望输入数据以特定的格式:有特殊的tokens来标记句子/源文本的开头([CLS])和结尾([SEP])。与此同时,tokenization包括将输入文本拆分为词汇表中可用的tokens列表。对词汇表外的单词进行word-piece的处理,一个单词被逐步分解为子单词,这些子单词是词汇表的一部分。该过程可以通过预先训练好的Huggingface的Tokenizer轻松实现,我们只需要注意填充。
我们最后从源文本的输入中得到了三个矩阵(标记、掩码、序列id)。它们是我们的transformers的输入。在单个BERT的情况下,我们只有一个矩阵的元组。这是因为我们同时将两个文本序列传递给我们的tokenizer,这两个文本序列被自动拼接起来(使用[SEP] token)。
我们的模型结构非常简单:transformer直接与我们在上面构建的矩阵相连接。最后,通过平均池操作减少了transformer的最终隐藏状态。概率分数是由最终的dense层计算出来的。
我们的简单BERT对测试数据的准确率达到83%。性能报告在下面的混淆矩阵中。
我们的第二个结构可以定义为双路BERT,因为它使用了两个不同的transformers。他们有相同的组成,但训练用不同的输入。第一个接收新闻标题,另一个接收简介。输入被编码为两个矩阵元组(token, mask, sequence ids),每个输入一个。对于两个数据源,我们的transformers的最终隐藏状态都使用平均池来聚合。它们被拼接起来,并通过一个全连接层传递。
通过这些设置,我们可以获得测试数据84%的准确度。
我们最后的模型是一种Siamese的结构。可以这样定义它,因为两个不同的数据源是在同一个可训练的transformer结构中同时传递的。输入矩阵与Siamese BERT的情况相同。对于这两个数据源,transformer的最终隐藏状态是通过平均操作聚合的。产生的连接在一个全连接层中传递,该层将它们组合在一起并产生概率。
我们的siamese结构在我们的测试数据上达到82%的准确度。
在这篇文章中,我们应用BERT结构来执行一个多类分类任务。我们实验的附加价值是使用transformers 以不同的方式处理多个输入源。我们从只有一个源中的所有输入的经典拼接结构开始,并以为模型提供分开的文本输入作为结束。双路BERT和siamese BERT都能够实现良好的性能。由于这个原因,它们可以被认为是经典的单变压器结构的良好替代品。
import torch
from transformers import *
# Transformers has a unified API
# for 10 transformer architectures and 30 pretrained weights.
# Model | Tokenizer | Pretrained weights shortcut
MODELS = [(BertModel, BertTokenizer, 'bert-base-uncased'),
(OpenAIGPTModel, OpenAIGPTTokenizer, 'openai-gpt'),
(GPT2Model, GPT2Tokenizer, 'gpt2'),
(CTRLModel, CTRLTokenizer, 'ctrl'),
(TransfoXLModel, TransfoXLTokenizer, 'transfo-xl-wt103'),
(XLNetModel, XLNetTokenizer, 'xlnet-base-cased'),
(XLMModel, XLMTokenizer, 'xlm-mlm-enfr-1024'),
(DistilBertModel, DistilBertTokenizer, 'distilbert-base-cased'),
(RobertaModel, RobertaTokenizer, 'roberta-base'),
(XLMRobertaModel, XLMRobertaTokenizer, 'xlm-roberta-base'),
]
# To use TensorFlow 2.0 versions of the models, simply prefix the class names with 'TF', e.g. `TFRobertaModel` is the TF 2.0 counterpart of the PyTorch model `RobertaModel`
# Let's encode some text in a sequence of hidden-states using each model:
for model_class, tokenizer_class, pretrained_weights in MODELS:
# Load pretrained model/tokenizer
tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
model = model_class.from_pretrained(pretrained_weights)
# Encode text
input_ids = torch.tensor([tokenizer.encode("Here is some text to encode", add_special_tokens=True)]) # Add special tokens takes care of adding [CLS], [SEP], ... tokens in the right way for each model.
with torch.no_grad(): # requires_grad=True 要求计算梯度,requires_grad=False 不要求计算梯度,with torch.no_grad()或者@torch.no_grad()中的数据不需要计算梯度,也不会进行反向传播
last_hidden_states = model(input_ids)[0] # Models outputs are now tuples
# Each architecture is provided with several class for fine-tuning on down-stream tasks, e.g.
BERT_MODEL_CLASSES = [BertModel, BertForPreTraining, BertForMaskedLM, BertForNextSentencePrediction,
BertForSequenceClassification, BertForTokenClassification, BertForQuestionAnswering]
# All the classes for an architecture can be initiated from pretrained weights for this architecture
# Note that additional weights added for fine-tuning are only initialized
# and need to be trained on the down-stream task
pretrained_weights = 'bert-base-uncased'
tokenizer = BertTokenizer.from_pretrained(pretrained_weights)
for model_class in BERT_MODEL_CLASSES:
# Load pretrained model/tokenizer
model = model_class.from_pretrained(pretrained_weights)
# Models can return full list of hidden-states & attentions weights at each layer
model = model_class.from_pretrained(pretrained_weights,
output_hidden_states=True,
output_attentions=True)
input_ids = torch.tensor([tokenizer.encode("Let's see all hidden-states and attentions on this text")])
all_hidden_states, all_attentions = model(input_ids)[-2:]
# Models are compatible with Torchscript
model = model_class.from_pretrained(pretrained_weights, torchscript=True)
traced_model = torch.jit.trace(model, (input_ids,))
# Simple serialization for models and tokenizers
model.save_pretrained('./directory/to/save/') # save
model = model_class.from_pretrained('./directory/to/save/') # re-load
tokenizer.save_pretrained('./directory/to/save/') # save
tokenizer = BertTokenizer.from_pretrained('./directory/to/save/') # re-load
# SOTA examples for GLUE, SQUAD, text generation...
https://blog.csdn.net/qq_28168421/article/details/104285490?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
ELU
GELU高斯误差线性单元激活函数在最近的 Transformer 模型(谷歌的 BERT 和 OpenAI 的 GPT-2)中得到了应用。GELU 的论文来自 2016 年,但直到最近才引起关注。
*扩展型指数线性单元激活函数(SELU)*其性质能够实现 SNN(自归一化神经网络)
微分的 GELU 激活函数。
在神经网络的建模过程中,模型很重要的性质就是非线性,同时为了模型泛化能力,需要加入随机正则,例如dropout(随机置一些输出为0,其实也是一种变相的随机非线性激活), 而随机正则与非线性激活是分开的两个事情, 而其实模型的输入是由非线性激活与随机正则两者共同决定的。
GELUs正是在激活中引入了随机正则的思想,是一种对神经元输入的概率描述,直观上更符合自然的认识,同时实验效果要比Relus与ELUs都要好。
GELUs其实是 dropout、zoneout、Relus的综合,GELUs对于输入乘以一个0,1组成的mask,而该mask的生成则是依概率随机的依赖于输入。假设输入为X, mask为m,则m服从一个伯努利分布(Φ(x) \Phi(x)Φ(x), Φ(x)=P(X<=x),X服从标准正太分布 \Phi(x)=P(X<=x), X服从标准正太分布Φ(x)=P(X<=x),X服从标准正太分布),这么选择是因为神经元的输入趋向于正太分布,这么设定使得当输入x减小的时候,输入会有一个更高的概率被dropout掉,这样的激活变换就会随机依赖于输入了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MAZSh2B8-1603024782028)(C:\Users\VULCAN\AppData\Roaming\Typora\typora-user-images\image-20200617161002699.png)]
cdf = 0.5 * (1.0 + tf.tanh(
(np.sqrt(2 / np.pi) * (x + 0.044715 * tf.pow(x, 3)))))
return x * cdf
def gelu(input_tensor):
cdf = 0.5 * (1.0 + tf.erf(input_tensor / tf.sqrt(2.0)))
return input_tesnsor*cdf
pyltp,Spacy,funNLP,hanlp,textrank,textgrapher,bert中文翻译,transformers
算法原理:TextRank自动摘要算法源于Google公司提出的PageRank算法,主要思想是把文档划分为由若干文本单元(词语或者句子)构成的节点,文本单元间的相似度构成节点间的边形成图模型,利用PageRank算法对图模型进行迭代计算,直到节点的累加权重收敛,然后根据累加权重值对所有节点进行排序,输出关键句,算法流程如图1所示。
算法的优劣与提升空间 :
虽然使用TextRank 摘要算法具有不依赖标注数据、计算快速等优点,另外,TextRank是完全无监督的,而且与其他受监督的系统不同,它完全依赖于从文本本身提取的信息,这使得它很容易移植到其他文本集合、域和语言。但是迭代计算时没有考虑句子的语义相似度,没有考虑典型的摘要句特征信息,生成的摘要句可能会出现冗余而导致文摘不够全面。
(1)句子相似度度量问题。TextRank摘要算法使用相同词语个数度量两个句子的相似距离,没有使用语义信息,导致后续的迭代计算不够准确,如“美国总统”和“奥巴马”语义关系非常紧密,但是相同词个数为0。
(2)连接边权重优化问题。TextRank 摘要算法中的句子节点的累加权重取决于该句子与其他句子的相似度,相似度越高,则该节点得到的其他节点的分享权重越大,但是没有考虑句子自身的位置、长度、转折词等特征,在对长句进行摘要计算时会引入干扰。经过对大量业务数据的统计分析,很多摘要句在句子位置、长度以及转折词等方面有比较明显的特征。可以尝试综合考虑多种典型摘要句特征,并对累加权重进行修正,提高了最终摘要结果的准确性。
(3)摘要冗余问题。因为TextRank 摘要算法根据句子相似度分享权重,当按照节点的累加权重值从高到低的顺序选取前N个句子形成摘要时可能会有冗余,即提取的摘要中包含多个意思比较相近或相似的句子。为了兼顾摘要的准确性和多样性,在提取摘要句时可以性,可尝试引入最大边缘相关(Maximal Marginal Relevance,MMR)算法。MMR的思想是使入选摘要句既与原文主题的相关度较高来保证摘要的相关性,又使该句与已选中摘要句的差异尽可能大来保证摘要的多样性,从而实现提取相关性和多样性平衡的高质量摘要。
参考:https://zhuanlan.zhihu.com/p/126733456以及一种基于TextRank的中文自动摘要方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8kHjRJc-1603024782029)(C:\Users\VULCAN\AppData\Roaming\Typora\typora-user-images\image-20200621210208653.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OuwSQl34-1603024782030)(C:\Users\VULCAN\AppData\Roaming\Typora\typora-user-images\image-20200621210424843.png)]
一、文本分词
将需要进行分析的文本进行分词(英文直接按照空格分隔词汇,中文则需通过分词工具分隔之后,把词之间加上空格)
二、去停用词
在文本中可以发现类似”the”、”a”等词的词频很高,但是这些词并不能表达文本的主题,我们称之为停用词。
对文本预处理的过程中,我们希望能够尽可能提取到更多关键词去表达这句话或文本的中心思想,因此我们可以将这些停用词去掉后再编码。
三、将词编号
按照词频(次出现的频率)进行倒序编号,如英文中一篇文章出现最多的应该是“a”,“the”等词汇(假设‘a’出现次数大于‘the’),则把“a”编号为“1”,‘the’编号为“2”,以此类推。
这样在文本中出现过的词都会有自己特有的编号。对每个词编码之后,每句话中的每个词就可以用对应的编码表示,即每条文本已经转变成一个向量了。
四、文本长度统一
对每个词编码之后,每条文本中的每个词就可以用对应的编码表示,即每条文本已经转变成一个向量。但是,由于文本的长度不唯一,需要将每条文本的长度设置一个固定值。
假设每个句子的长度都固定为100,如果长度大于100,则将超过的部分截掉;如果小于100,则在最前面用0填充。
五、将词编码转化为词向量
在神经网络中一般要将文本转化成矩阵进行计算,单单将文本转化为向量还是不够,所以需要将每个词编码转化成词向量。
此步骤一般先使用“one-hot”编码方式编码,这样就会将一条文本转化为一个n*n的矩阵(n表示文本中出现的不同的词个数)。然后通过神经网络的训练迭代更新得到一个合适的权重矩阵(具体实现过程可以参考skip-gram模型),行大小为n,列大小为词向量的维度(小于n)。
至此已经将文本数据预处理完毕,将每个影评样本转换为一个数字矩阵,矩阵的每一行表示一个词向量。
作者:LinT
链接:https://www.zhihu.com/question/347678607/answer/864217252
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关注这个问题有一段时间了,一直没有看到太满意的回答,来讲一下我的见解。
首先,需要明确的是,建模位置信息(无论是绝对位置还是相对位置)并不是必须用到三角函数,否则fairseq和BERT中使用的positional embedding也不会奏效了。我想,作者在这里使用正余弦函数,只是根据归纳偏置和一些经验作出的选择罢了。
不妨从零构想一个位置编码的方法。首先,给定一个长为 的文本,最简单的位置编码就是计数,即使用 作为文本中每个字的位置编码了。当然这样的瑕疵非常明显,这个序列是没有上界的。设想一段很长的(比如含有500个字的)文本,最后一个字的位置编码非常大,这是很不合适的:1. 它比第一个字的编码大太多,和字嵌入合并以后难免会出现特征在数值上的倾斜;2. 它比一般的字嵌入的数值要大,难免会抢了字嵌入的「风头」,对模型可能有一定的干扰。
从这里,我们知道位置编码最好具有一定的值域范围,这样就有了第二个版本:使用文本长度对每个位置作归一化,得到 。这样固然使得所有位置编码都落入 区间,但是问题也是显著的:不同长度文本的位置编码步长是不同的,在较短的文本中紧紧相邻的两个字的位置编码差异,会和长文本中相邻数个字的两个字的位置编码差异一致。这显然是不合适的,我们关注的位置信息,最核心的就是相对次序关系,尤其是上下文中的次序关系,如果使用这种方法,那么在长文本中相对次序关系会被「稀释」。
再重新审视一下位置编码的需求:1. 需要体现同一个单词在不同位置的区别;2. 需要体现一定的先后次序关系,并且在一定范围内的编码差异不应该依赖于文本长度,具有一定不变性。我们又需要值域落入一定数值区间内的编码,又需要保证编码与文本长度无关,那么怎么做呢?一种思路是使用有界的周期性函数。在前面的两种做法里面,我们为了体现某个字在句子中的绝对位置,使用了一个单调的函数,使得任意后续的字符的位置编码都大于前面的字,如果我们放弃对绝对位置的追求,转而要求位置编码仅仅关注一定范围内的相对次序关系,那么使用一个sin/cos函数就是很好的选择,因为sin/cos函数的周期变化规律非常稳定,所以编码具有一定的不变性。简单的构造可以使用下面的形式
其中 用来调节位置编码函数的波长,当 比较大时,波长比较长,相邻字的位置编码之间的差异比较小。
这样的做法还是有一些简陋,周期函数的引入是为了复用位置编码函数的值域,但是这种 的映射,还是太单调:如果 比较大,相邻字符之间的位置差异体现得不明显;如果 比较小,在长文本中还是可能会有一些不同位置的字符的编码一样,这是因为 空间的表现范围有限。既然字嵌入的维度是 ,自然也可以使用一个 维向量来表示某个位置编码—— 的表示范围要远大于 (醉酒的鸟儿永远飞不回家)。
显然,在不同维度上应该用不同的函数操纵位置编码,这样高维的表示空间才有意义。可以为位置编码的每一维赋予不同的 ;甚至在一些维度将 替换为 …一种构造方法就是论文中的方法了
这里不同维度上 的波长从 到 都有;区分了奇偶数维度的函数形式。这使得每一维度上都包含了一定的位置信息,而各个位置字符的位置编码又各不相同。这里可以顺便为
@小莲子
的疑问作一个可能的解释:为什么官方代码tensor2tensor的最初版本只是简单地分了两段,却没有什么性能差异呢?因为 的交替使用只是为了使编码更「丰富」,在哪些维度上使用 ,哪些使用 ,不是很重要,都是模型可以调整适应的。
当然,我觉得深究这里的三角函数形式的位置编码没有太大意义。因为至少现在看来:1. 这个函数形式很可能是基于经验得到的,并且应该有不少可以替代的方法;2. 谷歌后期的作品BERT已经换用位置嵌入(positional embedding)了,这可能说明编码的方案有一定的问题(猜测)。
https://www.zhihu.com/question/347678607
王同学死磕技术已关注
NLP(自然语言处理)领域一个特别重要的任务叫做——文本摘要自动生成。此任务的主要目的是快速的抽取出一篇文章的主要内容,这样读者就能够通过最少的文字,了解到文章最要想表达的内容。由于抽取出来的摘要表达出了文章最主要的含义,所以在做长文本分类任务时,我们可以采用文本摘要算法将长文本的摘要抽取出来,在采用短文本分类模型去做文本分类,有时会起到出奇的好效果。
文本摘要抽取算法主要分为两大类:
MMR算法又叫最大边界相关算法,此算法在设计之初是用来计算Query文本与被搜索文档之间的相似度,然后对文档进行rank排序的算法。算法公式如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zaBz73Rk-1603024782045)(https://math.jianshu.com/math?formula=%5Cmathrm%7BMMR%7D(%5Cmathrm%7BQ%7D%2C%20%5Cmathrm%7BC%7D%2C%20%5Cmathrm%7BR%7D)]%3DA%20r%20g%20%5Cmax%20_%7B%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bi%7D%7D%20%5Cmathrm%7Bin%20%2CC%7D%7D%5E%7Bk%7D%5Cleft%5B%5Clambda%20%5Coperatorname%7Bsim%7D%5Cleft(%5Cmathrm%7BQ%7D%2C%20%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bi%7D%7D%5Cright)-(1-%5Clambda)%20%5Cmax%20_%7B%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bj%7D%7D%20%5Cmathrm%7Bi%7D%20%5Cmathrm%7Bk%7D%7D%5Cleft(%5Coperatorname%7Bsim%7D%5Cleft(%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bi%7D%7D%2C%20%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bj%7D%7D%5Cright)%5Cright)%5Cright%5D)
其中 Q 是 Query文本,C 是被搜索文档集合,R是一个已经求得的以相关度为基础的初始集合,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l634A3oY-1603024782045)(https://math.jianshu.com/math?formula=A%20r%20g%20%5Cmax%20_%7B%5Cmathrm%7Bd%7D_%7B%5Cmathrm%7Bi%7D%7D%20%5Cmathrm%7Bin%20%2CC%7D%7D%5E%7Bk%7D%5B*%5D)]指的是搜索返回的K个的句子的索引。
当我们做摘要抽取时,我们需要换个角度去看公式中的字符表示,在摘要抽取时:
仔细观察下公式方括号中的两项,其中前一项的物理意义指的是待抽取句子和整篇文档的相似程度,后一项指的是待抽取句子和已得摘要的相似程度,通过减号相连,其含义是希望:抽取的摘要既能表达整个文档的含义,有具备多样性 。而[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-alAujNle-1603024782048)(https://math.jianshu.com/math?formula=%5Clambda)] 则是控制摘要多样性程度的一个超参数,你可以根据自己的需求去调节。
使用sklearn 的 CountVectorizer 接口计算句子的词袋向量,然后定义余弦相识度函数计算句子和文档直接相似度,最后实现MMR算法。
from sklearn.feature_extraction.text import CountVectorizer
from pprint import pprint
import operator
def encode_sen(sen,corpus):
"""
input: sentence and corpus
output : bag of words vector of sentence
"""
cv = CountVectorizer()
cv = cv.fit(corpus)
vec = cv.transform([sen]).toarray()
return vec[0]
def cosin_distance(vector1, vector2):
"""
input: two bag of words vectors of sentence
output : the similarity between the sentence
"""
dot_product = 0.0
normA = 0.0
normB = 0.0
for a, b in zip(vector1, vector2):
dot_product += a * b
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return None
else:
return dot_product / ((normA * normB) ** 0.5)
def doc_list2str(doc_list):
"""
transform the doc_list to str
"""
docu_str = ""
for wordlist in doc_list:
docu_str += " ".join(wordlist)
return docu_str
def MMR(doc_list,corpus):
"""
input :corpus and the docment you want to extract
output :the abstract of the docment
"""
Corpus = corpus
docu = doc_list2str(doc_list)
doc_vec = encode_sen(docu,Corpus)
QDScore = {
}
###calculate the similarity of every sentence with the whole corpus
for sen in doc_list:
sen = " ".join(sen)
sen_vec = encode_sen(sen,corpus)
score = cosin_distance(sen_vec,doc_vec)
QDScore[sen] = score
n = 2
alpha = 0.7
Summary_set = []
while n > 0:
MMRScore = {
}
### select the first sentence of abstract
if Summary_set == []:
selected = max(QDScore.items(), key=operator.itemgetter(1))[0]
Summary_set.append(selected)
Summary_set_str = " ".join(Summary_set)
for sentence in QDScore.keys():
#calculate MMR
if sentence not in Summary_set:
sum_vec = encode_sen(Summary_set_str, corpus)
sentence_vec = encode_sen(sentence,corpus)
MMRScore[sentence] = alpha * QDScore[sentence] - (1 - alpha) * cosin_distance(sentence_vec,sum_vec)
selected = max(MMRScore.items(), key=operator.itemgetter(1))[0]
Summary_set.append(selected)
n -= 1
# print(len(Summary_set))
return Summary_set
在网上找了一个关于2018年世界杯后姆巴佩转会巴黎的新闻,进行摘要抽取。
import jieba
docment = "伴随着世界杯的落幕,俱乐部联赛筹备工作又成为主流,转会市场必然也会在世界杯的带动下风起云涌,不过对于在本届赛事上大放异彩的姆巴佩而言,大巴黎可以吃一颗定心丸,世界杯最佳新秀已经亲自表态:留在巴黎哪里也不去。在接受外媒采访时,姆巴佩表达了继续为巴黎效忠的决心。“我会留在巴黎,和他们一起继续我的路途,我的职业生涯不过刚刚开始”,姆巴佩说道。事实上,在巴黎这座俱乐部,充满了内部的你争我夺。上赛季,卡瓦尼和内马尔因为点球事件引发轩然大波,而内马尔联合阿尔维斯给姆巴佩起“忍者神龟”的绰号也让法国金童十分不爽,为此,姆巴佩的母亲还站出来替儿子解围。而早在二月份,一场与图卢兹的比赛,内马尔也因为传球问题赛后和姆巴佩产生口角。由此可见,巴黎内部虽然大牌云集,但是气氛并不和睦。内马尔离开球队的心思早就由来已久,而姆巴佩也常常与其它俱乐部联系在一起,在躲避过欧足联财政公平法案之后,巴黎正在为全力留下二人而不遗余力。好在姆巴佩已经下定决心,这对巴黎高层而言,也算是任务完成了一半。本届世界杯上,姆巴佩星光熠熠,长江后浪推前浪,大有将C罗、梅西压在脚下的趋势,他两次追赶贝利,一次是在1/8决赛完成梅开二度,另一次是在世界杯决赛中完成锁定胜局的一球,成为不满20岁球员的第二人。另外他在本届赛事中打进了4粒入球,和格列兹曼并列全队第一。而对巴黎而言,他们成功的标准只有一条:欧冠。而留下姆巴佩,可以说在争夺冠军的路上有了仰仗,卡瓦尼在本届世界杯同样表现不错,内马尔虽然内心波澜,但是之前皇马官方已经辟谣没有追求巴西天王,三人留守再度重来,剩下的就是图赫尔的技术战术与更衣室的威望,对图赫尔而言,战术板固然重要,但是德尚已经为他提供了更加成功的范本,像团结法国队一样去团结巴黎圣日耳曼,或许这才是巴黎取胜的钥匙。"
sen_list = docment.strip().split("。")
sen_list.remove("")
doc_list = [jieba.lcut(i) for i in sen_list]
corpus = [" ".join(i) for i in doc_list]
corpus
结果如下:从抽取的摘要基本可以得知本篇报道主要是想说明世界杯后姆巴佩将转化巴黎,而且可能性很大。和全文主要想表达的含义基本吻合。证明MMR算法确实厉害。
MMR(doc_list,corpus)
abstract
这里笔者只是简单的介绍了MMR摘要算法的原理,以及简单实现。代码部分也不是此算法的最优实现。真正能够落地的摘要算法,一定是融合了更多的其他思想,如textrank,文本句子和标题的相似度,或者引入词向量或者句子向量来更好的表达句子语义等等。本文只是想让大家初步了解摘要算法的一些知识,以及感受一下摘要算法的神奇之处。
https://blog.csdn.net/ZJRN1027/article/details/81136761
美团搜索是美团App上最大的连接人和服务的入口,覆盖了团购、外卖、电影、酒店、买菜等各种生活服务。随着用户量快速增长,越来越多的用户在不同场景下都会通过搜索来获取自己想要的服务。理解用户Query,将用户最想要的结果排在靠前的位置,是搜索引擎最核心的两大步骤。但是,用户输入的Query多种多样,既有商户名称和服务品类的Query,也有商户别名和地址等长尾的Query,准确刻画Query与Doc之间的深度语义相关性至关重要。基于Term匹配的传统相关性特征可以较好地判断Query和候选Doc的字面相关性,但在字面相差较大时,则难以刻画出两者的相关性,比如Query和Doc分别为“英语辅导”和“新东方”时两者的语义是相关的,使用传统方法得到的Query-Doc相关性却不一致。
2018年底,以Google BERT[1]为代表的预训练语言模型刷新了多项NLP任务的最好水平,开创了NLP研究的新范式:即先基于大量无监督语料进行语言模型预训练(Pre-training),再使用少量标注语料进行微调(Fine-tuning)来完成下游的NLP任务(文本分类、序列标注、句间关系判断和机器阅读理解等)。美团AI平台搜索与NLP部算法团队基于美团海量业务语料训练了MT-BERT模型,已经将MT-BERT应用到搜索意图识别、细粒度情感分析、点评推荐理由、场景化分类等业务场景中[2]。
作为BERT的核心组成结构,Transformer具有强大的文本特征提取能力,早在多项NLP任务中得到了验证,美团搜索也基于Transformer升级了核心排序模型,取得了不错的研究成果[3]。
近年来,以BERT为代表的预训练语言模型在多项 NLP 任务上都获得了不错的效果。下图1简要回顾了预训练语言模型的发展历程。2013年,Google提出的 Word2vec[4]通过神经网络预训练方式来生成词向量(Word Embedding),极大地推动了深度自然语言处理的发展。针对Word2vec生成的固定词向量无法解决多义词的问题,2018年,Allen AI团队提出基于双向LSTM网络的ELMo[5]。ELMo根据上下文语义来生成动态词向量,很好地解决了多义词的问题。2017年底,Google提出了基于自注意力机制的Transformer[6]模型。
相比RNN模型,Transformer语义特征提取能力更强,具备长距离特征捕获能力,且可以并行训练,在机器翻译等NLP任务上效果显著。Open AI团队的GPT[7]使用Transformer替换RNN进行深层单向语言模型预训练,并通过在下游任务上Fine-tuning验证了Pretrain-Finetune范式的有效性。在此基础上,Google BERT引入了MLM(Masked Language Model)及NSP(Next Sentence Prediction,NSP)两个预训练任务,并在更大规模语料上进行预训练,在11项自然语言理解任务上刷新了最好指标。BERT的成功启发了大量后续工作,总结如下:
基于预训练好的BERT模型可以支持多种下游NLP任务。BERT在下游任务中的应用主要有两种方式:即Feature-based和Finetune-based。其中Feature -based方法将BERT作为文本编码器获取文本表示向量,从而完成文本相似度计算、向量召回等任务。而Finetune-based方法是在预训练模型的基础上,使用具体任务的部分训练数据进行训练,从而针对性地修正预训练阶段获得的网络参数。该方法更为主流,在大多数任务上效果也更好。
由于BERT在NLP任务上的显著优势,一些研究工作开始将BERT应用于文档排序等信息检索任务中。清华大学Qiao等人[18]详细对比了Feature-based和Finetune-based两种应用方式在段落排序(Passage Ranking)中的效果。滑铁卢大学Jimmy Lin团队[19]针对文档排序任务提出了基于Pointwise和Pairwise训练目标的MonoBERT和DuoBERT模型。此外,该团队[20]提出融合基于BERT的Query-Doc相关性和Query-Sentence相关性来优化文档排序任务的方案。为了优化检索性能和效果,Bing广告团队[21]提出一种双塔结构的TwinBERT分别编码Query和Doc文本。2019年10月,Google在其官方博客介绍了BERT在Google搜索排序和精选摘要(Featured Snippet)场景的应用,BERT强大的语义理解能力改善了约10%的Google搜索结果[22],除了英文网页,Google也正在基于BERT优化其他语言的搜索结果。值得一提的是美团AI平台搜索与NLP部在WSDM Cup 2020检索排序评测任务中提出了基于Pairwise模式的BERT排序模型和基于LightGBM的排序模型,取得了榜单第一名的成绩[23]。
美团搜索场景下相关性任务定义如下:给定用户Query和候选Doc(通常为商户或商品),判断两者之间相关性。搜索Query和Doc的相关性直接反映结果页排序的优劣,将相关性高的Doc排在前面,能提高用户搜索决策效率和搜索体验。为了提升结果的相关性,我们在召回、排序等多个方面做了优化,本文主要讨论在排序方面的优化。通过先对Query和Doc的相关性进行建模,把更加准确的相关性信息输送给排序模型,从而提升排序模型的排序能力。Query和Doc的相关性计算是搜索业务核心技术之一,根据计算方法相关性主要分为字面相关性和语义相关性。
字面相关性
早期的相关性匹配主要是根据Term的字面匹配度来计算相关性,如字面命中、覆盖程度、TFIDF、BM25等。字面匹配的相关性特征在美团搜索排序模型中起着重要作用,但字面匹配有它的局限,主要表现在:
语义相关性
为了解决上述问题,业界工作包括传统语义匹配模型和深度语义匹配模型。传统语义匹配模型包括:
这些方法弥补了字面匹配方法的不足,不过从实际效果上来看,还是无法很好地解决语义匹配问题。随着深度自然语言处理技术的兴起,基于深度学习的语义匹配方法成为研究热点,主要包括基于表示的匹配方法(Representation-based)和基于交互的匹配方法(Interaction-based)。
基于表示的匹配方法:使用深度学习模型分别表征Query和Doc,通过计算向量相似度来作为语义匹配分数。微软的DSSM[26]及其扩展模型属于基于表示的语义匹配方法,美团搜索借鉴DSSM的双塔结构思想,左边塔输入Query信息,右边塔输入POI、品类信息,生成Query和Doc的高阶文本相关性、高阶品类相关性特征,应用于排序模型中取得了很好的效果。此外,比较有代表性的表示匹配模型还有百度提出 SimNet[27],中科院提出的多视角循环神经网络匹配模型(MV-LSTM)[28]等。
基于交互的匹配方法:这种方法不直接学习Query和Doc的语义表示向量,而是在神经网络底层就让Query和Doc提前交互,从而获得更好的文本向量表示,最后通过一个MLP网络获得语义匹配分数。代表性模型有华为提出的基于卷积神经网络的匹配模型ARC-II[29],中科院提出的基于矩阵匹配的的层次化匹配模型MatchPyramid[30]。
基于表示的匹配方法优势在于Doc的语义向量可以离线预先计算,在线预测时只需要重新计算Query的语义向量,缺点是模型学习时Query和Doc两者没有任何交互,不能充分利用Query和Doc的细粒度匹配信号。基于交互的匹配方法优势在于Query和Doc在模型训练时能够进行充分的交互匹配,语义匹配效果好,缺点是部署上线成本较高。
BERT语义相关性
BERT预训练使用了大量语料,通用语义表征能力更好,BERT的Transformer结构特征提取能力更强。中文BERT基于字粒度预训练,可以减少未登录词(OOV)的影响,美团业务场景下存在大量长尾Query(如大量数字和英文复合Query)字粒度模型效果优于词粒度模型。此外,BERT中使用位置向量建模文本位置信息,可以解决语义匹配的结构局限。综上所述,我们认为BERT应用在语义匹配任务上会有更好的效果,基于BERT的语义匹配有两种应用方式:
Feature-based方式是经过BERT得到Query和Doc的表示向量,然后计算余弦相似度,所有业务场景下Query-Doc相似度都是固定的,不利于适配不同业务场景。此外,在实际场景下为海量Doc向量建立索引存储成本过高。因此,我们选择了Finetune-based方案,利用搜索场景中用户点击数据构造训练数据,然后通过Fine-tuning方式优化Query-Doc语义匹配任务。图2展示了基于BERT优化美团搜索核心排序相关性的技术架构图,主要包括三部分:
数据增强
BERT Fine-tuning任务需要一定量标注数据进行迁移学习训练,美团搜索场景下Query和Doc覆盖多个业务领域,如果采用人工标注的方法为每个业务领域标注一批训练样本,时间和人力成本过高。我们的解决办法是使用美团搜索积累的大量用户行为数据(如浏览、点击、下单等), 这些行为数据可以作为弱监督训练数据。在DSSM模型进行样本构造时,每个Query下抽取1个正样本和4个负样本,这是比较常用的方法,但是其假设Query下的Doc被点击就算是相关的,这个假设在实际的业务场景下会给模型引入一些噪声。
此处以商家(POI)搜索为例,理想情况下如果一个POI出现在搜索结果里,但是没有任何用户点击,可认为该POI和Query不相关;如果该POI有点击或下单行为,可认为该POI和Query相关。下单行为数据是用户“用脚投票”得来的,具有更高的置信度,因此我们使用下单数据作为正样本,使用未点击过的数据构造负样本,然后结合业务场景对样本进一步优化。数据优化主要包括对样本去噪和引入品牌数据两个方面。此外,为了评测算法离线效果,我们从构造样本中随机采样9K条样本进行了人工标注作为Benchmark数据集。
样本去噪
无意义单字Query过滤。由于单字Query表达的语义通常不完整,用户点击行为也比较随机,如<优,花漾星球专柜(中央大道倍客优)>,这部分数据如果用于训练会影响最终效果。我们去除了包含无意义单字Query的全部样本。
正样本从用户下单的POI中进行随机采样,且过滤掉Query只出现在POI的分店名中的样本,如<大润发,小龙坎老火锅(大润发店)>,虽然Query和POI字面匹配,但其实是不相关的结果。
负样本尝试了两种构造方法:全局随机负采样和Skip-Above采样。
品牌样本优化
美团商家中有很多品牌商家,通常品牌商家拥有数百上千的POI,如“海底捞”、“肯德基”、“香格里拉酒店”等,品牌POI名称多是“品牌+地标”文本形式,如“北京香格里拉饭店”。对Query和POI的相关性进行建模时,如果仅取Query和POI名进行相关性训练,POI名中的“地标”会给模型带来很大干扰。例如,用户搜“香格里拉酒店”时会召回品牌“香格里拉酒店”的分店,如“香格里拉酒店”和“北京香格里拉饭店”等,相关性模型受地标词影响,会给不同分店会打出不同的相关性分数,进而影响到后续排序模型的训练。因此,我们对于样本中的品牌搜索样本做了针对性优化。搜索品牌词有时会召回多个品牌的结果,假设用户搜索的品牌排序靠后,而其他品牌排序靠前会严重影响到用户体验,因此对Query和POI相关性建模时召回结果中其他品牌的POI可认为是不相关样本。针对上述问题,我们利用POI的品牌信息对样本进行了重点优化。
经过样本去噪和品牌样本优化后,BERT相关性模型在Benchmark上的Accuracy提升23BP,相应地L2排序排序模型离线AUC提升17.2BP。
模型优化
知识融合
我们团队基于美团业务数据构建了餐饮娱乐领域知识图谱—“美团大脑”[32],对于候选Doc(POI/SPU),通过图谱可以获取到该Doc的大量结构化信息,如地址、品类、团单,场景标签等。美团搜索场景中的Query和Doc都以短文本为主,我们尝试在预训练和Fine-tuning阶段融入图谱品类和实体信息,弥补Query和Doc文本信息的不足,强化语义匹配效果。
引入品类信息的预训练
由于美团搜索多模态的特点,在某些情况下,仅根据Query和Doc标题文本信息很难准确判断两者之间的语义相关性。如<考研班,虹蝶教育>,Query和Doc标题文本相关性不高,但是“虹蝶教育”三级品类信息分别是“教育-升学辅导-考研”,引入相关图谱信息有助于提高模型效果,我们首先基于品类信息做了尝试。
在相关性判别任务中,BERT模型的输入是对。对于每一个输入的Token,它的表征由其对应的词向量(Token Embedding)、片段向量(Segment Embedding)和位置向量(Position Embedding)相加产生。为了引入Doc品类信息,我们将Doc三级品类信息拼接到Doc标题之后,然后跟Query进行相关性判断,如图4所示。
对于模型输入部分,我们将Query、Doc标题、三级类目信息拼接,并用[SEP]分割,区分3种不同来源信息。对于段向量,原始的BERT只有两种片段编码EA和EB,在引入类目信息的文本信息后,引入额外的片段编码EC。引入额外片段编码的作用是防止额外信息对Query和Doc标题产生交叉干扰。由于我们改变了BERT的输入和输出结构,无法直接基于MT-BERT进行相关性Fine-tuning任务。我们对MT-BERT的预训练方式做了相应改进,BERT预训练的目标之一是NSP(Next Sentence Prediction),在搜索场景中没有上下句的概念,在给定用户的搜索关键词和商户文本信息后,判断用户是否点击来取代NSP任务。
添加品类信息后,BERT相关性模型在Benchmark上的Accuracy提升56BP,相应地L2排序模型离线AUC提升6.5BP。
引入实体成分识别的多任务Fine-tuning
在美团搜索场景中,Query和Doc通常由不同实体成分组成,如美食、酒店、商圈、品牌、地标和团购等。除了文本语义信息,这些实体成分信息对于Query-Doc相关性判断至关重要。如果Query和Doc语义相关,那两者除了文本语义相似外,对应的实体成分也应该相似。例如,Query为“Helens海伦司小酒馆”,Doc为“Helens小酒馆(东鼎购物中心店)”,虽然文本语义不完全匹配,但二者的主要的实体成分相似(主体成分为品牌+POI形式),正确的识别出Query/Doc中的实体成分有助于相关性的判断。微软的MT-DNN[33]已经证明基于预训练模型的多任务Fine-tuning可以提升各项子任务效果。由于BERT Fine-tuning任务也支持命名实体识别(NER)任务,因而我们在Query-Doc相关性判断任务的基础上引入Query和Doc中实体成分识别的辅助任务,通过对两个任务的联合训练来优化最终相关性判别结果,模型结构如下图5所示:
多任务学习模型的损失函数由两部分组成,分别是相关性判断损失函数和命名实体识别损失函数。其中相关性损失函数由[CLS]位的Embedding计算得到,而实体成分识别损失函数由每个Token的Embedding计算得到。2种损失函数相加即为最终优化的损失函数。在训练命名实体识别任务时,每个Token的Embedding获得了和自身实体相关的信息,从而提升了相关性任务的效果。
引入实体成分识别的多任务Fine-tuning方式后,BERT相关性模型在Benchmark上的Accuracy提升219BP,相应地L2排序模型AUC提升17.8BP。
Pairwise Fine-tuning
Query-Doc相关性最终作为特征加入排序模型训练中,因此我们也对Fine-tuning任务的训练目标做了针对性改进。基于BERT的句间关系判断属于二分类任务,本质上是Pointwise训练方式。Pointwise Fine-tuning方法可以学习到很好的全局相关性,但忽略了不同样本之前的偏序关系。如对于同一个Query的两个相关结果DocA和DocB,Pointwise模型只能判断出两者都与Query相关,无法区分DocA和DocB相关性程度。为了使得相关性特征对于排序结果更有区分度,我们借鉴排序学习中Pairwise训练方式来优化BERT Fine-tuning任务。
Pairwise Fine-tuning任务输入的单条样本为三元组,对于同一Query的多个候选Doc,选择任意一个正例和一个负例组合成三元组作为输入样本。在下游任务中只需要使用少量的Query和Doc相关性的标注数据(有监督训练样本),对BERT模型进行相关性Fine-tuning,产出Query和Doc的相关性特征。Pairwise Fine-tuning的模型结构如下图6所示:
对于同一Query的候选Doc,选择两个不同标注的Doc,其中相关文档记为Doc+,不相关文档记Doc-。输入层通过Lookup Table 将Query, Doc+以及Doc-的单词转换为 Token 向量,同时会拼接位置向量和片段向量,形成最终输入向量。接着通过BERT模型可以分别得到(Query, Doc+)以及(Query, Doc-)的语义相关性表征,即BERT的CLS位输出。经过Softmax归一化后,可以分别得到(Query, Doc+)和(Query, Doc-)的语义相似度打分。
对于同一Query的候选Doc,选择两个不同标注的Doc,其中相关文档记为Doc+,不相关文档记Doc-。输入层通过Lookup Table 将Query, Doc+以及Doc-的单词转换为 Token 向量,同时会拼接位置向量和片段向量,形成最终输入向量。接着通过BERT模型可以分别得到(Query, Doc+)以及(Query, Doc-)的语义相关性表征,即BERT的CLS位输出。经过Softmax归一化后,可以分别得到(Query, Doc+)和(Query, Doc-)的语义相似度打分。
Pairwise Fine-tuning除了输入样本上的变化,为了考虑搜索场景下不同样本之间的偏序关系,我们参考RankNet[34]的方式对训练损失函数做了优化。令为同一个Query下相比更相关的概率,其中和分别为和的模型打分,则:
使用交叉熵损失函数,令表示样本对的真实标记,当比更相关时(即为正例而为负例),为1,否则为-1,损失函数可以表示为:
其中N表示所有在同Query下的Doc对。
使用Pairwise Fine-tuning方式后,BERT相关性模型在Benchmark上的Accuracy提升925BP,相应地L2排序模型的AUC提升19.5BP。
联合训练
前文所述各种优化属于两阶段训练方式,即先训练BERT相关性模型,然后训练L2排序模型。为了将两者深入融合,在排序模型训练中引入更多相关性信息,我们尝试将BERT相关性Fine-tuning任务和排序任务进行端到端的联合训练。
由于美团搜索涉及多业务场景且不同场景差异较大,对于多场景的搜索排序,每个子场景进行单独优化效果好,但是多个子模型维护成本更高。此外,某些小场景由于训练数据稀疏无法学习到全局的Query和Doc表征。我们设计了基于Partition-model的BERT相关性任务和排序任务的联合训练模型,Partition-model的思想是利用所有数据进行全场景联合训练,同时一定程度上保留每个场景特性,从而解决多业务场景的排序问题,模型结构如下图7所示:
输入层:模型输入是由文本特征向量、用户行为序列特征向量和其他特征向量3部分组成。
共享层:底层网络参数是所有场景网络共享。
场景层:根据业务场景进行划分,每个业务场景单独设计网络结构,打分时只经过所在场景的那一路。
损失函数:搜索业务更关心排在页面头部结果的好坏,将更相关的结果排到头部,用户会获得更好的体验,因此选用优化NDCG的Lambda Loss[34]。
联合训练模型目前还在实验当中,离线实验已经取得了不错的效果,在验证集上AUC提升了234BP。目前,场景切分依赖Query意图模块进行硬切分,后续自动场景切分也值得进行探索。
由于BERT的深层网络结构和庞大参数量,如果要部署上线,实时性上面临很大挑战。在美团搜索场景下,我们对基于MT-BERT Fine-tuning好的相关性模型(12层)进行了50QPS压测实验,在线服务的TP99增加超过100ms,不符合工程上线要求。我们从两方面进行了优化,通过知识蒸馏压缩BERT模型,优化排序服务架构支持蒸馏模型上线。
模型轻量化
为了解决BERT模型参数量过大、前向计算耗时的问题,常用轻量化方法有三种:
在Query意图分类任务[2]中,我们基于MT-BERT裁剪为4层小模型达到了上线要求。意图分类场景下Query长度偏短,语义信息有限,直接裁剪掉几层Transformer结构对模型的语义表征能力不会有太大的影响。在美团搜索的场景下,Query和Doc拼接后整个文本序列变长,包含更复杂的语义关系,直接裁剪模型会带来更多的性能损失。因此,我们在上线Query-Doc相关性模型之前,采用知识蒸馏方式,在尽可能在保持模型性能的前提下对模型层数和参数做压缩。两种方案的实验效果对比见下表1:
在美团搜索核心排序的业务场景下,我们采用知识蒸馏使得BERT模型在对响应时间要求苛刻的搜索场景下符合了上线的要求,并且效果无显著的性能损失。知识蒸馏(Knowledge Distillation)核心思想是通过迁移知识,从而通过训练好的大模型得到更加适合推理的小模型。首先我们基于MT-BERT(12 Layers),在大规模的美团点评业务语料上进行知识蒸馏得到通用的MT-BERT蒸馏模型(6 Layers),蒸馏后的模型可以作为具体下游任务Fine-tuning时的初始化模型。在美团搜索的场景下,我们进一步基于通用的MT-BERT蒸馏模型(6 Layers)进行相关性任务Fine-tuning ,得到MT-BERT蒸馏(2 Layers)进行上线。
排序服务架构优化
美团搜索线上排序服务框架如上图8所示,主要包括以下模块:
为了进一步提升性能,我们将头部Query进行缓存只对长尾Query进行在线打分,线上预估结合缓存的方式,即节约了GPU资源又提升了线上预估速度。经过上述优化,我们实现了50 QPS下,L2模型TP99只升高了2ms,满足了上线的要求。
线上效果
针对前文所述的各种优化策略,除了离线Benchmark上的效果评测之外,我们也将模型上线进行了线上AB评测,Baseline是当前未做任何优化的排序模型,我们独立统计了各项优化在Baseline基础上带来的变化,由于线上真实环境影响因素较多,为了确保结论可信,我们同时统计了QVCTR和NDCG两个指标,结果如表2所示:
从表2可以看出,各项优化对线上排序核心指标都带来稳定的提升。用户行为数据存在大量噪声不能直接拿来建模,我们基于美团搜索排序业务特点设计了一些规则对训练样本进行优化,还借助POI的品牌信息对样本进行映射和过滤。通过人工对样本进行评测发现,优化后的样本更加符合排序业务特点以及“人”对相关性的认知,同时线上指标的提升也验证了我们优化的有效性。知识融合的BERT模型引入大量结构化文本信息,弥补了POI名本身文本信息少的问题,排序模型CTR和NDCG都有明显的提升。对数据样本的优化有了一定的效果。
为了更加匹配业务场景,我们从模型的角度进行优化,模型损失函数改用排序任务常用的Pairwise Loss,其考虑了文档之间的关系更加贴合排序任务场景,线上排序模型NDCG取得了一定的提升。
本文总结了搜索与NLP算法团队基于BERT在美团搜索核心排序落地的探索过程和实践经验,包括数据增强、模型优化和工程实践。在样本数据上,我们结合了美团搜索业务领域知识,基于弱监督点击日志构建了高质量的训练样本;针对美团搜索多模态特点,在预训练和Fine-tuning阶段融合图谱品类和标签等信息,弥补Query和Doc文本较短的不足,强化文本匹配效果。
在算法模型上,我们结合搜索排序优化目标,引入了Pairwise/Listwise的Fine-tuning训练目标,相比Pointwise方式在相关性判断上更有区分度。这些优化在离线Benchmark评测和线上AB评测中带来了不同幅度的指标提升,改善了美团搜索的用户体验。
在工程架构上,针对BERT在线预估性能耗时长的问题,参考业界经验,我们采用了BERT模型轻量化的方案进行模型蒸馏裁剪,既保证模型效果又提升了性能,同时我们对整体排序架构进行了升级,为后续快速将BERT应用到线上预估奠定了良好基础。
搜索与NLP算法团队会持续进行探索BERT在美团搜索中的应用落地,我们接下来要进行以下几个优化:
参考资料
[1] Devlin, Jacob, et al. “BERT: Pre-training of deep bidirectional transformers for language understanding.” arXiv preprint arXiv:1810.04805 (2018).
[2] 杨扬、佳昊等.美团BERT的探索和实践
[3] 肖垚、家琪等.Transformer在美团搜索排序中的实践
[4] Mikolov, Tomas, et al. “Efficient estimation of word representations in vector space.” arXiv preprint arXiv:1301.3781 (2013).
[5] Peters, Matthew E., et al. “Deep contextualized word representations.” arXiv preprint arXiv:1802.05365 (2018).
[6] Vaswani, Ashish, et al. “Attention is all you need.” Advances in neural information processing systems. 2017.
[7] Radford, Alec, et al. “Improving language understanding by generative pre-training.”
[8] Sun, Yu, et al. “Ernie: Enhanced representation through knowledge integration.” arXiv preprint arXiv:1904.09223 (2019).
[9] Zhang, Zhengyan, et al. “ERNIE: Enhanced language representation with informative entities.” arXiv preprint arXiv:1905.07129 (2019).
[10] Liu, Weijie, et al. “K-bert: Enabling language representation with knowledge graph.” arXiv preprint arXiv:1909.07606 (2019).
[11] Sun, Yu, et al. “Ernie 2.0: A continual pre-training framework for language understanding.” arXiv preprint arXiv:1907.12412 (2019).
[12] Liu, Yinhan, et al. “Roberta: A robustly optimized bert pretraining approach.” arXiv preprint arXiv:1907.11692 (2019).
[13] Joshi, Mandar, et al. “Spanbert: Improving pre-training by representing and predicting spans.” Transactions of the Association for Computational Linguistics 8 (2020): 64-77.
[14] Wang, Wei, et al. “StructBERT: Incorporating Language Structures into Pre-training for Deep Language Understanding.” arXiv preprint arXiv:1908.04577 (2019).
[15] Lan, Zhenzhong, et al. “Albert: A lite bert for self-supervised learning of language representations.” arXiv preprint arXiv:1909.11942 (2019)
[16] Clark, Kevin, et al. “Electra: Pre-training text encoders as discriminators rather than generators.” arXiv preprint arXiv:2003.10555 (2020).
[17] Qiu, Xipeng, et al. “Pre-trained Models for Natural Language Processing: A Survey.” arXiv preprint arXiv:2003.08271 (2020).
[18] Qiao, Yifan, et al. “Understanding the Behaviors of BERT in Ranking.” arXiv preprint arXiv:1904.07531 (2019).
[19] Nogueira, Rodrigo, et al. “Multi-stage document ranking with BERT.” arXiv preprint arXiv:1910.14424 (2019).
[20] Yilmaz, Zeynep Akkalyoncu, et al. “Cross-domain modeling of sentence-level evidence for document retrieval.” Proceedings of the 2019 Conference on Empirical Methods in Natural Language Processing and the 9th International Joint Conference on Natural Language Processing (EMNLP-IJCNLP). 2019.
[21] Wenhao Lu, et al. “TwinBERT: Distilling Knowledge to Twin-Structured BERT Models for Efficient Retrieval.” arXiv preprint arXiv: 2002.06275
[22]Pandu Nayak.
[23] 帅朋、会星等.WSDM Cup 2020检索排序评测任务第一名经验总结
[24] Blei, David M., Andrew Y. Ng, and Michael I. Jordan. “Latent dirichlet allocation.” Journal of machine Learning research 3.Jan (2003): 993-1022.
[25] Jianfeng Gao, Xiaodong He, and JianYun Nie. Click-through-based Translation Models for Web Search: from Word Models to Phrase Models. In CIKM 2010.
[26] Huang, Po-Sen, et al. “Learning deep structured semantic models for web search using clickthrough data.” Proceedings of the 22nd ACM international conference on Information & Knowledge Management. 2013.
[27]SimNet.
[28] Guo T, Lin T. Multi-variable LSTM neural network for autoregressive exogenous model[J]. arXiv preprint arXiv:1806.06384, 2018.
[29] Hu, Baotian, et al. “Convolutional neural network architectures for matching natural language sentences.” Advances in neural information processing systems. 2014.
[30] Pang, Liang, et al. “Text matching as image recognition.” Thirtieth AAAI Conference on Artificial Intelligence. 2016.[31] 非易、祝升等.大众点评搜索基于知识图谱的深度学习排序实践.
[32] 仲远、富峥等.美团餐饮娱乐知识图谱——美团大脑揭秘.
[33] Liu, Xiaodong, et al. “Multi-task deep neural networks for natural language understanding.” arXiv preprint arXiv:1901.11504 (2019).
[34] Burges, Christopher JC. “From ranknet to lambdarank to lambdamart: An overview.” Learning 11.23-581 (2010): 81.
[35] Hinton, Geoffrey, Oriol Vinyals, and Jeff Dean. “Distilling the knowledge in a neural network.” arXiv preprint arXiv:1503.02531 (2015).
[36] Sanh, Victor, et al. “DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter.” arXiv preprint arXiv:1910.01108 (2019).
[37] Jiao, Xiaoqi, et al. “Tinybert: Distilling bert for natural language understanding.” arXiv preprint arXiv:1909.10351 (2019).
[38] Faster Transformer.
作者简介
李勇,佳昊,杨扬,金刚,周翔,朱敏,富峥,陈胜,云森,永超,均来自美团 AI 平台搜索与 NLP 部。
---------- END ----------
招聘信息
美团搜索核心排序组,长期招聘搜索推荐算法工程师,坐标北京。欢迎感兴趣的同学发送简历至:[email protected](邮件标题注明:基础技术部-存储技术中心)
也许你还想看
| 美团BERT的探索和实践
| Transformer 在美团搜索排序中的实践
| 美团大脑:知识图谱的建模方法及其应用