【58 同城】语言模型及其应用


本文地址:http://www.6aiq.com/article/1551014338548
知乎专栏 点击关注
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出

1. 背景

语言模型在自然语言处理具有重要的地位,它是一种基于概率统计的模型,主要的目标是描述字 / 词在句子中的概率。同时,语言模型是从大量的语料信息中训练出的模型,它“学习”到的词的概率是通用语义的信息,可以和很多实际应用相结合,尤其是在一些基于统计模型的领域,如语音识别,分词,情感分析以及机器翻译等领域,有着广泛的应用。近些年随着各种新的算法的出现以及模型结构的改进,语言模型的性能也在逐渐进步,在很多应用场景,尤其是语音识别和机器翻译等领域,取得了很好的效果。

在 58 集团这样的分类网站的业务背景下,语言模型也有很多的实际应用的场景。例如,58 的租房,二手房等业务,每天都有大量的发帖,用户在搜索这些帖子后的展示顺序是非常重要的,我们希望将最优质和最适合的帖子展示在网页的最前面,以提高服务的质量。语言模型则可以根据这些帖子的内容,评价帖子的文本质量,并作为帖子的一个质量因子,参与帖子的排序。在这篇文章中,我们也将主要讲解语言模型的构建,及其在 58 相关业务的帖子文本质量评价上的应用。

2. 语言模型简介

语言模型是用来表示某一种语言的概率模型,其目的是描述给定词序列的概率分布,也就是计算一个句子 / 段落 / 文档的概率,或者说,就是判断一句话符合自然语言的表达习惯的可能性。经过近二三十年的发展,主流语言模型的实现方法也经历了从 n-gram、RNN 到 LSTM、GRU 等方法过程,如图 1 所示。

图 1 语言模型的发展历程

一段文字是不是自然语言,可以通过这段文字的概率分布进行判断。当然我们无法确切的给出“是”或者“否”的答案,但是我们可以通过这段文字的概率分布,来确定其是自然语言的“可能性”的大小。比如有一段文字,由 w1, w2, w3, …., wm 这 m 个词构成,一般我们可以通过以下方式来计算其联合概率:

也就是当前的词出现的概率,是和这个词之前的所有词都是相关的。但基于马尔可夫假设,可以简化语言模型的计算,即 wi 出现的概率只和 wi 之前的 n-1 个词有关,这就是 n-gram 语言模型。如果词表大小为 _|V|, 那么对于 n-gram 来讲,就需要一个|V|n_ 规模的矩阵来存储,随着 n 的增大,需要的内存也会指数级增长。一般而言,n 等于 5,就已经会占用很大的存储空间了。

为了解决 n-gram 的局限性,即 n-gram 模型的参数随着 n 呈指数级增长,Bengio 等人在 2003 年提出了使用循环神经网络(Recurrent NeuralNetwork, RNN)来实现语言模型。循环神经网络理论上可以“向前看”任意多个词,而所需的存储空间并不会指数级增长,而是和词表的大小规模相关。

即便 RNN 理论上 RNN 可以“记忆”某个词之前很长的内容,但是训练起来是比较困难的,往往伴随着梯度爆炸和梯度消失的问题, 通常梯度爆炸可以通过 Gradient Clipping 的方式解决,而解决 RNN 的梯度消失问题,可以通过替换激活函数(比如将激活函数从 sigmoid 换为 relu)来解决,但更好的方式是使用 LSTM 等改进版的循环神经网络。LSTM 早在 1997 年就由 Schmidhuber 等人提出,但直到 2007 年之后 ,LSTM 及其一些改进的模型,才开始在各个领域逐渐超越传统模型。近些年随着各种改进版的 LSTM 结构出现,如 GRU,BiLSTM 等, 语言模型的性能也在不断改进。因此在实际的应用中,我们也采用了 LSTM 的结构来实现语言模型。

3. 语言模型训练和部署

完成一个语言模型,一般需要三个步骤,分别是数据的准备,训练调参,以及导出模型,如果需要线上预测,还需要将模型部署在线上提供服务,整体的过程如图 2 所示。

图 2. 语言模型的实现流程

3.1 数据准备

数据准备是训练模型的第一步,如果数据的获取、清洗和预处理没有做好,之后训练的模型的效果会受到严重的影响,所以数据的准备是非常重要的。在准备数据的时候,需要获取与业务相关的数据,例如我们在做 58 租房或二手房帖子文本质量评测的时候,就需要获取租房或二手房的历史帖子的内容;同时数据要尽可能的均衡,例如可以随机抽取过去 30 天的 50 万条的帖子数据,然后进行清洗和预处理。数据清洗的目的是,使清洗后的数据是“高质量”的文本,这样使用这些“高质量”文本训练出的模型才能够更准确地识别出“低质量”的帖子内容。

