《第十章》
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
跳字模型(skip-gram):假设基于某个词来生成它在文本序列周围的词。给定中心词“loves”,生成与它距离不超过2个词的背景词“the”“man”“his”“son”的条件概率。
给定中心词生成背景词的概率,如下:
其中,词w,每个词有两个d维向量,为中心词时是v,为背景词时是u。
梯度公式说明了它的计算需要所有词以w_c为中心词的条件概率。
跳字模型的似然函数,即给定任一中心词生成所有背景词的概率:
假设背景窗口大小为m,时间步t,文字长度为T。
训练中,通过最大化似然函数来学习模型参数,等于最小化以下损失函数:
训练过程的梯度使用前面定义的公式,训练结束后,对于词典中的任一索引为i的词,我们均得到该词作为中心词和背景词的两组词向量vi和ui。在自然语言处理应用中,一般使用跳字模型的中心词向量作为词的表征向量。(表征是指可以指代某种东西的符号或信号,即某一事物缺席时,它代表该事物。)
连续词袋模型(continuous bag of words):连续词袋模型假设基于某中心词在文本序列前后的背景词来生成该中心词。连续词袋模型关心的是,给定背景词“the”“man”“his”“son”生成中心词“loves”的条件概率
一般使用连续词袋模型的背景词向量作为词的表征向量。
CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。
练习
每次梯度的计算复杂度是多少?当词典很大时,会有什么问题?
答:每一步的梯度计算都包含词典大小数目V。当然,CBOW的激素计算复杂度要高于Skip-Gram,主要体现在求单个的概率P的时候,CBOW需要计算多个背景词求和后再进行点积运算。而Skip-Gram直接中心词和背景词点积。
英语中有些固定短语由多个词组成,如“new york”。如何训练它们的词向量?提示:可参考word2vec论文第4节 [2]。
答:通过下面的公式,将评分高的当作一个短语。δ主要是作为一个折扣系数防止太多的短语组成非常罕见的词被形成。
让我们以跳字模型为例思考word2vec模型的设计。跳字模型中两个词向量的内积与余弦相似度有什么关系?对语义相近的一对词来说,为什么它们的词向量的余弦相似度可能会高?
答:余弦相似度是交集除以并集,两个词向量的内积是交集。词向量如果使用one-hot方式表示,余弦相似度表示了向量在方向上的距离。单词的语义接近,说明它在某些地方是可以被替换成另外一个单词的,或者使用的方式是类似的。所以在高维空间中,其方向是接近的,余弦相似度自然也高。
近似训练:由于跳字模型和连续词袋模型的梯度计算的复杂度较高,使用近似计算的方法,来简化复杂度。
负采样(negative sampling):使用负的样本来简化计算。
层序softmax(hierarchical softmax):
练习
在阅读下一节之前,你觉得在负采样中应如何采样噪声词?
答:随机取样?均衡取样?
本节中最后一个公式为什么成立?
答:对于任意两个拥有同个父节点的子结点,相加等于其父结点。所以所有叶子结点之和等于倒数第二层结点之和,等于倒数第三层,直至等于根结点,等于1。
如何将负采样或层序softmax用于训练连续词袋模型?
答:不确定。负采样思路:
虽然两个模型中u和v表示的分别相反的背景词和中心词,但是数学上可以看成是类似的计算。从而代入负取样的设计方法中。将u和v分别替换成连续词袋模型的。
softmax思路:同上相似。
二次采样:计算出一个词语被丢弃的概率。(越高频越容易丢弃)
提取中心词和背景词:
负采样:
swapaxes(a,b):将第a维和第b维调换,类似于transpose。
nd.batch_dot(X, Y):给定两个形状分别为( n , a , b )和( n , b , c )的NDArray,小批量乘法输出的形状为( n , a , c )
练习
在创建nn.Embedding
实例时设参数sparse_grad=True
,训练是否可以加速?查阅MXNet文档,了解该参数的意义。
答:
sparse_grad (bool) – If True, gradient w.r.t. weight will be a ‘row_sparse’ NDArray.加速了两三秒。代表使用稀疏行来计算梯度权重。但只有一部分优化算法支持稀疏梯度,包括SGD,AdaGrad,Adam.
我们用batchify
函数指定DataLoader
实例中小批量的读取方式,并打印了读取的第一个批量中各个变量的形状。这些形状该如何计算得到?
答:批量为512,中心词只有1个,60是最大长度
试着找出其他词的近义词。
调一调超参数,观察并分析实验结果。
答:学习率0.01,结果差不多。批量1024,学习率0.01,结果差不多。批量1024,学习率0.02,结果略差。
修改embed_size=250,批量1024,学习率0.02,效果提高。
注:embedding层主要起到了降维的作用,embed_size稍高,保留了较多特征,故而loss更低。
当数据集较大时,我们通常在迭代模型参数时才对当前小批量里的中心词采样背景词和噪声词。也就是说,同一个中心词在不同的迭代周期可能会有不同的背景词或噪声词。这样训练有哪些好处?尝试实现该训练方法。
答:节约时间,迭代的时候才采样,避免在一开始采样数据集时候使用了过多的时间。另外当前小批量里德背景词和噪声词之和的最大值,比较小,避免填充了太多,浪费空间。不会实现。
将单词当成一个由字符构成的序列来提取n元语法。例如,当n=3时,我们得到所有长度为3的子词:“”以及特殊子词“”。
将它所有长度在3∼6的子词和特殊子词的并集记为Gw,假设词典中子词g的向量为zg
计算复杂度更高。但较生僻的复杂单词,甚至是词典中没有的单词,可能会从同它结构类似的其他词那里获取更好的词向量表示。
练习
子词过多(例如,6字英文组合数约为3×10^8)会有什么问题?你有什么办法来解决它吗?提示:可参考fastText论文3.2节末尾 [1]。
答:会导致很多重复的子词在不同地方出现。使用一个特殊的哈希函数Fowler-Noll-Vo来存储字符。最终一个单词通过索引和n元语法的哈希来表示。
We hash character sequences using the Fowler-Noll-Vo hashing function (specifically the FNV-1a variant).We set K = 2.10^6 below. Ultimately, a word is represented by its index in the word dictionary and the set of hashed n-grams it contains.
如何基于连续词袋模型设计子词嵌入模型?
答:(不确定)将上述子词嵌入中的中心词改为背景词。词典中子词g的向量为zg
这一章比较不理解。希望在之后的应用环节能够再学到代码。
原来的跳字模型如下:
GloVe模型改进的地方:
练习
如果一个词出现在另一个词的背景窗口中,如何利用它们之间在文本序列的距离重新设计条件概率pij的计算方式?(提示:可参考GloVe论文4.2节 [1]。)
答:论文中没找到参考方法。仅有文中的"如果词wi出现在词wj的背景窗口里,那么词wj也会出现在词wi的背景窗口里。也就是说,x_ij=x_ji。不同于word2vec中拟合的是非对称的条件概率p_ij,GloVe模型拟合的是对称的log(x_ij)。因此,任意词的中心词向量和背景词向量在GloVe模型中是等价的。"
对于任意词,它在GloVe模型的中心词偏差项和背景词偏差项是否等价?为什么?
答:是,因为任意词的中心词向量和背景词向量在GloVe模型中是等价的。
近义词:通过KNN挑选TopN的作为近义词。
类比词:有关系的,可以类比的,例如最高级和普通级,形容词和名词等
'woman'-'man'+'son'='daughter'
练习
测试一下fastText的结果。值得一提的是,fastText有预训练的中文词向量(pretrained_file_name='wiki.zh.vec'
)。
答:近义词很糟糕,比较少遇到符合语义上的近义词。
类比词也不好,一般结果都是输出原来的。
如果词典特别大,如何提升近义词或类比词的搜索速度?
答:生成时排序,而后二分查找?通过哈希算法,提高搜索速度?
情感分析(sentiment analysis):使用文本情感分类来分析文本作者的情绪。
练习
增加迭代周期。训练后的模型能在训练和测试数据集上得到怎样的准确率?再调节其他超参数试试?
答:增加迭代周期后,训练集准确率一直提高,测试集提高仅到0.855左右,过拟合了。
使用更大的预训练词向量,如300维的GloVe词向量,能否提升分类准确率?
答:遇到了 Check failed: e == CUDNN_STATUS_SUCCESS (4 vs. 0) : cuDNN: CUDNN_STATUS_INTERNAL_ERROR
可能是因为显存或内存不够或者cudnn驱动有问题?
可以正常训练三轮,第四轮时候出问题了。目测分类精确率没有显著提高。
使用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 -m spacy download en
需要用管理员的方式打开命令行再执行。精确率有提高,两轮便达到0.857的概率,媲美之前的五轮周期。但第三轮超过0.86后,便很快过拟合,开始下降了。
练习
动手调参,从准确率和运行效率比较情感分析的两类方法:使用循环神经网络和使用卷积神经网络。
答:从运行效率和准确率上,卷积神经网络均优于循环神经网络。
使用上一节练习中介绍的3种方法(调节超参数、使用更大的预训练词向量和使用spaCy分词工具),能使模型在测试集上的准确率进一步提高吗?
答:使用300维的词向量,准确率达到0.87左右。使用spaCy工具,再100维的词向量,准确率达到0.86。
还能将textCNN应用于自然语言处理的哪些任务中?
答:TextCNN对文本浅层特征的抽取能力很强,在短文本领域如搜索、对话领域专注于意图分类时效果很好,应用广泛,且速度快,一般是首选;对长文本领域,TextCNN主要靠filter窗口抽取特征,在长距离建模方面能力受限,且对语序不敏感。
强制教学(teacher forcing):它是一种网络训练方法,对于开发用于机器翻译,文本摘要,图像字幕的深度学习语言模型以及许多其他应用程序至关重要。它每次不使用上一个state的输出作为下一个state的输入,而是直接使用训练数据的标准答案(ground truth)的对应上一项作为下一个state的输入。
编码器用来分析输入序列,解码器用来生成输出序列。(是一种循环神经网络)两者都可以用于不定长序列。
编码器、解码器最后有“”(end of sequence)以表示序列的终止。
解码器最初有“”(beginning of sequence)表示序列开始。
编码器(encoder):作用是把一个不定长的输入序列转换成一个定长的背景向量c,该背景向量包含了输入序列的信息,常用的编码器是循环神经网络。
解码器(decoder):假设编码器输入x1,x2,...,xt经过变换后变成隐藏变量h1,h2,...,ht,然后进入c,解码器通过c获取编码器的内容,进行变换后得到输出y1,y2,yt`。
理解:解码器和编码器都可以使用循环神经网络来实现,都用到了上一个时间步的输入或输出。
练习
除了机器翻译,你还能想到编码器-解码器的哪些应用?
答:用于CV:
Encoder: 本身其实就是一连串的卷积网络。该网络主要由卷积层,池化层和BatchNormalization层组成。 卷积层负责获取图像局域特征,池化层对图像进行下采样并且将尺度不变特征传送到下一层,而BN主要对训练图像的分布归一化,加速学习。 Decoder: 既然Encoder已经获取了所有的物体信息与大致的位置信息,那么下一步就需要将这些物体对应到具体的像素点上 Decoder对缩小后的特征图像进行上采样,然后对上采样后的图像进行卷积处理,目的是完善物体的几何形状,弥补Encoder当中池化层将物体缩小造成的细节损失。
概括地说,encoder对图像的低级局域像素值进行归类与分析,从而获得高阶语义信息(“汽车”, “马路”,“行人”),Decoder收集这些语义信息,并将同一物体对应到相应的像素点上,每个物体都用不同的颜色表示。
有哪些方法可以设计解码器的输出层?
答:seq2seq是RNN和RNN的结合。在编码器-解码器框架中,CNN和RNN可以杂交,谁充当编码器,谁充当解码器,都是可以的,可灵活组合用于各种不同的任务。
贪婪搜索(greedy search):每一次搜索,选择最值来组合结果。
穷举搜索(exhaustive search):穷举所有的组合。
束搜索(beam search):每一次搜索,选择前n个值,来组合加过。
练习
穷举搜索可否看作特殊束宽的束搜索?为什么?
答:可以,因为穷举等于束宽最大的束搜索。
在“循环神经网络的从零开始实现”一节中,我们使用语言模型创作歌词。它的输出属于哪种搜索?你能改进它吗?
答:predict_rnn()函数属于贪婪搜索Y[0].argmax(axis=1).asscalar()
这一句选择了Y中最大的值,可以使用束搜索改进。
注意力机制(Attention):以循环神经网络为例,注意力机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每一时间步调整这些权重,即注意力权重,从而能够在不同时间步分别关注输入序列中的不同部分并编码进相应时间步的背景变量。
计算背景变量:
X表示乘以权重,a表示函数,可以有多种选择,内积(如果输入向量长度相同),或者如下:
矢量化(向量)计算:在上面的例子中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。
更新隐藏状态:使用GRU门控循环单元为例。
注意力机制能够为表征中较有价值的部分分配较多的计算资源。
练习
为什么不可以将解码器在不同时间步的隐藏状态连结成查询项矩阵Q,从而同时计算不同时间步的含注意力机制的背景变量c?
答:因为softmax函数是将所有的数组元素均参与进去计算,而不是每一行的计算。
不修改“门控循环单元(GRU)”一节中的gru
函数,应如何用它实现本节介绍的解码器?
答:把背景向量c和分别和三个权重W_cr,W_cz,W_cs点乘后,再分别于b_r,b_z,b_s相加。然后当成三个偏差b_r,b_z,b_h传入下面函数。
机器翻译:将一段文本从一种语言自动翻译到另一种语言。
nd.ones((1,20)).squeeze(axis=0):将第一个维度挤掉,跟expand_dims(axis=0)相反。
jupyter魔法命令:
%lsmagic:查看所有的魔法命令。
%%time:给出cell的代码运行一次所花费的世界。
%timeit statement_name:空格后加代码,可以测出一行所用的时间。
%prun statement_name: 产生一个有序表格来展示在该语句中所调用的每个内部函数调用的次数,每次调用的时间与该函数累计运行的时间。
!shell_commend:执行shell命令有可以添加自动填充和代码美化的技术,下一步研究。
BLEU(Bilingual Evaluation Understudy):评价机器翻译结果常使用的系数。
当预测序列和标签序列完全一致时,BLEU为1;
其中exp部分是惩罚系数。
练习
如果编码器和解码器的隐藏单元个数不同或隐藏层个数不同,该如何改进解码器的隐藏状态的初始化方法?
答:在下方函数中根据enc_state,进行reshape。
在训练中,将强制教学替换为使用解码器在上一时间步的输出作为解码器在当前时间步的输入,结果有什么变化吗?
答:使用如下函数出现格式不兼容,使用了reshape([-1])后,也不符合。测试发现,dec_output是(2,39),reshape是(2),不知如何作为输入,按行求和?也不行,出现错误“Embedding layer doesn't support calculate data gradient”。
试着使用更大的翻译数据集来训练模型,如WMT [2] 和Tatoeba Project [3]。
答:不测了。