技术

高性能计算与存储 Linux2.1.13网络源代码学习 《大数据经典论文解读》 三驾马车学习 Spark 内存管理及调优 Yarn学习 从Spark部署模式开始讲源码分析 容器狂占内存资源怎么办? 多角度理解一致性 golang io使用及优化模式 Flink学习 c++学习 学习ebpf go设计哲学 ceph学习 学习mesh kvm虚拟化 学习MQ go编译器 学习go 为什么要有堆栈 汇编语言 计算机组成原理 运行时和库 Prometheus client mysql 事务 mysql 事务的隔离级别 mysql 索引 坏味道 学习分布式 学习网络 学习Linux go内存分配 golang 系统调用与阻塞处理 Goroutine 调度过程 重新认识cpu mosn有的没的 负载均衡泛谈 单元测试的新解读 《Redis核心技术与实现》笔记 《Prometheus监控实战》笔记 Prometheus 告警学习 calico源码分析 对容器云平台的理解 Prometheus 源码分析 并发的成本 基础设施优化 hashicorp raft源码学习 docker 架构 mosn细节 与微服务框架整合 Java动态代理 编程范式 并发通信模型 《网络是怎样连接的》笔记 go channel codereview gc分析 jvm 线程实现 go打包机制 go interface及反射 如何学习Kubernetes 《编译原理之美》笔记——后端部分 《编译原理之美》笔记——前端部分 Pilot MCP协议分析 go gc 内存管理玩法汇总 软件机制 istio流量管理 Pilot源码分析 golang io 学习Spring mosn源码浅析 MOSN简介 《datacenter as a computer》笔记 学习JVM Tomcat源码分析 Linux可观测性 学习存储 学计算 Gotty源码分析 kubernetes operator kaggle泰坦尼克问题实践 kubernetes扩缩容 神经网络模型优化 直觉上理解深度学习 如何学习机器学习 TIDB源码分析 什么是云原生 Alibaba Java诊断工具Arthas TIDB存储——TIKV 《Apache Kafka源码分析》——简介 netty中的线程池 guava cache 源码分析 Springboot 启动过程分析 Spring 创建Bean的年代变迁 Linux内存管理 自定义CNI IPAM 共识算法 spring redis 源码分析 kafka实践 spring kafka 源码分析 Linux进程调度 让kafka支持优先级队列 Codis源码分析 Redis源码分析 C语言学习 《趣谈Linux操作系统》笔记 docker和k8s安全访问机制 jvm crash分析 Prometheus 学习 Kubernetes监控 容器日志采集 Kubernetes 控制器模型 容器狂占资源怎么办? Kubernetes资源调度——scheduler 时序性数据库介绍及对比 influxdb入门 maven的基本概念 《Apache Kafka源码分析》——server Kubernetes类型系统 源码分析体会 《数据结构与算法之美》——算法新解 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 ansible学习 Kubernetes源码分析——从kubectl开始 jib源码分析之Step实现 jib源码分析之细节 线程排队 跨主机容器通信 jib源码分析及应用 为容器选择一个合适的entrypoint kubernetes yaml配置 《持续交付36讲》笔记 mybatis学习 程序猿应该知道的 无锁数据结构和算法 CNI——容器网络是如何打通的 为什么很多业务程序猿觉得数据结构和算法没用? 串一串一致性协议 当我在说PaaS时,我在说什么 《数据结构与算法之美》——数据结构笔记 PouchContainer技术分享体会 harbor学习 用groovy 来动态化你的代码 精简代码的利器——lombok 学习 《深入剖析kubernetes》笔记 编程语言那些事儿 rxjava3——背压 rxjava2——线程切换 spring cloud 初识 《深入拆解java 虚拟机》笔记 《how tomcat works》笔记 hystrix 学习 rxjava1——概念 Redis 学习 TIDB 学习 如何分发计算 Storm 学习 AQS1——论文学习 Unsafe Spark Stream 学习 linux vfs轮廓 《自己动手写docker》笔记 java8 实践 中本聪比特币白皮书 细读 区块链泛谈 比特币 大杂烩 总纲——如何学习分布式系统 hbase 泛谈 forkjoin 泛谈 看不见摸不着的cdn是啥 《jdk8 in action》笔记 程序猿视角看网络 bgp初识 calico学习 AQS——粗略的代码分析 我们能用反射做什么 web 跨域问题 《clean code》笔记 《Elasticsearch权威指南》笔记 mockito简介及源码分析 2017软件开发小结—— 从做功能到做系统 《Apache Kafka源码分析》——clients dns隐藏的一个坑 《mysql技术内幕》笔记 log4j学习 为什么netty比较难懂? 递归、动态规划和回溯 apollo client源码分析及看待面向对象设计 学习并发 docker运行java项目的常见问题 OpenTSDB 入门 spring事务小结 分布式事务 javascript应用在哪里 《netty in action》读书笔记 netty对http2协议的解析 ssl证书是什么东西 http那些事 苹果APNs推送框架pushy apple 推送那些事儿 编写java框架的几大利器 java内存模型和jvm内存布局 java exception Linux IO学习 netty内存管理 测试环境docker化实践 netty在框架中的使用套路 Nginx简单使用 《Linux内核设计的艺术》小结 Go并发机制及语言层工具 Linux网络源代码学习——数据包的发送与接收 《docker源码分析》小结 docker namespace和cgroup zookeeper三重奏 数据库的一些知识 Spark 泛谈 链式处理的那些套路 netty回顾 Thrift基本原理与实践(二) Thrift基本原理与实践(一) 回调 异步执行抽象——Executor与Future Docker0.1.0源码分析 java gc Jedis源码分析 深度学习泛谈 Linux网络命令操作 JTA与TCC 换个角度看待设计模式 Scala初识 向Hadoop学习NIO的使用 以新的角度看数据结构 并发控制相关的硬件与内核支持 systemd 简介 quartz 源码分析 基于docker搭建测试环境(二) spring aop 实现原理简述 自己动手写spring(八) 支持AOP 自己动手写spring(七) 类结构设计调整 分析log日志 自己动手写spring(六) 支持FactoryBean 自己动手写spring(九) 总结 自己动手写spring(五) bean的生命周期管理 自己动手写spring(四) 整合xml与注解方式 自己动手写spring(三) 支持注解方式 自己动手写spring(二) 创建一个bean工厂 自己动手写spring(一) 使用digester varnish 简单使用 关于docker image的那点事儿 基于docker搭建测试环境 分布式配置系统 JVM执行 git maven/ant/gradle/make使用 再看tcp kv系统 java nio的多线程扩展 《Concurrency Models》笔记 回头看Spring IOC IntelliJ IDEA使用 Java泛型 vagrant 使用 Go常用的一些库 Python初学 Goroutine 调度模型 虚拟网络 《程序员的自我修养》小结 Kubernetes存储 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件 Go基础 JVM类加载 硬币和扑克牌问题 LRU实现 virtualbox 使用 ThreadLocal小结 docker快速入门