以用于文本质量评测的语言模型训练为例,我们可以进行以下数据的处理:

  • 删除不相关的内容。例如,去掉无用的标题、链接、广告内容等。

  • 一些特殊符号的处理。例如,删除文本中的换行符 \r, 软键盘字符,表情符号等。

  • 标点符号的处理。一般而言,标点符号是停用词的一种,通常要删掉。

  • 停用词的处理。对于一些语气词,虚词,代词,或者没有特定含义的词等,可以作为停用词被删掉。

  • html 文本处理。对于带有 html 标签的文本,需要去掉这些标签并还原文本的格式。

  • 文字编码。在训练模型之前,需要对语料进行“数字”编码。最简单的编码方式是 one-hot 编码。但由于 one-hot 编码比较稀疏,而且当语料的词汇数很大时,编码的维度也会变得很大,所以一般采用其他的编码或多种编码相结合的方式,比较常见的是 embedding 的编码方式,编码维度相比于 one-hot 大大降低,模型训练速度也会加快很多。

  • 数据分批训练。为了加快训练速度,一般将语料分成多个 batch,分批输入模型进行训练。

3.2 模型训练

首先要确定训练模型使用的损失函数和优化方法。LSTM 模型采用的是交叉熵损失函数,具体的是将预测值 prediction 和目标值 target 之间的交叉熵作为目标函数。LSTM 的优化方法有很多种,例如 SGD, RMSprop 等,而在实际应用中发现 Adam 优化方法的效果很不错,通常要好与其他几种优化方法。值得注意的是,语言模型的通用衡量指标“困惑度”(perplexity)和交叉熵损失的内涵是一致的,它们是呈指数关系的,具体的表达式是 perplexity =2cross_entropy,因此困惑度有时也可以作为模型训练的损失函数。

其次我们简单描述一下语言模型的训练过程和数据维度。

  • 训练语言模型时,一般是一批一批地输入数据进行训练,每一批数据让多个句子(batch_size)同时训练。

  • 每个句子的单词数为 num_steps,在 LSTM/RNN 中,句子长度就是时间步(time step)的长度,因此 num_steps 既代表了 LSTM 模型的时间序列的长度,也代表了句子长度。

  • 在自然语言处理中,每个词(或者汉语中的字)都是用词向量来表示的,可以采用 one-hot 或者 embedding 的方式将词编码成词向量。通常在 tensorflow 中使用 embedding 的方式对词进行编码,编码的维度对应的是 embedding_size。因此实际上每次输入到 LSTM 模型中的数据的大小是:batch_sizenum_stepsembedding_size。



  • LSTM 每个单元有 4 个神经网络,神经网络的隐藏层的节点数为 hidden_size, 那么这个 LSTM 单元中就有 4*hidden_size 个隐藏单元。

  • 每个 LSTM 的输出都是向量,包括状态向量 Ct 和输出向量 ht,它们的长度都是当前 LSTM 单元的 hidden_size。

  • LSTM 的输出通常要加一个 softmax 全连接层,将输出映射到“词汇表”的维度,最终的输出值则是“词汇表”中每个字的“概率值”。

根据输出值,可以使用交叉熵损失或者困惑度(perplexity)来表征模型的好坏。同时在使用训练之后的语言模型进行文本质量评价时,我们也可以使用困惑度来表征文本质量的高低。

在训练的过程中,通常也有一些常用的技巧。例如:

  • 为了防止过拟合,一般要在 LSTM 单元中加上 dropout 层。

  • 数据集的编码不要直接采用 one-hot,因为过于稀疏以及维度较大,通常使用 embedding 的方式作降维,例如将 embedding size 设置为 128 左右。

  • 在设置学习率的时候,可以先将学习率设置的较大一些,然后逐渐降低学习率,或者使用 early stopping(早停法),当训练的模型在验证集上效果逐渐变差时,停止训练。

  • 采用多层 LSTM 的时候,增加层数不一定会增加模型的准确率,通常 2~3 层就足够,在一些情况下 2 层 lstm layer 就能保证较高的准确率,而且参数会少很多,训练和预测速度也会加快。

  • 复杂的 LSTM 的结构不一定会提高模型的准确率,而且过于复杂的结构会增加参数的数量,在训练和线上预测时,会严重影响速度。因此需要根据实际情况选择合适的模型结构和参数。

