一、问题背景随着深度学习的广泛应用,越来越多的深度学习模型被部署到搜索引擎/推荐系统/机器视觉等业务系统的在线服务中。离线训练机器学习模型时,一般需要对输入数据进行特征工程预处理,然后输入模型在TensorFlowPyTorch等框架上进行训练。1.常用特征工程逻辑常用特征工程逻辑包括:binning/bucketing离散化log/exp对数/幂等数学numpy常用数学运算特征缩放/归一化/截断交集特征生成分词匹配度计算字符字符串分隔匹配等特征工程代码判断通默认值填充等等数据平滑,onehot编码,hash编码等等,当然一般都是用python这个深度学习最重要的语言来实现的。2.业务痛点线下训练完成,模型上线后,这些Python特征工程逻辑代码也必须用C++重新实现。我们发现“用C++重新实现”这一步给实际业务带来了很多问题:繁琐、费时、费力,而且很容易出现python和C++代码不一致的情况。不一致会直接影响模型的上线效果,导致业务指标低劣预计各种badcase不一致难以发现,无法测试,无法监控,往往依赖于用户投诉反馈,甚至市场异常资料一探究竟1.行业解决方案针对这些问题,我研究了这些行业解决方案://www.infoq.cn/article/2E6LCqb1GeqFRAjkkjX3《自主研发、不断总结经验,美团搜索推荐机器学习平台》https://cloud.tencent.com/developer/article/1357309《京东电商推荐系统实践》https://www.infoq.cn/article/1OkKmb_gEYNR3YqC9RcW》模型线上线下的一致性对模型的效果非常重要,我们使用特征日志实时记录特征,保证特征的一致性。这样,在离线处理的时候,实时的用户反馈会结合特征日志生成训练样本,然后更新到模型训练平台。平台更新后会推送上线,让整个排名形成闭环。》总结起来有几个思路:存储在线特征供离线使用,将在线C++代码编译成so,导出离线使用,根据一个配置生成离线和在线代码,提取常用代码,加强代码复用等软件减少Inconsistency的工程方法2.自动翻译方案(1).现有方案的缺点,但是这些思路有各种缺点:allfeatures所有在线请求,这个存储量大,算法改代码需要等待后台开发,降低了算法同学工作效率特征处理代码的复杂度,转移到配置文件中,可能表达不全,配置格式增加了学习成本。从真正的离线特征处理代码来看在这里,大部分代码都无法抽取公共代码进行重用。(2).译者回到问题的起点,很明显这个问题归结为需要“python到c++转换器”。其实“转译器Transpiler”,类似于编译器解释器,也是一个老热门Topic,比如WebAssembly、CoffeeScript、Babel、GoogleClosureCompiler、f2c搜索了一下,发现从python到C++的翻译器有很多,其中Pythran是一个新的流行的开源项目。于是经过一番尝试,借助pythran,我们实现了:一条命令自动将Python翻译成等价的C++,严格等价保证重写,彻底消除不一致,彻底去除重新实现的工作量,后台开发成本降为0,完全解放生产力算法同学们继续使用纯python,开发效率无影响,**无学习成本**并且可以扩展到其他需要python重写成后台C++代码的业务场景,解放生产力3.过程使用pythran(1)。安装一个命令来安装:pip3installpythran(2)。编写Python代码下面的pythondemo是pythran的官方demo。importmathimportnumpyasnpdefzero(n,m):return[[0]*nforcolinrange(m)]#pythranexportmatrix_multiply(floatlistlist,floatlistlist)defmatrix_multiply(m0,m1):new_matrix=zero(len(m0),len(m1[0]))foriinrange(len(m0)):forjinrange(len(m1[0])):forkinrange(len(m1)):new_matrix[i][j]+=m0[i][k]*m1[k][j]returnnew_matrix#pythranexportarc_distance(float[],float[],float[],float[])defarc_distance(theta_1,phi_1,theta_2,phi_2):"""Calculatesthepairwisearcdistancebetweenallpointsinvectoraandb.""temp=(np.sin((theta_2-theta_1)/2)**2+np.cos(theta_1)*np.cos(theta_2)*np.sin((phi_2-phi_1)/2)**2)distance_matrix=2*np.arctan2(np.sqrt(temp),np.sqrt(1-temp))returndistance_matrix#pythranexportdprod(intlist,intlist)defdprod(l0,l1):"""WoW,generatorexpression,zipandsum."""returnsum(x*yforx,yinzip(l0,l1)))#pythranexportget_age(int)defget_age(age):ifage<=20:age_x='0_20'elifage<=25:age_x='21_25'elifage<=30:age_x='26_30'elifage<=35:age_x='31_35'elifage<=40:age_x='36_40'elifage<=45:age_x='41_45'elifage<=50:age_x='46_50'else:age_x='50+'returnage_x(3).将Python转换为C++,使用一条命令即可完成转换:pythran-edemo.py-odemo.hpp(4)。编写C++代码并调用pythran/pythonic/目录是python标准库的C++等效实现,翻译后的C++代码需要包含这些头文件编写C++代码调用:#include"demo.hpp"#include"pythonic/numpy/random/rand.hpp"#include
