# 论文: Snorkel DryBell: A Case Study in Deploying Weak Supervision at Industrial Scale

> &#x20;工作上做机器学习模型的瓶颈往往在于标注数据的缺乏，因此本文提出了一套弱监督学习的算法管理系统：Snorkel DryBell，并介绍了该系统在Google内部项目上带来的提升。

## 1. 介绍

根据在Google内部的一些经验，本文提出一个好的弱监督系统需要满足如下三个准则：

* 易于融合公司内部的知识

  公司内有各种各样的数据源，一堆分类器的结果，文本、图片等数据输入方式。Snorkel可以快速融合这些结果用来训练模型。
* 多特征生产服务部署

  公司内部通常会有很多离线特征，例如一些长期的统计指标等等。Snorkel可以快速将这些无法部署服务的公司内部特征转变为一些可以部署的实时特征。
* 弱监督数据获取和模型训练分离

  将负责制定弱监督数据获取规则的专家，和模型训练进行解耦。实现人力工作和机器计算的独立，进行高效迭代。

![Snorkel DryBell组织公司内各资源进行弱监督训练](/files/-LnGkzCrpg_ijh3NxvCF)

第二节将介绍弱监督领域内的相关工作和Snorkel使用的方法。

第三节介绍了Snorkel在Google内部项目上使用的一个例子。

第四节介绍了Snorkel如何将离线特征转化为可部署的在线特征。

第五节介绍Snorkel的架构。

第六节介绍Snorkel的实验结果。

最后总结了如何在工业生产机的器学习项目上融合弱监督流程，并且讨论在不同类型公司的应用。

## 2. 背景知识

近年来，虽然机器学习算法已经取得了巨大成功，但大多都是在标注数据充足的领域。然而实际工作中，这样的标注数据获取代价非常高，因此弱监督学习越来越被重视。

Snorkel DryBell在最近提出的无监督学习框架Snorkel基础上改进而来，Snorkel框架主要流程有三步：

* 编写标注函数(Labeling Function)对未标注数据进行标记，输出带噪声的“标签“或者“无法确定标签“
* 根据多个LF的标注结果，产出一个生成模型用来衡量不同LF的准确率，随后对不同的LF产出一个权重，再对每个数据得到多个LF的加权标注结果
* 用上面的标注数据训练判别模型，作为最终模型

下面用公式来表示这个主要流程：

$$X=(X\_1, ..., X\_m), X\_i \in \chi$$ 表示m个未标注的数据，它们的标签(未标注)为 $$Y=(Y\_1, ..., Y\_m)$$。简化起见， 这里先考虑二分类，即 $$Y\_i \in {-1, 1}$$ .

在弱监督任务中真实标签$$Y\_i$$是未知的，Snorkel的目的也是为了去估计这些未知标签，然后根据估计的标签去训练模型。我们使用n个标记函数， $$\lambda = (\lambda\_1, ..., \lambda\_n)， \lambda\_i \in {-1, 0, 1}$$ ，其中0表示无效标注，就是说这个LF对这个样本不能作出判断。

接着使用生成模型去确定使用哪些LF，并且给不同的LF计算权重。根据LF的打标结果，得到一个 $$m \* n$$ 的矩阵 $$\Lambda$$ ，其中每个元素 $$\Lambda\_{i,j}=\lambda\_j(X\_i)$$ 表示第i个数据被第j个LF标记的结果。然后生成模型需要根据最大边际似然估计得到一组参数 $$w$$ ：

$$\tilde{w} = \arg\max\limits\_w logP\_w(\Lambda) = \arg\max \limits\_wlog\sum\_{Y\in {-1, 1}^m}P\_w(\Lambda, Y)$$&#x20;

这里会对所有可能的 $$Y^m$$ 序列进行概率求和，因此并不会用到无法获取的真实标签，而是从不同LF的标注结果中提炼有用信息，具体怎么估计在后文再说。

再得到了生成模型之后，就可以得到我们预测出来的每个样本的标签分布 $$\tilde{Y}*i = P*{\tilde{w}}(Y\_i|\Lambda)$$ ，和以往的hard形式的标签不同，这里得到的标签是概率分布形式的，将会被用来进行最终的判别模型的训练。训练判别模型 $$h\_\theta$$ 的过程就是最小化关于带噪声标签 $$\tilde{Y}$$ 的损失 $$l$$ 的过程：

$$\tilde{\theta} = \arg\min\_{\theta}\sum\_{i=1}^mE\_{y\sim\tilde{Y}*i}\[l(h*\theta(X\_i), y)]$$&#x20;

