以数据为中心的机器学习——构建Shopify Inbox的信息分类模型

219 阅读15分钟

以数据为中心的机器学习。建立Shopify Inbox的信息分类模型

Shopify Inbox是一个单一的商业聊天应用程序,它在一个地方管理所有Shopify商家的客户沟通,并将聊天转化为转化。在我们开发产品的过程中,了解商家的客户如何使用聊天应用程序对我们来说至关重要。他们是否在寻找产品推荐?想知道一件商品是否能运送到他们的目的地?还是他们只是在打招呼?有了这些信息,我们就可以帮助商家优先考虑那些可以转化为销售的回复,并指导我们的产品团队下一步要建立什么功能。然而,由于Shopify收件箱中每月有数百万条独特的信息交流,这将是一项具有挑战性的自然语言处理(NLP)任务。

不过,我们的团队不需要从头开始:每个人都可以广泛使用现成的NLP模型。考虑到这一点,我们决定采用一种新近流行的机器学习过程--以数据为中心的方法。我们希望专注于在我们自己的数据上对这些预训练的模型进行微调,以产生最高的模型精度,并为我们的商户提供最佳体验。

Shopify收件箱的信息分类

我们将分享我们通过应用以数据为中心的方法为Shopify Inbox建立一个信息分类模型的历程。从定义我们的分类标准到仔细训练我们的标注者,我们将深入探讨以数据为中心的方法,加上最先进的预训练模型,如何导致我们现在在生产中运行的非常准确的预测服务。

为什么采用以数据为中心的方法?

传统的机器学习开发模式是从获取训练数据开始的,然后陆续尝试不同的模型架构来克服任何糟糕的数据点。这种以模型为中心的过程通常是由那些希望推进最先进技术的研究人员或那些没有资源来清理众包数据集的人所遵循的。

相比之下,以数据为中心的方法侧重于反复使训练数据变得更好,以减少不一致的地方,从而为一系列模型产生更好的结果。由于任何人都可以下载一个性能良好的预训练模型,所以获得一个高质量的数据集是能够产生一个高质量系统的关键区别。在Shopify,我们相信,更好的训练数据产生的机器学习模型可以更好地服务于我们的商户。如果你有兴趣听到更多关于以数据为中心的方法的好处,请查看Andrew Ng关于MLOps:从以模型为中心到以数据为中心的演讲。

我们的第一个原型

我们的第一步是建立一个内部原型,我们可以快速发货。为什么?我们想建立一个能让我们理解买家所说的东西。它不需要完美或复杂,它只需要证明我们可以提供有影响力的东西。我们可以在之后进行迭代。

对于我们的第一个原型,我们不想在探索上花很多时间,所以我们必须用有限的资源构建模型和训练数据。我们的团队选择了TensorFlow Hub上的一个预训练模型,叫做Universal Sentence Encoder。这个模型可以为整个句子输出嵌入,同时考虑到单词的顺序。这对于理解含义至关重要。例如,下面的两条信息使用了相同的词组,但它们的情感非常不同:

  • "爱!请再来点。不要停止烘烤这些饼干。"
  • "请不要再烤更多的饼干了!不要爱这些。"

为了快速建立我们的训练数据集,我们试图使用各种降维和聚类技术,包括UMAPHDBScan,来识别具有相似含义的消息组。在手动将主题分配给大约20个信息群组之后,我们应用了一种半监督技术。这种方法需要少量的标记数据,结合大量的无标记数据。我们从每个主题中手工标记了一些有代表性的种子信息,并利用它们来寻找更多相似的例子。例如,给定一个 "你能帮我订购吗?"的种子信息,我们使用嵌入来帮助我们找到类似的信息,如 "如何订购?"和 "我如何能得到我的订单?"。然后我们从这些信息中取样,反复建立训练数据。

在我们的一次探索中,信息集群的可视化。

我们用这个数据集来训练一个简单的预测模型,包含一个嵌入层,然后是两个完全连接的密集层。我们的最后一层包含了用于预测类的数量的logits数组。

这个模型给了我们一些有趣的洞察力。例如,我们观察到很多聊天信息都是关于订单的状态。这有助于我们决定建立一个订单状态请求,作为Shopify Inbox的即时解答FAQ功能的一部分。然而,我们的内部原型有很大的改进空间。总的来说,我们的模型达到了70%的准确率,只能对35%的信息进行高置信度的分类(我们称之为覆盖率)。虽然我们使用嵌入法给信息贴标签的方法很迅速,但标签并不总是每条信息的基本事实。很明显,我们还有一些工作要做。

