当我们在谈论推荐系统的时候,我们在谈论什么

Posted 爱好上班摸鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当我们在谈论推荐系统的时候,我们在谈论什么相关的知识,希望对你有一定的参考价值。

本文纯属乱说,如有雷同纯属巧合。




工业界的推荐系统中,推荐的东西呈现出不同的形态,可能是商品,视频,文章等。每一种产品和形态对推荐结果的满意度有不同的衡量指标。对于商品,指标是ctr点击率和gmv;对于视频文章这些内容领域,指标是用户时长和内容生态(互动,粉丝量等)。
  
由于我对视频推荐有更多的道听途说,所以围绕这块展开。


一、视频推荐的目标

视频推荐大致来说有三个目标。

(1)、用户时长
用户更愿意主动花时间来消费app所推荐的视频,才说明该产品有一个好的推荐。时长越长说明用户粘性越好。
(2)、用户规模
即产品的dau,增加dau的两种方法无非是拉新和留存。通过运营互动等各种手段获取新用户,通过好的推荐让用户留下来。
(3)、内容生态
 对一个视频app,账号主(博主)、产品平台、用户这三方会形成一个关系链。用户希望看到自己喜欢的优质视频来获得消遣,平台希望服务好用户来获取用户时长,进而得到广告变现,博主希望自己上传的视频得到高的流量分发。打造一个好的内容生态即是让各方都有利可取。一般可通过用户的点赞,分享,评论,关注指标来衡量。

推荐系统的整个架构,策略,算法模型都是为这三个目标服务的,任何一次策略的上线都需要通过ab实验来证明其中的目标有明显的收益。


   二、推荐系统基本架构

用户打开一个视频app进行一刷便是对推荐系统发出一次请求,推荐系统要在毫秒级的时间内从百万或者千万级的视频库筛选出很少的几条视频返回给用户。其中的实现需要一个精细而稳定的架构。
从漏斗层面来讲,推荐系统会分为召回层和排序层。



(1)、召回层
召回层由很多的召回策略构成,每一个召回策略会从视频索引库中选出k条视频(k远小于视频索引库中的视频数量)。
召回策略有很多,常见的比如协同过滤召回,语义召回,graph embedding,fm召回,本地召回,热点召回,同tag召回等等。

  • 本地召回:当系统识别到用户在哪个地区时,策略会把该地区相关的视频选出来送到排序层;

  • 热点召回:会把当前打有热点标签的视频(大多是一些突发的事件)筛选出来;

  • 协同过滤召回分为ucf和icf,简单的说,用户最近喜欢什么视频,便召回相关视频,或是相似用户喜欢某视频,便召回相关视频。

  • 语义召回:会有一个语义双塔模型把每个用户和每个视频都表征为向量,该召回拿到用户向量后,会根据候选集中的视频向量与用户向量内积大小(度量两个向量的距离),选出内积较小的若干条视频


所有的召回策略选出的视频合起来,过滤一些不安全的视频后,会返回给排序层。 对排序层来讲,它所面对的候选视频集(千级)已经远远小于视频索引库中的量(百万或千万集)。

(2)、排序层

排序层分为粗排,精排,混排。
面对召回给到的千级别数量的视频,如果只用一个复杂而精细的模型去给这些视频打分,把得分高的前几条视频返回给用户,这个过程的耗时是用户无法接受的。大规模推荐系统中最精细的模型大小量级为TB,用TB级别的模型去计算几千条视频的得分,这样的耗时无法做到让用户无感知, 我们需要多层的排序去做漏斗。

粗排是模型大小量级为GB的相对简单和计算快速的模型,它计算千级别的候选视频,选出打分靠前的视频给到精排(返回的量级为百级别的)。精排的复杂模型(TB级别)拿到百级别的视频之后会对每一个视频进行打分,让视频按得分从高到底进行排序,在精排层不会做过滤,它会把这些百级别的视频全部给混排,混排会考虑精排得分,多样性得分,打散规则等等选出几条视频返回给用户。


三、关于排序的若干

我们之前提到了粗排模型和精排模型,这些模型的目标必然与推荐主目标一致——提升用户的时长和互动。模型自然离不开样本,有监督学习的样本会有feature和label,我们从label,feature,样本生成,模型结构这几方面展开,其实每一个方面都是一个很庞大的课题。

  • 样本label


 在视频场景,如果我们的目标是提升对视频的点击,毫无疑问,对于曝光且点击的视频为正样本,曝光未点击的样本为负样本。但这样一个简单的策略一般会面临几个问题:

