乐趣区

关于算法:统一预估引擎的设计与实现

1. 背景

随着互联网的疾速倒退,互联网上呈现了各种海量的信息。怎么样为用户举荐感兴趣的信息是个很大的挑战?各种各样的举荐算法、零碎都涌现进去。而预估引擎能够说是举荐零碎中比拟重要的一环,预估引擎成果的好坏重大影响了算法成果。联合 oppo 的业务场景,咱们的预估引擎须要解决几个问题:

(1)通用性:oppo 的举荐业务场景十分多,包含信息流、商店、短视频、联盟、锁屏杂志、音乐等业务,预估引擎要反对这么多的场景,框架肯定要通用。

(2)多模型预估:在广告场景中,须要反对 ocpx,须要一次申请同时预估 ctr 和 cvr,可能是多个不同的转化模型(例如下载、付费等)。

(3)模型的动静更新:有些模型是小时更新、有些模型是天级更新,须要做到可能无感的动静更新。

(4)扩展性:各个业务用到的特色、字典、模型类型都可能不一样,要做到比拟容易扩大。

2. 定位与技术选型

思考到各个业务的业务特色差别比拟大,对立预估引擎如果要反对各个业务的策略试验和分流试验,会让预估引擎模块十分臃肿,没法保护。所以最终决定预估引擎只做预估相干的事件。
从原始数据到失去预估 ctr 后果,须要通过特征提取,提取特色之后的后果再进行模型预估。思考到特征提取后果比拟大,一次预估须要用的特色后果大概有 2M,这么大的数据如果通过网络来传输,耗时太长。所以预估引擎总体的流程包含了两局部:特征提取和模型预估。

3. Predictor 的设计与实现

3.1 Predictor 模块在整个举荐零碎中的地位

以 oppo 手机利用市场为类来阐明 predictor 模块在整个零碎中的地位,ranker 模块负责排序,包含各种分流试验和各种经营策略等。它通过 grpc 框架与 predictor 模块进行通信。

3.2 Predictor 模块的主体流程

图中示意了两个申请的解决流程,图中提特色包含多个特色 conf,每个样本、每个特色配置提取一次。预估也会是多个模型,每个样本、每个 conf、每个模型会预估屡次。特征提取依赖内部字典,预估依赖内部的模型文件,内部字典的更新、双 buf 切换都是通过字典治理模块来实现的。上面别离就字典治理模块、分 task, 提特色,预估,merge 进行具体阐明。

3.3 字典治理模块

如下图所示:conf1, conf2, lr_model_x0 等示意磁盘上的文件,每个文件名都是通过不同的字典解析类来解析,这个字典解析类负责管理这个文件的加载,双 buf 切换。例如:FeatureConfDict 负责解析 conf1,它外部保留两个 FeatureConfList 类型的 buf,当 conf1 文件产生更新时,就用备的 FeatureConfList 进行加载,加载实现后,在加载过程中,服务应用主的 FeatureConfList 指针。加载实现后,进行主从切换,待没有申请应用老的 buf,就开释到老的 buf 内存。

3.4 分 task 逻辑

接管到一个申请,这个申请指定了多 conf 多模型来预估。如下图所示:

上图示意一共有 8 条样本,别离用两个 conf:conf0, conf1 来提取特色,其中 conf0 的后果由 model0,model1 来预估,conf1 由 model2,model3 来预估。依照 2 个样本一个 task,拆分完 task 之后会失去 4 个 task,如下图所示:

依照样本维度进行拆分成 4 个 task,丢到线程池去执行。

3.5 Merge 流程

在预估实现之后,须要依照 conf/model 这个维度进行组织预估后果给 ranker,最终的 response 如下图右子图所示。

3.6 特征提取框架的设计

特征提取框架线上、线下都会用到,这样比拟好保障线上线下的一致性。所以设计的时候要同时思考到线上线下的业务场景。

线上是将申请带来的数据与字典数据拼成一条条样本,进行特征提取的。而线下是编译 so,通过 mapreduce 来调用,样本是通过反序列化 hdfs 的一条条文本失去的。

3.6.1 特色配置文件格式

特色配置文件包含两局部: schema 局部,特色算子局部。

3.6.2 schema 局部

上图中有 5 个 schema 配置

user_schema:示意以后的用户相干信息,只在在线形式应用,由上游申请带过去。

item_schema:示意举荐的 item 相干信息,只在在线形式应用,一部分由申请带过去,一部分由字典文件中获取。

context_schema:示意举荐的上下文相干信息,只在在线形式应用,由上游戏申请带过去。例如:以后网络状态是 wifi 还是 4G。