我们知道,我们的商户生活繁忙,希望对买家信息作出快速反应,因此我们需要提高2.0版本的准确性、覆盖率和速度。希望遵循以数据为中心的方法,我们专注于如何改进我们的数据以提高我们的性能。我们决定投入更多的精力,通过重新审视信息标签来定义训练数据,同时也得到帮助,对更多的信息进行人工注释。我们试图以一种更系统的方式来做这一切。

创建一个新的分类法

首先,我们深入研究了用于训练原型的话题和信息集群。我们发现有几个广泛的主题包含了数百个例子,这些例子混淆了不同的语义。例如,询问不同目的地的运输情况的信息(购买前)与询问订单状态的信息(购买后)被归入同一主题。

其他主题的例子非常少,而大量的信息根本不属于任何特定的主题。难怪在这样一个高度不平衡的数据集上训练出来的模型不能达到很高的准确性或覆盖率。

我们需要一个新的标签系统,它要准确并对我们的商户有用。它还必须是明确的,易于注释者理解的,这样标签的应用才会一致。这是一个双赢的局面。

这让我们开始思考:谁能帮助我们完成分类法的定义和注释过程?幸运的是,我们有一群才华横溢的同事。我们与我们的员工内容设计师和产品研究员合作,他们拥有Shopify Inbox领域的专业知识。我们还能得到一群支持顾问的兼职帮助,他们对Shopify和我们的商户(以及延伸到他们的买家)有深刻的了解。

在两个月的时间里,我们开始对数百条信息进行筛选,并提出了一个新的分类法。我们在电子表格中列出了每个新的主题,以及详细的描述、交叉引用、歧义和信息样本。这份文件将作为项目中每个人(数据科学家、软件工程师和注释者)的真理来源。

在进行分类学工作的同时,我们还研究了最新的预训练NLP模型,目的是根据我们的需要对其中的一个模型进行微调。Transformer系列是最受欢迎的模型之一,我们已经在我们的产品分类模型中使用了这种架构。我们选择了DistilBERT,这个模型承诺在性能、资源使用和准确性之间取得良好的平衡。在一个由我们新生的分类法构建的小数据集上进行的一些原型设计非常有希望:该模型已经比1.0版本表现得更好,所以我们决定加倍努力获得一个高质量的、有标签的数据集。

我们最终的分类法包含了40多个主题,被归入五个类别:

  • 产品
  • 购买前
  • 购买后
  • 商店
  • 杂项

我们通过思考注释者如何通过买方的视角来对信息进行分类,从而得出了这个层次结构。首先要确定的是:当信息被发送时,买家在他们的购买旅程中处于什么位置?他们是在询问产品的某个细节,比如颜色或尺寸?或者,买家是在询问付款方式吗?或者,也许产品坏了,他们想要退款?在注释过程中,确定类别有助于缩小我们的主题列表。

我们的内部注释工具显示了要分类的信息,以及一些可能的主题,按类别分组

每个类别都包含一个其他的主题,以分组那些没有足够内容与特定主题明确关联的信息。我们决定不使用被分类为其他的例子来训练模型,因为根据定义,它们是我们自己无法在建议的分类法中分类的信息。在生产中,这些信息会被模型以低概率分类。通过对分类法中的每个主题设置一个概率阈值,我们可以在以后决定是否忽略它们。

由于这个分类法相当大,我们想确保每个人对它的解释是一致的。我们与我们的注释团队举行了几次培训会议,介绍我们的分类项目和理念。我们把注释者分成两组,让他们用我们的分类法来注释同一组信息。这个练习有两方面的好处:

  1. 它给了注释者使用我们内部注释工具的第一手经验。
  2. 它允许我们衡量注释者之间的一致性

这个过程很耗时,因为我们需要做几轮练习。但是,培训使我们通过消除不一致的地方、澄清描述、添加额外的例子以及添加或删除主题来完善分类法本身。它还让我们确信,注释者在信息分类的任务上是一致的。

让注释开始

一旦我们和注释者认为他们准备好了,小组就开始注释信息。我们为每个人建立了一个Slack频道,以便在出现棘手的信息时进行协作和工作。这使得每个人都能看到用于达成分类的思考过程。