1、对于很多的正样本,并不是用户真正的喜欢,只是视频本身是个标题党,所以造成了大量的点击,如果以这样的正负样本划分方式,会造成很多标题党视频的分发。
2、对于抖音,快手这类的app,他的视频体验是沉浸式的,没有点击的概念,往下刷的每一个视频都会自动播放,又如何来决定正负样本呢?

接下来我们仅考虑沉浸式视频自动播放的场景。很自然我们会去思考是不是播放时长比较长的为正样本,播放时长比较短的为负样本。这样的考虑带来的问题是,有一个物理时长(即视频本身长度)为100秒的视频和一个物理时长为10秒的视频,用户都播放了10秒,到底哪一个视频更好呢。想到这里就能知道,我们不仅要看播放时长,还要看播放完成率。

如果仅仅看播放时长(比如播放时长大于k秒为正样本,反之为负),那么物理时长很长的视频更有可能变成正样本,导致我们分发的全是长时长的。

同样若仅仅看完成率,那么物理时长短的自然完成率会很高,就会变成正样本,导致我们分发的全是短时长的。

自然的结论便是两个维度我们都需要关注。那么两个维度我们需要怎么结合一起看呢,我们是不是一定要区分样本的正负,去做一个分类模型呢?面对这些问题不同的企业或许有不同的方法。

另外上述我们谈的都是与时长相关的问题,如何去解决互动的问题呢,因为我们还希望面对分发的视频,用户会有点赞,分享,评论的动作。很简单的思路便是,我们做一个模型,用户有互动行为为正样本,否则会负样本。这里面对的问题是:互动行为是很稀疏的,大多数样本都是用户没有互动的,这个模型怎么才会训练得更好呢。即使训练出了一个很好的模型,又怎么和上述的时长目标去结合呢?

这一系列问题之后会新开一个专题来分享—— “推荐系统中的多任务学习”

  • 样本feature


之前提到粗排模型的大小为GB级别,精排模型的大小为TB级别。可能行业外的同学很难想象这个规模大小。这里原因最主要的便是——特征规模。

 对于一个有一定用户规模大小的推荐系统,特征的规模通常是千亿级甚至更多的。 id类别的特征永远是推荐系统的大杀器 ,即用户id,视频id,用户id与视频类别id的交叉特征等等,这些将是最重要的特征,特别是用户id。

如果产品的用户是上亿的,那么在用户id这个维度已经是上亿规模的特征。对于小规模的机器学习来说,可能离散的特征都是由one-hot的形式去进行表征,如果用该思路,那便是一个亿级别的稀疏向量,每个用户会命中这个向量的其中一个1,其他位置全是0,这样一个向量再投影到随即初始化的embedding矩阵,这样每个用户将会得到一个初始化的稠密向量表达。当然这个embedding矩阵的规模将是百亿级别的。当然在工业界的推荐系统中,我们不会采用one-hot的方法,通常我们会把用户id通过哈希的方式映射到这个slot下的某个key,形成一个稀疏的表达,再通过这个key去找到用户的lookup-embedding。

所以对于一个深度网络模型来讲,最大的地方就在于这个embedding层,上层的一些结构大小都可忽略不计。 精排相比于粗排,会用到更多的id类特征及对应的交叉特征以及更复杂的上层网络结构。

那么特征是不是越多越好,我们要怎样去维护特征才会让推荐效果得到不断迭代呢,这些问题也能开一个新的专题—— “推荐系统中的特征思考”

样本生成

在学术界或者论文中的实验部分,我们都会拿到一些离线的样本数据,用这些数据训练模型,不断进行模型优化,使得模型在测试集上有一个好的表现。但在工业界这是一个比较复杂的架构。样本的生成、存储和模型更新的频率有关。对于粗排来说,一般会进行小时级的更新;对于精排来说,我们有更高的要求,会对模型进行实时训练,是一个online-learning的模型。

 (1)、小时级更新模型:

比如当前5点我们有一个模型A,用户在5点会在模型A的推荐下进行视频消费,消费的数据会产生,并以样本的形式存储在hdfs,在6点的时候,我们会在模型A的基础上继续训练5点存储的数据,形成模型B,模型B继续为用户服务。

