还能这样?把 Python 自动翻译成 C++
作者:byronhe,腾讯 WXG 开发工程师
一、问题背景
随着深度学习的广泛应用,在搜索引擎/推荐系统/机器视觉等业务系统中,越来越多的深度学习模型部署到线上服务。
机器学习模型在离线训练时,一般要将输入的数据做特征工程预处理,再输入模型在 TensorFlow PyTorch 等框架上做训练。
1.常见的特征工程逻辑
常见的特征工程逻辑有:
分箱/分桶 离散化
log/exp 对数/幂等 math numpy 常见数学运算
特征缩放/归一化/截断
交叉特征生成
分词匹配程度计算
字符串分隔匹配判断 tong
缺省值填充等
数据平滑
onehot 编码,hash 编码等
这些特征工程代码,当然一般使用深度学习最主要的语言 python 实现。
二、业务痛点
离线训练完成,模型上线部署后,同样要用 C++ 重新实现 这些 python 的特征工程逻辑代码。
我们发现,“用 C++ 重新实现” 这个步骤,给实际业务带来了大量的问题:
繁琐,费时费力,极容易出现 python 和 C++ 代码不一致
不一致会直接影响模型在线上的效果,导致大盘业务指标不如预期,产生各种 bad case
不一致难以发现,无法测试,无法监控,经常要靠用户投诉反馈,甚至大盘数据异常才能发现
1. 业界方案
针对这些问题,我调研了这些业界方案:
《推荐系统中模型训练及使用流程的标准化》
https://www.infoq.cn/article/2E6LCqb1GeqFRAjkkjX3
《自主研发、不断总结经验,美团搜索推荐机器学习平台》
https://cloud.tencent.com/developer/article/1357309
《京东电商推荐系统实践》
https://www.infoq.cn/article/1OkKmb_gEYNR3YqC9RcW
“模型线上线下一致性问题对于模型效果非常重要,我们使用特征日志来实时记录特征,保证特征的一致性。这样离线处理的时候会把实时的用户反馈,和特征日志做一个结合生成训练样本,然后更新到模型训练平台上,平台更新之后在推送到线上,这样整个排序形成了一个闭环。”
总结起来,有几种思路:
在线特征存储起来给离线用
在线 C++ 代码编译成 so 导出给离线用
根据一份配置生成离线和在线代码
提取公共代码,加强代码复用,等软件工程手段,减少不一致
2. 自动翻译方案
(1) .已有方案的缺点
但这些思路都有各种缺点:
所有在线请求的所有特征,这个存储量数据量很大
算法改代码需要等待后台开发,降低了算法同学的工作效率
特征处理代码的复杂度转移到配置文件中,不一定能充分表达,而且配置格式增加学习成本
就这边真实离线特征处理代码来看,大部分代码都无法抽取出公共代码做复用。
(2). 翻译器
回到问题出发点考虑,显而易见,这个问题归根结底就是需要一个 “ python 到 c++ 的翻译器 ” 。
那其实 “翻译器 Transpiler ” ,和编译器解释器类似,也是个古老的热门话题了,比如 WebAssembly, CoffeeScript ,Babel ,
Google Closure Compiler,f2c
于是一番搜索,发现 python 到 C++ 的翻译器也不少,其中 Pythran 是新兴比较热门的开源项目。
于是一番尝试后,借助 pythran,我们实现了:
一条命令 全自动把 Python 翻译成等价 C++
严格等价保证改写,彻底消除不一致
完全去掉重新实现 这块工作量,后台开发成本降到 0 ,彻底解放生产力
算法同学继续使用纯 python,开发效率无影响,** 无学习成本 **
并能推广到其他需要 python 改写成后台 C++ 代码 的业务场景,解放生产力
三、pythran 的使用流程
(1). 安装
一条命令安装:
pip3 install pythran
(2). 写 Python 代码
下面这个 python demo,是 pythran 官方 demo
import mathimport numpy as np
def zero(n, m): return [[0]*n for col in range(m)]
#pythran export matrix_multiply(float list list, float list list)def matrix_multiply(m0, m1): new_matrix = zero(len(m0),len(m1[0])) for i in range(len(m0)): for j in range(len(m1[0])): for k in range(len(m1)): new_matrix[i][j] += m0[i][k]*m1[k][j] return new_matrix
#pythran export arc_distance(float[], float[], float[], float[])def arc_distance(theta_1, phi_1, theta_2, phi_2): """ Calculates the pairwise arc distance between all points in vector a and b. """ 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)) return distance_matrix
#pythran export dprod(int list, int list)def dprod(l0,l1): """WoW, generator expression, zip and sum.""" return sum(x * y for x, y in zip(l0, l1))
#pythran export get_age(int )def get_age(age): if age <= 20: age_x = '0_20' elif age <= 25: age_x = '21_25' elif age <= 30: age_x = '26_30' elif age <= 35: age_x = '31_35' elif age <= 40: age_x = '36_40' elif age <= 45: age_x = '41_45' elif age <= 50: age_x = '46_50' else: age_x = '50+' return age_x
(3). Python 转成 C++
一条命令完成翻译
pythran -e demo.py -o demo.hpp
(4). 写 C++ 代码调用
pythran/pythonic/ 目录下是 python 标准库的 C++ 等价实现,翻译出来的 C++ 代码需要 include 这些头文件
写个 C++ 代码调用
#include "demo.hpp"#include "pythonic/numpy/random/rand.hpp"#include <iostream>
using std::cout;using std::endl;
int main() { pythonic::types::list<pythonic::types::list<double>> m0 = {{2.0, 3.0}, {4.0, 5.0}}, m1 = {{1.0, 2.0}, {3.0, 4.0}}; cout << m0 << "*" << m1 << "\n=\n" << __pythran_demo::matrix_multiply()(m0, m1) << endl << endl;
auto theta_1 = pythonic::numpy::random::rand(3), phi_1 = pythonic::numpy::random::rand(3), theta_2 = pythonic::numpy::random::rand(3), phi_2 = pythonic::numpy::random::rand(3); cout << "arc_distance " << theta_1 << "," << phi_1 << "," << theta_2 << "," << phi_2 << "\n=\n" << __pythran_demo::arc_distance()(theta_1, phi_1, theta_2, phi_2) << endl << endl;
pythonic::types::list<int> l0 = {2, 3}, l1 = {4, 5}; cout << "dprod " << l0 << "," << l1 << "\n=\n" << __pythran_demo::dprod()(l0, l1) << endl << endl;
cout << "get_age 30 = " << __pythran_demo::get_age()(30) << endl << endl;
return 0;}
(5). 编译运行
g++ -g -std=c++11 main.cpp -fopenmp -march=native -DUSE_XSIMD -I /usr/local/lib/python3.6/site-packages/pythran/ -o pythran_demo
./pythran_demo
四、pythran 的功能与特性
(1). 介绍
按官方定义,Pythran 是一个 AOT (Ahead-Of-Time - 预先编译) 编译器。给科学计算的 python 加注解后,pythran 可以把 python 代码变成接口相同的原生 python 模块,大幅度提升性能。
并且 pythran 也可以利用 OpenMP 多核和 SIMD 指令集。
支持 python 3 和 Python 2.7 。
pythran 的 manual 挺详细:
https://pythran.readthedocs.io/en/latest/MANUAL.html
(2). 功能
pythran 并不支持完整的 python, 只支持 python 语言特性的一个子集:
polymorphic functions 多态函数(翻译成 C++ 的泛型模板函数)
lambda
list comprehension 列表推导式
map, reduce 等函数
dictionary, set, list 等数据结构
exceptions 异常
file handling 文件处理
部分 numpy
不支持的功能:
classes 类
polymorphic variables 可变类型变量
(3). 支持的数据类型和函数
pythran export 可以导出函数和全局变量。
支持导出的数据类型,BNF 定义是:
argument_type = basic_type | (argument_type+) # this is a tuple | argument_type list # this is a list | argument_type set # this is a set | argument_type []+ # this is a ndarray, C-style | argument_type [::]+ # this is a strided ndarray | argument_type [:,...,:]+ # this is a ndarray, Cython style | argument_type [:,...,3]+ # this is a ndarray, some dimension fixed | argument_type:argument_type dict # this is a dictionary
basic_type = bool | byte | int | float | str | None | slice | uint8 | uint16 | uint32 | uint64 | uintp | int8 | int16 | int32 | int64 | intp | float32 | float64 | float128 | complex64 | complex128 | complex256
可以看到基础类型相当全面,支持各种 整数,浮点数,字符串,复数
复合类型支持 tuple, list, set, dict, numpy.ndarray 等,
对应 C++ 代码的类型实现在 pythran/pythonic/include/types/ 下面,可以看到比如 dict 实际就是封装了一下 std::unordered_map
https://pythran.readthedocs.io/en/latest/SUPPORT.html
可以看到支持的 python 基础库,其中常用于机器学习的 numpy 支持算比较完善。
五、pythran 的基本原理
和常见的编译器/解释器类似, pythran 的架构是分成 3 层:
python 代码解析成抽象语法树 AST 。用 python 标准库自带的的 ast 模块实现
代码优化。
在 AST 上做优化,有多种 transformation pass,比如 deadcode_elimination 死代码消除,loop_full_unrolling 循环展开 等。还有 Function/Module/Node 级别的 Analysis,用来遍历 AST 供 transformation 利用。后端,实现代码生成。目前有 2 个后端,Cxx / Python, Cxx 后端可以把 AST 转成 C++ 代码( Python 后端用来调试)。
目前看起来 ,pythran 还欠缺的:
字符串处理能力欠缺,缺少 str.encode()/str.decode() 对 utf8 的支持
缺少正则表达式 regex 支持
看文档要自己加也不麻烦,看业务需要可以加。
六、相关文章
《京东电商推荐系统实践》
https://www.infoq.cn/article/1OkKmb_gEYNR3YqC9RcW
《自主研发、不断总结经验,美团搜索推荐机器学习平台》
https://cloud.tencent.com/developer/article/1357309
《推荐系统中模型训练及使用流程的标准化》
https://www.infoq.cn/article/2E6LCqb1GeqFRAjkkjX3
numba
http://numba.pydata.org
还能这样?把 Python 自动翻译成 C++相关推荐
- python动态图片转字符画_GIF动态图,视频?都能用Python转换成字符画图像
字符画是一种由字母.标点或其他字符组成的图画,它产生于互联网时代,在聊天软件中使用较多,本文我们看一下如何将自己喜欢的图片转成字符画. 静态图片 首先,我们来演示将静态图片转为字符画,功能实现主要用到 ...
- cmd python封装成exe_别再问我怎么Python打包成exe了!
也许我们不一定是专业的程序员,但是我们仍然可以通过代码提高我们的效率,尽量少加班,多陪陪媳妇(如果有).再不行,让代码替我们干着重复的工作,我们有节省出来的时间打游戏不好嘛,是吧,哈哈哈. 但是呢,我 ...
- canvas全局合成画月牙_GIF动态图,视频?都能用Python转换成字符画图像
字符画是一种由字母.标点或其他字符组成的图画,它产生于互联网时代,在聊天软件中使用较多,本文我们看一下如何将自己喜欢的图片转成字符画. 静态图片 首先,我们来演示将静态图片转为字符画,功能实现主要用到 ...
- python编译成c代码_python如何调用c编译好可执行程序
以下总结出几种在Python 中调用 C/C++ 代码的方法 -------------------------------------------------------------------- ...
- 你还不会用python进行数据分析吗
你还不会用python进行数据分析吗 1.案例背景 用户价值细分是了解用户价值度的重要途径,而销售型公司中对于订单交易尤为关注,因此基于订单交易的价值度模型将更适合运营需求.针对交易数据分析的常用模型 ...
- python打包成独立exe_用PyInstaller把Python代码打包成单个独立的exe可执行文件
之前就想要把自己的BlogsToWordpress打开成exe了.一直没去弄. 又看到有人提到python打开成exe的问题. 所以打算现在就去试试. 注:此处之所有选用BlogsToWordpres ...
- 如何在MATLAB中调用(运行)“用Python写成的函数或脚本”
如何在MATLAB中调用"用Python写成的函数或脚本",首先要确保MATLAB知道咱们的Python解释器的位置在哪里. 如果安装了Python的时候把Python加入了系统环 ...
- 别再问我怎么Python打包成exe了!
作者 | Python进阶者 来源 | Python爬虫与数据挖掘 阅读文本大概需要 10 分钟 前言 也许我们不一定是专业的程序员,但是我们仍然可以通过代码提高我们的效率,尽量少加班,多陪陪媳妇(如 ...
- 别再问我Python打包成exe了!(终极版)
大家好,我是小五 <老板又出难题,气得我写了个自动化软件> 上次这篇文章中,评论区有好几条留言都是关心如何将python脚本打包成10多M的? 那今天小五就给大家全面总结一下:Python ...
最新文章
- PHP定时执行任务的实现
- 星际2正在等待暴雪服务器的响应,win7系统玩星际2一直停留在"正在更新暴雪启动器"页面的解决方法...
- html5绘制小鱼,HTML5 Canvas 深海游弋的鱼群
- WIN10系统如何取消任务栏处的窗口缩略图
- C# WPF MVVM开发框架Caliburn.Micro 自定义Conventions⑩
- 连接SQL Server数据库
- MySQL的SQL预处理(Prepared)
- centos7源码编译安装mariadb
- 很好听,可没机会跟你分享
- 独立样本t检验、方差齐性检验
- Android 11 usb调试默认打开
- c++手机编程软件_手机也能编程?盘点这5个可以用手机编程的App!快收藏!
- OSI七层模型的功能以及设备
- SAS学习——SAS逻辑库
- 性能测试中的二八原则
- GDOI 2018 Day1 小学生图论题
- 关于开源神经影像数据集如何使用的协议
- Linux性能排查——CPU软中断问题
- 用 SwiftUI 实现 AI 聊天对话 app - iChatGPT
- 副驾驶的意义_副驾驶对女人的意义是什么样的?
热门文章
- redmine常见问题
- 黑暗的富士康服务器被黑厂商用户名密码被泄
- $@等特定shell变量的含义
- Delphi 2010 新增功能之: TWICImage 类[4] - 图像的修剪
- 2021年中国大学生程序设计竞赛 女生专场 - 热身赛 Problem C. 口算训练(质因子分解)
- POJ - 3294 Life Forms(二分+后缀数组)
- CodeForces - 197A Plate Game(博弈+思维)
- 中石油训练赛 - The King’s Ups and Downs(记忆化搜索)
- MMDetection-简介
- Win10任务计划+PowerShell实现Git自动推送