推荐系统中可能遇到的坑

  1. 使用用户的 user ID 特征,需要用户非常多的行为才会使其收敛
  2. 不稳定的网络会导致 Embedding 效果变差,由于业务场景下短视频的冷启动问题非常严重,Embedding 的质量至关重要;
  3.  embedding 空间需要对齐:在不同业务下,embedding 的空间分布存在差异。可以把当前用户来自于不同业务的差异作为特征来学习一个gate映射网络来直接学习这种映射关系,然后直接对输入层进行映射。
  4. 特征重要性需要对齐:一些特征在不同业务下的重要性是不一样的。例如 Click 模型在双列产品上非常重要,但是在上下滑就不太重要。需要针对不同的业务用户视频来学习特征级别的重要性。
  5. 使用 Target Attention 来替换 transformer self attention 部分,发现 self attention相对于 Target Attention 并没有显著的收益,但是计算量非常大。以此替换可以降低计算的复杂度。
  6. 使用视频观看时间戳取代 position embedding。短期行为序列建模希望模型更关注近期的观看历史行为。
  7. 借鉴 DIN 中介绍的 adaptive l2 regularization 的方式,挑选了一批类似用户id这种高维稀疏 id 类特征做动态正则。对正则系数做适当调整后,模型训练正常,全量数据过 5 个 epoch 也不会出现过拟合现象。

  8. 对于序列特征中的poi并不是考虑越多的属性效果会更好,选择的属性需要覆盖度高,不然序列中太多的属性默认值会导致模型训练不佳。

一个字符串的序列 user_click_seq =[ [“6,5,4,3,2,1”] [“10,9,8,7,6,5,4,3,2,1”]]  切分之后会得到一个sparse类型的tensor
sparse_tensor = tf.string_split(user_click_seq, ',')
fea = tf.SparseTensor(sparse_tensor.indices, tf.string_to_number(sparse_tensor.values, tf.int64), sparse_tensor.dense_shape)

主要包含三个信息,存放值的index、具体的值、展开之后shape,这里的shape是一次输入模型时的最大shape,离线训练是一个batch里最大的,线上预估是这个人最大的,这里就可能出现数据线上线下不一致的问题。

离线训练时 tf.sparse_tensor_to_dense(fea, default_value=0) 会填充默认值,将SparseTensor扩充成一个batch最大的维度的Tensor,[ [6,5,4,3,2,1,0,0,0,0] [10,9,8,7,6,5,4,3,2,1]] ,如果有其他操作,离线训练时是没问题的,因为保证了shape一致,但是线上预估的时候,[ [“6,5,4,3,2,1”] [“6,5,4,3,2,1”]],会被切分为[ [6,5,4,3,2,1] [6,5,4,3,2,1]],因为是同一个user,这里的最大shape是一样的,所以会产生离线训练 长度为10,线上预估长度为6 ,10 != 6 导致打分失败。

如果在序列左边padding,虽然不会继续报错,但还是会出现线上线下特征不一致的现象

[ [0,0,0,0,0,0,0,0,0,0,6,5,4,3,2,1,0,0,0,0] [0,0,0,0,0,0,0,0,0,0,10,9,8,7,6,5,4,3,2,1]],离线训练时我们一般会使用最近的T个序列,还是会得到[ [6,5,4,3,2,1,0,0,0,0] [10,9,8,7,6,5,4,3,2,1]]

线上预估时是对同一个用户进行打分,[ [6,5,4,3,2,1] [6,5,4,3,2,1]]会被padding后为[ [0,0,0,0,0,0,0,0,0,0,6,5,4,3,2,1] [0,0,0,0,0,0,0,0,0,0,6,5,4,3,2,1]],切分最后十个会得到[ [0,0,0,0,6,5,4,3,2,1] [0,0,0,0,6,5,4,3,2,1]],

离线训练时使用的是[6,5,4,3,2,1,0,0,0,0],而线上预估的时候使用的是[0,0,0,0,6,5,4,3,2,1],这会导致线上线下特征不一致!!离线胜出很多,但是线上效果可能并没有那么明显。

解决方法:

dense = tf.sparse_tensor_to_dense(fea, default_value=7000)
mask = tf.cast(tf.not_equal(dense, 7000), tf.int8)
seq_lengths = tf.count_nonzero(mask, axis=1)
dense_reverse = tf.reverse_sequence(dense, seq_lengths=seq_lengths, seq_axis=1, batch_axis=0)

将序列特征反转之后,在右边padding

这里面的坑主要围绕几点:数据本身,业务,技术,人。

  1. 埋点没做,或者埋点弄错了,导致统计的数据不对或者统计不到数据;
  2. 因为每个人的口径不同,写的文档不完整,把数据口径弄错;

1、数据问题。没有足量、准确的数据是很难做好推荐系统的,而从数据打点上报到数据清洗,最终生成出算法模型需要的输入数据,中间每一步都要谨慎处理。数据量太小,稀疏的样本数据找不到大量的正负样本导致没办法去训练模型;

2、工程效率问题。