我们希望得到的判别模型相对生成模型无论是在模型生成部署方面，还是在模型的泛化方面都能有所提升，详细的分析将在后文讨论到。

## 3. CASE分析：弱监督快速部署实例

本节通过三个Google内部的分类任务(两个关于产品主题和类目的分析，一个关于平台事件的实时分析)来分析Snorkel DryBell是如何融合公司内部多种数据源作为LF的。

这里将LF的来源分成了4类：

* 基于内容来源的启发式获取

  一般是根据内容来源制定规则来决定是否使用，例如：61当天的亲子内容被当作儿童节相关
* 基于内容本身的启发式获取

  根据内容本身制定规则，例如：文本中包含六一，儿童节相关关键词的内容被当作儿童节相关
* 基于其他模型的预测结果获取

  公司内的其他很多模型结果可以直接拿来筛选数据，例如现在想要获取菜品Aspect的情感分析结果，可以用NER判断为菜品且通用情感分析判断的情感分析结果作为菜品的情感值
* 基于图谱的标签拓展

  根据已有知识图谱寻找已有标签的拓展标注

下面分析每个任务的数据源

![三个任务的LF来源构成](/files/-LnNRtH7VV7Xf0-xKFBi)

### 3.1 主题分类

可以理解为就是想对内容涉及的主题进行分类，然而组内有超过100个类似的分类器，然后每个有自己的训练数据集。为了更快速灵活的调整模型，肯定是将这些模型都整合到一起比较好。

Snorkel 首先通过关键词过滤的方式粗略筛选了684000个未标注数据，然后基于各种规则制定了10个LF，主要包括：

* 基于内容的URL链接，其实可以看作是数据的来源
* NER标注的结果
* Google内部的主题模型，虽然这个主题模型直接用在我们的任务上粒度过粗了，不过可以用来标注一些负例

最终我们得到了媲美使用80000人工标注数据的模型的结果，比起使用175000人工标注数据的模型，F1值也只低了4.6

### 3.2 产品分类

判断产品所属的分类，原来已经有一个现成的模型，但是现在需要扩展一些新的类别。因为可能混有新添加的类别，以前的other类就不能用了。

这里我们定义了8个LF，包括：

* 基于关键词筛选
* 基于知识图谱拓展了其他语言上的关键词，主要是为了适应不同语言内容的场景
* 利用主题模型给明显不相关的内容打上负例

在此基础上的模型达到了12000标注数据的训练模型效果，比50000标注数据的结果F1下降5.1以内。

### 3.3 实时事件分类

常见事件分类的做法是根据离线特征，尤其是一些统计指标来对事件进行分类，因此有明显的滞后性。这里使用机器学习的方法来进行实时分类。

这里的挑战主要在于实时特征标注数据的缺失，因此用了140个基于离线特征的LF来标注数据，然后基于实时特征训练模型。

可以看到这些任务的做法是差不多的，都是通过LF到生成模型到判别模型的过程。后面可以看到Snorkel DryBell最厉害之处在于将平时融合多来源数据，调整各来源权重的繁重任务简化的非常好。只需要制定好LF函数，然后根据准确率估计来调整LF模型，去掉质量低的LF，非常方便。

## 4. 跨特征模型部署

Snorkel DryBell一个明显优势是实现了将一些无法部署的复杂特征中的知识“迁移“到了灵活的实时特征中。

![Snorkel DryBell利用非在线特征训练基于在线特征的分类器](/files/-LnaNz_5Qwyn2IJxYxaK)

Snorkel DryBell的这种模式，实现了将知识从基于特征 $$F\_A$$ 的模型A迁移到基于特征 $$F\_B$$上，可以算得上是一种特殊的迁移学习或者模型蒸馏。只不过大家常说的迁移学习都是在相同或者类似的模型结构上，使用相同的基础特征进行的。

上面提到的三个例子就是这样的场景，它们都或多或少依赖一些实时上很难获取的特征，例如数据的统计特征，爬虫特征等等。通过这种迁移的模式，就可以非常方便的利用到这些知识，去构建一些仅依靠实时特征的模型。

## 5. 系统架构

### 5.1 标注函数(LF)模版库

这节主要是讲为了融合进Google内部的开发系统，是如何设计高效开发的LF模版库的。这个反正不同公司不通用，不看了。。

### 5.2 不依靠采样实现的生成模型

Snorkel DryBell的核心工作就是如何利用带噪声的多个LF的标记结果去估计样本的真实标记，这里提出了一种非CPU密集型的易于分布式实现的方法。根据之前的讨论，我们关心这样的条件独立的生成模型，对于n个样本点，给定一组真实标签Y，其概率分布为：