最后简单介绍一下对模型性能的评估。上面我们已经提到了使用交叉熵损失或“困惑度”(perplexity)来作为语言模型的损失函数,困惑度的物理上的含义是指,“如果根据语言模型随机地挑选词语,那么平均需要挑选多少次才能挑到正确的词”[参考论文:NeuralMachine Translation and Sequence-to-sequence Models: A Tutorial],也就是说困惑度越小,被挑选的词就越“确定”、“范围越小”,概率越大。相应的,如果使用“困惑度”来评价文本质量,输入语言模型的文本越是符合自然语言的习惯,语言模型针对这段文本给出的概率值就越大,相应的“困惑度”也就越低,同时我们可以根据“困惑度”的值,做一些处理(例如归一化处理),作为文本的质量分数。

但是单从“困惑度”,或者“损失函数”在训练过程中判断语言模型的好坏,是不够直观的,通常还可以使用另一种方式,比如使用语言模型来生成一段文本等具体任务,人为的观察语言模型的好坏。因此,可以每训练几轮存储一个临时的 checkpoint 模型,然后执行一些具体任务,比如生成一段和租房业务相关的文本,通过观察这段文本的通顺程度、合理程度,来直观上判断训练出的模型的性能。

3.3 模型导出和部署

在模型训练完成之后,需要将模型部署到线上,提供预测服务。在上线之前,我们需要将训练好的模型导出,在实际使用 tensorflow 搭建和训练模型时,通常会用到以下几种模型格式来导出和存储训练模型,这些模型的应用场景是有所不同的,需要根据特定的场景进行选择。

  • checkpoint 格式:保存的是模型的权重,只包含 variables 对象序列化后的数据,但不包括图结构,所以需要提供代码才能重建计算图。checkpoint 模型主要用于模型训练过程中参数的备份和模型训练热启动。在训练中,可以每隔几个 epoch 会存储一次 checkpoint 模型,然后调用并查看模型的效果,比如在训练语言模型时,可以调用导出的 checkpoint 模型来自动生成一段文本,观察是否通顺,从直观上判断训练的模型的好坏。

  • GraphDef 格式:这种格式包含了 protobuf 对象序列化之后的数据和计算图,可以从中获取 operators,tensors 和 variables 的定义,但是不包括 variables 的值,所以训练的权值仍然需要从 checkpoint 格式的模型中恢复。

  • SavedModel 格式:这种格式是用于 Tensorflow Serving 的,该格式可以看做 GraphDef 和 checkpoint 的结合,此外在使用的时候还需要指定模型的输入和输出参数的 SignatureDef,以便在调用模型的时候传递输入输出数据。在实际上线模型对外提供服务的时候,一般需要采用这种格式的模型。

上面已经提到,通常使用 SavedModel 格式的模型用于线上服务,我们在实际的上线中也使用了 SavedModel 模型。Google 官方提供了 Tensorflow Serving 的框架,可以实现从模型应用到实际生产的解决方案。Tensorflow serving 提供了基于 gRPC 的客户端和服务端的通信,而且可以进行模型热更新和自动的模型版本管理,这样使用者只需要关注线下的模型训练即可,而不必花很大的精力在线上服务上。在 58 集团内部平台则提供了 SCF 服务来调用 Tensorflow serving 方式,更加的方便快捷,用户只需要将输入数据封装,然后发送到服务端;Tensorflow serving 接收到请求后,返回模型的计算结果给 SCF 客户端,即完成了一次输入到预测的流程。

4. 语言模型的应用

模型部署完毕之后,就可以使用语言模型提供线上服务了,在我们的实际场景中,主要尝试了文本质量评价和文本生成两方面的应用。结合上面的介绍,我们在图 3 中简要的概括了的语言模型在一个实际应用的流程,整体上分为:数据准备、模型训练、线上部署和实际应用四个步骤。在接下来的内容中,我们将更加具体的介绍语言模型在这两种实际应用中的一些细节。

图 3. 语言模型在实际应用场景中的流程

4.1 文本质量评价

在根据特定业务的语料(例如租房业务)训练语言模型之后,我们可以使用这个语言模型来对业务相关的帖子进行质量评价。通常帖子质量是有不同的评价维度的,可以是和具体业务相关的,例如租房帖子中房子的户型,面积,地理位置等;也可以是和帖子本身相关的,例如帖子内容的文本质量,而语言模型可以在文本质量评价上发挥作用。