架构

特征平台 实时训练 分布式链路追踪 helm tensorflow原理——python层分析 如何学习tensorflow 数据并行——allreduce 数据并行——ps 机器学习中的python调用c 机器学习训练框架概述 embedding的原理及实践 tensornet源码分析 大模型训练 X的生成——特征工程 tvm tensorflow原理——core层分析 模型演变 《深度学习推荐系统实战》笔记 keras 和 Estimator tensorflow分布式训练 分布式训练的一些问题 基于Volcano的弹性训练 图神经网络 pytorch弹性分布式训练 在离线业务混部 RNN pytorch分布式训练 CNN 《动手学深度学习》笔记 pytorch与线性回归 多活 volcano特性源码分析 推理服务 kubebuilder 学习 mpi 学习pytorch client-go学习 tensorflow学习 提高gpu 利用率 GPU与容器的结合 GPU入门 AI云平台 tf-operator源码分析 k8s批处理调度 喜马拉雅容器化实践 Kubernetes 实践 学习rpc BFF 生命周期管理 openkruise学习 可观察性和监控系统 基于Kubernetes选主及应用 《许式伟的架构课》笔记 Kubernetes webhook 发布平台系统设计 k8s水平扩缩容 Scheduler如何给Node打分 Scheduler扩展 controller 组件介绍 openkruise cloneset学习 controller-runtime源码分析 pv与pvc实现 csi学习 client-go源码分析 kubelet 组件分析 调度实践 Pod是如何被创建出来的? 《软件设计之美》笔记 mecha 架构学习 Kubernetes events学习及应用 CRI 资源调度泛谈 业务系统设计原则 grpc学习 元编程 以应用为中心 istio学习 下一代微服务Service Mesh 《实现领域驱动设计》笔记 serverless 泛谈 概率论 《架构整洁之道》笔记 处理复杂性 那些年追过的并发 服务器端编程 网络通信协议 架构大杂烩 如何学习架构 《反应式设计模式》笔记 项目的演化特点 反应式架构摸索 函数式编程的设计模式 服务化 ddd反模式——CRUD的败笔 研发效能平台 重新看面向对象设计 业务系统设计的一些体会 函数式编程 《左耳听风》笔记 业务程序猿眼中的微服务管理 DDD实践——CQRS 项目隔离——案例研究 《编程的本质》笔记 系统故障排查汇总及教训 平台支持类系统的几个点 代码腾挪的艺术 abtest 系统设计汇总 《从0开始学架构》笔记 初级权限系统设计 领域驱动理念入门 现有上传协议分析 移动网络下的文件上传要注意的几个问题 推送系统的几个基本问题 用户登陆 做配置中心要想好的几个基本问题 不同层面的异步 分层那些事儿 性能问题分析 当我在说模板引擎的时候,我在说什么 用户认证问题 资源的分配与回收——池 消息/任务队列