离线训练算法模型时的效率问题:决定了模型的迭代速度:简单调整一个参数,重新生成模型却要一整天的时间,这显然是不能接受的。

线上最终预测时的效率问题:决定了对于一个请求能从多大规模的候选集中选出推荐结果:从一万个item中召回一百个结果,然后rerank选出最终的十个结果,需要长达十秒钟,用户肯定早就不耐烦了。

3、算法评估指标一致性问题。

具体来说就是离线指标与线上指标是否一致,线上指标和线上效果又是否一致。对于一个新的算法模型来说,线上ab测试是需要一定的时间才能知道结果的,因此想要快速迭代模型,准确的、与线上表现一致的离线评估指标是不可或缺的。

除了以上所说的几点,具体到不同应用场景中,又会有不同的问题出现。

比如信息流推荐中,低俗内容和标题党内容往往能在短期内让kpi有可观的提升,但这些内容对却会对整个生态造成影响,长远来说是有害的,如何处理这部分内容是值得思考的问题。又比如在电商推荐中,如何处理重复推荐的情况也是一直以来都存在的问题。


 

  • i2i/simirank等相似计算算法中的哈利波特问题,相似性计算在推荐系统的召回起到非常重要的作用,而热门物品和用户天然有优势。因此,处理方法基本上都是凭经验,会出现各种magic number的参数。
  • svd/svd++等算法,在各种比赛中大放异彩,但是据我所知,各大互联网公司中基本没有用它的。
  • i2i及它的各种变种真是太好用了,大部分公司的业务量,从ROI来看,其实没有必要再做什么优化了。
  • 推荐的召回策略多优于少,但系统的计算rt是个问题,没有好的系统架构,也没有什么优化空间。
  • i2i等类似计算算法,实际业务中容易跑挂,比如用spark就容易oom,很容易发生倾斜,处理起来又有很多trick和dirty job。
  • 推荐系统不只有召回,召回后的ranking起到非常大的作用,这个和广告的点击率预估有点像。
  • 非常多的业务没有办法向头条/facebook之类的有稳定的用户留存指标,而留存是推荐系统非常重要目标,因此需要找各种折中的指标去知道abtest。
  • 训练样本穿越/泄露问题,即在训练的特征中包含了测试集的样本的信息,这个是初期非常容易犯的错误,在后期有时也会隐秘的发生。
  • 大部分推荐系统的训练数据需要在离线条件下去拼接,其中用户的行为状态和时间有关,拼接非常容易出问题,因为系统当时的状态会有各种状况(延时、数据不一致)等,导致训练和实际在线的数据不一致,建议把训练需要的日志在实际请求中直接拼接好打印落盘。
  • 最后,算法的作用有点像前辈们讲的:短期被人高估,长期被人低估。按目前国内业务方对算法有了解的特别少,算法对生态的长短期影响,只能靠算法负责人去判断,因此,就算你只是个打工的,请有一颗做老板的心

1.召回算法的离线评价问题。在做召回的过程中,没有一个合适的离线评价指标来评价召回的质量,大多数都是人为主观的判断,然后做abtest,看指标,更多的是运气成分。

2.召回策略过多问题。该问题导致新加一个策略后,排序阶段效率低。遇到这种情况,大多还是工程方面的问题,遇到瓶颈之后只能尽可能的减少召回数量,但可能影响效果。所以说推荐系统的工程架构也很重要。

3.推荐的精准个性化问题。热门的item总是更容易得到推荐,长尾的item得到的曝光机会少。

4.新用户的冷启动问题。新用户的冷启动一直是推荐系统的一大问题,没有过多的数据,只能通过大量的规则和策略进行,或者使用额外的数据来进行补充。目前还在摸索中。


 

总结起来是数据工程,特征工程,模型工程,系统工程这些方面的问题。

数据工程上:

日志去重问题,日志中正例丢失分析和处理的问题,作弊流量清洗的问题,样本迁移学习的问题等等。

特征工程:

用户行为特征如何结构化。session内用户行为特征如何设计。长尾item CTR预估偏高,如何设计特征进行打压的问题。高阶特征如何自动挖掘的问题

模型工程:

1)如何优化计算框架和算法,支持千亿特征规模的问题

2)如何优化召回算法和排序算法不一致性带来的信息损失

3)如何把多样性控制、打散、疲劳控制等机制策略融入到模型训练中去的问题

4)如何优化FTRL来更好地刻画最新样本的问题。

5)还有很多,像CF怎么优化的问题。至今对阿里ATA上那篇swing印象深刻。

系统工程:

1)实时样本流中日志如何对齐的问题

2)如何保证样本流稳定性和拼接正确性

3)调研样本如何获取动态特征的问题:服务端落快照和离线挖出实时特征

4)基于fealib保证线上线下特征抽取的一致性问题。

5)在线预估服务怎么优化特征抽取的性能。如何支持超大规模模型的分布式存储,主流的模型通常在100G以上规模了。

6)内容系统进行如何实时内容理解,如何实时构建索引,以及高维索引等相关问题。