all_schema: 示意最终的样本的 schema 信息。在线模式是将 user_schema, item_schema,context_schema 的各个字段放在 all_schema 的对应地位,离线模块是将 hdfs 的一行行文本,依照 all_schema_type 指定的类型进行反序列化生成的。不论是在线还是离线,特色框架的样本最终的字段程序都是依照 all_schema 程序寄存的

all_schema_type: 离线模式才会用到,指定了各个 schema 的类型,这些类型名都是当时定义好的,在离线模式下,依据 schema 类型来反序列化各个字段。

3.6.3 特色算子配置局部

每个特色包含上面这些字段:

Name: 特色名字

Class:示意这个特色用的哪个特色算子类,对应代码里类名

Slot: 惟一标识一个特色

Depend: 示意该特色依赖哪些字段, 这个字段在上述 all_schema 中必须存在

Args: 示意传给特色算子的参数, 框架会转成 float 传给算子

Str_args: 传给特色算子的参数,以字符串的模式传递。

3.6.4 特色分 group(common 和 uncommon)

一次预估申请外面,所有样本的用户和 context 信息是一样的,思考到有些特色只依赖用户和 context 信息,这部分特色只须要提取一次,所有样本共用。

特色配置外面一部分特色会依赖其余的特色(例如组合特色、cvm 特色),所以须要对特色的依赖进行剖析,用来判断一个特色最终依赖的字段信息。

i_id 特色依赖 item 字段的 item_id,所以它是 uncommon 特色

u_a/net 特色只依赖 user_schema 或者 context 字段, 不依赖 item 字段,所以它是 common 特色
u_a-i_id 组合特色依赖 i_id 特色,距离依赖 item_id,所以它是 uncommon 特色,

u_a-net 组合特色只依赖 u_a 和 network 字段,所以它是 common 特色,在特征提取的时候,一次申请只算一次。

留神:这里特色分 group 是异步字典更新线程来负责计算好的,不是申请来了现算的。

3.7 预估局部

后面提到了,一个申请外面指定了用哪个特色配置文件来提取特色,用哪个模型来预估。所有的模型都是有异步字典更新线程来负责更新。目前反对了 LR, FM, DSSM,Deep&Wide 等模型的预估,并且比拟容易扩大。上面大略介绍下两个依据业务场景做了深度优化的模型:

3.7.1 FM 模型预估(LR 相似)


其中

思考到业务场景,多个样本的 user/context 信息是一样的,那么线上 FM 的 预估能够写成这个模式:

标红局部所有样本都是一样的,一个申请只用计算一次。

3.7.2 DSSM(双塔)模型

双塔模型的网络结构如下图所示:

实际上一共有三个塔,C(context 信息),U(user 信息), I(item 信息),user 与 item 子塔失去的向量通过点积,再与 C 进行求和。

3.7.3 在线 serving 局部

思考一些场景的 item 的信息变动比较慢,个别离线将 item 的子塔先计算好,失去向量,通过字典的形式动静加载。

在线的时候只用计算 c 塔,u 塔, 一个申请只有一条样本须要计算;I 塔局部由查字典失去向量。计算量相比全连贯,大幅度缩小。性能有大幅度的晋升,然而因为 user 信息与 item 只有一层点积相乘,相比全连贯,离线 auc 会降落 1%,所以比拟适宜召回或者粗排等对准确度要求不高的场景。在信息流广告、联盟广告业务替换原来的统计 ctr 粗排,综合指标晋升 5、6 个百分点。

3.8 性能优化

预估引擎模块对时延要求很高,然而为了达到比拟好的算法成果,特色规模又在一直的减少,所以在设计预估引擎的时候,做了很多性能优化的考量。次要包含以下几个方面:

(1)通过对象池来缩小内存调配,进步性能。

(2)特色字段的依赖都当时转化成下标,在提取特色的时候,就间接应用下标来取对应的字段,缩小计算量。

(3)有些特色依赖其余特色后果,会频繁依照 slot 去查问对应后果,思考到 slot 数据无限,采纳数组来代替。

4. 总结

目前 predictor 模块反对了大多数举荐场景,包含信息流内容、信息流广告、利用市场、联盟、搜寻、短视频、oppo 锁屏杂志、音乐等场景,部署在近 2000 台机器上,阐明这套设计还比较稳定、扩展性比拟好。目前反对业务平滑的切换到 dnn 模型,各个业务场景都获得肯定的收益。

作者简介

肖超 高级数据挖掘工程师

10+ 年的广告系统工程落地教训,在 oppo 次要负责模型的特征提取、推理的工程落地工作。

更多精彩内容,请扫码关注【OPPO 互联网技术】公众号

退出移动版