$$P\_w(\Lambda,Y) = \prod\_{i=1}^nP\_w(Y\_i)\prod\_{j=1}^mP\_w(\lambda\_j(X\_i)|Y\_i)$$&#x20;

这里为了简化问题，假设 $$P\_w(Y\_i)$$ 服从均匀分布，不过这个分布也是可以学到的。

模型学习的目标就是上文说的最大化边际似然函数，也可以等价为最小化负的边际似然，即最小化 $$-logP\_w(\Lambda)$$ 。换句话说就是给定关于所有LF关于n个点的标注结果 $$\Lambda$$ ，利用最大似然去最大化这个似然概率 $$P\_w(\Lambda)$$ 。之前开源Snorkel的做法是利用Gibbs采样来计算该目标函数的梯度，这种方式非常依赖CPU计算性能，并且难以并行化。

论文中提到基于TensorFlow使用无需采样的优化方法。上文提到计算 $$P\_w(\Lambda)=\sum\_{Y\in {-1, 1}^m}P\_w(\Lambda, Y)$$ 可以被看作是对每个可能的Y序列的概率求和而得。我们可以换一种计算方式，先计算观测矩阵中每个点$$\Lambda\_i$$的概率，然后对m个点求积，即 $$P\_w(\Lambda) = \prod\_{i=1}^mP\_w(\Lambda\_i)=\prod\_{i=1}^m(P\_w(\Lambda\_i, Y\_i = 1) + P\_w(\Lambda\_i, Y\_i = -1))$$&#x20;

对上式求log得到：

$$-log(P\_w(\Lambda)) = -\sum\_{i=1}^mlog(P\_w(\Lambda\_i, Y\_i=1) + P\_w(\Lambda\_i, Y\_i = -1))$$&#x20;

为了最小化这个目标函数，定义生成模型参数 $$w$$ 为：

* 定义0表示第j个LF对样本无法给出标签的log未归一化概率值(即 $$log\tilde{P}(\Lambda\_j(x\_i) = 0)$$ )
* $$\beta\_j$$ 表示第j个LF对样本给出标签的log未归一化概率值(即 $$log\tilde{P}(\Lambda\_j(x\_i) \neq 0)$$ )
* $$\alpha\_j$$ 表示第j个LF对样本给出标签时，标记正确的log未归一化概率值(即$$log\tilde{P}(\Lambda\_j(x\_i) = Y\_i|\Lambda\_j(x\_i) \neq 0)$$)

于是$$\alpha\_j + \beta\_j$$ 表示 $$LF\_j$$ 对样本有标记且标记正确的log未归一化概率值， $$\beta\_j - \alpha\_j$$ 表示 $$LF\_j$$ 对样本有标记且标记错误的log未归一化概率值，0是第j个LF对样本无法给出标签的log未归一化概率值。于是得到归一化参数

$$Z\_j = e^{\alpha\_j + \beta\_j} + e^{-\alpha\_j + \beta\_j} + e^0 = e^{\alpha\_j + \beta\_j} + e^{-\alpha\_j + \beta\_j}  + 1$$&#x20;

于是可以得到目标函数的显示形式：

&#x20;$$logP\_w(\Lambda\_i, Y\_i = 1) = \sum\_{j=1}^n(\bold{1}\[\lambda\_j(X\_i=1)]\(\alpha\_j + \beta\_j - Z\_j) + \bold{1}\[\lambda\_j(X\_i=-1)]\(-\alpha\_j + \beta\_j - Z\_j) + \bold{1}[\lambda\_j(X\_i = 0)](https://shangzhi-huang.gitbook.io/workspace/ruo-jian-du-xue-xi/-Z_j))$$&#x20;