多样性怎么保证,E&E怎么去做,内容质量怎么评级,低俗内容如何打压。如何做全场景化的推荐引擎使得各页面各栏位能更好地配合推荐。


 

线下auc涨,线上ctr/cpm跌可能的原因有几个:

1、特征/数据出现穿越

使用了和label强相关的特征导致的数据泄漏

2、线上线下特征不一致

离线和在线用不同的代码抽取就很容易存在这种代码带来的不一致,例如,离线对用户特征的加工处理采用scala/python处理,抽取用户最近的50个行为,在线特征抽取用c++实现只用了30个。

另外一种线上线下不一致,是由于数据的不一致导致。这在离线拼接样本和特征的pipeline中比较常见。一般离线特征都是按照天处理的,考虑各种数据pipeline的流程,处理时间一般都会有延迟,离线特征处理完之后导到线上供线上模型预估时请求使用。

这种不一致都是怎么产生的?例如4月15日这天,线上预估请求用的特征是4月14号的特征数据。到了4月16日,特征pipeline开始处理数据,到了凌晨4点,离线特征处理完了导到线上。那么在4月16日0点-4点,这段时间线上请求的特征使用的是老的特征数据,也就是4月14日的特征数据。4月16日4点-24点,线上特征使用的是4月15日的数据。而在离线样本生成过程中,到了4月17日0点,如果是按天拼接的,那么4月16号这天的所有样本,都会使用4月15日的特征。

这样,4月16日0-4日的样本,在离线样本拼接的阶段,使用的是4月15日的特征数据,而在线上请求特征的时候使用的还是4月14日的特征。特征pipeline流程处理越长,这种不一致会越大。

要严格保证线上线下的特征一致性,最根本的方法就是同一套代码和数据源抽取特征,业内目前通用的方法就是,在线实时请求打分的时候落地实时特征,训练的时候就没有特征拼接的流程,只需要关联label,生成正负样本即可

3、数据分布的不一致

如果仔细排查,既不存在数据泄漏,也没有出现不一致的问题,离线auc明明就是涨了很多,线上就是下降,而且是离线涨的越多,线上下降越多,还有一种可能就是数据的不一致,也就是数据的“冰山效应”----离线训练用的是有偏的冰山上的数据,而在线上预估的时候,需要预测的是整个冰山的数据,包括大量冰面以下的数据!

这种情况其实在推荐系统里非常常见,但是往往非常的隐蔽,一时半会很难发现。我们看下面这张图。左边是我们的Baseline,绿色的表示正样本,红色表示负样本,灰色部分表示线上由于推荐系统的“偏见”(预估分数较低),导致根本没有展现过的数据。

离线阶段,我们通过各种优化,新模型的离线评估表现更好了,例如图中第二列,可以发现第4个绿色的正样本和第7个绿色的正样本排到了第3和第6的位置,离线的auc指标涨了。

到了真正线上的预估也就是第三列,发现对于这部分离线见过的样本,模型的预估序并未改变。但是新模型给了灰色没有见过的数据更高的预估分数,这部分数据一旦表现不好,很可能造成我们前面说的情况,离线(第二列)评估指标明明涨了不少,在线(第三列)评估指标ctr却下降。

这种情况也不是必现的,在LR以特征工程为主要迭代的时代很少见。主要的原因是模型的前后迭代差异并不大。新模型对比老模型最主要的特点是新加入了一部分特征,往往模型的打分差异并不大,从图中第二列到第三列,原来那些冰山下的数据也就是旧模型预估分数偏低的部分,在新模型中能够脱颖而出拿到很高的预估分数的概率并不高。

而在模型有较大变化的时候,例如lr->树模型,lr->深度模型,不同网络结构的深度模型变化,这种情况容易出现,原因就是新旧模型的变化较大,预估分数变化也较大。

举一个简单的例子,假设我们的baseline是热门模型,样本都是老的热门模型生产出的热门样本,这个时候我们用简单的lr模型去拟合,到了真正的线上预估的时候,对于大量之前没见过的非热门的数据,模型自然很难预估好。没有足够好的样本,模型也很难学到足够有用的信息。

说另一个很有意思的现象,之前在某个组的时候,两个team优化同一个场景,大家用的回流样本都是一样的,但是特征和模型都是自己独立优化和迭代。有意思的是,如果一个team的优化取得了比较明显的提升之后,另一个team哪怕什么都不做,过一段时间效果也会慢慢涨上来。

对于这种情况,最根本的手段就是解决数据的有偏问题。尤其是新模型,一开始相当于都是在拟合老模型产生的样本,刚上线效果如果比较差,经过一段时间迭代,影响的样本分布慢慢趋近于新模型,也能收敛,但效率较低。这里给下两个在我们这还比较有效的经验:

(1)对无偏数据进行上采样

这里的无偏是相对的,可以是随机/探索流量产生的样本,也可以是新模型产生的样本。大概意思,就是尽可能利用这些对新模型有利的样本

(2)线上线下模型融合

比较trick的方法,没有太多方法论,但是确实能work。