标签


特征平台

2022年06月27日

简介

实时特征计算平台架构方法论和实践

为什么会有特征平台

如何提高模型效果?

  1. Model-centric: 以调整模型代码、调优模型超参数为主的系统调优策略,在这种策略下,可以认为数据集是固定的 Data-centric:
  2. 与Model-centric相对,以调整数据集为主的系统调优策略,在这种策略下,可以认为模型是固定的(只对数据集作适应性调整) Andrew认为,在搭建模型时,特征生产与模型训练的时间占比应该是8:2,然而目前大部分AI研究的文章(>99%),均发力于模型探索方面。人们很容易认为模型效果不好,是因为模型不好,却忽略了数据集本身对模型效果的巨大影响。如何在工程中实现Data-centric策略?MLOps。

你真的需要特征存储吗?有三种方法可以确保在训练期间所做的预处理在预测期间是相同的

  1. 将预处理代码放在模型中,比如tf 有专门的feature_column库
    1. 优点,不需要额外的基础设施,预处理步骤将自动成为模型的一部分,如果需要在边缘或在另一个云上部署模型,不需要做什么特别的事情。
    2. 缺点,预处理步骤在通过训练数据集的每次迭代中会重复,计算的预处理的步骤越复杂,浪费的时间就越多。另一个缺点是,必须在与ML模型相同的框架中实现预处理代码。例如,如果模型是使用Pytorch编写的,那么预处理也必须使用Pytorch完成。如果预处理代码使用自定义库,会变得非常麻烦。
  2. 使用转换函数,将预处理步骤封装成函数,并将该函数一次性的应用于原始数据。然后对预处理后的数据进行模型训练,,这样预处理只进行了一次,可以提高效率。但是必须确保预测代码中也需要调用相同函数。像Tensorflow Extended (TFX)这样的框架提供了转换功能来简化相关操作。一些基于sql的ML框架,比如BigQuery ML,也支持TRANSFORM子句。
  3. 使用特征存储。
    1. 预测时需要动态特征,这种动态特征必须在服务器上计算,这时特性库就发挥了作用。例如动态定价模型的特征之一可能是过去一小时内网站上商品列表的访问数量。请求酒店价格的客户是无法实获取这个特征的,这些信息是在服务器上通过点击流数据的流管道进行实时计算的,所以特征库可以保存实时的计算结果并且提供对外的访问。PS:没看懂,大概是训练时刻t1 “过去一小时内网站上商品列表” 和 推理时刻t2 “过去一小时内网站上商品列表” 不一样,所以要把t1 时刻 “过去一小时内网站上商品列表” 保存下来给推理用
    2. 防止不必要的数据拷贝。例如有一个计算开销很大的特性,并且在多个ML模型中使用。与使用转换函数并将转换后的特性存储在多个ML训练数据集中相比,将它存储在一个集中的存储库中是更加高效的选择。

