内容简要:
一、关于汇量科技
二、一个典型的推荐算法实验流程
三、问题和挑战
四、在Spark上构建推荐算法Pipeline
一、关于汇量科技(Mobvista)
汇量科技是:
• 一站式的移动广告服务和数据统计分析服务;
• 日均千亿次的在线广告个性化匹配;
• 全流量 DNN 模型排序;
• 构建了一站式机器学习平台MindAlpha。
二、一个典型的推荐算法实验流程
推荐算法的数据部分较为复杂,而语音图像数据集是一个静态的数据集。
推荐算法试验流程解析:
1) 数据准备
对数据进行处理、结合;
2) 特征样本生成
将数据进行特征拼接、Label拼接;
3) 特征存储
存储特征样本,包含在线学习样本和离线学习样本;
4) 模型训练
对样本进行模型训练,包括模型迭代、参数调优;
5) 在线评估
进行线上评估,如果发现问题返回之前的流程。例如参数优化问题,则返回模型调优,数据问题则返回第一步数据准备,从头开始。
三、问题和挑战
推荐算法与广告搜索类似,首先解决数据的问题,然后解决算法的问题。
推荐算法主要存在以下四个问题:
1.数据源多,特征处理流程繁琐
比如有实时特征、离线特征等。
2.离线学习、在线学习转换
在线学习与离线学习之间做无缝的转换。
3.模型训练与数据处理的衔接
数据源有很多不同类型的存储,算法需要适配,所以需要模型训练与数据处理的衔接。
4.上下游依赖多且频繁变动
线上算法有很多流量并行的实验,整个上下游的依赖比较繁琐,这方面出错的造成的问题比较严重。
四、在Spark上构建推荐算法 Pipeline
(一)Why Spark?
l 选择Spark的原因:
1)数据处理功能强大;
2)支持多种离线、实时数据源;
3)DataFrame的抽象;
4)支持多种调度系统和硬件;
5)PySpark。
(二)特征工程数据流
在解决特征数据流的问题上,最开始没有构建排版,业务算法工程师们一般是自己做数据拼接。这种拼接没有规范,直接拷贝代码输出数据源,在Spark里面进行 Join,每个实验形成一个数据集。
这种特征数据流存在许多问题:
• 多个实验各自产出数据;
• 99% 的列是重复的;
• 极大计算和存储浪费;
• 一小时的数据无法在一小时内处理完。
根据上面的问题,我们总结出特征数据流的解决方案与存储方案。
1.特征数据流的解决方案:
•统一列存储;
将同样的数据进行归置,避免多次计算。
•基础共用特征列;
特征列共用,包括标签。
•各实验的特征列;
每个实验添加自己的特征列,共用作业直接产出,其他作业只产出自己实验所需数据。
•模型训练通过列名配置读取DataFrame;
实验数据产出后做模拟训练,通过列名配置,从数据源里读取DataFrame。
2.存储方案选型
l Kudu 实时更新
Online Learning
l 天级 ORC 备份
离线实验
目前选用的是Kudu,含行级别和列级别,可以实时插入,近似于流式地写入Kudu。写完可以根据用户设定的调度周期,当时间窗口累计完成,触发一个训练任务,这就是Online Learning准实时学习的方案。
Kudu更新之后是天级ORC备份,将Kudu一天的数据备份到 OSS上。这里有两个目的,第一是备份,第二是缓Kudu本身的压力。
Kudu由本地磁盘搭建,本地磁盘存在成本大与性能瓶颈的问题。将数据存放到云存储上,可以借用云存储的服务能力做离线实验,实验时可以选择Kudu数据,也可以直接在OSS读历史数据。
(三)打通大数据和算法框架
1.Parameter Server on PySpark
l 为什么重新实现一套 Parameter Server?
l Python First API
n 与 Spark 调度集成
l 与 DataFrame 集成
1)Python First API
Python First API在做大规模离散深度学习训练时,需要解决Embedding参数稀疏的问题。
Embedding定义了几种Python接口,再向下可以分装成Embedding操作的API。对稀疏参数更新的问题,传统解决方法是放在Front Server节点上计算。
做Online Learning的时候,特征的个数是未知的,希望直接用原始的字符串或者用哈希值的方式做特征索引,特征的大小无法提前固定, Tenderflow框架不支持。
我们支持之后做内部转换,将每段哈希值映射到一个连续范围内,使得分片在比较小的范围内,它的索引最大不会超过分片总长度,使得可以直接用于各种接口。
2.与 Spark 调度集成
对于Parameter Server来说由两个部分,一个是Server节点,一个是Work节点。Spark从2.4开始有Rdd.barrier接口,接口的定义是所有的Excutor进程要么不起要么全起。
Spark存在猜测执行的机制,开启Rdd.barrier模式后,不会重复执行已有的进程,将原本大数据处理的方式换成机器学习的方式。
Rdd.barrier可以用于起Parameter Server作业,但要起Server与Worker两个节点。通过上述操作,完成了调度集成。
3.与DataFrame 集成
学习框架完成后开始训练,传统方法是使用UDF读取数据,Spark在2.3版本后提供了Pandas UDF,以Batch的形式将数据直接传到Python,然后转成Pandas的Data Frame。
由上图可看到,训练的代码均为UDF,执行训练直接调UDF,将Spark Columns传进去即可。
下面举例一个更复杂更全面的Demo,功能是在离线实时预估一致性监控On Spark Streaming。
实现监控的主要步骤:
1)事件的回流;
2)特征的回流;
3)做Window的GroupBy。
(四)解决数据上下游调度关系
完成数据、算法与训练后,最后要解决数据上下游调度关系。
在算法场景下的数据上下游调度与传统大数据调度有一定区别,存在以下两个问题:
问题一,最开始解决特征工程数据流时,共享部分拆成一个作业,由实验自己产出。每个实验自己产出额外需要的部分,此时会发现,其他实验需要依赖共用处于最上游的特征作业。
问题二,假设最初没有实验,线上是Baseline基线模型。算法工程师做实验时,例如加一个特征,就会基于Baseline的数据,再加入工程师自己的数据,两个数据之间自然就有上下游关系。后续基于这个Baseline又有其他实验,这样就有许多分支,再往后如果有一个实验效果不错,则成为新的Baseline,后续新实验就要基于新的Baseline重新进行实验,下图为分支管理方式。
实验依赖关系自动化
l 每个时刻,总是有一个Baseline (基线) 模型以及若干小流量模型(Master + 多个Branch);
l 小流量模型可能升级为基线模型(Merge);
l 此时各个实验数据依赖上游需要调整(Rebase);
l 基于Airflow;
l 通过一个配置文件自动生成Airflow DAG;
l 支持Fork、Merge、Rebase等操作。
基于上下游关系,我们将它们做成上下游的管理机制,每一个人做实验的时候,会去更新配置文件,描述实验的上游是谁。然后配置文件会自动刷新,刷新出来之后生成新的配置文件,就是上下游调度关系。
(五)未来方向
• PS on PySpark 2021 Q1开源
• Server/Worker异构资源分配(#SPARK-27495)
• 在 PS on PySpark上支持GNN