新模型预估分数 pctrnewpctr_{new} 和老模型预估分数 pctroldpctr_{old} 直接在线上做线性融合,刚上线的时候a选取比较小,随着慢慢迭代,a慢慢放大。

 
 

1. 数据错误

推荐算法依赖的数据来自于用户的行为反馈,这个极易出错又极难发现。


用户在屏幕上的一个点击,行为发生的上下文和一个推荐物品的上下文,需要客户端发送给服务端,服务端把信息上报给日志系统,日志系统把数据导入到大数据平台,算法才能开始他的工作,而其中的物品推荐上下文,通过推荐接口透传给服务端,服务端带给前端,前端要解析好才能使用。


这样的一整条链路,有太多的出错可能,而出错时又很难意识到错误的存在,更别说错误的排查。
讲一个愚蠢的错误。在一个初上线的业务上,依靠几天的日志搭建了Rank模型,也有收益,看起来没有任何问题。当时唯一的怪现象,这个场景的pv是uv的100倍,也就是人均的浏览数是100,按照经验这个数字高处之前同类业务的几倍,这个数字呗暴露出来一周,大家只是奇怪,没人真的怀疑。


我大概从觉得不对劲,到动手查,确认原因,到解决问题,花了一周的时间。服务端有一个环节把创作者的id和用户的id弄混了,所以才有人均100的浏览,实际的uv是创作者的数量。问题修复后,推荐效果涨了一倍!


2.离在线不一致

离在线一致性可以来自于人的失误,离线的特征处理和在线的特征处理天然是两个流程,出现问题的可能性非常大,但开始可以靠细致的检查来避免,甚至可以将离在线的关键流程用一套组件抽象和处理,降低认为出错的可能。而另一种离在线不一致性来自于系统本身,在系统限定下无可避免,当然可以通过系统的升级来缓解,但成本的曲线也会变得非常陡峭,下面就重点聊聊这个。


很多推荐系统的排序模型,在系统升级前或业务初期都是T+1更新的。

在离线,使用T-n到T-1的n天数据训练模型,用T天的数据进行测评,拿到了很好的离线指标,比如AUC为0.72。但是在线服务的模型,并不是这样的理想情况,一个模型每天重新迭代训练,需要新一天(T-1天)的日志,日志从数据队列传输到大数据平台,进行日志的处理,新一天各种特征的计算,组织训练样本,进行模型训练,之后还要把模型从大数据平台更新到在线服务器,整个流程走下来个把小时总是要的(图中例子为11点10分)。那么在新模型上线前,也就是11:10分之前,在线服务的是T-2的模型,相当于在离线用T-2的模型去测评T天的样本,效果会大打折扣。因而线上一整天的平均测评指标,是低于离线测评指标的。


有的业务和模型下,有可能T-2和T-1的差距不大,但推荐系统非常依赖ID型记忆型特征,T-2可能会导致非常差的结果。这个时候,让你的模型能越早上线,效果就越好。有可能你增加了离线特征的处理流程,使用了复杂的特征和模型,让AUC提升了一个点,但是模型晚上线了3个小时,在线效果可能就掉到了坑里。


升级到小时级模型更新,甚至流式更新,能避免这个系统性的问题。当然成本也会变大,也会要爬更多的新的坑。


再聊聊特征上的不一致,如果是天级别计算的离线特征,它有着和上面讨论的模型不一致的类似的问题。而使用实时特征,也有隐秘的不一致问题。


实时特征在线使用的时候,经过客户端上报,流式计算处理日志数据进入在线数据源或特征服务器,需要几秒到几十秒不等的时间。也就是说,如果你刚刚点击了鞋子,紧接着下滑翻页,系统是拿不到鞋子这个行为的。如果离线模型训练中有用到了带有鞋子的特征,由于近期行为的影响非常大,那么离在线的不一致会非常严重。


离线获取实时特征,一个是通过离线日志复现实时特征,依靠是日志中记录的时间戳,如果仅考虑样本的时间戳大于行为的时间戳,那么离在线不一致就发生了,相对明智的做法是流出一个时间GAP,让离线和在线尽可能一致。另外要注意,样本的时间戳,不是用户曝光行为的时间戳,而是推荐系统的时间戳,否则也会用到在线无法拿到的穿越特征


另一种方法,是将在线使用的特征直接依靠日志系统记录下来,在线的时间GAP假如是5到40秒飘忽不定的,整体上虽然离线在线一致了,但对于某个样本,有可能记录了最近的一个行为,有可能丢掉了最近的行为。这样做比离线复现实时特征的方法好多了,唯一的问题可能是要积攒一定天数的实时特征日志,才能完成初次模型上线,每次特征的修改也要等一段时间进行日志积累。
 

最大的坑莫过于排序模型AUC提升了但线上没效果。

离线AUC提升在线没有效果无外乎下面几个原因:

* 样本的设置是否正确,模型向错误的方向前进。

* 离在线不一致,在线serving的AUC没有提升。

* GAUC没有得到有效提升,AUC提升来自于排序无关的bias

* 多目标、多样性等后处理把有效的AUC提升给抹平了。

