NLP每天都会产生新的令人兴奋的结果,并且它是一个非常大的领域。然而,在与数百家公司合作之后,Insight团队发现一些关键的实际应用程序比其他应用程序出现得更频繁,例如:
虽然有许多线上NLP文件和教程,但我们发现很难找到有效地从底层解决这些问题的指导方针和技巧。
这篇文章解释了如何构建机器学习解决方案来解决上面提到的问题。我们将从最简单的方法开始,然后转向更细致的解决方案,比如特性工程、单词向量和深度学习。
读完这篇文章,你会知道如何:
我们把这篇文章作为一个分步指南;它还可以作为高度有效的标准方法的高级概述。
这篇文章附带了一个交互式笔记本,演示和应用所有这些技术。
交互式笔记本地址:https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb
示例数据来源
每一个机器学习问题都是从数据开始的,比如电子邮件、帖子或推文。文本信息的来源包括:
“社交媒体灾难”数据集
对于这篇文章,我们将使用CrowdFlower提供的称为“社交媒体灾难”的数据集,其中:
参与者查看了超过10,000条推文,其中包括“着火”、“隔离”和“防疫”等各种关键字的搜索,然后指出这条推文是否提到了灾难事件(而不是带有关键字的电影评论或笑话,和一些非灾难性的事件)。
我们的任务是检测哪些推文是关于灾难性事件的,而不是像电影这样无关紧要的话题。这个任务的特别在于,两个类都包含相同搜索词,因此我们将不得不使用更微妙的差异来区分它们。
在这篇文章的余下部分中,我们将把有关灾难的推文称为“灾难”,并把其他的推文称为“无关”。
标签
我们已经标记了数据,因此我们知道哪些推文属于哪个类别。正如Richard Socher所描述的那样,与试图优化复杂的无监督方法相比,用查找和标记足够的数据来训练模型,更快、更简单、成本更低。
Richard Socher的观点
我们遵循的第一条规则是:“数据的好坏影响着你的模型。”
数据科学家的关键技能之一就是知道下一步应该是研究模型还是数据。经验告诉我们应该先查看数据然后再洗数据集。干净的数据集将允许模型学习有意义的特性,而不是过度拟合无关的噪音。
以下是用来清洗你的数据的清单(详见代码):
代码地址:https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb
在遵循这些步骤并检查其他错误之后,我们可以开始使用干净的、标记的数据来训练模型。
机器学习模型以数值作为输入。例如,对图像进行处理的模型,利用矩阵表示颜色通道中每个像素的强度。
以数字矩阵表示的笑脸
我们的数据集是句子的列表,为了让我们的算法从数据中提取模式,我们首先需要找到一种方法以算法能够理解的方式来表示它,也就是一个数字列表。
独热编码(词袋)
表示计算机文本的一种方法是将每个字符单独编码为一个数字(例如ASCII)。如果我们要将这个简单的表示输入到分类器中,那么它必须只根据我们的数据来学习单词的结构,这对于大多数数据集来说是不可能的。我们需要使用更高级的方法。
例如,我们可以在我们的数据集中建立一个包含所有单词的词汇表,并为词汇表中的每个单词创建一个唯一索引。每个句子都被表示成一个列表,这个列表的长度取决于不同单词的数量。在这个列表中的每个索引中,我们标记出给定词语在句子中出现的次数。这被称为词袋模型,因为它是一种完全无视句子中词语顺序的表现形式。以下是插图说明:
把句子表示为词袋。左边是句子,右边是数字表示。向量中的每一个索引都代表一个特定的单词。
可视化嵌入
在“社交媒体灾难”数据集中,我们大约有2万个单词,这意味着每个句子都将被表示成长度为20000的向量。这每个句子只包含了我们词汇量的一小部分。
为了查看嵌入是否捕获了与我们问题相关的信息(例如,推文是否与灾难有关),可视化它们并查看分类是否正确,是一个好方法。由于词汇表是非常大的,并且在20,000个维度中可视化数据是不可能的,像PCA这样的技术将有助于将数据压缩到两个维度。
可视化词袋嵌入
这两个类看起来并没有很好地分离,这可能是嵌入的一个特性,或者仅仅是维度缩减。为了了解这些词袋的特点是否有任何用途,我们可以用它们来训练分类器。
当第一次尝试时,最好的做法一般是从最简单的工具开始着手解决问题。每当提到数据分类时,人们最喜欢用的是逻辑回归。这是非常简单的训练,结果是可以解释的,你可以很容易地从模型中提取最重要的系数。
我们将数据分解到一个训练集中,用于拟合我们的模型和测试集,以查看它对不可见的数据的概括程度。经过训练,我们的准确率达到75.4%。不是太糟糕。
混淆矩阵
第一步是了解我们的模型所犯错误的类型,以及哪些错误是最不可取的。在我们的例子中,误报将一个无关的推文归类为灾难,而漏报则将灾难推文分类为“无关”。如果首要任务是对预测灾难事件,我们就要降低我们的漏报率。如果我们在资源方面受到限制,我们可能会优先考虑降低误报率以减少假警报。一个很好的可视化这个信息的方法是使用混淆矩阵,它比较了我们的模型预测和真实标签。理想情况下,矩阵将是一条从左上到右下的对角线(我们的预测完全符合事实)。
混淆矩阵(绿色是高比例,蓝色是低比例)
我们的分类器的漏报率高于误报率(比例)。换句话说,我们的模型最常见的错误是错误地将灾难分类为“无关”。
解释模型
为了验证我们的模型并解释它的预测,重要的是看一下它用哪些单词来做决策。如果我们的数据有偏差,我们的分类器会在样本数据中做出准确的预测,但是模型在现实世界中不会很好地泛化。在这里,我们为“灾难”和“无关”类找出最重要的单词。用词袋和逻辑回归来绘制单词的重要度是很简单的,因为我们可以提取和排列模型用于预测的系数。
词袋:单词的重要度
我们的分类器正确地选择了一些模式(广岛,大屠杀),但显然似乎是过度拟合一些无意义的术语(heyoo, x1392)。现在,我们的词袋模型是处理大量的词汇,并对所有单词一视同仁。然而,有些词出现频率非常高,而且只会对我们的预测造成干扰。接下来,我们将尝试用一种方法来表示能够解释单词频率的句子,看看是否能从数据中获得更多的信号。
TF-IDF
为了帮助我们的模型更多地关注有意义的单词,我们可以在我们的词袋模型的顶部使用TF-IDF评分(术语频率,逆文档频率)。TF-IDF通过单词在数据集中出现的频率来衡量单词,在我们的数据集里,一些词是非常罕见的,而有些词太过频繁,只会增加噪音。这是我们新嵌入的PCA投影。
可视化TF-IDF嵌入
我们可以看到,这两种颜色之间有更明显的区别。这将使我们的分类器更容易区分两个组。让我们看看这会不会带来更好的性能。在我们新的嵌入式系统上训练另一个逻辑回归,我们得到了76.2%的精确度。
一个轻微的改善。我们的模型是否开始研究更重要的词汇?如果我们得到了更好的结果,同时防止模型“欺骗”我们,那么我们就可以真正地考虑升级这个模型。
TF-IDF:文字的重要度
它挑选的单词看起来更有意义!虽然我们在测试集上的度量只稍微增加了一点,但是我们对我们的模型使用的术语有了更多的信心,因此在将它部署到与客户交互的系统中会更好。
Word2Vec
我们的最新模型设法获得高信号单词。然而,很有可能的是,如果我们部署这个模型,我们将会遇到以前在我们的训练中没有看到的单词。之前的模型将无法准确地对这些推文进行分类,即使在训练过程中看到了非常相似的单词。
为了解决这个问题,我们需要掌握词语的语义。用来帮助我们捕捉语义的工具叫做Word2Vec。
使用预先训练的单词
Word2Vec是一种查找单词连续嵌入的技术。它听过阅读大量的文本来学习,并记住在类似的语境中出现的单词。在对足够的数据进行训练之后,它会在词汇表中为每个单词生成一个300维的向量,这些单词之间的意思相近。
该论文的作者开源了一个在非常大的语料库中预先训练的模型,我们可以利用它将一些语义的知识包含进我们的模型中。预先训练的向量可以在相关的资源库中找到。
论文地址:https://arxiv.org/abs/1301.3781
资源库地址:https://github.com/hundredblocks/concrete_NLP_tutorial
句子层面上的表示
让句子快速嵌入分类器的方法,是平均在我们的句子所有单词的Word2Vec分数。这是与以前方法类似的词袋,但是这次我们只去掉了句子的语法,同时保留一些语义信息。
Word2Vec句子嵌入
下面是我们使用以前的技术实现的新嵌入的可视化:
可视化Word2Vec嵌入
这两组颜色看起来更加分离,我们的新嵌入应该帮助分类器找到两个类之间的分离。在第三次(逻辑回归)训练了相同的模型后,我们的准确率为77.7%,这是我们最好的结果。是时候检查我们的模型了。
复杂性/可解释性权衡
由于我们的嵌入没有像我们以前的模型那样表示为每个单词的一维向量,所以很难看出哪些单词与我们的分类最相关。虽然我们仍然可以使用逻辑回归的系数,但它们与我们的嵌入的300个维度有关,而不是单词的索引。
对于如此低的精确度,失去所有的解释能力似乎是一种苛刻的取舍。但是,对于更复杂的模型,我们可以利用像LIME这样的黑箱解释器来了解我们的分类器是如何工作的。
LIME
Github通过开源软件包提供LIME。黑箱解释器允许用户通过扰动输入(在我们的例子中是从句子中移除单词)和观察预测如何改变来解释任何分类器在一个特定示例上的决定。
Github资源包地址:https://github.com/marcotcr/lime
让我们来看看我们的数据集中的几个句子的解释。
真正的灾难词被识别为“相关”
词语对分类的贡献似乎不那么明显
但是,我们没有时间去探索数据集中的数以千计的例子。我们要做的是在一个有代表性的测试示例样本上运行LIME,看看哪些词对于分类贡献度最高。使用这种方法,我们可以得到单词重要度分数,并验证我们模型的预测。
Word2Vec:文字的重要性
看起来模型提取出了高度相关的单词,这些单词暗示它做出可以理解的决定。这些看起来像是以前所有模型中最相关的词汇,因此我们更愿意部署到生产中。
我们已经介绍了快速有效的方法来生成紧凑的句子嵌入。然而,通过省略单词的顺序,我们放弃了句子的所有语法信息。如果这些方法不能提供足够的结果,则可以使用更复杂的模型,将整个句子作为输入并预测标签,而不需要建立中间表示。一种常见的方法是使用Word2Vec或其他方法,如GloVe或CoVe,将句子作为一个单词向量的序列。
高效的端到端架构
卷积神经网络的句子分类训练非常快,并且适用于作为入门级的深度学习架构。虽然卷积神经网络(CNN)主要以其在图像数据上的性能而著称,但它们在与文本相关的任务上的性能也非常好,而且通常比大多数复杂的NLP方法(例如LSTM和编码器/解码器架构)要快得多。这个模型保存了单词的顺序,并且学习了关于哪些单词序列可以预测目标类的有价值的信息。与以前的模式相反,它可以区分“Alex eats plants”和“Plants eat Alex.”。
训练这个模型不需要比以前的方法做更多的工作(详见代码),并且得到的模型会比以前的好得多,准确率高达79.5%。与上面的模型一样,下一步应该使用我们描述的方法来探索和解释预测,以验证它确实是最佳模型。
代码地址:https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb
成功方法的快速回顾:
这些方法被应用到一个特定的示例案例中,使用定制的模型来理解和利用诸如推文之类的短文本,但是这些想法广泛适用于各种问题。