在搜索、推荐、在线广告等业务场景中,embedding参数的规模常常非常庞大,达到数百GB甚至T级别;训练如此规模的模型需要用到多机分布式训练能力,将参数分片更新和保存;另一方面,训练好的模型,要应用于在线业务,也难以单机加载。Paddle Serving提供大规模稀疏参数读写服务,用户可以方便地将超大规模的稀疏参数以kv形式托管到参数服务,在线预测只需将所需要的参数子集从参数服务读取回来,再执行后续的预测流程。
本文以CTR预估任务为例,提供一个完整的基于PaddlePaddle的分布式训练和Serving的流程化部署过程。基于此流程,用户可定制自己的端到端深度学习训练和应用解决方案。
本文演示的基于PaddlePaddle的分布式训练和Serving流程化部署,基于CTR预估任务,原始模型可参见PaddlePaddle公开模型github repo。 整体拓扑架构如下图所示:
其中:
以下从4部分分别介绍上图中各个组件:
分布式训练采用volcano开源框架以及云平台实现,文档中以百度智能云以及CTR预估模型为例,演示如何实现大规模稀疏参数模型的分布式训练。
登录百度智能云官网,参考帮助文档创建容器引擎。
进入“产品服务>容器引擎CCE”,点击“集群管理>集群列表”,可看到用户已创建的集群列表。从集群列表中查看创建的集群信息。
点击左侧的”Helm>Helm实例”,点击安装链接为集群一键安装helm。百度智能云为集群安装的helm版本为2.12.3,kubectl版本为1.13.4
为了能够从外部登录集群节点,需要为集群中安装了tiller的节点申请弹性公网。点击”更多操作>控制台”。
点击”命名空间”选择kube-system,点击”容器组”,查看tiller开头的节点IP,根据节点IP可以在集群的节点列表找到对应的节点名称。
点击”产品服务>网络>弹性公网”
创建弹性公网实例,完成后选择创建的实例,点击”更多操作>绑定到BCC”,选择上一步找到的的节点名称。
配置过程需要开发机的root权限。
KubeCtl可以实现在本地开发机上连接百度智能云的Kubernets集群,建议参考百度云操作指南文档中通过KubeCtl连接集群部分进行安装。
建议参考Helm官方安装文档进行安装。
注意事项: 开发机上的kubectl与helm的版本需要与集群上的版本相一致,目前百度智能云为集群安装的helm版本为2.12.3,kubectl版本为1.13.4。
点击”集群列表”界面的”配置文件下载”,下载配置文件。
将下载的配置文件移动到~/.kube文件夹下,文件名修改为config。
通过之前创建的弹性公网ip登录运行tiller的节点,账户密码为创建集群时设置的账户和密码,默认账户为root。
将节点上的以下三个文件
/etc/kubernetes/pki/ca.pem
/etc/kubernetes/pki/admin.pem
/etc/kubernetes/pki/admin-key.pem
下载至开发机并放在相同的路径,添加四个环境变量
export HELM_TLS_ENABLE=true
export HELM_TLS_CA_CERT=/etc/kubernetes/pki/ca.pem
export HELM_TLS_CERT=/etc/kubernetes/pki/admin.pem
export HELM_TLS_KEY=/etc/kubernetes/pki/admin-key.pem
分别执行kubectl version
与helm version
,如果返回client端与server端信息,则证明配置成功。
示例:
如果只返回client端信息,server端信息显示”Forbidden”,检查开发机是否使用了代理,若有可以尝试关闭代理再次执行命令检查。
推荐安装Go 1.12
下载安装包
wget https://studygolang.com/dl/golang/go1.12.7.linux-amd64.tar.gz --no-check-certificate
解压到某一路径下,注意事项: 若已安装过其他版本的go,请不要放在同一路径下或清空该路径再安装。
tar zxvf go1.12.7.linux-amd64.tar.gz -C /path/to/go
设置环境变量
export GOROOT=/path/to/go
export PATH=/path/to/go/bin:$PATH
创建一个文件夹并设置为GOPATH。
参考volcano官方文档。
通过yaml文件安装
kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml
安装完成后执行kubectl get pods --namespace volcano-system
若出现以下信息则证明安装成功:
注意事项: 由于与dockerhub官网的网络连接不稳定,可能会出现安装失败的情况。如果安装失败,使用kubectl describe pods --namespace volcano-system
命令进行错误检查,确定为拉取镜像失败后请执行
kubectl delete -f https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml
然后重新安装。
无论是dense参数还是Sparse参数,在生成之后,都需要以某种方式将文件服务暴露出来。dense参数需要配送给Paddle Serving,稀疏参数需要配送给Cube大规模稀疏参数服务器。
配送的方式是通过K8S集群建立一个Http file server的pod,再通过注册负载均衡 load balancer service,映射file server的port给load balancer,最终可以直接通过公网IP:Port的方式来访问HTTP File Server。
fileserver.yaml 一同包含两个部分,第一个是file server pod的配置,这样可以启动file server的docker镜像,并暴露文件服务端口。第二个是load balancer的配置,这样可以启动load balancer分配公网IP并且映射文件服务端口给公网。 fileserver.yaml 文件示例如下:
apiVersion: v1
kind: Pod
metadata:
name: file-server
labels:
app: file-server
spec:
nodeSelector:
nodeType: model
volumes:
- hostPath:
path: /home/work
type: ""
name: file-home
containers:
- name: file-server
image: halverneus/static-file-server
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /web
name: file-home
---
kind: Service
apiVersion: v1
metadata:
name: loadbalancer
spec:
type: LoadBalancer
ports:
- name: file-server
port: 8080
targetPort: 8080
selector:
app: file-server
具体步骤如下
执行
kubectl apply -f fileserver.yaml
两项配置都执行成功之后,执行
kubectl get pod
会显示file-server,如下图所示。
kubectl get service
会显示load balancer,如下图所示。
其中External IP就是文件服务的公网IP,我们可以在任意一台可以连接公网的计算机上,输入wget http://IP:Port 。例如图片中的示例,输入wget http://180.76.113.149:8080 。
如果显示下载了 index.html
就说明服务搭建成功。
本节中获得的file server IP PORT将在下文中第2.4.1节和3.1.3.4节应用,请记住此file server地址
创建cluster role和service account,defaultserviceaccountclusterrole.yaml 文件示例如下:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: default
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: default
namespace: default
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: ClusterRole
name: default
apiGroup: rbac.authorization.k8s.io
执行
kubectl create -f defaultserviceaccountclusterrole.yaml
在本次训练任务中,产出的模型文件会存放在trainer0的node上,为了使file server服务可以找到产出的模型文件,需要通过kubectl get node
查看当前的node列表,通过以下命令指定某个node的nodeType为model
kubectl label node ${NODE NAME} nodeType=model
这样trainer0与file server服务都会被绑定到该node,即可以通过file server服务下载产出的模型文件。
CTR模型的训练镜像存放在dockerhub网站,通过kubectl加载yaml文件启动训练任务,CTR预估模型训练任务的yaml文件为volcano-ctr-demo-baiduyun.yaml。
执行
kubectl apply -f volcano-ctr-demo-baiduyun.yaml
通过kubectl get pods
命令可以查看训练任务的运行情况
通过kubectl logs $POD_NAME
可以查看对应的日志,例如kubectl logs edl-demo-trainer-0
也可以通过百度云平台提供的web页面观察集群的工作负载
CTR预估模型包含了embedding部分以及dense神经网络两部分,其中embedding部分包含的稀疏参数较多,在某些场景下单机的资源难以加载整个模型,因此需要将这两部分分割开来,稀疏参数部分放在分布式的稀疏参数服务,dense网络部分加载到serving服务中,稀疏参数和dense网络都需要通过http file server服务来进行配送(详见本文”1.4 搭建HTTP File Server服务”一节)。在本文中使用的CTR模型训练镜像中已经包含了模型裁剪和稀疏参数产出的脚本,以下简述其原理和工作过程。
产出用于paddle serving预测服务的dense模型需要对保存的原始模型进行裁剪操作,修改模型的输入以及内部结构。具体原理和操作流程请参考文档改造CTR预估模型用于大规模稀疏参数服务演示。
在trainer镜像中,模型裁剪的主要交互流程是:
pass-1000
时,表示训练任务完成 (默认训练轮次为1000)产出的dense参数是一个.tar.gz压缩包,路径为:
http://${FILE_SERVER_IP}:${FILE_SERVER_PORT}/data/ctr_model.tar.gz
FILE_SERVER_IP
与FILE_SERVER_PORT
请参考1.4节获取。
分布式稀疏参数服务由paddle serving的Cube模块实现。Cube服务接受的原始数据格式为Hadoop seqfile格式,因此需要对paddle保存出的模型文件进行格式转换。
在trainer镜像中,将模型参数转换为seqfile的主要流程是:
pass-1000
时,表示训练任务完成 (默认训练轮次为1000)产出的稀疏参数是一个目录,通过一个donefile来描述整个文件夹结构:
http://${FILE_SERVER_IP}:${FILE_SERVER_PORT}/data/ctr_cube/donefile/base.txt
Donefile的格式请参考2.4.5节。
FILE_SERVER_IP
与FILE_SERVER_PORT
请参考1.4节获取。
Cube大规模稀疏参数服务服务组件,用于承载超大规模稀疏参数的查询、更新等各功能。上述分布式训练产出的稀疏参数,在k8s中以http文件服务的形式提供下载;cube则负责将稀疏参数读取、加工,切分成多个分片,灌入稀疏参数服务集群,提供对外访问。
Cube一共拆分成四个组件,共同完成上述工作:
关于Cube的性能数据,请参考Cube Benchmark
本文仅描述从头部署Cube服务的流程。
Cube是Paddle Serving内置的组件,只要按常规步骤编译Serving即可。要注意的是,编译Cube需要Go语言编译器。
$ git clone https://github.com/PaddlePaddle/Serving.git
$ cd Serving
$ mkdir build
$ cd build
$ cmake -DWITH_GPU=OFF .. # 不需要GPU
$ make -jN # 这里可修改并发编译线程数
$ make install
$ cd output/
$ ls bin
cube cube-builder cube-transfer pdcodegen
$ ls conf
gflags.conf transfer.conf
其中: 1) bin/cube, bin/cube-agent, bin/cube-builder, bin/cube-transfer是上述3个组件的可执行文件。bin/cube是cube-server的可执行文件 2) conf/gflags.conf是配合bin/cube使用的配置文件,主要包括端口配置等等 3) conf/transfer.conf是配合bin/cube-transfer使用的配置文件,主要包括要监听的上游数据地址等等
接下来我们按cube server/agent, cube-builder, cube-transfer的顺序,介绍Cube的完整部署流程
首先修改cube server的配置文件,将port改为我们需要的端口号,(当本机内存资源紧张时,将in_mem修改为false将以磁盘访问的模式启动cube server):
--port=8000
--dict_split=1
--in_mem=true
将bin/cube,bin/cube-agent和conf/gflags.conf拷贝到多个物理机上。假设拷贝好的文件结构如下:
$ tree
.
|-- bin
| `-- cube
| `-- cube-agent
|-- conf
| `-- gflags.conf
nohup bin/cube &
nohup bin/cube-agent -P 8001 &
其中cube-agent在启动命令中使用 -P 参数指定监听端口号,在./log文件夹可以查看cube server的日志。
cube-builder配置项说明:
均在启动参数中提交
参数项如下:
cube-builder: Usage : ./cube-builder --help
Flags from /home/work/cube-builder/src/main.cpp:
-cur_version (current version, no need) type: int32 default: 0 //单机builder模式下不需要
-depend_version (depend version, job mode delta need) type: int32 default: 0 //单机builder base模式下不需要,patch模式找到meta_info里的base的key
-dict_name (dict name, no need) type: string default: "" //词典名,单机builder模式下不加默认空,用来和版本拼接生成索引文件名
-input_path (source data input path) type: string default: "" //必须,源数据所在路径,仅支持本地路径
-job_mode (job mode base/delta default:base) type: string default: "base" //默认base模式,delta模式:-job_mode=delta
-last_version (last version, job mode delta need) type: int32 default: 0 //单机builder base模式下不需要,patch模式找到meta_info里的base的id
-master_address (master address, no need) type: string default: "" //单机builder模式不需要,会把index meta信息写到本地output/meta_info目录下
-only_build (wheather build need transfer) type: bool default: true //单机builder模式不需要,代表是不是单机builder,如果false会向master_address发送请求,将index meta信息写到远程
-output_path (source data input path) type: string default: "" //必须,索引建库数据的输出路径,仅支持本地路径
-shard_num (shard num) type: int32 default: -1 //必须,数据切分的分片数量
需要将bin/cube-builder拷贝到物理机上。
只利用builder工具建立索引无特殊位置要求,如果接入配送环节使用必须和cube-transfer同机部署。
假设单独使用builder工具,文件结构如下:
$ tree
`-- cube-builder
|-- source
| `-- test_seqfile
|-- output
拷贝bin/cube-builder和cube-transfer程序到同一机器。
相关参数已经封装好,只需要在cube-transfer的conf/transfer.conf里配置好cube-builder的地址、源数据和建库数据output的地址即可, 执行cube-transfer时会通过配置文件中的路径调用cube-builder,所以通常不需要手动执行cube-builder。
假设分片数为2,词典名为test
启动cube-builder命令,参数中的路径需要为绝对路径
./cube-builder -input_path=${source} -output_path=${output} -shard_num=2 -dict_name=test
运行后会根据当前时间戳自动生成建库索引文件夹1565323045_1565323045和meta信息文件夹meta_info结构如下:
$ tree
`-- cube-builder
|-- source
| `-- test_seqfile
`-- output
|-- 1565323045_1565323045
| |-- test_part0
| | |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part0.tar
| |-- test_part0.tar.md5
| |-- test_part1
| | |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part1.tar
| `-- test_part1.tar.md5
`-- meta_info
|-- 1565323045_1565323045_0_0.json
`-- 1565323045_1565323045_1_0.json
test_part0.tar和test_part0.tar.md5是shard0分片的数据和md5校验,1565323045_1565323045_0_0.json是0号分片的索引长度和数量,在对应版本的delta建库中需要。
需要依赖于上次的base或者delta的id和key,1565323045_1565323045_0_0.json前一个时间戳是id,后一个是key(和分片数据的目录key_id相反),对应cube-builder输入参数-last_version和-depend_version,保持output和dict_name不变(builder会寻找上一轮的index meta信息)。
启动cube-builder命令,参数中的路径需要为绝对路径
./cube-builder -input_path=${source} -output_path=${output} -shard_num=2 -depend_version=1565323045 -last_version=1565323045 -job_mode=delta -dict_name=test
运行后会根据当前时间戳自动生成delta建库索引文件夹1565323045_1565326078和meta信息文件夹meta_info结构如下:
$ tree
`-- cube-builder
|-- source
| `-- test_seqfile
`-- output
|-- 1565323045_1565323045
| |-- test_part0
| | |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part0.tar
| |-- test_part0.tar.md5
| |-- test_part1
| | |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part1.tar
| `-- test_part1.tar.md5
|-- 1565323045_1565326078
| |-- test_part0
| |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part0.tar
| |-- test_part0.tar.md5
| |-- test_part1
| | |-- data.0
| | |-- data.n
| | |-- index.0
| | `-- index.n
| |-- test_part1.tar
| `-- test_part1.tar.md5
`-- meta_info
|-- 1565323045_1565323045_0_0.json
|-- 1565323045_1565323045_0_0.json
|-- 1565326078_1565323045_0_0.json
`-- 1565326078_1565323045_1_0.json
builder输入数据的源格式必须为seqfile,key为uint64(输入必须为二进制8个字节),value为序列化的二进制。
提供明文转seqfile工具和读seqfile工具,位置在output/tool里kvtool.py和kv_to_seqfile.py。
kvtool.py 是读seqfile工具,会输出读到的kv信息,参数是文件地址假设在/home/work/test下的seqfile,运行方式如下:
python kvtool.py /home/work/test/seqfile
kv_to_seqfile.py是明文转seqfile工具,依赖于kvtool.py,会将明文kv转为seqfile文件存储,并输出donefile,在kv_to_seqfile.py的27和30行修改输入和donefile路径:
BASE_DONEFILE = DATA_PATH + "donefile/base.txt" #base donefile文件地址
SOURCE_FILE = './source/file.txt' #明文源数据路径
要求明文txt内的格式,每行一对kv,用:分割,示例如下:
1:1
2:2
10:10 11 12
11:this is eleven
12:value can string
1676869128226002114:48241 37064 91 -539 114 51 -122 269 229 -134 -282
1657749292782759014:167 40 98 27 117 10 -29 15 74 67 -54
cube-transfer配置文件是conf/transfer.conf,配置比较复杂,配置文件中的路径需要为绝对路径,各个配置项含义如下:
[default]
dict_name: test_dict # 词典名
mode: base_delta # 配送模式base_only/base_delta
download_mode: http # 配送方式,可以选择http或ftp
wget_port: 80 # http服务的端口
buildtool_local: /path/to/cube-builder # builder工具位置,必须在本地,绝对路径
donefile_address: http://${FILE_SERVER_IP}:${FILE_SERVER_PORT}/data/ctr_cube/donefile/ # donefile路径,${FILE_SERVER_IP}:${FILE_SERVER_PORT}为1.4节搭建的file server地址。文件夹内包含base.txt, patch.txt和一批Hadoop SequenceFile文件
output_address: /some/path/to/output # builder产出的数据索引输出位置
tmp_address: /some/path/to/tmp # transfer工具运行中临时文件存放位置
shard_num: 2 # 分片数
copy_num: 1 # 每片副本数
deploy_path: /home/work/test_dict # 不用修改
transfer_address: 10.10.10.5 # cube-transfer本机的ip
[cube_agent]
agent0_0: 192.168.1.1:8001 # 0号分片0号副本的agent ip:port
cube0_0: 192.168.1.1:8000:/path/to/cube # 0号分片0号副本的cube,该路径下会存放配送的数据,需要与启动cube可执行文件时所在的路径一致 格式:ip:port:deploy_path
agent1_0: 192.168.1.2:8001 # 1号分片0号副本的agent ip:port
cube1_0: 192.168.1.2:8000:/path/to/cube # 1号分片0号副本的cube,该路径下会存放配送的数据,需要与启动cube可执行文件时所在的路径一致 格式:ip:port:deploy_path
将bin/cube-transfer和conf/transfer.conf拷贝到多个物理机上,构建output和tmp文件夹用来存放配送的中间文件。
注意事项: 请在transfer所在的物理机上启动http服务或ftp服务,确保cube-agent所在的物理机可以通过配置文件中的${transfer_address}:{wget_port}/${output_address}
下载目录下的数据。
假设拷贝好的文件结构如下:
$ tree
.
|-- cube-transfer
|-- output
|-- tmp
`-- conf
|-- transfer.conf
假设启动服务端口8099,-l参数是log等级 –config是配置文件位置,./log文件夹下可以查看cube-transfer的日志
./cube-transfer -p 8099 -l 4 --config conf/transfer.conf
配送完毕cube-transfer会进入监听数据更新的状态,日志以及命令行会输出以下信息
获取当前词典状态
http://10.10.10.5:8099/dict/info
获取实例当前状态
http://10.10.10.5:8099/instance/status
获取配送历史从最近的base到当前正在配送的delta
http://10.10.10.5:8099/dict/deploy/history
这里10.10.10.5:8099
是cube-transfer所在的IP地址和端口,参考2.4.1节配置项transfer_address
一旦cube-transfer部署完成,它就不断监听我们配置好的donefile数据位置,发现有数据更新后,即启动数据下载,然后通知cube-builder执行建库和配送流程,将新数据配送给各个分片的cube-server。
id最好使用版本产出时间戳,base和patch每产出一条直接在donefile文件最后加一行即可,文件名固定base.txt、patch.txt
base.txt每行一条,id和key相同,目录下可有多个文件,不能有文件夹
{"id":"1562000400","key":"1562000400","input":"/home/work/test_data/input/seqfile"}
patch.txt每行一条,key为base的id
{"id":"1562000401","key":"1562000400","input":"/home/work/test_data/input/seqfile"} {"id":"1562000402","key":"1562000400","input":"/home/work/test_data/input/seqfile"}
K8s集群上CTR预估任务训练完成后,模型参数分成2部分:
一是embedding数据,经过dumper.py已经转成hadoop SequenceFile格式,传输给cube建库流程构建索引和灌cube;Cube服务搭建整体流程详见第2节。
二是除embedding之外的参数文件,连同save_program.py裁剪后的program,一起配合传输给Serving加载。save_program.py裁剪原始模型的具体背景和详细步骤请参考文档Paddle Serving CTR预估模型说明。Dense参数存放在k8s集群中,可通过集群的file server获取:
wget http://${FILE_SERVER_IP}:${FILE_SERVER_PORT}/data/ctr_model.tar.gz
FILE_SERVER_IP
与FILE_SERVER_PORT
请参考1.4节获取。
本文介绍Serving使用上述模型参数和program加载模型提供预测服务的流程。
假设Cube服务已经成功部署,用于cube客户端API的配置文件如下所示:
[{
"dict_name": "test_dict",
"shard": 2,
"dup": 1,
"timeout": 200,
"retry": 3,
"backup_request": 100,
"type": "ipport_list",
"load_balancer": "rr",
"nodes": [{
"ipport_list": "list://192.168.1.1:8000"
},{
"ipport_list": "list://192.168.1.2:8000"
}]
}]
上述例子中,cube提供外部访问的表名是test_dict
,有2个物理分片,分别在192.168.1.1:8000和192.168.1.2:8000
注意事项: 配置文件填写请参考cube-transfer的配置文件,其中”dict_name”、”shard”、”dup”字段信息应当分别与cube-transfer配置文件中的”dict_name”、”shard_num”、”copy_num”字段相同,”nodes”中的ipport_list需要按照与cube-transfer中的”cube”字段的ip、端口相同的顺序填写。
截至写本文时,Serving develop分支已经提供了CTR预估服务相关OP,参考ctr_prediction_op.cpp,该OP从client端接收请求后会将每个请求的26个sparse feature id发给cube服务,获得对应的embedding向量,然后填充到模型feed variable对应的LoDTensor,执行预测计算。只要按常规步骤编译Serving即可。serving可执行文件以及相关配置文件位于build/output/demo/serving文件夹下,bin文件夹下为可执行文件,conf文件夹下为配置文件。
$ git clone https://github.com/PaddlePaddle/Serving.git
$ cd Serving
$ mkdir build
$ cd build
$ cmake -DWITH_GPU=OFF .. # 不需要GPU
$ make -jN # 这里可修改并发编译线程数
$ make install
$ cd output/demo/serving
$ ls
bin conf data kvdb
将–enable_cube改为true:
--enable_cube=true
Paddle Serving自带的model_toolkit.prototxt如下所示,如有必要可只保留ctr_prediction一个:
engines {
name: "image_classification_resnet"
type: "FLUID_CPU_NATIVE_DIR"
reloadable_meta: "./data/model/paddle/fluid_time_file"
reloadable_type: "timestamp_ne"
model_data_path: "./data/model/paddle/fluid/SE_ResNeXt50_32x4d"
runtime_thread_num: 0
batch_infer_size: 0
enable_batch_align: 0
}
engines {
name: "text_classification_bow"
type: "FLUID_CPU_ANALYSIS_DIR"
reloadable_meta: "./data/model/paddle/fluid_time_file"
reloadable_type: "timestamp_ne"
model_data_path: "./data/model/paddle/fluid/text_classification_lstm"
runtime_thread_num: 0
batch_infer_size: 0
enable_batch_align: 0
}
engines {
name: "ctr_prediction"
type: "FLUID_CPU_ANALYSIS_DIR"
reloadable_meta: "./data/model/paddle/fluid_time_file"
reloadable_type: "timestamp_ne"
model_data_path: "./data/model/paddle/fluid/ctr_prediction"
runtime_thread_num: 0
batch_infer_size: 0
enable_batch_align: 0
sparse_param_service_type: REMOTE
sparse_param_service_table_name: "test_dict"
}
注意事项: ctr_prediction model有如下2行配置:
sparse_param_service_type: REMOTE
sparse_param_service_table_name: "test_dict"
conf/cube.conf是一个完整的cube配置文件模板,其中只要修改nodes列表为真实的物理节点IP:port列表即可。例如 (与第3.1.1节cube配置文件内容一致):
[{
"dict_name": "test_dict",
"shard": 2,
"dup": 1,
"timeout": 200,
"retry": 3,
"backup_request": 100,
"type": "ipport_list",
"load_balancer": "rr",
"nodes": [{
"ipport_list": "list://192.168.1.1:8000"
},{
"ipport_list": "list://192.168.1.2:8000"
}]
}]
注意事项: 如果修改了dict_name
,需要同步修改3.1.3.2节中sparse_param_service_table_name
字段
Paddle Serving自带了一个可以工作的CTR预估模型,是从BCE上下载下来的,其制作方法为:
如果只是为了验证demo流程,serving此时已经可以用自带的CTR模型加载模型并提供预测服务能力。
为了应用重新训练的模型,只需要从k8s集群暴露的http服务下载新的ctr_model.tar.gz,解压到data/model/paddle/fluid下,并将内容移至原来的ctr_prediction目录即可:
$ cd data/model/paddle/fluid
$ wget http://${FILE_SERVER_IP}:${FILE_SERVER_PORT}/data/ctr_model.tar.gz # `FILE_SERVER_IP`与`FILE_SERVER_PORT`请参考1.4节获取。
$ tar zxvf ctr_model.tar.gz # 假设解压出一个inference_only目录
$ rm -rf ctr_prediction/* # 删除旧的ctr_prediction目录下内容
$ cp inference_only/* ctr_prediction/
$ cd ../../../../ # 切换至serving所在目录
$ ls
bin conf data kvdb log
$ killall serving # 杀死旧的serving进程
$ bin/serving & # 重启serving
执行./bin/serving
启动serving服务,在./log路径下可以查看serving日志。
参考从零开始写一个预测服务:client端文档,实现client端代码。
文档中使用的CTR预估任务client端代码存放在Serving代码库demo-client路径下,链接ctr_prediction.cpp。
CTR预估任务样例使用的数据来自于原始模型的测试数据,在样例中提供了1000个测试样本,如果需要更多样本可以参照原始模型下载数据的脚本。
按照3.1.2 Serving编译部分完成编译后,client端文件在output/demo/client/ctr_prediction路径下。
修改conf/predictors.prototxt文件ctr_prediction_service部分
predictors {
name: "ctr_prediction_service"
service_name: "baidu.paddle_serving.predictor.ctr_prediction.CTRPredictionService"
endpoint_router: "WeightedRandomRender"
weighted_random_render_conf {
variant_weight_list: "50"
}
variants {
tag: "var1"
naming_conf {
cluster: "list://127.0.0.1:8010"
}
}
}
配置Server端ip与端口号,默认为本机ip、8010端口。
执行./bin/ctr_prediction
启动client端,在./log路径下可以看到client端执行的日志。