5年迭代5次,抖音推荐系统演进历程推荐系统最基础的燃料是特征,高效生产基础特征对业务推荐系统的迭代至关重要。PS: 特征分为离线特征和 实时特征,计算、存储特点和难点又有所不同,需要基础特征生产平台统一管理。

  1. 离线特征计算的基本模式都是通过消费 Kafka、BMQ、Hive、HDFS、Abase、RPC 等数据源,基于 Spark、Flink 计算引擎实现特征的计算,而后把特征的结果写入在线、离线存储。各种不同类型的基础特征计算散落在不同的服务中,缺乏业务抽象,带来了较大的运维成本和稳定性问题。
  2. 构建统一的实时特征生产系统面临着较大挑战,主要来自四个方面:
    1. 巨大的业务规模
    2. 较高的特征实时化要求,在以直播、电商、短视频为代表的推荐场景下,为保证推荐效果,实时特征离线生产的时效性需实现常态稳定于分钟级别。
    3. 更好的扩展性和灵活性:随着业务场景不断复杂,特征需求更为灵活多变。从统计、序列、属性类型的特征生产,到需要灵活支持窗口特征、多维特征等,业务方需要特征中台能够支持逐渐衍生而来的新特征类型和需求。
    4. 业务迭代速度快:特征中台提供的面向业务的 DSL 需要足够场景,特征生产链路尽量让业务少写代码,底层的计算引擎、存储引擎对业务完全透明,彻底释放业务计算、存储选型、调优的负担,彻底实现实时基础特征的规模化生产,不断提升特征生产力;

AI工程化落地的数据和特征的挑战

全栈 FeatureOps:开源机器学习数据库 OpenMLDB举一个性化搜索的例子,比如小李同学,在某个时间点想买洗衣机,去搜索洗衣机,触发了搜索行为以后,后面整个特征计算会做什么?首先进来的实时行为特征,只是这三个原始的特征,就是User ID,date以及他在搜索东西。如果我们只是拿这三个特征去做模型训练和推理,它是达不到一个非常好的模型精度的。此时需要做一个特征工程,所谓的特征工程就是我们从数据库里去进一步的去拉取一些历史数据,比方说我们从交易数据库、商品数据库、用户数据库去拉取一些历史数据,然后组合、计算,得到一些更完整的更有意义的特征。

推荐模型本质上是一个函数,输入输出都是数字或数值型的向量。离线训练 要根据用户的原始特征(有的地方称为物料) 构建训练样本,在线服务要根据用户的uid/itemId 找到原始特征,并根据原始特征转换为训练特征(也叫实时特征),再调用预测服务得到预测值。这个过程中

  1. 因为数据量大,物料转特征要用到spark,而算法人员一般不会使用spark。且特征转换 多样,每个模型都不同
  2. 离线/在线一致性校验 千亿级模型在离线一致性保障方案详解 未细读
    1. 数据科学家他关注的点是模型的准确度、精确度、质量,但他不太关心模型上线后latency, QPS等等。大部分科学数据科学家做这个过程当中,用的是Python,RSQL这种偏向批处理比较易用的框架,这种面向批处理的这种框架,不能直接上线。所以一般会有一个工程化团队,把科学家做的特征工程的脚本和模型训练的建模方法,翻译成线上的一套东西,因为他们非常关注latency、QPS,他们会用一些高性能数据库,甚至去用c++自己搭建一套特征抽取的服务,打通后面预估服务这条线。因为线上线下是两套系统,由两个团队开发,所以一致性校验是不可避免的。
    2. 有的特征可能在训练过程中t1时刻被转为a(对应模型参数版本v1),但经过一段时间t2时刻(随着样本量的变化)会被转换为b,此时拿着t1 时刻的模型参数去预测t2 就会不准。AI算法模型中的特征穿越问题:原理篇

  3. 特征服务/feature serving: 在线服务可能qps 非常高,一般要用到特征缓存
    1. 缓存原始特征/物料,公司有很多个部门,也就是会有很多个物料服务,此时会有一个物料缓存网关。物料缓存网关的核心功能则为缓存和路由,其根据特征名称路由到不同的物料服务来计算。
    2. 缓存训练特征。预测时实时 将物料转换为训练特征,实时计算就意味着RT增加,特征越多,RT的压力越来越大。降低RT的常见思路为用空间换时间,类似年龄性别等人口属性和用户的长期兴趣是固定的,没有必要每次都计算,可以将某些类型的特征提前计算好并存储到缓存中,线上请求直接拉取对应的特征即可。要区分不同物料的计算频率,我们将物料区分为下面几种更新周期:天级别、分钟级别、实时级别。实时级别的特征还是需要每次请求都实时计算的。此时,物料缓存网关 实际是 物料and特征缓存网关。
  4. 实时推荐对上述处理过程的挑战

