-
Notifications
You must be signed in to change notification settings - Fork 1k
TDMServing
TDM Serving 是深度树匹配模型(TDM)的线上服务模块,提供了基于TDM的高性能大规模(千万级+)实时推荐能力。
目前 TDM Serving 以 C++ 库的形式提供 TDM 线上实时 Matching 能力,用户可通过 TDM Serving 提供的 C++ API 与 线下产出的 TDM 模型数据轻松搭建 TDM Matching 线上服务。
另外TDM Serving也提供了基于深度学习的统一 Matching 服务框架,随着算法能力的不断演进,可以扩展实现更多的实时推荐技术。
TDM算法框架与TDM线下模型训练参见: 深度树匹配模型(TDM)
TDM Serving 源码地址
TDM Serving 库分三层设计:API,Index,Model,如下所示:
- API层:为用户提供能力接口,使用方便进行数据加载与实时检索。
- Index层:提供实时检索相关能力,包括 TDM 树索引检索、索引管理与业务逻辑过滤。
- Model层:为 Index 层提供提深度模型打分能力,包括 TDM 分层模型打分与模型数据管理。
TDM 检索逻辑对树索引进行 Beam Search,进行逐层打分与排序截断,最终得到topn Item。而单点打分通过Model层深度神经网络打分能力实现。
模型数据加载与实时预估能力通过 Blaze 库实现, 高性能实时预估引擎 Balze 库的使用文档参见:Blaze使用文档
- gcc >= 4.8.5
- cmake >= 2.8
- python >= 2.7
- protobuf >= 2.4
- glog
- blaze
Blaze 编译与安装见 Blaze使用文档
在 TDM Serving 源码目录下执行
mkdir build
cd build
cmake ..
make -j 8
sudo make install
TDM模型通过XDL线下训练后产生的数据有:
- 原始 TDM 树索引数据,userbehavior_tree.pb
- 原始 TDM 模型数据,dense.txt、graph.txt、item_emb、sparse.txt
XDL线下数据需要经过处理,转换为线上数据文件,供 TDM Serving 使用。
原始 TDM 树索引数据,需要通过树索引转换工具转换为线上索引数据。 转换工具位于 TDM Serving 源码路径 tools/convert_tree_index 下。 输入数据文件为 userbehavior_tree.pb。 将输入数据文件放在转换工具路径下,可通过以下方式进行转换:
# python 版 protobuf 功能安装
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo python ./get-pip.py
sudo pip install --upgrade protobuf
# python ./converter.py {xdl_pb_data} {tree_split_num}
# {xdl_pb_data} 为原始 TDM 树索引数据
# {tree_split_num} 数据转换后文件分割的数量
# 由于索引数据以 pb 形势存放,受 pb message 最大长度 2G 限制,转换后数据文件可能需要分割
# 无文件分割需求,{tree_split_num} 配置 1 即可
python ./converter.py userbehavior_tree.pb 1
转换后产出数据文件为 meta.dat、tree.dat.0
原始 TDM 模型数据,需要通过模型转换工具转换为线上模型数据。 转换工具为 Balze 库提供。 输入文件为 dense.txt、graph.txt、item_emb、sparse.txt。 转换后产出数据文件为 model.dat、sparse_qed。
Balze 模型转换工具使用方法见Blaze 工具使用文档
TDM Serving 需要用户通过配置文件方式指定检索策略,分为索引配置与模型配置,前者指定索引数据实例与索引检索策略,后者指定模型数据实例与模型预估策略。
#索引实例名称
[item_tree_index]
#是否开启索引
enable=true
#索引类型,目前索引类型只有一种即 TDM 索引,名称为 tree_index
type=tree_index
#索引数据路径,即存放线上树索引数据(meta.dat、tree.dat.0)的文件夹路径
index_path=index/item_tree_index
#模型实例名称,对应模型配置文件中的模型实例名称
#如果索引需要模型预估能力,则需要配置,TDM 索引需要配置
model_name=item_tree_model
#业务过滤组件实例名称,对应业务过滤配置文件中的业务过滤组件实例名称
#如果业务过滤能力,则需要配置
filter_name=item_tree_filter
#索引构建时的并发数量
build_thread_num=5
#以下为TDM索引相关配置
#树索引各层检索结果数量
tree_level_topn=9,400;10,400;11,400;12,400;13,400;14,400;15,400;16,400;17,400;18,400;19,400;20,400;21,400;22,400;23,400;24,400
#广告特征组id,目前树索引共用同一特征组id
item_feature_group_id=701
#模型实例名称
[item_tree_model]
#是否开启模型
enable=true
#模型数据类型,目前模型数据类型只有一种,为 balze
#即通过 Blaze 实现模型识别与预估能力
#具体的模型数据类型,则通过 Balze 加载模型数据文件,进一步识别
type=blaze
#模型数据路径,即存放线上模型数据(model_balze_optimized、sparse_qed)的文件夹路径
model_path=model/item_tree_model
#模型运行环境 0-CPU 1-CUDA
blaze_device_type=0
#业务过滤组件实例名称
[item_tree_filter]
#业务过滤组件类型
#my_filter_type 见 4.5 业务过滤
type=my_filter_type
TDM Serving 为用户提供 c++ API 接口,完成检索相关操作。
通过数据加载接口,完成索引与模型数据的加载。
bool SearchManager::Init(const std::string& index_conf_path,
const std::string& model_conf_path
const std::string& filter_conf_path = "");
其中 index_conf_path 为索引配置文件路径,model_conf_path 为模型配置文件路径,filter_conf_path 为业务过滤组件配置文件路径,如无业务过滤需求可以不配置。
通过检索接口,完成一次索引检索请求处理。
bool SearchManager::Search(const SearchParam& search_param,
SearchResult* search_result);
检索接口数据,采用 protobuf 协议表示,数据规格为:
// 检索请求
message SearchParam {
// 索引实例名称
optional bytes index_name = 1;
// 检索结果数量
optional uint32 topn = 2;
// 用户信息
optional UserInfo user_info = 3;
// 业务过滤信息
optional FilterInfo filter_info = 4;
}
message UserInfo {
// 用户特征
optional FeatureGroupList user_feature = 1;
}
message FeatureGroupList {
// 特征组
repeated FeatureGroup feature_group = 1;
}
message FeatureGroup {
// 特征组 ID
required string feature_group_id = 1;
// 特征 KV
repeated FeatureEntity feature_entity = 2;
}
message FeatureEntity {
// 特征 ID
required uint64 id = 1;
// 特征值
required float value = 2;
}
// 用户自定义业务过滤信息
message FilterInfo {
}
// 检索结果
message SearchResult {
// 检索结果编码
required ResCode res_code = 1;
// 检索结果列表
repeated ResultUnit result_unit = 2;
}
// 检索结果编码定义
enum ResCode {
// 检索成功
RC_SUCCESS = 0;
// 检索内部错误
RC_SEARCH_ERROR = 1;
}
message ResultUnit {
// ID
optional uint64 id = 1;
// 分数
optional float score = 2;
}
TDM Serving 提供索引与模型数据热加载能力。 用户在索引与模型数据文件路径下配置 version 文件,即可开启热加载能力。
索引配置为:
#索引实例名称
[item_tree_index]
#索引数据路径
index_path=index/item_tree_index
#其他索引配置
...
模型配置为:
#模型实例名称
[item_tree_model]
#模型数据路径
model_path=model/item_tree_model
#其他模型配置
...
在索引数据路径 index/item_tree_index 下 创建 version 文件,配置内容为:
index_version=111
model_version=211
在模型数据路径 model/item_tree_model 下 创建 version 文件,配置内容为:
model_version=211
则当前最新索引版本为 111,当前最新模型版本为 211。
将数据部署为:
.
├── index
│ └── item_tree_index
│ ├── 111
│ │ ├── meta.dat
│ │ └── tree.dat.0
│ └── version
└── model
└── blaze_model
├── 211
│ ├── model.dat
│ └── sparse_qed
└── version
则系统会到 index/item_tree_index/111 下加载索引数据,model/item_tree_model/211 下加载模型数据。
若 version 文件内容有变化,系统会检测到文件变化并自动到对应路径下热加载新的索引与模型数据 如有新增数据,部署改变为:
.
├── index
│ └── item_tree_index
│ ├── 111
│ │ ├── meta.dat
│ │ └── tree.dat.0
│ ├── 112
│ │ ├── meta.dat
│ │ └── tree.dat.0
│ └── version
└── model
└── blaze_model
├── 211
│ ├── model.dat
│ └── sparse_qed
├── 212
│ ├── model.dat
│ └── sparse_qed
└── version
其中 index/item_tree_index/version 内容改变为
index_version=112
model_version=212
model/item_tree_model/version 内容改变为:
model_version=212
系统会检测到 version 文件变化,从 index/item_tree_index/112 下加载最新索引数据,model/item_tree_model/212 下加载最新模型数据。
如不需要热加载能力,不配置 version 文件即可 系统会直接从索引配置中指定的索引路径下加载索引数据,从模型配置中指定的模型路径下加载模型数据。 如数据部署为:
.
├── index
│ └── item_tree_index
│ ├── meta.dat
│ └── tree.dat.0
└── model
└── blaze_model
├── model.dat
└── sparse_qed
无 version 文件配置,系统会直接从 index/item_tree_index 与 model/item_tree_model 加载数据,并关闭数据日加载能力。
TDM 树检索过程中,会对每层检索出的候选 Item 对象进行过滤,用户可以在现有 Matching 框架下,编写自己的业务过滤扩展逻辑。
以下举例说明,用户自定义业务过滤逻辑的流程。
- 编写并注册自定义业务过滤逻辑
#include "biz/filter.h"
// 编写自定义 Filter 逻辑:
class MyFilter : public Filter {
public:
// 业务过滤组件初始化
virtual bool Init(const std::string& section,
const util::ConfParser& conf_parser) {
// 自定义初始化逻辑
return true;
}
// Item 过滤接口
// 此接口会在索引检索过程中被调用,用于过滤每个检索出的 Item
virtual bool IsFiltered(const FilterInfo* filter_info,
const Item& item) {
// 自定义业务过滤逻辑
return false;
}
};
// 注册用户自定义过滤组件
REGISTER_FILTER(my_filter_type, MyFilter);
- 编写业务过滤配置文件
#自定义业务过滤组件实例名称
[my_filter_name]
#自定义业务过滤组件名称,对应组件注册时使用的名称
#同一种业务过滤逻辑,可被多次实例化
type=my_filter_type
- 编写索引配置文件
#索引实例名称
[my_index]
#指定此TDM 树索引,检索过程中,使用 my_filter_name 过滤逻辑实例
filter_name=my_filter_name
#其他索引配置
...
- 扩展 Filter Info 用户可以扩展检索请求中 FilterInfo 部分,在实时检索时传递业务过滤时所需的信息
message FilterInfo {
// 用户自定义业务过滤信息
string filter_info;
}
基本使用样例见 example/tdm_example.cpp。 用户自定义业务过滤,使用样例见 example/tdm_with_filter_example.cpp。
效果评估样例见 evaluation/tdm_evaluation.cpp,可统计Matching效果,用于与线下测试效果对齐。 其中效果评估使用的数据需要用户生成,生成方法为:
- 参照深度树匹配模型(TDM)训练产出 TDM 模型与索引数据
- 参照 4.1 节内容将线下数据转换为线上 TDM Serving 使用的索引与模型数据
树索引规模(叶子节点数量) 400万,取 top 400 最优结果。
环境 | 平均响应时间(ms) | QPS |
---|---|---|
单卡 GPU,DNN模型 | 42.1 | 118 |
单卡 GPU,Attention模型 | 113 | 17 |