先复习一下AUC

Point-Wise排序模型与二分类无异,对于二分类模型,在正负样本均衡下,以0.5为阈值可以评价模型的准确率、召回率和F1值。以CTR估计为例,正负样本是不均衡的,0.5作为阈值是不合理的,如何评价模型的好坏呢?

答案是多选一些阈值,对于每一个选定的阈值,计算出对应的混淆矩阵,得到多组真正率和假正率,画到一个坐标中,连成一条曲线,就是ROC曲线,下面的面积就是AUC。它还有另一个物理意义,正负样本pair中预估值正序的比例,这与ROC下面积占比的数值是一致的,且更能表征模型的排序能力。

确保样本设置是否正确

对于精排,样本看似没有什么学问,以CTR为例,曝光和点击按照用户、物品和请求ID做一个join,样本就生成了。但实际中未必有这么简单。

以前某个业务,推荐列表会露出一个头,但有一半的用户是直奔搜索,但这露头的两个商品作为曝光未点击,充当了负样本,模型要提升AUC,就是要学习到用户不喜欢这两个商品,这两个商品是推荐系统精挑细选的用户历史兴趣最match的两个。

某个业务,有个所见即所得模块,在引流处展示了商品的封面图,用户点击后进入一个feeds流,首个坑位放在引流处的商品。在这种情况下,曝光和点击join,样本还正确么?首个坑位在所见即所得模块的加持下,PCTR在50%以上,其余的坑位只有5%,模型为了提高AUC,把点击的因素归因给了物品、位置等特征。

以上两个例子都是业务相关的个例,下面举一个公例。当模型升级流式学习之后,样本需要从多个行为流进行join,曝光日志会先到,需要等待点击日志,构造成点击样本,一般要设置一个窗口,窗口大小很有讲究,点击晚到的就被当做了负样本,过大会导致样本晚发,影响模型的实时性。例如,CVR任务样本在某些业务里要等几个小时才能完全拼接正确,窗口这么大已经退化成了小时级训练了,可以的作法是,用一个足够大的窗口,保证80%的样本正确,然后一旦遇到正样本,即便过了窗口,进行正样本的补发,即虽然之前发过一次负样本,再发一次正样本弥补。

样本正确的前提下,AUC的提升才是真的。否则,模型就是向着错误的方向奔跑。

离在线一致性

先看看Online AUC,记录下在线的预估分和用户反馈label,计算在线AUC,如果在线AUC低于离线的AUC,那么存在离在线不一致性。

Online AUC比baseline更高了,排序一定更好了么?未必,举一个我遇到过的极端的例子,所在的场景有一个特点,越是近期发布的物品转化率越好,比如当前发布是8%,次日是4%,按天半衰。有一个AB的Online AUC已经超越了baseline两个点了,效果却低了五个点。仔细查下来,新模型把当天发布的物品占比给排低了,更倾向于老物品了。AUC更高的原因,是那些老物品有更丰富的行为反馈,预估的自然更准了。AUC的绝对数字更高了,只能代表模型预估的准,不能代表模型排序的好。

这与我们拿AUC作为测评标准矛盾么?仔细思考上面Online AUC的例子,每个模型会独占一批样本,所以两个模型对比Online AUC是没有意义的。Online AUC正确的用法是和同一批样本的离线AUC进行对比。

除了对比Online AUC,对比离线预估和在线预估的均值,也是一个发现离在线不一致的方法。

所有需要在离线进行特征构造的系统,都难以逃脱离在线不一致的噩梦,最好的方式就是在线样本构造,即预估时的特征构造通过日志系统落盘,用于接下来的训练,这样就能一劳永逸的避免离在线不一致性。

Group AUC

排除了离在线一致性,AUC确实涨了,效果还没有出来,看看GAUC。

从AUC的定义来看,它取决于正序对的个数,即你预估A比B的分数高,也确实A的label是1而B的是0,如果有一个用户什么都没有点击,另一个用户看见什么都点,你的模型能区分出来,AUC也能提升,但是这对排序没有意义。我们可以把Group定义为用户,在每一个用户上计算AUC,然后按照样本数加权平均,得到GAUC,如果这个没有增长或是下降,也预示这模型的一些问题。

在搜索和相关推荐场景下,可以把Group定为query和trigger_item来看,这些场景下,你的模型只放query和trigger_item,就能获得不错的AUC,但这没有意义,它们只是模型的bias,如果以他们为Group的GAUC提升,才有意义。

后处理的影响

如果GAUC也提升了,还没有效果,再看看后处理的影响。

一般,推荐系统有多个目标,有多个模型或多任务模型的预估值进行分数融合,你带来的提升有可能改变预估值的均值和方差,带来融合公式作用的改变,对排序不利。

另外,推荐系统除了面向指标优化,还会做一些多样性控制、规则强插之类的逻辑,它们有没有破坏你的排序。