整体设计

网易新闻推荐工程优化 - 特征平台篇业内常见的特征平台的核心设计往往为数据表,比如设计用户表和文章表。离线训练时将日志信息、用户表、文章表做join处理以生成样本;在线服务时则有专门的服务加速从数据表中获取内容的过程。

推荐系统(6): 特征平台实践与思考 由于特征种类多样,线上数据的来源也常常五花八门

  1. 比如物品的实时统计特征,可能通过客户端上报实时计算点击数、点赞数、购买数。
  2. 用户画像可能是离线计算,从hive 或hdfs 每天更;
  3. 物品的一些基础属性也可能是通过mysql db表生成。

因此,一个统一的特征平台(包括离线流程),可以:

  1. 统一特征口径: 特征的统计口径唯一,减少沟通成本,通过统一的接入作业,也可以复用模块代码,加快迭代速度
  2. 特征复用: 统一特征接入和上线流程,每个特征唯一id,上线过程复核,减少特征的重复。
  3. 质量监控: 特征覆盖率,分布统一监控,同时收拢出口,可以监控和限制特征的使用频率,及时下线淘汰的特征,减少成本。

特征平台(Feature Store):序论 业界已经有 Feast/Tecton/Databricks Feature Store/LinkedIn Feathr 等

  1. Feature Registry:一般数据库即可,以承载特征元数据,用来描述: 数据从哪里来,经过什么处理,变成什么样子,最后存到哪里去,这一整个流程。
  2. 特征计算/ Feature Pipeline。从各类原始数据,例如日志、记录、表,经过关联、统计、转化、聚集等操作得到的一系列值。这些Pipeline通常是Spark、Flink、Hive、SQL作业,并且批处理作业还需要一个编排系统(例如Apache Airflow)进行管理。PS: 以下工程通过python 等描述后,交给spark 执行
    1. 对于需要从原始数据计算得到的特征,Feathr称之为Anchored Feature,即该Feature是Anchor(锚定)在某个数据源上的。其Feature定义过程如下:
      1. 声明特征数据源,比如使用HDFS上的文件作为数据源
      2. 声明Feature对象,该对象记录了name、feature_type(数据类型)、transform(特征计算逻辑)等信息
      3. 声明FeatureAnchor对象
    2. 对于基于其他特征计算得到的特征,Feathr称之为Derived Feature(衍生特征)。其定义过程与AnchorFeature类似,只是将Source换成input_features。
  3. Offline Store:同时支持SQL数据库/数据仓库和数据湖,包含了特征的所有版本
    1. Feast方案中是一个时序表,包含timestamp/entity/feature 等
    2. shema free: 比如json。但这种格式无论是存储占用还是序列化开销都比较大
    3. Protobuf: pb协议相对通用,在没有复杂嵌套情况下,可以简单定义 feature_id,feature_type,feature_value三个类型,类似于tensorflow example的协议。
    4. Flatbuffer: 。同样是谷歌出品,通过打平+offset的方式,反序列化基本为0。但缺点是构造复杂,不适合嵌套结构。
  4. Online Store:比如Redis,服务于模型推理时的特征在线消费场景。一些公司会用到特征分组:特征分组将相同维度下的多个特征进行聚合,以减少特征Key的数量,避免大量Key读写对KV存储性能造成的影响。还有定期全量刷新 和 增量同步等问题。 业界常见的特征在线存储方式有两种:单一版本存储和多版本存储。
    1. 单一版本存储即覆盖更新,用新数据直接覆盖旧数据,实现简单,对物理存储占用较少,但在数据异常的时候无法快速回滚。
    2. 多版本存储相比前者,增加了版本概念,每一份数据都对应特定版本,虽然物理存储占用较多,但在数据异常的时候可通过版本切换的方式快速回滚,保证线上稳定性。
  5. SDK:比如基于Python开发的SDK,供用户使用