在训练语言模型的时候我们已经提到了一个概念,叫做“困惑度”(perplexity),它和交叉熵损失本质上是等价的,可以作为训练模型时的目标函数,同时可以用来衡量文本符合自然语言表达习惯的程度。因此可以将“困惑度”作为一个度量的指标来判断帖子文本的内容是否合理通顺。

比如,可以将租房、二手房等帖子的内容作为输入,使用相应的语言模型计算帖子内容的“困惑度”,作为衡量帖子好坏的一个质量因子。具体地,当我们在使用语言模型评价 58 集团的租房网站上的帖子时,如果帖子中有较多的乱码,或者较多不相关的广告宣传,或者语句不通顺等,通过语言模型计算出来的“困惑度”就会较高,对应的帖子的质量分数也就会比较低。在实际应用中,我们会将语言模型评价出的文本质量分数,作为帖子的一个质量因子,参与线上帖子的排序。

此外,为了进一步保证语言模型对文本质量的评分是合理的,我们还需要将语言模型打分和人工打分进行对比。在实际的应用中,我们采用的方法是,首先使用语言模型对大量帖子进行质量评分;然后根据帖子的质量分数以及设定的质量分阈值,从这些帖子中随机选出“高、中、低”质量的帖子各若干条;之后人工对这些帖子进行评分,并对比语言模型评分和人工评分的结果。例如针对实际的个人租房业务的帖子的文本质量评分,如果以人工评分作为对比的标准,语言模型评价“高质量”和“中等质量”帖子的平均准确率在 90% 以上,在评价“低质量”帖子时的平均准确率在 95% 以上。由于我们在训练语言模型时使用的数据都是经过预处理和清洗的“高质量”文本数据,所以在挑选“低质量”的帖子内容的时候,准确率相对更高。在实际应用时,我们可以使用语言模型针对性地筛选“低质量”的帖子,在线上排序时对这些帖子进行降序。

同时,对于文本质量的评测有很多种方法,除了语言模型的方法,使用一些人工规则,例如过滤词规则,垃圾文本分类,非法联系方式筛选等,也会产生很明显的效果。在实际的应用中,如果将这些规则和语言模型的文本质量评价相结合,共同作为帖子内容的质量因子,会进一步提升文本质量的评测的维度和准确率。

4.2 文本生成

前面说到,语言模型是一个关于词序列的概率模型,也就是说下一个字 / 单词出现的概率取决于之前的字 / 词。根据这个原理,我们可以提供一个“种子”(seed)词,利用语言模型生成“种子”词之后的文本。此外,在根据“种子”词生成文本时,可以通过一种“top K 采样”的方法,增加文本生成的丰富度。例如,当语言模型的输入是“小区附近”时,如果在选择下一个字的时候只选择概率最大的,那么生成的句子是唯一的。如果在选择下一个字的时候,从 K 个(通常 K 取 3~5)最大概率的字中随机选择一个,然后重复使用 top K 采样得到下一个字,那么生成的文本多样性就会增加很多。比如输入“xx 小区附近”,生成的文本可能是“xx 小区附近交通方便”,也可能是“xx 小区附近生活便利”等。

因此可以利用“文本生成”的方法和思路,当用户在特定业务(例如租房)网站进行相关的搜索时,对搜索词进行纠错、补全,或者提供备用的搜索选项,可以保证用户在搜索时搜索词的准确性,减少出现同音字,错别字,拼音的情况,为用户提供更好更精准的搜索。

此外,“文本生成”可以用来判断训练过程中语言模型训练的好坏。之前提到,使用交叉熵损失或者困惑度来判断语言模型的好坏只能进行“数值”上的判断,如果每隔几个训练节点,使用当前正在训练语言模型生成一段文本,并观察文本是否通顺,是否符合自然语言表达习惯,可以更加直观的判断语言模型训练的好坏,以及在训练过程中是否产生了过拟合等。

5. 总结

语言模型是描述文本的概率分布的模型,它可以用来衡量文本内容是否合理,是否符合自然语言的表达习惯。目前语言模型通常使用传统 RNN,LSTM,GRU 等网络结构来进行训练,而 LSTM 是其中比较常用并且效果很好的一种。本文从语言模型的概念,训练,上线和应用等方面对其进行了简单的介绍。在实际的应用中,通过线上服务,可以方便的调用语言模型进行帖子文本质量评价,文本生成等任务。同时这个领域也在不断的进步和发展中,相信在未来会出现性能更出色的算法和模型,在自然语言处理应用上,尤其是在“中文”相关的应用领域更进一步。


本文地址:http://www.6aiq.com/article/1551014338548
知乎专栏 点击关注
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出