要看到这一点,可以按照物品曝光position的顺序,计算label的GAUC,对比你预估值和label之间的GAUC。比如,你的CTR和点击label之间的GAUC是0.65,但Position和label之间的AUC是0.52,就说明整个排序几乎没有按照这个分数排序。就可以按照上面提到的常见的两点原因排查了。


 

指标

推荐系统精排与粗排最常用来衡量排序效果的指标是 AUC, AUC的含义非常简单直白, 给定一批带正负标签的样本(如曝光/点击, 点击/加购, 加购/转化等), 模型进行打分排序之后, 有多少对样本是正样本排在负样本之前的, 再除以正负样本能组成的对数. 所以, 如果正样本排在负样本之前的对数很多, 那说明模型能将正样本往前排, 我们就认为模型的排序效果好.

但在许多物料差异较大的场景, 看AUC的意义就不是很大. 例如电商场景中, 手机和桌椅的点击率天然不同, 拿这些物品的打分去做比较意义不大. 一般我们都使用请求粒度gAUC进行评估, 即使用requestid groupby数据进行gAUC的计算, 同一请求中物料一般比较相近, 所以gAUC是比较合理的指标. 使用请求粒度gAUC也不一定处处都合理. 例如在一些类feed流的场景, 通常用户滑过若干个物品(如10个), 程序就会向后台重新发起请求, 再对页面进行刷新, 这就是两个不同的请求了. 这时可能会产生大量没有点击行为的请求, 无法计算其gAUC, 而直接丢弃又不妥, 这时就可以计算user粒度的gAUC, 从用户角度来看, 也感受不到后台分页请求的行为.

总的来说, 指标是用来描述模型打分的总体情况的, 不同场景应该使用不同的指标, 关键是看所用的指标是否能合理地描述场景的特点, 这是最容易出现问题的地方.

2. 埋点上报

这是十分容易出现问题的地方, 一般又十分隐蔽. 一般流程是算法同学提出需求, 由埋点同学进行开发, 埋点数据上报到消息队列再落到Hive中. 由于前端页面跳转, 场景刷新, 字段更新机制等并不是算法同学直接确定, 所以容易出现误解, 导致训练数据的CPV表做得不精准.

例如, 用户从列表页点击进入落地页, 又重新返回列表页. 一般此时用userid, itemid, requestid, pageid就能唯一确定一条曝光, 但若此时pageid带着时间戳, 就会导致曝光记录有重复; 用户在落地页中点击了同一商品的不同skuid, 导致点击归因到列表页的曝光记录出现错误; 业务方强行插入坑位, 对数据的分布造成扰动; 不同版本的APP覆盖率不同, 即使相同场景也可能有不同埋点名称, 容易少捞或者多捞数据.

算法同学如果对埋点上报没有很强的控制权, 那模型还没上线就已经有很多问题存在了.

3. 系统性的不一致

这是个老生常谈的问题了. 一般会有这样的表现: 线下gAUC涨了, 线上gAUC没涨甚至反而跌了, 一般都是有不一致的情况存在. 不一致可能来源于多个不同的方面.

数据穿越. 这个问题相对比较好查, 一般的表现是线下gAUC有较大的涨幅, 线上gAUC以及各种指标却跌了, 典型的数据穿越就是模型训练用了"未来"的数据. 例如, 离线的长周期统计数据本来应该使用[T-n, T-1]统计窗口以供T日进行预估使用, 离线拼接训练样本的时候却将T日也涵盖在统计窗口之内, 造成T日的训练数据产生穿越; 用户的实时行为任务与训练数据的生成任务是异步的, 有时候用户刚点击的数据会同时出现在样本之中, 变成一个与标签强相关的穿越特征. 这种情况一般要在打分的时候将用户的实时行为数据挂上requestid保存下来, 再在离线使用CPV表中的requestid进行拼接方可解决.

数据不一致. 现在的推荐系统实时性很强, 很多数据的不一致性都是因为系统本身的复杂性导致的. 例如, T日使用T-1日的数据进行打分, 像user侧和item侧的一些固定属性一般都是如此操作. 但日更新需要消耗一定的计算时间, 在这段计算时间内, T日其实是使用T-2日的数据进行打分, 而离线拼接训练样本时却全都使用T-1日的数据, 导致数据不一致; 对于日更的模型, 通常使用[T-n, T-2]日数据进行训练, 使用T-1日数据进行testing, 而线上gAUC的计算则是用T日数据, 在数据分布变化较快的应用场景下面, 这样的时间gap会导致线上线下指标差距较大. 一个有效的办法是缩短时间的gap, 设计小时级别甚至分钟级别的数据回流流程, 进行online的模型训练.

特征不一致. 线上线下没有采用同一套算子进行特征的抽取, 例如线下用Python进行特征抽取, 线上却用Cpp. 这就容易导致抽取特征的逻辑不是一致的. 例如, 使用用户的实时点击序列做Attention操作, 离线截断最近的30个, 在线却截断最近的20个.

4. 上下游变动