工作流程大概如下

  1. 特征元数据
  2. 特征计算,使用python或dsl 描述特征计算逻辑,交给spark 等处理,处理完成后存储到 Offline Store 中,并同步一份给 Online Store
  3. 模型训练,训练时从 Offline Store 中拼接 训练样本
  4. 推理时,业务方根据SDK 从 Online Store 中拿到某个用户的特征数据,调用serving 服务拿到预估值。

特征监控

  1. 离线天级可以通过抽样全量特征,主要分析来源数据是否异常。
    1. 特征异常值
    2. 特征覆盖率
    3. 特征max min avg 中位数等数据分布
  2. 在线监控主要是从 feature server 端,抽样上报,主要分析特征调用方,调用数据源,调用频率等等。除了用来统计流量来源,也可以及时发现一些过期不用的特征,通过下线存储来达到节约成本的目的。

业务dsl

从业务视角提供高度抽象的特征生产 DSL 语言,屏蔽底层计算、存储引擎细节,让业务方聚焦于业务特征定义。业务 DSL 层提供:数据来源、数据格式、数据抽取逻辑、数据生成特征类型、数据输出方式等。

vivo

vivo推荐中台升级路:机器成本节约75%,迭代周期低至分钟级

  1. 为了打通离线训练与在线推理的特征解析,我们对多个业务进行抽象设计,制定了 vivo 模型特征统一配置规范,VMFC(vivo Model Feature Configration)。
  2. 算法工程师在样本生产时,先在特征仓库勾选形成样本需要的特征集,在创建离线模型训练任务的时候,选择该模型训练与该特征集匹配。最终模型训练完成之后,在模型中心对其一键部署为在线推理服务。
  3. 在线推理服务对外提供统一接口,业务方使用时只需要指定对应的业务与模型代码,配置化推理服务找到该模型的 VMFC,便可以自动查询需要的特征,拼接为模型入参,返回预测结果。

在 vivo 传统的推荐系统架构中,特征的获取、特征的处理、特征的拼接以及推理预测是耦合在推荐工程的代码中的,每次算法实验的迭代,每增加一个特征,甚至是增加一个用于回传的特征,都需要在离线训练和推荐工程端硬编码新增的特征名称。然后把特征处理函数“搬运”过来,显然存在以下难以解决的痛点:

  1. 架构耦合对单机压力愈来愈大:特征获取与模型预测耦合,推荐系统服务器单机运行压力大;
  2. 硬编码迭代效率慢成为工程落地的瓶颈:特征获取与特征处理的逻辑不够灵活,无法应对算法实验的快速迭代需求,成为推荐系统流水线的瓶颈环节;
  3. 特征数据不一致:频繁的多分支多版本算法实验,多人协作带来较大沟通成本;训练的特征集、特征处理函数可能与线上推理预测的不一致,进而导致特征数据不一致;
  4. 特征复用困难:各个业务场景的特征都依赖于数据流算法工程师的经验,对多个团队类似的业务场景,特征的数据和经验不共享,导致增加了特征重复处理、存储等问题。数据孤岛效应明显,成本也很难缩减。