$$logP\_w(\Lambda\_i, Y\_i = -1) = \sum\_{j=1}^n(\bold{1}\[\lambda\_j(X\_i=1)]\(-\alpha\_j + \beta\_j - Z\_j) + \bold{1}\[\lambda\_j(X\_i=-1)]\(\alpha\_j + \beta\_j - Z\_j) + \bold{1}[\lambda\_j(X\_i = 0)](https://shangzhi-huang.gitbook.io/workspace/ruo-jian-du-xue-xi/-Z_j))$$&#x20;

生成模型的训练就是要对每个标记函数，得到它能给出非0标签的概率，和它标记正确的概率，这就需要计算每个标记函数的参数 $$\alpha\_j$$和 $$\beta\_j$$ 。在得到了这些参数之后对于样本点i的真实标签可以由( $$P(Y\_i = 1|\Lambda\_i) = \frac{P(\Lambda\_i, Y\_i = 1)}{P(\Lambda\_i)}和P(Y\_i = -1|\Lambda\_i)=\frac{P(\Lambda\_i, Y\_i=-1)}{P(\Lambda\_i)}$$ )，也就是上面两个概率的归一化形式代替。相较于平时的{0, 1}的hard标签，这里得到的是数据的概率标注。

### 5.3 部署判别模型

论文中使用了TFX来进行端到端的部署，这个使用的时候还是综合自己的需要来。反正标记数据得到后，之后按照正常的模型训练和部署就好。

### 5.4 和原始Snorkel架构的比较

只要还是在于生成模型的实现上，Snorkel DyrBell更加贴近大规模生成，相较于原始的采样实现，新方法利用TensorFlow可以快速计算。

## 6. 实验

### 6.1 主题和产品分类

以下是两个任务的数据分布情况，n表示了可用的未标注数据。

![](/files/-LngTQXTgb64QoTczVib)

在和仅依靠Dev集上标注数据的Base模型相比，得到如下结果：

![](/files/-LngU3LXkFkZyLGcvn0K)

上面两组数据一组是依靠生成模型的结果对LF的标记结果进行加权组合直接得到，另一个是在加权结果的基础上判别模型得到。相较于生成模型，经过训练的判别模型效果提升非常明显。说明判别模型获取了LF基础之上额外的信息，Snorkel DryBell有效的将离线特征中的知识迁移到了我们定义的实时特征之上。

### 6.2 对比不同标记数据的效果

弱监督是缺乏标记数据时采用的策略，如果有足够的标记数据，肯定还是有监督的效果会更好一点。这里作者也做了一系列实验来观察多少标记数据下的有监督模型会超越弱监督模型。

![](/files/-LngVvYhthxzU4pFWUZl)

上图可知，在标记数据分别达到80000和12000后，有监督模型效果会更好。

### 6.3 消融实验

#### 离线特征的影响

![](/files/-LngWbStGZ0_gyWOmidH)

#### 生成模型对LF加权的影响

![](/files/-LngX-LDerj5j3ogm0AI)

这里作者对比了使用生成模型计算LF之间不同的权重和直接等权重计算概率标签后得到的判别模型的效果，可以看到使用生成模型得到了平均4.8%的提升。

### 6.4 实时事件

对比了Snorkel DryBell和使用或运算组合LF的弱监督效果对比。

![](/files/-Lng_yvXUsDzdksg_x9V)

可以看到使用Snorkel的模型，预测的结果更加平滑合理，而不是聚集在两个极端。

## 7. 讨论

Snorkel DryBell的优点：

* LF的形式很适合融合公司内部的各方数据源
* Snorel DryBell通过生成模型到判别模型可以有效的剔除LF中的标记噪声，并且非常方便的将离线特征中的知识迁移到实时模型中
* LF对业务的抽象方便相关人员基于自己的领域知识和业务理解快速开发

## 8. 相关工作

在机器学习领域，半监督学习致力于将有限的人工标注数据和大量的未标注数据结合起来。通常来说，它通过无监督方法挖掘未标注数据，来得到数据的结构信息，例如聚类信息，来更好的利用标记数据进行模型训练。

迁移学习通过某些任务的已有标注数据训练模型，来减轻新任务上对于标注数据的依赖。zero-shot学习致力于学习到类别描述和标注样本之间的关系，然后在新类型出现时，只要依赖类别的描述就可以进行新类目的分类，而不需要新的标注样本。主动学习致力于获取对模型改进最重要的样本给到人进行标注，减小总的标注量。

在数据系统中，相关的工作有数据融合和真理发现。主要目的是估计不同数据源中标注样本的冲突，并设法将它们合并到一起组成正确可用的数据集。另外一种广泛使用的工作是数据清洗，主要为了识别出数据集中的错误标注。解决这些问题的方法多和Snorkel DryBell类似，就是将样本的真实标签看作隐变量。在Snorkel中，通过生成模型来计算这些隐变量。

## 9. 总结

本文介绍了弱监督框架Snorkel DryBell在工业级别的应用，它在不利用人工标注数据的情况下，整合公司内部的各个数据源，得到了堪比万级标注数据的模型效果。

除此之外，Snorkel可以非常方便实现离线特征到在线模型的知识迁移，这种弱监督模式在缺乏标注数据且实时要求高的工业级项目上有着非常重要的意义。

## 参考文献

\[1] [Snorkel DryBell: A Case Study in Deploying Weak Supervision at Industrial Scale](https://arxiv.org/abs/1812.00417v2) - S. Bach et al.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shangzhi-huang.gitbook.io/workspace/ruo-jian-du-xue-xi/lun-wen-snorkel-drybellacase-study-in-deploying-weak-supervision-at-industrial-scale.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