工业界的推荐系统, 无论规模大小, 都不会只是单纯依赖模型进行打分排序, 许多与业务强相关的逻辑都需要规则来辅助完成, 例如, 去掉一些敏感的物品, 这些物品的自然点击率可能不错, 但是不宜出现在首页或者推荐的列表页之中; 利用规则进行打散, 使品牌或者品类不会过于集中, 保持一个多样性的状态, 提升用户体验. 这些都使得用户看到的排序结果不会是模型排序的自然结果, 有时这种变动会带来比较大的负向影响. 虽然一般在AB实验中, 我们使用正交的流量打散到下游的规则层去, 但如果此时下游的规则层都对落地的排序有负向影响, 在排序层的gAUC、copc等是反应不出问题的, 有可能排序的AB实验本来是有收益的, 但都被规则层破坏掉了.

排序的上游变动同样会带来相应的影响. 用户的一个请求会经历召回、粗排、精排, 每一层的打分本质上都是为了把用户可能感兴趣的物品尽量往前排, 增加这些物品的曝光率, 提升精排的排序效率, 让后续的排序层能更容易地把用户可能感兴趣的物品呈现在列表页之中. 如果召回或者粗排没能做到这点, 精排就很难有好的提升, 即使在同层的正交实验会有收益, 但天花板就被限制了, 不能发挥模型应该有的能力.

线下有提升线上没提升原因分析:

1 offline 与 online 的特征没有对齐
工作中添加新的特征经常会出现offline配置文件没有同步到online,特征解析错误或者抽取方式存在区别,这些均会导致offline模型训练用到的数据和online预测用到的数据不一致。因此需要上线特征之前,需要先对比相同样本 online和offline特征是否对齐。

2 online特征监控
特征来源有很多方法,直接线上抽取、从DB获取、从redis获取等,一旦某个环节出现问题,就会导致特征缺失甚至错误,因此需要针对不同来源的特征进行监控,例如各个时段特征分布、峰值、耗时等。

3 特征更新不符合预期
用户侧和物品侧不同特征更新的频率不同:

长期:用户年龄、性别;物品的类别、来源,周级别更新就可以 中期:用户物品画像中的统计特征,例如某个topic下点击率,某文章昨天的统计特征,天级别更新 短期:app安装列表 实时:用户点击物品后兴趣/点击历史等需要及时更新、物品当前总的pv等

特征更新延迟,例如今天晚上预测用的用户前几次行为之前的画像,因为用户短时兴趣和电机列表话,会导致线上实验效果的衰减会特别厉害。

4 偏置特征的使用
对于bias特征,例如position bias,使用不当会造成offline和online的差距很大。

线上效果只和用户看到后的点击的可能性有关,和position等偏置因素无关的。而线下一般是不同position的样本混合训练,因此线上和线下评估不对等。

5 数据划分的问题
训练集和测试集存在重叠的部分

6 数据穿越
样本数据含昨天/今天的数据,7:3 按随机方式划分数据,训练数据今明两天的都有,测试数据今明两天的也都有, 不能保证测试数据比训练数据新。

7 模型训练时过拟合了
8 线上服务不正常
线上服务挂了、serving超时、模型实时更新延迟或者中断

9 流量划分偏差
模型的验证都是通过AB实验完成的,如果流量划分不均匀正交会带来偏差,结果也就没有置信度,常用方法是通过AABB来判断提升是否稳定。

10 上线实验后训练数据分布变化
模型offline评估时拟合的是base模型跑出来的数据分布,online上训练数据里既有base模型产生的也有treat模型产生的训练数据,且treat模型产生的训练数据占比在不断变化,也就死数据分布在变。常用办法是在模型训练过程中,将model_name作为bias特征,添加到wide部分。

Reference
线下AUC提升不能带来线上提升
线上线下效果一致性杂谈
 


 

1. 样本采样问题

推荐系统中最重要的就是模型的训练样本,影响最大的就是样本的分布。很多时候我们都会对样本采样,比如按正负样本固定比例,也有为了解决长尾问题对高热资源降采样。虽然很多时候能解一些业务问题,但是采样带来的另一个问题是特征和语料分布的不一致,特征基于全语料统计计算,而语料又是做了采样。另外copc也失去了意义,在CTR预估场景中,copc经常用来分析业务问题,但是采样导致copc偏离真实值。我们的经验是能不采样尽量不采样,如果是为了解长尾、流行度偏差,完全可以通过其它方法,比如调整loss

2. 线上线下不一致问题

经常遇到离线指标提了,但是线上指标不提的情况。有可能是离线指标设置不合理,比如CTR预估,离线使用AUC作为指标,但是线上排序是对单个用户,而AUC是不区分用户,可以使用GAUC等其它方法。当然这不是最主要的,主要的是因为样本空间不一致问题,离线评估都是曝光过的资源,而线上排序很多是没有曝光的资源,也就是离线评估的样本集是排序空间的子集。这种问题没有最优的解法,我们的经验是多个维度评估离线模型效果,而不是单一指标,会让一致性问题缓解。比如离线评估的时候,不仅考虑AUC指标,同时考虑top序的多样性等。

3. 复杂结构不一定有效(Attention不一定有效)