基于上述痛点,为了从根源解决算法迭代效率的问题,创造性的提出了特征仓库,特征集和通用特征服务的三大概念。

  1. 特征仓库,是通过特征工程把 Raw 数据抽取转化为一个特征,在特征平台注册为一个新特征元数据信息(Metadata),描述了这个特征存储的方式,数据类型,长度,默认值等,并且可以对该特征设置多项目共享,达到特征复用的目的。字节跳动基于 Iceberg 的海量特征存储实践
  2. 特征集,是一个虚拟灵活的特征集合概念,按照模型迭代的需求,可以自由从特征仓库上勾选需要的特征元数据,类似购物车的概念,按需动态勾选一个匹配当前模型训练的特征集。如果一个特征已经在平台上注册过,其他业务和场景需要复用,相应的算法工程师只需要申请共享,通过合规审批之后,就可以通过勾选特征集,用于自己的模型训练和在线推理。
  3. 特征服务,把特征获取这个关键步骤直接服务化,与特征管理平台联动的一个可配置化特征服务。在线获取特征的时候,调用通用特征服务的接口,传入特征集的唯一 ID,特征服务根据特征集元数据动态灵活获取需要的特征,一次返回给在线推理工程,通过特征拼接进入 Tensorflow 模型进行 CTR 实时预测。给出推荐结果。

网易

网易新闻推荐工程优化 - 特征算子篇

对训练样本需要的特征进行汇总分析,并对依赖的原始数据进行梳理,整理出由原始数据到特征样本之间所有的变换、组合关系,我们称之为特征算子。抽象算子之后,我们将进行特征描述和组合。我们选择json作为配置描述语言。

根据特征算子的输入、输出依赖关系将特征算子列表转成特征算子依赖关系图,该图为一个有向无环图。运行时,只需要根据图结点的依赖关系进行遍历计算,即可得到最终的特征数据。

美团

美团外卖特征平台的建设与实践 未全明白,比较全面。

外卖广告大规模深度学习模型工程实践 比较全面。

字节

5年迭代5次,抖音推荐系统演进历程特征生产的链路分为数据源抽取 / 拼接、状态存储、计算三个阶段,Flink SQL 完成特征数据的抽取和流式拼接,Flink State 完成特征计算的中间状态存储。

疑问

  1. 很多特征平台涉及到了特征存储的格式,说明特征平台负责了特征数据的计算和存储(美团叫 特征共享表),数据仓库 ==> 特征平台(管理特征集等) ==> 训练样本(模型支持的数据格式) ==> 训练。有了特征平台之后,只要根据特征集配置 从特征平台抽取 各个特征组成训练样本即可。那么特征平台是否负责存储 从原始数据转换后的 特征? 这个取决于是 临时进行特征计算快,还是特征计算完成后 每个特征单独存储,然后按需join 拼凑训练样本更快?
    1. 存储。优点是特征转换结果可以复用。缺点是,技术上因为要做point in time join,样本生成会很耗时。可以试着切分任务,比如说一次要生成三个月的样本。那么就把它拆成三个任务,每次只生成一个月的,相当于手动分桶优化。因为join时会有数据膨胀,而且是很夸张的膨胀,所以在计算资源固定的情况下,降低作业的数据量就会有明显提速。另一方面,point in time join的特性,本身就会受益于分桶优化。Point-in-Time Correct Join:Feast Spark版实现
    2. 不存储。 “特征平台”只是描述了 特征从哪里来、从原始数据如何转换,每次训练时要从原始数据抓取开始、特征转换、拼接训练样本。
    3. 实时生成样本,比如一个模型选了 n个特征,根据模型推理服务的请求,另外搞一个数据流根据模型的 特征转换dsl 实时转成样本存起来(推理 也包含一个原始特征 转为样本特征的过程,直接样本特征落盘也ok)。
  2. 平台里的kv 存储,存的是raw 特征 ,还是转换后的特征?
    1. 能预计算的,肯定是算好再存,这样快且简单
    2. 一些不能预计算的,例如组合特征、上下文特征,就只能在查询时,实时计算好再返回了

其它

模型仓库与模型服务

  1. 模型仓库,主要是对离线训练完成的模型进行统一管理,并且提供离线模型的一键部署能力。算法同事在完成模型训练之后,只需要确定该离线模型符合预期并加入模型仓库。
  2. 模型服务,“模型即服务”(Model as a Service), 基于 VMFC 的离线训练得到模型,在模型仓库一键部署成为在线服务,即可对外提供标准的在线预测接口。