在训练数据的预处理过程中,我们摒弃了单字符信息和仅由表情符号组成的信息。在注释阶段,我们从训练数据中排除了其他类型的噪音。注释者还标记了实际上不是由买家输入的信息的内容,例如当买家剪切并粘贴他们从Shopify商店收到的确认购买的电子邮件的内容。正如老话所说,垃圾进,垃圾出。最后,由于我们目前的范围和资源限制,我们不得不把非英语信息放在一边。

处理敏感信息

你可能想知道我们如何处理个人信息(PI),如电子邮件或电话号码。个人信息偶尔会出现在买方信息中,我们特别注意确保它被适当地处理。这是一个复杂的,有时是手动的过程,涉及许多步骤和工具。

为了避免在任何含有PI的信息上训练我们的机器学习模型,我们不能直接忽略它们。这可能会使我们的模型出现偏差。相反,我们想识别含有PI的信息,然后用现实的模拟数据来取代它。这样一来,我们就有了真实信息的例子,而这些信息对任何真实的人来说都是无法识别的。

这个匿名化过程始于我们的注释者对含有PI的信息进行标记。接下来,我们使用一个叫做Presidio的开源库来分析和匿名化PI。这个工具在我们的数据仓库中运行,将我们商家的数据保存在Shopify的系统中。Presidio能够识别许多不同类型的PI,而且匿名器提供了不同种类的运算符,可以将PI的实例转化为其他东西。例如,你可以完全删除它,屏蔽它的一部分,或用其他东西代替它。

在我们的案例中,我们使用了另一个叫做Faker的开源工具来替换PI。这个库是可定制和本地化的,它的提供者可以生成现实的地址、名字、地点、URL等。下面是它的Python API的一个例子。

结合Presidio和Faker,我们可以半自动化地替换PI,请看下面的一个编造的例子:

原创

我今天可以取货吗? 我今天上午订购:Sahar Singh 我的电话是852 5555 1234。电子邮件是 saharsingh@example.com

匿名的

我今天上午订购:Sahar Singh 我的电话是090-722-7549。电子邮件是 osamusato@yoshida.jp

如果你是一个敏锐的读者,你会注意到(就像我们一样),我们的工具在上面的例子中没有识别出一点捏造的PI(提示:名字)。尽管Presidio使用了各种技术(正则表达式、命名实体识别和校验),一些PI还是从缝隙中溜走了。名字和地址有很大的可变性,很难可靠地识别。这意味着我们仍然需要检查前后的输出,以确定是否仍有任何PI存在。任何PI都被手动替换成一个占位符(例如,Sahar Singh这个名字被替换成)。最后,我们运行另一个脚本,用Faker生成的数据替换占位符。

来自趋势的一点帮助

在注释项目接近尾声时,我们注意到一个在整个活动中持续存在的趋势:我们分类法中的一些主题在训练数据中占比过高。事实证明,买家会问很多关于产品的问题。

我们的注释者已经经历了成千上万的信息。我们不能把最受欢迎的信息的主题拆开来重新分类,但我们怎样才能确保我们的模型在少数类别上表现良好?我们需要从代表性不足的话题中获得更多的训练实例。

由于我们不断地在已标记的信息上训练模型,当它们可用时,我们决定用它来帮助我们找到更多的信息。利用该模型的预测,我们排除了任何被归入代表性过高的主题的信息。剩下的例子属于其他主题,或者是模型不确定的主题。然后,这些信息由我们的注释者手动标注。

结果

那么,在为创建一个高质量的、一致标记的数据集所做的所有努力之后,结果是什么?它与我们的第一个原型相比如何?一点也不差。我们实现了我们的目标,即更高的准确性和覆盖率:

衡量标准

1.0版原型

生产中的2.0版本

训练集的大小

40,000

20,000

注释策略

基于嵌入相似性

人类标记的

分类学类别

20

45

模型精度

~70%

~90%

高置信度覆盖率

~35%

~80%

我们成功的另一个关键部分是与不同的主题专家进行合作。引入我们的支持顾问、员工内容设计师和产品研究员,提供了我们作为数据科学家无法单独实现的观点和专业知识。

虽然我们交付了一些我们引以为豪的东西,但我们的工作并没有完成。这是一个活生生的项目,需要继续发展。随着趋势和情绪的变化,Shopify Inbox中的对话主题也会相应地发生变化。我们将需要保持我们的分类法和培训数据的更新,并创建新的模型,以继续保持我们的高标准。