在数据足够充足的情况下,越复杂的模型,效果越好?如果不考虑计算开销,这个结论大多数成立,但是也和数据本身息息相关,就像CNN结构适合图像,而不适合推荐这样的稀疏场景,而Attention结构适合电商、广告,而不一定适合时效性很高的图文推荐场景。推荐中的一个典型案例,Attention结构对于item集合不固定,长尾严重的场景,很难学习到相关性效果。


 

线上线下结果不一致

线上的指标我们往往看的都是业务指标,比如流媒体就会更关注观看时长。Booking 发现,线下的模型指标和线上的业务指标几乎没有任何相关性。比如就算线上的 CTR 提升了,但是观看时长并不一定提升。Booking 提出了几种可能的原因:

  1. 过度优化:当模型已经被优化了很多次之后,再提升的空间已经很小了,在当前的 AB 测试框架中可能已经检测不出来了。
  2. 恐怖谷效应:过好的推荐结果甚至可能让人感觉害怕。在下图的例子中,用户仅仅输入了Salzbug 和 London 之后网站就猜测他需要在 Vienna 停留,这完全猜中了他的计划,让他非常害怕,其他用户甚至建议他查看是否开启了麦克风,认为网站会偷听日常对话。但 Booking 说这仅仅是一个马尔可夫模型的推荐而已。
  3. 过度优化替代目标:我们线上的业务指标更多的是类似于观看时长,而线下很难直接对其优化,所以往往选用替代的 CTR。但过度优化也可能会带来反效果,反而不利于线上业务指标的增长。

还有一点 Booking 没有提但是很常见的就是 Presentation Bias。历史数据里面只有用户看到的数据,但是对于用户没有看到过的数据的真实互动情况我们并不知道。过拟合历史数据也并不一定是好事。

业务指标不好可能不是模型的问题,而是建模的方式不对

很多时候我们试图用机器学习模型去提升一个业务指标,但是不管怎么优化,模型线下表现不错,但是线上的结果不好。这个时候的问题可能并不是模型本身,而是我们建模的角度不对。不要仅仅钻进黑箱模型中只顾着提升线下几个点,而是要回归用户,想想如何建模更加合理。

线上监控很重要,也很难

实时地监控模型表现对于线上环境来说十分重要,也很难,比如:

  1. 有些 True Label 线上并不能获取的到。比如 Booking 的例子是预测用户是否会要 Special Request,但是用户最终可能会去酒店签到的时候才要,线上无法获取。
  2. 有些 True Label 会延迟很久。比如预测用户是否会写反馈,用户可能要一周后才会写。

  1. 样本准备好了,突然发现某个特征有问题,然后改代码,重新回头刷数据,于是半天就白费了。
  2. android 端和ios端开发同学的前端埋点不一致,例如一个位置从0开始、一个从1开始。
  3. 发现在线特征和离线特征不一致
  4. 引擎对缺失值处理的方式不一,例如null和空字符串。


 

广告算法迁移新闻推荐系统时遇到的坑:

学习率不宜过小,mini_batch_size不宜过大

训练数据较少时,模型在学习率较小和mini_batch_size太大的时候都无法学充分,这就导致模型误差可能只在某个局部取得极小值

广告预估ctr最高的结果不一定会被用户看到

广告系统是个三方博弈的过程,也就是广告主、平台、用户之间的一个平衡,广告主希望自己的广告有更多的曝光机会并且出价还低,平台希望选出ctr和ecpm都高的广告,这样广告主满意,自己挣的钱也多,用户至少是不希望出现自己讨厌的广告,有多大兴趣点击就不一定了。这样对比就知道,往往广告平台推荐系统给出的ctr很高、离线和实时的auc很高,但是收入可能没怎么增长,所以广告的ctr优化比新闻推荐系统ctr优化要更难。

喜欢新闻的人不一定对类似的广告也感兴趣

这个比较好理解,经常刷新闻看某个频道的人不一定就对类似的广告感兴趣。刚开始的时候我们把用户看新闻得到的用户画像直接用在广告ctr预估模型里面,通过计算模型特征的sensitivity,结果发现很多用户新闻特征对广告ctr预估模型的贡献并不大。所以在广告算法里面,做look like很重要,也就是通过一类人找到另一类相似的人,比如通过分析一批种子用户的财富水平得到其他所有用户的财富水平,这对于贷款类、珠宝类广告主就非常有用,因为一般穷人更愿意贷款,有钱人才消费的起珠宝。

cvr模型预估的数据延迟上报问题

广告推荐系统里面有很多不同类型的广告,比如cpc、cpm、cpi、cps等等。除了需要预估ctr模型,我们通常还会预估cvr模型,cvr模型可以简单理解为点击到安装的预估,主要是cpi类型的广告,这类广告通常需要给出一个install/click的预估值。很多时候用户click信息上报的比较快,但是install信息由于存在广告收入归因的问题,往往可能在一天甚至几天后才收到这个数据,这对我们模型训练有很大的干扰,因为线上的cvr预估往往都是近实时的,如果一个正例来的很晚,模型准确率自然就低。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值