刚才提到“消费的数据会产生并并以样本的形式存储在hdfs”,这个是如何实现的呢?(以下架构比较复杂,如无兴趣可跳过)
   
  • 用户进行对app的一刷便是向功能端发出请求。

  • 功能端会去向混排层发出请求去拿展现给用户的视频。

  • 混排层会去向精排层发出请求要视频。

  • 精排层会向粗排层发出请求去拿数百条视频。

  • 粗排层拿到召回层吐出的视频后,会去请求模型预测服务获取模型打分。

  • 模型预测服务会请求特征服务获取特征。

  • 此时特征服务一方面赋予这些视频特征,让这些视频拥有特征后进入模型预测服务获得模型打分,另一方面特征服务会把这些视频的特征传给进行样本拼接的join服务。

  • join服务拿到这些样本的特征后会进行等待,看这些样本是否会展现给用户,用户对这些视频播放了多长时间,是否对这些视频进行了互动。用户的这一系列动作同样会上报给join服务作为样本label,特征和用户的动作都拿到之后,join服务会进行样本拼接。

  • 样本拼接好之后一方面会落到hdfs,另一方面会传给kafka。


(2)、实时训练模型:

上面提到的kafka作用是什么呢。精排模型是实时训练的,即用户消费了一条视频,那么在短暂(分钟级)的延迟后,这条样本被join服务拼接后送到kafka,kafka是一个分布式的消息流处理工具,kafka会关联模型,模型从中拿去join服务生产的样本进行消费。这个过程便是一个生产者-消费者的模式。如果训练模型过慢(比如获取的训练worker的个数和cpu过少),会造成生产者的速度大于消费者,结果便是模型的数据延迟,无法做到实时训练。模型用这些数据一直进行训练,并且随时可以在我们要求的时间以全量-增量的模式完成模型上线,上线到模型预测服务。对于一个TB级大小的模型,模型的embedding层在上线后会有一个分布式缓存。

  • 模型结构和业务理解


精排的模型主体结构其实在工业界无非那么几种,包括wide and deep,deepfm等等,各个企业根据业务在主体结构框架下做一些变体,比如加上attention,考虑sequence等等。如果是多目标学习,可能是share bottom,mmoe等。这些网络结构的优越性已经在各大知识平台上被翻来覆去的解读。这里不再赘述。甚至有很多论文会去做更深更复杂的模型,在所谓的离线测试样本上跑出更优秀的离线指标。

实际上对于企业来讲,推荐研发团队的主要任务是提升用户体验和用户时长,研发人员设计精细的算法模型是优化推荐系统从而达到目标的途径之一。当我还是在校生时,也总是去追求复杂而看似高级的模型,觉得“技术至上”。但当真正在企业生产线时,越发觉得从事业务的算法人员的核心价值在于对业务场景的深刻理解,在理解业务的基础上,一些小小的策略变动更能在低成本下为公司创造价值。

例如在排序时,我们可能会直接用模型去预估用户的播放时长,对于一个用户,有候选视频a和b,如果模型预估出来用户对b的播放时长更长,我们会把b排在a的前面。但模型真的能预估准确播放时长吗,可能对某一些物理时长的视频,模型能预估准确,但对于一些本身非常长的视频,模型预估效果可能不尽人意。那我们应该从模型上,从样本上做出一些什么改变来让模型对于长时长的视频预估得更准呢。这可能需要我们同时有对技术和对业务的深刻理解。


四、近期思考

絮絮叨叨进入尾声,若能看到这里,感谢支持,会留几个近期关于推荐的思考,大家可以一起交流。

  • 我们对新老用户在整个推荐架构上应该有怎样的区分策略。模型上的区分?画像上的区分?特定品类的加权降权?

  • 在pointwise的模式下,我们能否有一个好的序,让用户在一个session下的消费和时长达到较优。在混排做listwise?如何考虑耗时?

  • 在沉浸式的场景下,是否有一个好的方法来解决离线指标和在线指标的一致性

    

用一段打油诗结束:

特征做成精,模型如掌纹。召回双评估,排序秒监控。机制讲透彻,工程需将军。运营敢出牌,产品讲温度。技术有品味,任务无挂碍。


最后再次声明,本文纯属乱说,如有雷同,纯属巧合。





    

    
    
   

   
    

以上是关于当我们在谈论推荐系统的时候,我们在谈论什么的主要内容,如果未能解决你的问题,请参考以下文章

当我们在谈论JMM(Java memory model)的时候,我们在谈论些什么

当我们谈论不可变基础设施时,我们在谈论什么

当我们在谈论multidex65535时,我们在谈论什么

当我们在谈论multidex65535时,我们在谈论什么

当讨论面向对象的时候,我们到底谈论什么?

流动的推荐系统——兴趣Feed技术架构与实现