mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-16 22:23:45 +08:00
mod
This commit is contained in:
119
极客时间专栏/深度学习推荐系统实战/模型评估篇/24 | 离线评估:常用的推荐系统离线评估方法有哪些?.md
Normal file
119
极客时间专栏/深度学习推荐系统实战/模型评估篇/24 | 离线评估:常用的推荐系统离线评估方法有哪些?.md
Normal file
@@ -0,0 +1,119 @@
|
||||
<audio id="audio" title="24 | 离线评估:常用的推荐系统离线评估方法有哪些?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f1/df/f15b259d4e853yyd741924d8d00b39df.mp3"></audio>
|
||||
|
||||
你好,我是王喆。今天我们要进入一个全新的章节,模型评估篇。
|
||||
|
||||
在推荐系统这个行业,所有人都在谈效果。就像我们在学习推荐模型篇的时候,你肯定也有过这样的疑问:
|
||||
|
||||
- DIEN这个模型的效果到底怎么样啊?
|
||||
- 我们用深度学习来构建模型到底能让推荐系统效果提高多少啊?
|
||||
- DeepFM的效果是不是会比Wide&Deep好呢?
|
||||
|
||||
**那这个所谓的“效果”到底指的是什么呢?我们一般用什么方法来衡量这个“效果”呢?我们又应该如何根据效果评估的结果来更新模型呢?**这就是模型评估篇要解决的问题。
|
||||
|
||||
在所有推荐系统的评估方法中,离线评估是最常用、最基本的。顾名思义,“离线评估”就是我们将模型部署于线上环境之前,在离线环境下进行的评估。由于不用部署到生产环境,“离线评估”没有线上部署的工程风险,也不会浪费宝贵的线上流量资源,而且具有测试时间短,可多组并行,以及能够利用丰富的线下计算资源等诸多优点。
|
||||
|
||||
因此,在模型上线之前,进行大量的离线评估是验证模型效果最高效的手段。这节课,我们就来讲讲离线评估的主要方法,以及怎么在Spark平台上实现离线评估。
|
||||
|
||||
## 离线评估的主要方法
|
||||
|
||||
离线评估的基本原理是在离线环境下,将数据集分为“训练集”和“测试集”两部分,“训练集”用来训练模型,“测试集”用于评估模型。但是如何划分测试集和训练集,其实这里面有很多学问。我总结了一下,常用的离线评估方法主要有五种,分别是:Holdout检验、交叉检验、自助法、时间切割、离线Replay。接下来,我们一一来看。
|
||||
|
||||
### Holdout检验、交叉检验和自助法
|
||||
|
||||
**首先,我们来看Holdout检验。** Holdout 检验是最基础,最常用的离线评估方法,它将原始的样本集合随机划分为训练集和测试集两部分,**所以Holdout 检验的关键词就是“随机”**。举例来说,对于一个推荐模型,我们可以把样本按照 70%-30% 的比例随机分成两部分。其中,70% 的样本用于模型的训练,30% 的样本用于模型的评估。
|
||||
|
||||
虽然Holdout检验很简单实用,但它的缺点也很明显,就是评估的结果有一定随机性,因为训练集和验证集的划分是随机的,所以如果只进行少量的Holdout检验,得到的评估指标会存在一定的波动。那为了消除这种随机性,我们就要使用“交叉检验”的方法。
|
||||
|
||||
为了进行交叉检验,我们需要先将全部样本划分成k个大小相等的样本子集,然后依次遍历这k个子集,每次把当前遍历到的子集作为验证集,其余所有的子集作为训练集,这样依次进行k次模型的训练和评估。最后,我们再将所有k次评估指标的平均值作为最终的评估指标。在我们的实践中,k经常取10,也就是依次进行10次检验然后取指标均值。
|
||||
|
||||
不管是Holdout检验还是交叉检验,都是基于划分训练集和测试集的方法进行模型评估的。然而,当样本规模比较小时,将样本集进行划分会让训练集进一步减小,这往往会影响模型的训练效果。那有没有能维持训练集样本规模的验证方法呢?
|
||||
|
||||
“自助法”就可以在一定程度上解决这个问题。我这里所说的**自助法(Bootstrap)是基于自助采样的检验方法**,它的主要过程是:对于总数为n的样本集合,我们先进行n次有放回地随机抽样,得到大小为n的训练集。在n次采样过程中,有的样本会被重复采样,有的样本没有被抽出过,我们再将这些没有被抽出的样本作为验证集进行模型验证,这就是自助法的验证过程。
|
||||
|
||||
虽然自主法能够保持训练集的规模,但是它的缺点也很明显,它其实改变了原有数据的分布,有可能让模型产生一定程度的偏差。至于,到底是自助采样增加训练样本规模的收益大,还是数据分布被改变带来的损失大,这就需要我们在实践中进行验证了。
|
||||
|
||||
### 时间切割
|
||||
|
||||
说完了前三种方法,我们再来看时间切割法。在“[模型实战准备(二)](https://time.geekbang.org/column/article/308812)”那节课里,我们曾经讲过一个概念,叫“未来信息”。它是说,如果我们在t时刻进行模型预测,那么 t+1 时刻的信息就是未来信息。在构建特征工程的时候,我们要避免引入“未来信息”。
|
||||
|
||||
其实,在进行模型评估的时候,我们同样不应该在训练集中包含“未来”的样本。怎么理解这句话呢?比如,我们所有的样本数据分布在t<sub>0</sub>到t<sub>n</sub>这样的时间轴上,如果训练样本是通过随机采样得到的,那么训练数据也会分布在t<sub>0</sub>到t<sub>n</sub>上,同样,测试数据也会分布在t<sub>0</sub>到t<sub>n</sub>上。
|
||||
|
||||
如果你细想,这个事情其实是有点反常理的。因为训练模型的时候,我们已经使用了t<sub>n</sub>这个时间窗口的数据,结果你却用它来预测t<sub>0</sub>的事件,这不是很荒谬吗?这就相当于你有一个时光机,已经穿越到了明天,知道股票会涨,结果你又穿越回来,预测说明天股票会涨,这哪是预测呢?这就是“作弊”。
|
||||
|
||||
为了防止这类“信息穿越”导致的模型作弊现象发生,我们一般会使用时间切割的方案去划分训练集和测试集,它的做法很简单。比如,你一共处理了30天的样本,从第25天末开始切割,前25天的样本作为训练集,后5天的样本作为测试集,这样我们就从根源上切断了引入“未来信息”的可能。当然切割的比例到底如何,也需要根据你的实践来定,一般来说我们控制训练集跟测试集的比例在3:1到10:1之间,比例太小训练样本不够,比例太大测试结果不够稳定。
|
||||
|
||||
### 离线Replay
|
||||
|
||||
时间切割的方法虽然能避免“信息穿越”,但也不是没有缺点的。它的缺点就在于整个评估过程是静态的,模型不会随着评估的进行而更新,这显然是不符合事实的。就拿我们刚才举的例子来说,用前25天的数据做训练集,用后5天的数据做测试集。如果在生产环境中,模型是日更新的,那后5天的评测过程就不准确,因为在离线测试中,我们并没有在后5天的评测过程中做到日更模型。
|
||||
|
||||
那怎么解决这个问题呢?我们也可以在离线状态下对线上更新过程进行仿真,让整个评估过程“动”起来。**业界把这样离线仿真式的评估方式叫做离线Replay。**
|
||||
|
||||
下图就是动态的Replay评估法与静态的时间分割评估法的对比示意图。我们可以看到,“Replay评估方法”先根据产生时间对测试样本,由早到晚地进行排序,再让模型根据样本时间的先后进行预测。在模型更新的时间点上,模型需要增量学习更新时间点前的测试样本,更新模型后,再继续评估更新点之后的样本。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4a/fe/4a530c53ef61ca5fee367a58070c32fe.png" alt="" title="图1 静态时间分割评估与动态Replay评估 (出自《深度学习推荐系统》)">
|
||||
|
||||
你应该也发现了,Replay评估的过程更接近于真实的线上环境,因为它在线下还原了模型在线上的更新、预估过程。这也让Replay方法的评估结果更加权威可信,毕竟,我们最终的目标是让模型在线上产生更好的效果。
|
||||
|
||||
当然,Replay评估方法也有弊端,因为它需要在评估过程中不断更新模型,这让评估过程的工程实现难度加大,因为包含了模型训练的时间,所以整个评估过程的总时长也会加长,影响评估和调参的效率。到底是要评估的准确性,还是要评估的效率,这又是一个需要权衡的问题,我们需要根据自己工程上的侧重点进行选择。
|
||||
|
||||
## 基于Spark的离线评估方法实践
|
||||
|
||||
熟悉了离线环节的主要模型评估方法,就又到了实践的环节。其实,无论是基于Python的TensorFlow还是基于Scala的Spark,都有很多支持离线评估的库,这里我们选择了Spark进行实践,主要是因为在业界数据集很大的情况下,Spark在分布式环境下划分训练集和测试集的效率是最高的。
|
||||
|
||||
下面,我就来看一下如何使用Spark实现Holdout检验、交叉检验和时间切割评估法。至于另外两种方法,由于自助法不太常用,离线Replay又涉及过多的附加模块,我们暂时就不在项目里实现。
|
||||
|
||||
实现Holdout检验的时候,我们要清楚如何利用Spark随机划分测试集和训练集。它的关键代码只有下面这一行,就是利用randomSplit函数把全量样本samples按比例分割成trainingSamples和testSamples。在Spark的后端,这个randomSplit函数会在各个节点分布式执行,所以整个执行效率是非常高的。源代码你可以参考 com.wzhe.sparrowrecsys.offline.spark.featureeng.FeatureEngForRecModel 中的splitAndSaveTrainingTestSamples函数。
|
||||
|
||||
```
|
||||
val Array(trainingSamples, testSamples) = samples.randomSplit(Array(0.9, 0.1))
|
||||
|
||||
```
|
||||
|
||||
实现交叉检验的过程相对比较复杂,好在,Spark已经提供了交叉检验的接口可以直接使用,我们直接看一下这部分的关键代码。
|
||||
|
||||
```
|
||||
val cv = new CrossValidator()
|
||||
.setEstimator(modelPipeline)
|
||||
.setEvaluator(new BinaryClassificationEvaluator)
|
||||
.setEstimatorParamMaps(paramGrid)
|
||||
.setNumFolds(10) // Use 3+ in practice
|
||||
val cvModel = cv.fit(training)
|
||||
|
||||
```
|
||||
|
||||
这段代码中有三个关键参数,一是setEstimator,这是我们要评估的对象,它需要把我们构建的模型pipeline设置进去;二是setEvaluator,它用来设置评估所用的方法和指标;三是setNumFolds,它设置的是交叉检验中k的值,也就是把样本分成多少份用于交叉检验。本质上Spark的CrossValidator其实是通过交叉检验来选择模型的最优参数,但也可以通过模型中cvModel.avgMetrics参数查看模型的评估指标。
|
||||
|
||||
接下来,我们来实现时间切割方法。既然是要按时间划分,如果你知道样本的时间跨度,直接用where语句就可以把训练集和测试集划分开了,这也是我最推荐的方法,因为它最高效,不用专门判断切割点。
|
||||
|
||||
如果你不知道样本的时间跨度,就要按照时间求取样本的分位数。具体来说就是,通过Spark的approxQuantile函数,我们可以找到划分样本集为8:2的训练集和测试集的时间戳的值。那么接下来我们根据这个值通过where语句划分就可以了。我把这个过程的关键代码贴到了下面,供你参考。完整的源代码,你可以参考 com.wzhe.sparrowrecsys.offline.spark.featureeng.FeatureEngForRecModel 中的splitAndSaveTrainingTestSamplesByTimeStamp函数。
|
||||
|
||||
```
|
||||
//找到时间切割点
|
||||
val quantile = smallSamples.stat.approxQuantile("timestampLong", Array(0.8), 0.05)
|
||||
val splitTimestamp = quantile.apply(0)
|
||||
//切割样本为训练集和测试集
|
||||
val training = smallSamples.where(col("timestampLong") <= splitTimestamp).drop("timestampLong")
|
||||
val test = smallSamples.where(col("timestampLong") > splitTimestamp).drop("timestampLong")
|
||||
|
||||
|
||||
```
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们学习了五种主流的推荐模型离线评估方法,它们分别是Holdout检验、交叉检验、自助法、时间切割和离线Replay。
|
||||
|
||||
其中,Holdout检验最简单常用,它通过随机划分的方式把样本集划分成训练集和测试集。而交叉检验的评估效果更加稳定准确,它通过划分样本集为k份,再进行k次评估取平均的方式得到最终的评估指标。
|
||||
|
||||
自助法是为了解决样本量过少而提出的,它可以通过有放回采样的方式扩充训练集,但有改变数据本身分布的风险。而时间切割法在某个时间点上把样本分成前后两份,分别用于模型训练和评估,避免引入未来信息。最后是离线Replay,它通过仿真线上模型更新过程来进行评估,是最接近线上环境的离线评估方法,但实现起来比较复杂。
|
||||
|
||||
总之,各种评估方法都有优有劣,你需要根据实践中的侧重点选择使用,我把它们的优缺点也总结在了文稿的表格里,方便你进行对比。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/19/fd/198bea8ba6ae2ecfe2d65617a6efe7fd.jpeg" alt="">
|
||||
|
||||
这节课我们讲了评估模型效果的方法之一,离线评估。但我们并没有具体来讲“效果”的衡量指标到底是什么。别着急,下节课我们就来学习推荐系统主要使用的效果评估指标,也会利用这节课学习到的评估方法来生成这些指标。
|
||||
|
||||
## 课后思考
|
||||
|
||||
你觉得离线Replay这个方法,跟我们之前讲过的增强学习有什么相似之处吗?你知道它们两个还有什么更深层次的关系吗?
|
||||
|
||||
期待在留言区看到你的发现和思考,我们下节课见!
|
||||
166
极客时间专栏/深度学习推荐系统实战/模型评估篇/25 | 评估指标:我们可以用哪些指标来衡量模型的好坏?.md
Normal file
166
极客时间专栏/深度学习推荐系统实战/模型评估篇/25 | 评估指标:我们可以用哪些指标来衡量模型的好坏?.md
Normal file
@@ -0,0 +1,166 @@
|
||||
<audio id="audio" title="25 | 评估指标:我们可以用哪些指标来衡量模型的好坏?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d5/7f/d57f931540d997717e99c3a6f9f8a17f.mp3"></audio>
|
||||
|
||||
你好,我是王喆。今天,我们来学习推荐模型的评估指标。
|
||||
|
||||
上节课,我们讲了五种评估方法,清楚了它们都是怎么把样本分割为训练集和测试集的。但是只分割样本是远远不够的,为了比较模型效果的好坏,还得用一些指标进行衡量。就像我们工作中经常说,我的模型提高了“一个点”的效果,那所谓的“一个点”指的是什么呢?它其实说的就是,我们的模型在一些经典的推荐指标上提升了1%的效果,这节课我就带你来捋一捋这些经典的推荐评估指标。
|
||||
|
||||
## 低阶评估指标
|
||||
|
||||
我按照指标计算的难易程度,和评估的全面性,把推荐系统的评估指标可以分成低阶评估指标和高阶评估指标两大类。对于低阶评估指标来说,准确率、精确率与召回率、对数损失、均方根误差,这四个指标在推荐模型评估中最常用,计算起来也最容易。所以,我们就先来学习一下这几个低阶评估指标的具体含义。
|
||||
|
||||
### 1. 准确率
|
||||
|
||||
准确率 (Accuracy)是指分类正确的样本占总样本个数的比例,公式1就是:$\text {Accuracy}=\frac{n_{\text {correct }}}{n_{\text {total }}}$。
|
||||
|
||||
其中, ncorrect是正确分类的样本个数, ntotal是样本的总数。
|
||||
|
||||
准确率是分类任务中非常直观的评价指标,可解释性也很强,但它也存在明显的缺陷,就是当不同类别的样本比例非常不均衡的时候,占比大的类别往往成为影响准确率的最主要因素。比如,负样本占99%,那么分类器把所有样本都预测为负样本也可以获得99%的准确率。
|
||||
|
||||
在之前的课程中,我们经常把推荐问题看作是一个点击率预估型的分类问题。这个时候,我们就可以用准确率来衡量推荐模型的好坏。但在实际的推荐场景中,我们往往会生成一个推荐列表,而不是用所谓的分类正不正确来衡量最终的效果,那我们该怎么评估一个推荐列表的效果呢?这个时候,我们就会利用到精确率和召回率这两个指标。
|
||||
|
||||
### 2. 精确率与召回率
|
||||
|
||||
我这里所说的**精确率(Precision)指的是分类正确的正样本个数占分类器判定为正样本个数的比例,召回率(Recall)是分类正确的正样本个数占真正的正样本个数的比例**。
|
||||
|
||||
在推荐列表中,通常没有一个确定的阈值来把预测结果直接判定为正样本或负样本,而是采用Top N 排序结果的精确率(Precision@N)和召回率(Recall@N)来衡量排序模型的性能。具体操作,就是认为模型排序的前N个结果就是模型判定的正样本,然后分别计算Precision@N和Recall@N。
|
||||
|
||||
事实上,精确率和召回率其实是矛盾统一的一对指标。这是什么意思呢?就是,为了提高精确率,模型需要尽量在“更有把握”时把样本预测为正样本,但此时,我们往往会因为过于保守而漏掉很多“没有把握”的正样本,导致召回率降低。
|
||||
|
||||
那有没有一个指标能综合地反映精确率和召回率的高低呢?其实是有的,那就是F1-score。F1-score的定义是精确率和召回率的调和平均值,具体的定义你可以看看下面的公式2。F1-score的值越高,就证明模型在精确率和召回率的整体表现上越好。
|
||||
|
||||
$$<br>
|
||||
\mathrm{F} 1=\frac{2 \cdot \text { precision } \cdot \text { recall }}{\text { precision }+\text { recall }}<br>
|
||||
$$
|
||||
|
||||
### 3. 对数损失
|
||||
|
||||
接着,我们来说一说对数损失(Logloss)这个评估指标。
|
||||
|
||||
首先,在一个二分类问题中,对数损失函数的定义就是下面的公式3。<br>
|
||||
$$<br>
|
||||
-\frac{1}{N} \sum_{i=1}^{N}\left(y_{i} \log P_{\mathrm{i}}+\left(1-y_{i}\right) \log \left(1-P_{i}\right)\right)<br>
|
||||
$$
|
||||
|
||||
在这个公式中,$y_{i}$是输入实例 $x_{i}$ 的真实类别, $p_{i}$是预测输入实例 $x_{i}$ 是正样本的概率,$N$是样本总数。
|
||||
|
||||
而面对多分类问题的时候,对数损失函数定义就变成了下面公式4的样子:
|
||||
|
||||
$$<br>
|
||||
\text { Multi-LogLoss }=-\frac{1}{n} \sum_{i=1}^{n} \sum_{j=1}^{m} y_{i, j} \log \left(p_{i, j}\right)<br>
|
||||
$$
|
||||
|
||||
如果你仔细看公式就会发现,二分类和多分类模型的Logloss其实就是我们之前讲过的逻辑回归和Softmax模型的损失函数,而大量深度学习模型的输出层正是逻辑回归或Softmax,因此,采用Logloss作为评估指标能够非常直观地反映模型损失函数的变化。所以在训练模型的过程中,我们在每一轮训练中都会输出Logloss,来观察模型的收敛情况。
|
||||
|
||||
### 4. 均方根误差
|
||||
|
||||
刚才我们说的准确率、精确率、召回率、LogLoss都是针对分类模型指定的指标。分类模型就是指预测某个样本属于哪个类别的模型,最典型的就是点击率预估模型。除了这类分类模型以外,还有回归模型,它是用来预测一个连续值,比如预测某个用户对某个电影会打多少分,这就是一个回归模型。
|
||||
|
||||
那我们对于回归模型有什么合适的评估指标吗?对于回归模型来说,最常用的评估指标就是**均方根误差**(RMSE,Root Mean Square Error)。它的公式是求预测值跟真实值之间差值的均方根:
|
||||
|
||||
$$<br>
|
||||
\mathrm{RMSE}=\sqrt{\frac{\sum_{i=1}^{n}\left(y_{i}-\hat{y}_{l}\right)^{2}}{n}}<br>
|
||||
$$
|
||||
|
||||
这个公式中,$y_{i}$是第i个样本点的真实值,$ \hat{y}_{l}$是第i个样本点的预测值,n是样本点的个数。那么均方根误差越小,当然就证明这个回归模型预测越精确。
|
||||
|
||||
总的来说,我们刚才说的这四个评估指标,虽然在推荐系统中最常用,计算起来也最简单,但它们反应的结果还不够精确和全面。
|
||||
|
||||
比如说,精确率和召回率可以反应模型在Top n个排序结果上的表现,但我们要知道,在真正的推荐问题中,n的值是变化的,因为用户可能会通过不断的翻页、下滑来拉取更多的推荐结果,这就需要有更高阶的评估指标来衡量模型在不同数量推荐结果上的综合性能。所以,我们接下来再讲几个非常流行,也非常权威的高阶评估指标。
|
||||
|
||||
## 高阶评估指标
|
||||
|
||||
那在高阶评估指标部分,我会给你讲P-R曲线、ROC曲线、平均精度均值,这三个最常用的评估指标。
|
||||
|
||||
### 1. P-R曲线
|
||||
|
||||
首先,我要说的是P-R曲线,这里的P就是我们之前学过的精确率Precision,R就是召回率Recall。刚才我们说了,为了综合评价一个推荐模型的好坏,不仅要看模型在一个Top n值下的精确率和召回率,还要看到模型在不同N取值下的表现,甚至最好能绘制出一条n从1到N,准确率和召回率变化的曲线。这条曲线就是P-R曲线。
|
||||
|
||||
P-R曲线的横轴是召回率,纵轴是精确率。对于一个推荐模型来说,它的P-R曲线上的一个点代表“在某一阈值下,模型将大于该阈值的结果判定为正样本,将小于该阈值的结果判定为负样本时,整体结果对应的召回率和精确率”。整条P-R曲线是通过从高到低移动正样本阈值生成的。如图1所示,它画了两个测试模型,模型A和模型B的对比曲线。其中,实线代表模型A的P-R曲线,虚线代表模型B的P-R曲线。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/27/40/27c1669b30da6817fc7275354fc1ff40.jpg" alt="">
|
||||
|
||||
从图中我们可以看到,在召回率接近0时,模型A的精确率是0.9,模型B的精确率是1。这说明模型B预测的得分前几位的样本全部是真正的正样本,而模型A即使是得分最高的几个样本也存在预测错误的情况。
|
||||
|
||||
然而,随着召回率的增加,两个模型的精确率整体上都有所下降。特别是当召回率在0.6附近时,模型A的精确率反而超过了模型B。这就充分说明了,只用一个点的精确率和召回率是不能全面衡量模型性能的,只有通过P-R曲线的整体表现,才能对模型进行更全面的评估。
|
||||
|
||||
虽然P-R曲线能全面衡量模型的性能,但是它总归是一条曲线,不是一个数字,我们很难用它直接来判断模型的好坏。那有没有一个指标能用来衡量P-R曲线的优劣呢?当然是有的,这个指标就是AUC(Area Under Curve),曲线下面积。顾名思义,AUC指的是P-R曲线下的面积大小,因此计算AUC值只需要沿着P-R曲线横轴做积分。AUC越大,就证明推荐模型的性能越好。
|
||||
|
||||
### 2. ROC曲线
|
||||
|
||||
接着,我们再来介绍第二个高阶指标,ROC曲线,它也是一个非常常用的衡量模型综合性能的指标。ROC曲线的全称是the Receiver Operating Characteristic曲线,中文名为“受试者工作特征曲线”。ROC曲线最早诞生于军事领域,而后在医学领域应用甚广,“受试者工作特征曲线”这一名称也正是来源于医学领域。
|
||||
|
||||
ROC曲线的横坐标是False Positive Rate(FPR,假阳性率),纵坐标是True Positive Rate (TPR,真阳性率)。这两个名字读上去就有点拗口,我们还是通过它们的定义来理解一下 :
|
||||
|
||||
$$<br>
|
||||
\mathrm{FPR}=\frac{\mathrm{FP}}{N}, T P R=\frac{\mathrm{TP}}{P}<br>
|
||||
$$
|
||||
|
||||
在公式中,P指的是真实的正样本数量,N是真实的负样本数量;TP指的是P个正样本中被分类器预测为正样本的个数,FP指的是N个负样本中被分类器预测为正样本的个数。但我估计你看了这个定义,可能还是不好理解这个ROC曲线是怎么得到的。没关系,我们真正去画一条ROC曲线,你就明白了。
|
||||
|
||||
和P-R曲线一样,ROC曲线也是通过不断移动模型正样本阈值生成的。假设测试集中一共有20个样本,模型的输出如下表所示,表中第一列为样本序号,Class为样本的真实标签,Score为模型输出的样本为正的概率,样本按照预测概率从高到低排序。在输出最终的正例、负例之前,我们需要指定一个阈值,并且设定预测概率大于该阈值的样本会被判为正例,小于该阈值的会被判为负例。
|
||||
|
||||
比如,我们指定0.9为阈值,那么只有第一个样本会被预测为正例,其他全部都是负例。这里的阈值也被称为 “截断点”。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4c/66/4c7f89a6717e0d272527a77a5fe64266.jpeg" alt="">
|
||||
|
||||
接下来,我们要做的就是动态地调整截断点,从最高的得分开始(实际上是从正无穷开始,对应着ROC曲线的零点),逐渐调整到最低得分。每一个截断点都会对应一个FPR和TPR的值,在ROC图上绘制出每个截断点对应的位置,再连接每个点之后,我们就能得到最终的ROC曲线了。那么ROC曲线上的点具体应该怎么确定呢?
|
||||
|
||||
我们来看几个例子,当截断点选择为正无穷的时候,模型会把全部样本预测为负例,那FP和TP必然都为0,FPR和TPR也都为0,因此曲线的第一个点就是 (0,0) 。当把截断点调整为0.9的时候,模型预测1号样本为正样本,并且这个样本也确实是正样本。因此,在20个样本中,当TP=1,所有正例数量P=10的时候,TPR=TP/P=1/10。
|
||||
|
||||
我们还可以看到,这个例子里没有预测错的正样本,也就是说当FP=0,负样本总数N=10的时候,FPR=FP/N=0/10=0,对应着ROC图上的点(0,0.1)。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a5/e6/a54e03043e1dca53a47d601c7b2e51e6.jpg" alt="">
|
||||
|
||||
其实,还有一种更直观的绘制ROC曲线的方法。首先,我们根据样本标签统计出正负样本的数量,假设正样本数量为P,负样本数量为N。然后,我们把横轴的刻度间隔设置为1/N,纵轴的刻度间隔设置为1/P。接着,我们再根据模型输出的预测概率对样本进行从高到低的排序。
|
||||
|
||||
最后,依次遍历样本。同时,从零点开始绘制ROC曲线,每遇到一个正样本就沿纵轴方向绘制一个刻度间隔的曲线,每遇到一个负样本就沿横轴方向绘制一个刻度间隔的曲线,直到遍历完所有样本,曲线最终停在 (1,1) 这个点,整个ROC曲线就绘制完成了。
|
||||
|
||||
在绘制完ROC曲线后,我们也可以像P-R曲线一样,计算出 ROC曲线的AUC,AUC越高,推荐模型的效果就越好。
|
||||
|
||||
### 3. 平均精度均值
|
||||
|
||||
最后,我们来说平均精度均值mAP(mAP,mean average precision)这个高阶指标,它除了在推荐系统中比较常用,在信息检索领域也很常用。mAP其实是对平均精度(AP,average precision)的再次平均,因此在计算mAP前,我们需要先学习什么是平均精度AP。
|
||||
|
||||
假设,推荐系统对某一用户测试集的排序结果是1, 0, 0, 1, 1, 1。其中,1代表正样本,0代表负样本。接下来,我们就按照之前学过的方法,计算这个序列中每个位置上的precision@N。你可以自己先试着计算一下,也可以直接看我下面计算好的结果。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f9/bb/f91acb00e50aa1f273cc1610148953bb.jpeg" alt="" title="每个位置的precision@N值">
|
||||
|
||||
计算平均精度AP的时候,我们只取正样本处的precision进行平均,根据得到的表格AP =(1/1 + 2/4 + 3/5 + 4/6)/4 = 0.6917。接下来,我们再来看什么是mAP。
|
||||
|
||||
如果推荐系统对测试集中的每个用户都进行样本排序,那么每个用户都会计算出一个AP值,再对所有用户的AP值进行平均,就得到了mAP。也就是说,mAP是对精确度平均的平均。
|
||||
|
||||
这里就需要注意了,mAP的计算方法和P-R曲线、ROC曲线的计算方法是完全不同的,因为mAP需要对每个用户的样本进行分用户排序,而P-R曲线和ROC曲线均是对全量测试样本进行排序。这一点在实际操作中是需要注意的。
|
||||
|
||||
## 合理选择评估指标
|
||||
|
||||
到这里,这节课的7个评估指标我们就讲完了。如果你是第一次接触它们,可能现在已经有点茫然了。事实上,除了这些评估指标,还有很多其他的推荐系统指标,比如归一化折扣累计收益(Normalized Discounted Cumulative Gain,NDCG)、覆盖率(Coverage)、多样性(Diversity)等等。那面对这么多评估指标,你肯定想问,我们应该怎么选择它们呢?
|
||||
|
||||
很可惜,这次又是一个开放式的问题,评估指标的选择同样没有标准答案。但我还是会把一些经验性的选择总结出来,希望能够帮助到你。
|
||||
|
||||
比如,在对推荐模型的离线评估中,大家默认的权威指标是ROC曲线的AUC。但AUC评估的是整体样本的ROC曲线,所以我们往往需要补充分析mAP,或者对ROC曲线进行一些改进,我们可以先绘制分用户的ROC,再进行用户AUC的平均等等。
|
||||
|
||||
再比如,在评估CTR模型效果的时候,我们可以采用准确率来进行初步的衡量,但我们很有可能会发现,不管什么模型,准确率都在95%以上。仔细查看数据我们会发现,由于现在电商点击率、视频点击率往往都在1%-10%之间。也就是说,90%以上都是负样本,因此准确率这个指标就不能够精确地反应模型的效果了。这时,我们就需要加入精确率和召回率指标进行更精确的衡量,比如我们采用了Precision@20和Recall@20这两个评估指标,但它终究只衡量了前20个结果的精确率和召回率。
|
||||
|
||||
如果我们要想看到更全面的指标,就要多看看Precision@50和Recall@50,Precision@100和Recall@100,甚至逐渐过渡到P-R曲线。
|
||||
|
||||
总的来说,评估指标的选择不是唯一的,而是一个动态深入,跟你评测的“深度”紧密相关的过程。而且,在真正的离线实验中,虽然我们要通过不同角度评估模型,但也没必要陷入“完美主义”和“实验室思维”的误区,选择过多指标评估模型,更没有必要为了专门优化某个指标浪费过多时间。
|
||||
|
||||
离线评估的目的在于快速定位问题,快速排除不可行的思路,为线上评估找到“靠谱”的候选者。因此,我们根据业务场景选择2~4个有代表性的离线指标,进行高效率的离线实验才是离线评估正确的“打开方式”。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们重点介绍了模型离线评估中使用的评估指标。我把它们分成了两部分,简单直接的低阶评估指标,还有复杂全面的高阶评估指标。
|
||||
|
||||
低阶评估指标主要包括准确率,精确率,召回率和均方根误差。**准确率是指分类正确的样本占总样本个数的比例,精确率指的是分类正确的正样本个数占分类器判定为正样本个数的比例**,**召回率是分类正确的正样本个数占真正的正样本个数的比例,而均方根误差**的定义是预测值跟真实值之间差值的均方根。
|
||||
|
||||
高阶指标包括P-R曲线,ROC曲线和平均精度均值。P-R曲线的横坐标是召回率,纵坐标是精确率;ROC曲线的横坐标是假阳性率,纵坐标是真阳性率。P-R曲线和ROC曲线的绘制都不容易,我希望你能多看几遍我在课程中讲的例子,巩固一下。最后是平均精度均值mAP,这个指标是对每个用户的精确率均值的再次平均。
|
||||
|
||||
最后,为了方便你记忆和对比,我也把所有指标的概念都总结在了文稿的表格里,你可以去看看。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e1/1a/e1a0566473b367633f0d18346608661a.jpeg" alt="">
|
||||
|
||||
## 课后问题
|
||||
|
||||
对于我们今天学到的P-R曲线和ROC曲线,你觉得它们的优缺点分别是什么呢?在正负样本分布极不均衡的情况下,你觉得哪个曲线的表现会更稳定、更权威一点?
|
||||
|
||||
期待在留言区看到你对这节课的思考,我们下节课见!
|
||||
149
极客时间专栏/深度学习推荐系统实战/模型评估篇/26 | 在线测试:如何在推荐服务器内部实现A|B测试?.md
Normal file
149
极客时间专栏/深度学习推荐系统实战/模型评估篇/26 | 在线测试:如何在推荐服务器内部实现A|B测试?.md
Normal file
@@ -0,0 +1,149 @@
|
||||
<audio id="audio" title="26 | 在线测试:如何在推荐服务器内部实现A/B测试?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/95/ff/955624bf0f8874eda7c6a4e48yyd3cff.mp3"></audio>
|
||||
|
||||
你好,我是王喆。这节课我们来聊一聊推荐系统的线上A/B测试。
|
||||
|
||||
上两节课,我们进行了推荐系统离线评估方法和指标的学习。但是无论采用哪种方法,离线评估终究无法还原线上的所有变量。比如说,视频网站最想要提高的指标是用户观看时长,在离线评估的环境下可以模拟出这个指标吗?显然是非常困难的。即使能够在离线环境下生成这样一个指标,它是否能真实客观地反映线上效果,这也要打一个问号。
|
||||
|
||||
所以,对于几乎所有的互联网公司来说,线上A/B测试都是验证新模型、新功能、新产品是否能够提升效果的主要测试方法。这节课,我们就来讲一讲线上A/B测试,希望通过今天的课程,能帮助你了解到A/B测试的基本原理,A/B测试的分层和分桶方法,以及怎么在SparrowRecSys的推荐服务器中实现A/B测试模块。
|
||||
|
||||
## 如何理解A/B测试?
|
||||
|
||||
A/B测试又被称为“分流测试”或“分桶测试”,它通过把被测对象随机分成A、B两组,分别对它们进行对照测试的方法得出实验结论。具体到推荐模型测试的场景下,它的流程是这样的:先将用户随机分成实验组和对照组,然后给实验组的用户施以新模型,给对照组的用户施以旧模型,再经过一定时间的测试后,计算出实验组和对照组各项线上评估指标,来比较新旧模型的效果差异,最后挑选出效果更好的推荐模型。
|
||||
|
||||
好了,现在我们知道了什么是线上A/B测试。那它到底有什么优势,让几乎所有的互联网公司主要使用它来确定模型最终的效果呢?你有想过这是什么原因吗?我总结了一下,主要有三点原因。接下来,我们就一起来聊聊。
|
||||
|
||||
**首先,离线评估无法完全还原线上的工程环境。** 一般来讲,离线评估往往不考虑线上环境的延迟、数据丢失、标签数据缺失等情况,或者说很难还原线上环境的这些细节。因此,离线评估环境只能说是理想状态下的工程环境,得出的评估结果存在一定的失真现象。
|
||||
|
||||
**其次,线上系统的某些商业指标在离线评估中无法计算。** 离线评估一般是针对模型本身进行评估的,无法直接获得与模型相关的其他指标,特别是商业指标。像我们上节课讲的,离线评估关注的往往是ROC曲线、PR曲线的改进,而线上评估却可以全面了解推荐模型带来的用户点击率、留存时长、PV访问量这些指标的变化。
|
||||
|
||||
其实,这些指标才是最重要的商业指标,跟公司要达成的商业目标紧密相关,而它们都要由A/B测试进行更全面准确的评估。
|
||||
|
||||
**最后是离线评估无法完全消除数据有偏(Data Bias)现象的影响。** 什么叫“数据有偏”呢?因为离线数据都是系统利用当前算法生成的数据,因此这些数据本身就不是完全客观中立的,它是用户在当前模型下的反馈。所以说,用户本身有可能已经被当前的模型“带跑偏了”,你再用这些有偏的数据来衡量你的新模型,得到的结果就可能不客观。
|
||||
|
||||
正是因为离线评估存在这三点硬伤,所以我们必须利用线上A/B测试来确定模型的最终效果。明确了这一点,是不是让我们的学习更有方向了?接下来,我们再深入去学习一下A/B测试的核心原则和评估指标。
|
||||
|
||||
## A/B测试的“分桶”和“分层”原则
|
||||
|
||||
刚才,我们说A/B测试的原理就是把用户分桶后进行对照测试。这听上去好像没什么难的,但其实我们要考虑的细节还有很多,比如到底怎样才能对用户进行一个公平公正的分桶呢?如果有多组实验在同时做A/B测试,怎样做才能让它们互不干扰?
|
||||
|
||||
下面,我就来详细的讲一讲A/B测试的“分桶”和“分层”的原则,告诉你让A/B测试公平且高效的执行方法长什么样。
|
||||
|
||||
在A/B测试分桶的过程中,我们需要注意的是**样本的独立性和分桶过程的无偏性。**这里的“独立性”指的是同一个用户在测试的全程只能被分到同一个桶中。“无偏性”指的是在分桶过程中用户被分到哪个实验桶中应该是一个纯随机的过程。
|
||||
|
||||
举个简单的例子,我们把用户ID是奇数的用户分到对照组,把用户ID是偶数的用户分到实验组,这个策略只有在用户ID完全是随机生成的前提下才能说是无偏的,如果用户ID的奇偶分布不均,我们就无法保证分桶过程的无偏性。所以在实践的时候,我们经常会使用一些比较复杂的Hash函数,让用户ID尽量随机地映射到不同的桶中。
|
||||
|
||||
说完了分桶,那什么是分层呢?要知道,在实际的A/B测试场景下,同一个网站或应用往往要同时进行多组不同类型的A/B测试。比如,前端组正在进行不同App界面的A/B测试的时候,后端组也在进行不同中间件效率的A/B测试,同时算法组还在进行推荐场景1和推荐场景2的A/B测试。这个时候问题就来了,这么多A/B测试同时进行,我们怎么才能让它们互相不干扰呢?
|
||||
|
||||
你可能会说,这还不简单,我们全都并行地做这些实验,用户都不重叠不就行了。这样做当然可以,但非常低效。你如果在工作中进行过A/B测试的话肯定会知道,线上测试资源是非常紧张的,如果不进行合理的设计,很快所有流量资源都会被A/B测试占满。
|
||||
|
||||
为了解决这个问题,我们就要用到A/B测试的分层原则了。Google在一篇关于实验测试平台的论文《Overlapping Experiment Infrastructure: More, Better, Faster Experimentation》中,详细介绍了A/B测试分层以及层内分桶的原则。
|
||||
|
||||
如果你没看过这篇论文,没有关系,你记住我总结出来的这句话就够了:**层与层之间的流量“正交”,同层之间的流量“互斥”。**它是什么意思呢?接下来,我就针对这句话做个详细的解释。
|
||||
|
||||
首先,我们来看层与层之间的流量“正交”,它指的是层与层之间的独立实验的流量是正交的,一批实验用的流量穿越每层实验时,都会再次随机打散,然后再用于下一层的实验。
|
||||
|
||||
这么说好像还是太抽象,我们来看下面的示意图。假设,在一个X层的实验中,流量被随机平均分为X1(蓝色)和X2(白色)两部分。当它们穿越到Y层的实验之后,X1和X2的流量会被随机且均匀地分配给Y层的两个桶Y1和Y2。
|
||||
|
||||
如果Y1和Y2的X层流量分配不均匀,那么Y层的样本就是有偏的,Y层的实验结果就会被X层的实验影响,也就无法客观地反映Y层实验组和对照组变量的影响。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e0/7b/e0da06ee473e3f551ac2cyy987957d7b.jpeg" alt="" title="层与层之间流量正交示例">
|
||||
|
||||
理解了第一句话,我们再来看看什么叫同层之间的流量“互斥”。这里的“互斥”具体有2层含义:
|
||||
|
||||
1. 如果同层之间进行多组A/B测试,不同测试之间的流量不可以重叠,这是第一个“互斥”;
|
||||
1. 一组A/B测试中实验组和对照组的流量是不重叠的,这是第二个“互斥”。
|
||||
|
||||
在基于用户的A/B测试中,“互斥”的含义可以被进一步解读为,不同实验之间以及A/B测试的实验组和对照组之间的用户是不重叠的。特别是对推荐系统来说,用户体验的一致性是非常重要的。也就是说我们不可以让同一个用户在不同的实验组之间来回“跳跃”,这样会严重损害用户的实际体验,也会让不同组的实验结果相互影响。因此在A/B测试中,保证同一用户始终分配到同一个组是非常有必要的。
|
||||
|
||||
A/B测试的“正交”与“互斥”原则共同保证了A/B测试指标的客观性,而且由于分层的存在,也让功能无关的A/B测试可以在不同的层上执行,充分利用了流量资源。
|
||||
|
||||
在清楚了A/B测试的方法之后,我们要解决的下一个问题就是,怎么选取线上A/B测试的指标。
|
||||
|
||||
## 线上A/B测试的评估指标
|
||||
|
||||
一般来说,A/B测试是模型上线前的最后一道测试,通过A/B测试检验的模型会直接服务于线上用户,来完成公司的商业目标。因此,**A/B测试的指标应该与线上业务的核心指标保持一致**。这就需要我们因地制宜地制定最合适的推荐指标了。
|
||||
|
||||
具体怎么做呢?实际也不难,那在实际的工作中,我们需要跟产品、运营团队多沟通,在测试开始之前一起制定大家都认可的评估指标。为了方便你参考,我在下表中列出了电商类推荐模型、新闻类推荐模型、视频类推荐模型的主要线上A/B测试评估指标,你可以看一看。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/eb/48/eb1c9db619f6ec5b8e62fc2a81419948.jpeg" alt="">
|
||||
|
||||
看了这些指标,我想你也发现了,线上A/B测试的指标和离线评估的指标(诸如AUC、F1- score等),它们之间的差异非常大。这主要是因为,离线评估不具备直接计算业务核心指标的条件,因此退而求其次,选择了偏向于技术评估的模型相关指标,但公司更关心的是能够驱动业务发展的核心指标,这也是A/B测试评估指标的选取原则。
|
||||
|
||||
总的来说,在具备线上环境条件时,利用A/B测试验证模型对业务核心指标的提升效果非常有必要。从这个意义上讲,线上A/B测试的作用是离线评估永远无法替代的。
|
||||
|
||||
## SparrowRecSys中A/B测试的实现方法
|
||||
|
||||
搞清楚了A/B测试的主要方法,下一步就让我们一起在SparrowRecSys上实现一个A/B测试模块,彻底掌握它吧!
|
||||
|
||||
既然是线上测试,那我们肯定需要在推荐服务器内部来实现这个A/B测试的模块。模块的基本框架不难实现,就是针对不同的userId,随机分配给不同的实验桶,每个桶对应着不同的实验设置。
|
||||
|
||||
比较方便的是,我们可以直接在上一篇刚实现过的“猜你喜欢”功能上进行实验。实验组的设置是算法NerualCF,对照组的设置是Item2vec Embedding算法。接下来,我们说一下详细的实现步骤。
|
||||
|
||||
首先,我们在SparrowRecSys里面建立了一个ABTest模块,它负责为每个用户分配实验设置。其中,A组使用的模型bucketAModel是emb,代表着Item2vec Embedding算法,B组使用的模型bucketBModel是Nerualcf。除此之外,我们还给不在A/B测试的用户设置了默认模型emb,默认模型是不在实验范围内的用户的设置。
|
||||
|
||||
模型设置完,就到了分配实验组的阶段。这里,我们使用getConfigByUserId函数来确定用户所在的实验组。具体怎么做呢?因为这个函数只接收userId作为唯一的输入参数,所以我们利用userId的hashCode把数值型的ID打散,然后利用userId的hashCode和trafficSplitNumber这个参数进行取余数的操作,根据余数的值来确定userId在哪一个实验组里。
|
||||
|
||||
你可能对trafficSplitNumber这个参数的作用还不熟悉,我来进一步解释一下。这个参数的含义是把我们的全部用户分成几份。这里,我们把所有用户分成了5份,让第1份用户参与A组实验,第2份用户参与B组实验,其余用户继续使用系统的默认设置。这样的操作就是分流操作,也就是把流量划分之后,选取一部分参与A/B测试。
|
||||
|
||||
```
|
||||
public class ABTest {
|
||||
final static int trafficSplitNumber = 5;
|
||||
final static String bucketAModel = "emb";
|
||||
final static String bucketBModel = "nerualcf";
|
||||
final static String defaultModel = "emb";
|
||||
public static String getConfigByUserId(String userId){
|
||||
if (null == userId || userId.isEmpty()){
|
||||
return defaultModel;
|
||||
}
|
||||
if(userId.hashCode() % trafficSplitNumber == 0){
|
||||
System.out.println(userId + " is in bucketA.");
|
||||
return bucketAModel;
|
||||
}else if(userId.hashCode() % trafficSplitNumber == 1){
|
||||
System.out.println(userId + " is in bucketB.");
|
||||
return bucketBModel;
|
||||
}else{
|
||||
System.out.println(userId + " isn't in AB test.");
|
||||
return defaultModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
上面是A/B测试模块的主要实现。在实际要进行A/B测试的业务逻辑中,我们需要调用A/B测试模块来获得正确的实验设置。比如,我们这次选用了猜你喜欢这个功能进行A/B测试,就需要在相应的实现RecForYoService类中添加A/B测试的代码,具体的实现如下:
|
||||
|
||||
```
|
||||
if (Config.IS_ENABLE_AB_TEST){
|
||||
model = ABTest.getConfigByUserId(userId);
|
||||
}
|
||||
//a simple method, just fetch all the movie in the genre
|
||||
List<Movie> movies = RecForYouProcess.getRecList(Integer.parseInt(userId), Integer.parseInt(size), model);
|
||||
|
||||
```
|
||||
|
||||
我们可以看到,这里的实现非常简单,就是调用ABTest.getConfigByUserId函数获取用户对应的实验设置,然后把得到的参数model传入后续的业务逻辑代码。需要注意的是,我设置了一个全局的A/B测试使能标识Config.IS_ENABLE_AB_TEST,你在测试这部分代码的时候,要把这个使能标识改为true。
|
||||
|
||||
上面就是经典的A/B测试核心代码的实现。在实际的应用中,A/B测试的实现当然要更复杂一些。比如,不同实验的设置往往是存储在数据库中的,需要我们从数据库中拿到它。再比如,为了保证分组时的随机性,我们往往会创建一些复杂的hashCode函数,保证能够均匀地把用户分到不同的实验桶中。但整个A/B测试的核心逻辑没有变化,你完全可以参考我们今天的实现过程。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们讲解了线上A/B测试的基本原理和评估指标,并且在SparrowRecsys上实现了A/B测试的模块。我带你从A/B测试的定义和优势、设计原则以及在线评估指标这三个方面回顾一下。
|
||||
|
||||
A/B测试又叫“分流测试”或“分桶测试”,它把被测对象随机分成A、B两组,通过对照测试的方法得出实验结论。相比于离线评估,A/B测试有三个优势:
|
||||
|
||||
1. 实验环境就是线上的真实生产环境;
|
||||
1. 可以直接得到线上的商业指标;
|
||||
1. 不受离线数据“数据有偏”现象的影响。
|
||||
|
||||
在A/B测试的设计过程中,我们要遵循层与层之间的流量“正交”,同层之间的流量“互斥”这一设计原则,这样才能既正确又高效地同时完成多组A/B测试。除此之外,在线上评估指标的制定过程中,我们要尽量保证这些指标与线上业务的核心指标保持一致,这样才能更加准确地衡量模型的改进,有没有帮助到公司的业务发展,是否达成了公司的商业目标。
|
||||
|
||||
为了方便你复习,我把一些核心的知识点总结在了表格中,你可以看一看。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2b/0e/2b470d744b02c013b0a4bb00748b010e.jpeg" alt="">
|
||||
|
||||
## 课后思考
|
||||
|
||||
今天讲的A/B测试的分层和分桶的原则你都理解了吗?如果我们在测试模型的时候,一个实验是在首页测试新的推荐模型,另一个实验是在内容页测试新的推荐模型,你觉得这两个实验应该放在同一层,还是可以放在不同的层呢?为什么?
|
||||
|
||||
期待在留言区看到你的思考,如果有其他疑问也欢迎你随时提出来,我会一一解答,我们下节课见!
|
||||
125
极客时间专栏/深度学习推荐系统实战/模型评估篇/27 | 评估体系:如何解决A|B测试资源紧张的窘境?.md
Normal file
125
极客时间专栏/深度学习推荐系统实战/模型评估篇/27 | 评估体系:如何解决A|B测试资源紧张的窘境?.md
Normal file
@@ -0,0 +1,125 @@
|
||||
<audio id="audio" title="27 | 评估体系:如何解决A/B测试资源紧张的窘境?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/cd/87/cd720c74b71b85962d3649yy64d9dc87.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
我们在进行推荐系统评估时经常会遇到两类问题。
|
||||
|
||||
一类是在做线上A/B测试的时候,流量经常不够用,要排队等别人先做完测试之后才能进行自己的测试。线上A/B测试资源紧张的窘境,会大大拖慢我们试验的新思路,以及迭代优化模型的进度。
|
||||
|
||||
另一类是,离线评估加上在线评估有那么多种测试方法,在实际工作中,我们到底应该选择哪一种用来测试,还是都要覆盖到呢?
|
||||
|
||||
其实,这两个问题的答案是有深刻联系的,并不是孤立的。我认为最好的解决办法就是,建立起一套**推荐系统的评估体系,用它来解决不同评估方法的配合问题,以及线上A/B测试资源紧张的问题。这节课,我就带你一起来厘清如何建立起一整套推荐系统评估体系。**
|
||||
|
||||
## 什么是推荐系统的评估体系?
|
||||
|
||||
首先,什么是评估体系呢?我先给它下一个定义,**推荐系统的评估体系指的是,由多种不同的评估方式组成的、兼顾效率和正确性的,一套用于评估推荐系统的解决方案**。一个成熟的推荐系统评估体系应该综合考虑评估效率和正确性,可以利用很少的资源,快速地筛选出效果更好的模型。
|
||||
|
||||
那对一个商业公司来说,最公正也是最合理的评估方法就是进行线上测试,来评估模型是否能够更好地达成公司或者团队的商业目标。但是,正如我们开头所说,线上A/B测试要占用宝贵的线上流量资源,这些有限的线上测试机会远远不能满足算法工程师改进模型的需求。所以如何有效地把线上和离线测试结合起来,提高测试的效率,就是我们迫切的需求。
|
||||
|
||||
那我们该怎么去构建起一整套评估体系呢?图1就是一个典型的评估体系示意图。从图中我们可以看到,处于最底层的是传统的离线评估方法,比如Holdout检验、交叉检验等,往上是离线Replay评估方法,再往上是一种叫Interleaving的线上测试方法,我们等会还会详细介绍,最后是线上A/B测试。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/yy/92/yy44dd15a4e727c8b6eec89fb187e392.jpg" alt="" title="图1 推荐系统的评测体系 [br](出自《深度学习推荐系统》)">
|
||||
|
||||
这四层结构共同构成完整的评估体系,做到了评估效率和评估正确性之间的平衡,越是底层的方法就会承担越多筛选掉改进思路的任务,这时候“评估效率”就成了更关键的考虑因素,那对于“正确性”的评估,我们反而没有多么苛刻的要求了。
|
||||
|
||||
总的来说,离线评估由于有着更多可供利用的计算资源,可以更高效、快速地筛选掉那些“不靠谱”的模型来改进思路,所以被放在了第一层的位置。
|
||||
|
||||
随着候选模型被一层层筛选出来,越接近正式上线的阶段,评估方法对评估“正确性”的要求就越严格。因此,在模型正式上线前,我们应该以最接近真实产品体验的A/B测试,来做最后的模型评估,产生最具说服力的在线指标之后,才能够进行最终的模型上线,完成模型改进的迭代过程。
|
||||
|
||||
讲了这么多,你可能会觉得,道理没问题,但工作中真的是这样吗?不如,我们来看个例子。下图就是一个很形象的工作中的模型筛选过程。
|
||||
|
||||
假设,现在有30个待筛选的模型,如果所有模型都直接进入线上A/B测试的阶段进行测试,所需的测试样本是海量的,由于线上流量有限,测试的时间会非常长。但如果我们把测试分成两个阶段,第一个阶段先进行初筛,把30个模型筛选出可能胜出的5个,再只对这5个模型做线上A/B测试,所需的测试流量规模和测试时间长度都会大大减少。这里的初筛方法,就是我们在评估体系中提到的离线评估、离线Replay和在线Interleaving等方法。
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/da/1b/da57fcb9287b31ec436a4dce87f11c1b.jpg" alt="" title="图2 模型的筛选过程 [br](图片出自The Netflix Tech Blog)">](https://netflixtechblog.com/interleaving-in-online-experiments-at-netflix-a04ee392ec55)
|
||||
|
||||
到这里,我想你已经清楚了什么是推荐系统的评估体系,以及评估体系是有哪些方法组成的。但在这些组成方法中,我们还有两点要重点注意:**一个是离线Replay这个方法,虽然我们之前讲过离线Replay的原理,但是对于它的相关工程架构还没有讲过;第二个是上面提到过的线上Interleaving方法。** 下面,我就借着流媒体巨头Netflix的实践方案,来讲解一下离线Replay和在线Interleaving的细节。
|
||||
|
||||
## Netflix的Replay评估方法实践
|
||||
|
||||
借着下图3,我们来回顾一下,[第24讲](https://time.geekbang.org/column/article/317319)学过的离线Replay方法的原理:离线Replay通过动态的改变测试时间点,来模拟模型的在线更新过程,让测试过程更接近真实线上环境。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/cb/e4/cb05ba1a3a975f9d824df60bdaca7ee4.jpg" alt="" title="图3 静态时间分割评估与动态Replay评估 [br](出自《深度学习推荐系统》)">
|
||||
|
||||
但是在Replay方法的实现过程中,存在一个很棘手的工程问题,就是我们总提到的“未来信息”问题,或者叫做“特征穿越”问题。因此在Replay过程中,每次模型更新的时候,我们都需要用历史上“彼时彼刻”的特征进行训练,否则训练和评估的结果肯定是不准确的。
|
||||
|
||||
我来举个例子,假设Replay方法要使用8月1日到8月31日的样本数据进行重放,这些样本中包含一个特征,叫做“历史CTR”,这个特征只能通过历史数据来计算生成。
|
||||
|
||||
比如说,8月20日的样本就只能够使用8月1日到8月19日的数据来生成“历史CTR”这个特征,绝不能使用8月20日以后的数据来生成这个特征。在评估过程中,如果我们为了工程上的方便,使用了8月1日到8月31日所有的样本数据生成这个特征,供所有样本使用,之后再使用Replay的方法进行评估,那我们得到的结论必然是错误的。
|
||||
|
||||
那么问题来了,在工程上,为了方便按照Replay方法进行模型评估,我们应该怎么去建立一套数据处理的架构,支持这种历史特征的复现呢?接下来,我们就看一看Netflix是怎么解决这个问题的。
|
||||
|
||||
Netflix为了进行离线Replay的实验,建立了一整套从数据生成到数据处理再到数据存储的数据处理架构,并给它起了一个很漂亮的名字,叫做时光机(Time Machine)。
|
||||
|
||||
下图4就是时光机的架构,图中最主要的就是Snapshot Jobs(数据快照)模块。它是一个每天执行的Spark程序,它做的主要任务就是把当天的各类日志、特征、数据整合起来,形成当天的、供模型训练和评估使用的样本数据。它还会以日期为目录名称,将样本快照数据保存在分布式文件系统S3中(Snapshots),再对外统一提供API(Batch APIs),供其他模型在训练和评估的时候按照时间范围方便地获取。
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/3e/64/3e41699be3fa13709c7e898c4f07bf64.jpg" alt="" title="图4 Netflix的离线评估数据流架构——时光机 [br](出自The Netflix Tech Blog )">](https://netflixtechblog.com/distributed-time-travel-for-feature-generation-389cccdd3907)
|
||||
|
||||
这个Snapshot Jobs主任务的源数据是从哪来的呢?你可以重点关注它上方的Context Set模块和左边的Prana模块。接下来,我再详细和你说说这两个模块的任务。
|
||||
|
||||
**Context Set模块负责保存所有的历史当天的环境信息。** 环境信息主要包括两类:一类是存储在Hive中的场景信息,比如用户的资料、设备信息、物品信息等数据;另一类是每天都会发生改变的一些统计类信息,包括物品的曝光量、点击量、播放时长等信息。
|
||||
|
||||
**Prana模块负责处理每天的系统日志流。** 系统日志流指的是系统实时产生的日志,它包括用户的观看历史(Viewing History)、用户的推荐列表(My List)和用户的评价(Ratings)等。这些日志从各自的服务(Service)中产生,由Netflix的统一数据接口Prana对外提供服务。
|
||||
|
||||
因此,Snapshot Jobs这个核心模块每天的任务就是,通过Context Set获取场景信息,通过Prana获取日志信息,再经过整合处理、生成特征之后,保存当天的数据快照到S3。
|
||||
|
||||
在生成每天的数据快照后,使用Replay方法进行离线评估就不再是一件困难的事情了,因为我们没有必要在Replay过程中进行烦琐的特征计算,直接使用当天的数据快照就可以了。
|
||||
|
||||
在时光机这个架构之上,使用某个时间段的样本进行一次Replay评估,就相当于直接穿越到了彼时彼刻,用当时的日志和特征进行模型训练和评估,就像进行了一次时光旅行(Time Travel)一样。
|
||||
|
||||
## Interleaving评估方法是什么
|
||||
|
||||
讲完了离线Replay的工程实现方法,我们再来聊一聊什么是Interleaving在线评估方法。
|
||||
|
||||
那Interleaving评估方法提出的意义是什么呢?主要有两方面:首先,它是和A/B测试一样的在线评估方法,能够得到在线评估指标;其次,它提出的目的是为了比传统的A/B测试用更少的资源,更快的速度得到在线评估的结果。
|
||||
|
||||
清楚了Interleaving评估方法提出的意义,我们就可以更好地理解Interleaving方法的具体细节了。下面,我们对比A/B测试,来看看Interleaving方法的具体实现过程。
|
||||
|
||||
在传统的A/B测试中,我们会把用户随机分成两组。一组接受当前的推荐模型A的推荐结果,这一组被称为对照组 。另一组接受新的推荐模型B的推荐结果,这组被成为实验组。
|
||||
|
||||
在Interleaving方法中,不再需要两个不同组的用户,只需要一组用户,这些用户会收到模型A和模型B的混合结果。也就是说,用户会在一个推荐列表里同时看到模型A和模型B的推荐结果。在评估的过程中,Interleaving方法通过分别累加模型A和模型B推荐物品的效果,来得到模型A和B最终的评估结果。
|
||||
|
||||
下图可以帮助我们更形象地对比A/B测试和Interleaving方法。
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/e2/29/e2257304c4e450138f81ea9460ddef29.jpg" alt="" title="图5 传统A/B测试和Interleaving方法的比较 [br](出自The Netflix Tech Blog )">](https://netflixtechblog.com/interleaving-in-online-experiments-at-netflix-a04ee392ec55)
|
||||
|
||||
那你可能想问了,在使用Interleaving方法进行测试的时候,我们该怎么保证对模型A和模型B的测试是公平的呢?如果有一个模型的结果总排在第一位,这对另一个模型不就不公平了吗?
|
||||
|
||||
这个问题很好,我们确实需要考虑推荐列表中位置偏差的问题,要想办法避免来自模型A或者模型B的物品总排在第一位。因此,我们需要以相等的概率让模型A和模型B产生的物品交替领先。这就像在野球场打球的时候,两个队长会先通过扔硬币的方式决定谁先选人,再交替来选择队员。
|
||||
|
||||
理解了原理,我们再结合下面的图示,来进一步理解Interleaving方法混合模型A和B结果的过程。和刚才说的野球场选人的过程一样,我们先选模型A或者模型B的排名第一的物品作为最终推荐列表的第一个物品,然后再交替选择,直到填满整个推荐列表。所以,最后得到的列表会是ABABAB,或者BABABA这样的顺序,而且这两种形式出现的概率应该是相等的,这样才能保证两个模型的公平性。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ff/40/ffacf8e910e56233c3a9d004b8c22d40.jpg" alt="" title="图6 Interleaving方法中推荐列表的生成方法">
|
||||
|
||||
最后,我们要清楚推荐列表中的物品到底是由模型A生成的,还是由模型B生成的,然后统计出所有模型A物品的综合效果,以及模型B物品的综合效果,然后进行对比。这样,模型评估过程就完成了。
|
||||
|
||||
总的来说,Interleaving的方法由于不用进行用户分组,因此比传统A/B测试节约了一半的流量资源。但是Interleaving方法能彻底替代传统A/B测试吗?其实也不能,在测试一些用户级别而不是模型级别的在线指标时,我们就不能用Interleaving方法。
|
||||
|
||||
比如用户的留存率,用户从试用到付费的转化率等,由于Interleaving方法同时使用了对照模型和实验模型的结果,我们就不清楚到底是哪个模型对这些结果产生了贡献。但是在测试CTR、播放量、播放时长这些指标时,Interleaving就可以通过累加物品效果得到它们。这个时候,它就能很好地替代传统的A/B测试了。
|
||||
|
||||
到这里,我们就形成了一个完整、高效且准确的评估系统。希望你能从整体的角度重新审视一遍这个体系中的每个方法,如果有不清楚的,再好好回顾一下我讲的知识点。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们利用之前讲过的知识,总结出了推荐系统的评估体系。这个评估体系由传统离线评估、离线Replay、线上Interleaving,以及线上A/B测试四个层级组成。这四个层级由下到上评估效率逐渐降低,但是评估的准确性逐渐升高,它们共同组成一个能够高效筛选候选模型的评估体系。
|
||||
|
||||
针对这个评估体系中的两个要点,离线Replay实践和Interleaving方法,我们又深入学习了它们的工程架构和实现细节。
|
||||
|
||||
其中,离线Replay借鉴了Netflix时光机的经验,这个时光机的数据流体系通过融合日志流和场景信息数据,生成天级别的数据快照,并对外提供统一的API,供模型训练和评估使用,使用时就像做了一次时光旅行。
|
||||
|
||||
对于Interleaving方法,我们应该清楚它实现的三个要点:
|
||||
|
||||
- 它不进行用户分组;
|
||||
- 它的实验推荐列表是通过间隔地选择模型A和模型B的推荐物品得到的;
|
||||
- 为了保证它的公平性,我们要从模型A或者模型B中随机选择第一个物品,就像野球场选人一样完成推荐列表的生成。
|
||||
|
||||
还是老习惯,我把这节课的重要知识点总结在了下面的表格里,方便你及时回顾。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/75/12/7591c3bb54dd16caccb71cbdf995d012.jpeg" alt="">
|
||||
|
||||
这节课也是我们模型评估篇的最后一节课,希望通过整个模型评估篇的学习,你不仅能够熟悉起每一种评估方法,而且能够清楚它们之间的区别和联系,形成一个高效的评估体系。相信它会加快你模型迭代的速度,对你的实际工作产生非常积极的影响!
|
||||
|
||||
## 课后思考
|
||||
|
||||
在Interleaving方法中,推荐列表是由模型A和模型B的结果共同组成的,那如果模型A和模型B的结果中有重叠怎么办?是保留模型A的结果还是模型B的结果呢?你有什么好的想法吗?
|
||||
|
||||
今天讲的评估体系,你知道怎么建立了吗?欢迎把你的思考和疑问写在留言区,不妨也把这节课分享给你的朋友们,我们下节课见!
|
||||
107
极客时间专栏/深度学习推荐系统实战/模型评估篇/特别加餐|TensorFlow的模型离线评估实践怎么做?.md
Normal file
107
极客时间专栏/深度学习推荐系统实战/模型评估篇/特别加餐|TensorFlow的模型离线评估实践怎么做?.md
Normal file
@@ -0,0 +1,107 @@
|
||||
<audio id="audio" title="特别加餐|TensorFlow的模型离线评估实践怎么做?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/77/e7/7704d444f9fe7741752e41586dc4a6e7.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
上两节课,我们学习了离线评估的主要方法以及离线评估的主要指标。那这些方法和指标具体是怎么使用的,会遇到哪些问题呢?我们之前实现的深度学习模型的效果怎么样呢?
|
||||
|
||||
这节课,我们直接进入实战,在TensorFlow环境下评估一下我们之前实现过的深度学习模型。一方面这能帮助我们进一步加深对离线评估方法和指标的理解,另一方面,也能检验一下我们自己模型的效果。
|
||||
|
||||
## 训练集和测试集的生成
|
||||
|
||||
离线评估的第一步就是要生成训练集和测试集,在这次的评估实践中,我会选择最常用的Holdout检验的方式来划分训练集和测试集。划分的方法我们已经在[第23讲](https://time.geekbang.org/column/article/317114)里用Spark实现过了,就是调用Spark中的randomSplit函数进行划分,具体的代码你可以参考 FeatureEngForRecModel对象中的splitAndSaveTrainingTestSamples函数。
|
||||
|
||||
这里我们按照8:2的比例把全量样本集划分为训练集和测试集,再把它们分别存储在`SparrowRecSys/src/main/resources/webroot/sampledata/trainingSamples.csv`和`SparrowRecSys/src/main/resources/webroot/sampledata/testSamples.csv`路径中。
|
||||
|
||||
在TensorFlow内部,我们跟之前载入数据集的方式一样,调用`get_dataset`方法分别载入训练集和测试集就可以了。
|
||||
|
||||
## TensorFlow评估指标的设置
|
||||
|
||||
在载入训练集和测试集后,我们需要搞清楚如何在TensorFlow中设置评估指标,并通过这些指标观察模型在每一轮训练上的效果变化,以及最终在测试集上的表现。这个过程听起来还挺复杂,好在,TensorFlow已经为我们提供了非常丰富的评估指标,这让我们可以在模型编译阶段设置metrics来指定想要使用的评估指标。
|
||||
|
||||
具体怎么做呢?我们一起来看看下面的代码,它是设置评估指标的一个典型过程。首先,我们在model complie阶段设置准确度(Accuracy)、ROC曲线AUC(tf.keras.metrics.AUC(curve='ROC'))、PR曲线AUC(tf.keras.metrics.AUC(curve='PR')),这三个在评估推荐模型时最常用的指标。
|
||||
|
||||
同时,在训练和评估过程中,模型还会默认产生损失函数loss这一指标。在模型编译时我们采用了binary_crossentropy作为损失函数,所以这里的Loss指标就是我们在上一节课介绍过的二分类问题的模型损失Logloss。
|
||||
|
||||
在设置好评估指标后,模型在每轮epoch结束后都会输出这些评估指标的当前值。在最后的测试集评估阶段,我们可以调用model.evaluate函数来生成测试集上的评估指标。具体的实现代码,你可以参考SparrowRecsys项目中深度推荐模型相关的代码。
|
||||
|
||||
```
|
||||
# compile the model, set loss function, optimizer and evaluation metrics
|
||||
model.compile(
|
||||
loss='binary_crossentropy',
|
||||
optimizer='adam',
|
||||
metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC'), tf.keras.metrics.AUC(curve='PR')])
|
||||
# train the model
|
||||
model.fit(train_dataset, epochs=5)
|
||||
# evaluate the model
|
||||
test_loss, test_accuracy, test_roc_auc, test_pr_auc = model.evaluate(test_dataset)
|
||||
|
||||
```
|
||||
|
||||
在执行这段代码的时候,它的输出是下面这样的。从中,我们可以清楚地看到每一轮训练的Loss、Accuracy、ROC AUC、PR AUC这四个指标的变化,以及最终在测试集上这四个指标的结果。
|
||||
|
||||
```
|
||||
Epoch 1/5
|
||||
8236/8236 [==============================] - 60s 7ms/step - loss: 3.0724 - accuracy: 0.5778 - auc: 0.5844 - auc_1: 0.6301
|
||||
Epoch 2/5
|
||||
8236/8236 [==============================] - 55s 7ms/step - loss: 0.6291 - accuracy: 0.6687 - auc: 0.7158 - auc_1: 0.7365
|
||||
Epoch 3/5
|
||||
8236/8236 [==============================] - 56s 7ms/step - loss: 0.5555 - accuracy: 0.7176 - auc: 0.7813 - auc_1: 0.8018
|
||||
Epoch 4/5
|
||||
8236/8236 [==============================] - 56s 7ms/step - loss: 0.5263 - accuracy: 0.7399 - auc: 0.8090 - auc_1: 0.8305
|
||||
Epoch 5/5
|
||||
8236/8236 [==============================] - 56s 7ms/step - loss: 0.5071 - accuracy: 0.7524 - auc: 0.8256 - auc_1: 0.8481
|
||||
|
||||
|
||||
1000/1000 [==============================] - 5s 5ms/step - loss: 0.5198 - accuracy: 0.7427 - auc: 0.8138 - auc_1: 0.8430
|
||||
Test Loss 0.5198314250707626, Test Accuracy 0.7426666617393494, Test ROC AUC 0.813848614692688, Test PR AUC 0.8429719805717468
|
||||
|
||||
|
||||
```
|
||||
|
||||
总的来说,随着训练的进行,模型的Loss在降低,而Accuracy、Roc AUC、Pr AUC这几个指标都在升高,这证明模型的效果随着训练轮数的增加在逐渐变好。
|
||||
|
||||
最终,我们就得到了测试集上的评估指标。你会发现,测试集上的评估结果相比训练集有所下降,比如Accuracy从0.7524下降到了0.7427,ROC AUC从0.8256下降到了0.8138。这是非常正常的现象,因为模型在训练集上都会存在着轻微过拟合的情况。
|
||||
|
||||
如果测试集的评估结果相比训练集出现大幅下降,比如下降幅度超过了5%,就说明模型产生了非常严重的过拟合现象,我们就要反思一下是不是在模型设计过程中出现了一些问题,比如模型的结构对于这个问题来说过于复杂,模型的层数或者每层的神经元数量过多,或者我们要看一看是不是需要加入Dropout,正则化项来减轻过拟合的风险。
|
||||
|
||||
除了观察模型自己的效果,在模型评估阶段,我们更应该重视不同模型之间的对比,这样才能确定我们最终上线的模型,下面我们就做一个模型效果的横向对比。
|
||||
|
||||
## 模型的效果对比
|
||||
|
||||
在推荐模型篇,我们已经实现了EmbeddingMLP、NerualCF、Wide&Deep以及DeepFM这四个深度学习模型,后来还有同学添加了DIN的模型实现。
|
||||
|
||||
那接下来,我们就利用这节课的模型评估方法,来尝试对比一下这几个模型的效果。首先,我直接把这些模型在测试集上的评估结果记录到了表格里,当然,我更建议你利用SparrowRecsys项目中的代码,自己来计算一下,多实践一下我们刚才说的模型评估方法。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/06/c3/067c96ed1a4d59b1e2a8d610cb6888c3.jpeg" alt="">
|
||||
|
||||
通过上面的比较,我们可以看出,Embedding MLP和Wide&Deep模型在我们的MovieLens这个小规模数据集上的效果最好,它们两个的指标也非常接近,只不过是在不同指标上有细微的差异,比如模型Loss指标上Wide&Deep模型好一点,在Accuracy、ROC AUC、PR AUC指标上Embedding MLP模型好一点。
|
||||
|
||||
遇到这种情况,我们该如何挑出更好的那个模型呢?一般我们会在两个方向上做尝试:一是做进一步的模型调参,特别是对于复杂一点的Wide&Deep模型,我们可以尝试通过参数的Fine Tuning(微调)让模型达到更好的效果;二是如果经过多次尝试两个模型的效果仍比较接近,我们就通过线上评选出最后的胜出者。
|
||||
|
||||
说完了效果好的指标,不知道你有没有注意到一个反常的现象,那就是模型DeepFM的评估结果非常奇怪,怎么个奇怪法呢?理论上来说,DeepFM的表达能力是最强的,可它现在展示出来的评估结果却最差。这种情况就极有可能是因为模型遇到了过拟合问题。为了验证个想法,我们再来看一下DeepFM在训练集上的表现,如下表所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e6/41/e659147e8da20228ed722e3f38eea641.jpeg" alt="">
|
||||
|
||||
我们很惊讶地发现,DeepFM在测试集上的表现比训练集差了非常多。毫无疑问,这个模型过拟合了。当然,这里面也有我们数据的因素,因为我们采用了一个规模很小的采样过的MovieLens数据集,在训练复杂模型时,小数据集往往更难让模型收敛,并且由于训练不充分的原因,模型中很多参数其实没有达到稳定的状态,因此在测试集上的表现往往会呈现出比较大的随机性。
|
||||
|
||||
通过DeepFM模型效果对比的例子,也再一次印证了我们在[“最优的模型结构该怎么找?”](https://time.geekbang.org/column/article/315620)那节课的结论:推荐模型没有银弹,每一个业务,每一类数据,都有最合适的模型结构,并不是说最复杂的,最新的模型结构就是最好的模型结构,我们需要因地制宜地调整模型和参数,这才是算法工程师最大的价值所在。
|
||||
|
||||
## 小结
|
||||
|
||||
这节实践课,我们基于TensorFlow进行了深度推荐模型的评估,整个实践过程可以分成三步。
|
||||
|
||||
第一步是导入Spark分割好的训练集和测试集。
|
||||
|
||||
第二步是在TensorFlow中设置评估指标,再在测试集上调用model.evaluate函数计算这些评估指标。在实践过程中,我们要清楚有哪些TensorFlow的指标可以直接调用。那在这节课里,我们用到了最常用的Loss、Accuracy、ROC AUC、PR AUC四个指标。
|
||||
|
||||
第三步是根据四个深度推荐模型的评估结果,进行模型效果的对比。通过对比的结果我们发现Embedding MLP和Wide&Deep的效果是最好的。同时,我们也发现,本该表现很好的DeepFM模型,它的评估结果却比较差,原因是模型产生了非常严重的过拟合问题。
|
||||
|
||||
因此,在实际工作中,我们需要通过不断调整模型结构、模型参数,来找到最合适当前业务和数据集的模型。
|
||||
|
||||
## 课后思考
|
||||
|
||||
1.除了这节课用到的Loss、Accuracy、ROC AUC、PR AUC这四个指标,你在TensorFlow的实践中还会经常用到哪些评估指标呢? 你能把这些常用指标以及它们特点分享出来吗?(你可以参考TensorFlow的官方[Metrics文档](https://tensorflow.google.cn/api_docs/python/tf/keras/metrics) )
|
||||
|
||||
2.你认为DeepFM评估结果这么差的原因,除了过拟合,还有什么更深层次的原因呢?可以尝试从模型结构的原理上给出一些解释吗?
|
||||
|
||||
期待在留言区看到你对DeepFM模型的思考和使用评估指标的经验,我们下节课见!
|
||||
Reference in New Issue
Block a user