还能这样?把 Python 自动翻译成 C++
作者:byronhe,騰訊 WXG 開發(fā)工程師
一、問(wèn)題背景
隨著深度學(xué)習(xí)的廣泛應(yīng)用,在搜索引擎/推薦系統(tǒng)/機(jī)器視覺等業(yè)務(wù)系統(tǒng)中,越來(lái)越多的深度學(xué)習(xí)模型部署到線上服務(wù)。
機(jī)器學(xué)習(xí)模型在離線訓(xùn)練時(shí),一般要將輸入的數(shù)據(jù)做特征工程預(yù)處理,再輸入模型在 TensorFlow PyTorch 等框架上做訓(xùn)練。
1.常見的特征工程邏輯
常見的特征工程邏輯有:
分箱/分桶 離散化
log/exp 對(duì)數(shù)/冪等 math numpy 常見數(shù)學(xué)運(yùn)算
特征縮放/歸一化/截?cái)?/p>
交叉特征生成
分詞匹配程度計(jì)算
字符串分隔匹配判斷 tong
缺省值填充等
數(shù)據(jù)平滑
onehot 編碼,hash 編碼等
這些特征工程代碼,當(dāng)然一般使用深度學(xué)習(xí)最主要的語(yǔ)言 python 實(shí)現(xiàn)。
二、業(yè)務(wù)痛點(diǎn)
離線訓(xùn)練完成,模型上線部署后,同樣要用 C++ 重新實(shí)現(xiàn) 這些 python 的特征工程邏輯代碼。
我們發(fā)現(xiàn),“用 C++ 重新實(shí)現(xiàn)” 這個(gè)步驟,給實(shí)際業(yè)務(wù)帶來(lái)了大量的問(wèn)題:
繁瑣,費(fèi)時(shí)費(fèi)力,極容易出現(xiàn) python 和 C++ 代碼不一致
不一致會(huì)直接影響模型在線上的效果,導(dǎo)致大盤業(yè)務(wù)指標(biāo)不如預(yù)期,產(chǎn)生各種 bad case
不一致難以發(fā)現(xiàn),無(wú)法測(cè)試,無(wú)法監(jiān)控,經(jīng)常要靠用戶投訴反饋,甚至大盤數(shù)據(jù)異常才能發(fā)現(xiàn)
1. 業(yè)界方案
針對(duì)這些問(wèn)題,我調(diào)研了這些業(yè)界方案:
《推薦系統(tǒng)中模型訓(xùn)練及使用流程的標(biāo)準(zhǔn)化》
https://www.infoq.cn/article/2E6LCqb1GeqFRAjkkjX3
《自主研發(fā)、不斷總結(jié)經(jīng)驗(yàn),美團(tuán)搜索推薦機(jī)器學(xué)習(xí)平臺(tái)》
https://cloud.tencent.com/developer/article/1357309
《京東電商推薦系統(tǒng)實(shí)踐》
https://www.infoq.cn/article/1OkKmb_gEYNR3YqC9RcW
“模型線上線下一致性問(wèn)題對(duì)于模型效果非常重要,我們使用特征日志來(lái)實(shí)時(shí)記錄特征,保證特征的一致性。這樣離線處理的時(shí)候會(huì)把實(shí)時(shí)的用戶反饋,和特征日志做一個(gè)結(jié)合生成訓(xùn)練樣本,然后更新到模型訓(xùn)練平臺(tái)上,平臺(tái)更新之后在推送到線上,這樣整個(gè)排序形成了一個(gè)閉環(huán)。”
總結(jié)起來(lái),有幾種思路:
在線特征存儲(chǔ)起來(lái)給離線用
在線 C++ 代碼編譯成 so 導(dǎo)出給離線用
根據(jù)一份配置生成離線和在線代碼
提取公共代碼,加強(qiáng)代碼復(fù)用,等軟件工程手段,減少不一致
2. 自動(dòng)翻譯方案
(1) .已有方案的缺點(diǎn)
但這些思路都有各種缺點(diǎn):
所有在線請(qǐng)求的所有特征,這個(gè)存儲(chǔ)量數(shù)據(jù)量很大
算法改代碼需要等待后臺(tái)開發(fā),降低了算法同學(xué)的工作效率
特征處理代碼的復(fù)雜度轉(zhuǎn)移到配置文件中,不一定能充分表達(dá),而且配置格式增加學(xué)習(xí)成本
就這邊真實(shí)離線特征處理代碼來(lái)看,大部分代碼都無(wú)法抽取出公共代碼做復(fù)用。
(2). 翻譯器
回到問(wèn)題出發(fā)點(diǎn)考慮,顯而易見,這個(gè)問(wèn)題歸根結(jié)底就是需要一個(gè) “ python 到 c++ 的翻譯器 ” 。
那其實(shí) “翻譯器 Transpiler ” ,和編譯器解釋器類似,也是個(gè)古老的熱門話題了,比如 WebAssembly, CoffeeScript ,Babel ,
Google Closure Compiler,f2c
于是一番搜索,發(fā)現(xiàn) python 到 C++ 的翻譯器也不少,其中 Pythran 是新興比較熱門的開源項(xiàng)目。
于是一番嘗試后,借助 pythran,我們實(shí)現(xiàn)了:
一條命令 全自動(dòng)把 Python 翻譯成等價(jià) C++
嚴(yán)格等價(jià)保證改寫,徹底消除不一致
完全去掉重新實(shí)現(xiàn) 這塊工作量,后臺(tái)開發(fā)成本降到 0 ,徹底解放生產(chǎn)力
算法同學(xué)繼續(xù)使用純 python,開發(fā)效率無(wú)影響,** 無(wú)學(xué)習(xí)成本 **
并能推廣到其他需要 python 改寫成后臺(tái) C++ 代碼 的業(yè)務(wù)場(chǎng)景,解放生產(chǎn)力
三、pythran 的使用流程
(1). 安裝
一條命令安裝:
pip3?install?pythran(2). 寫 Python 代碼
下面這個(gè) 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 轉(zhuǎn)成 C++
一條命令完成翻譯
pythran?-e?demo.py?-o??demo.hpp(4). 寫 C++ 代碼調(diào)用
pythran/pythonic/ 目錄下是 python 標(biāo)準(zhǔn)庫(kù)的 C++ 等價(jià)實(shí)現(xiàn),翻譯出來(lái)的 C++ 代碼需要 include 這些頭文件
寫個(gè) C++ 代碼調(diào)用
#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). 編譯運(yùn)行
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 是一個(gè) AOT (Ahead-Of-Time - 預(yù)先編譯) 編譯器。給科學(xué)計(jì)算的 python 加注解后,pythran 可以把 python 代碼變成接口相同的原生 python 模塊,大幅度提升性能。
并且 pythran 也可以利用 OpenMP 多核和 SIMD 指令集。
支持 python 3 和 Python 2.7 。
pythran 的 manual 挺詳細(xì):
https://pythran.readthedocs.io/en/latest/MANUAL.html
(2). 功能
pythran 并不支持完整的 python, 只支持 python 語(yǔ)言特性的一個(gè)子集:
polymorphic functions 多態(tài)函數(shù)(翻譯成 C++ 的泛型模板函數(shù))
lambda
list comprehension 列表推導(dǎo)式
map, reduce 等函數(shù)
dictionary, set, list 等數(shù)據(jù)結(jié)構(gòu)
exceptions 異常
file handling 文件處理
部分 numpy
不支持的功能:
classes 類
polymorphic variables 可變類型變量
(3). 支持的數(shù)據(jù)類型和函數(shù)
pythran export 可以導(dǎo)出函數(shù)和全局變量。
支持導(dǎo)出的數(shù)據(jù)類型,BNF 定義是:
??????????????????|?(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
可以看到基礎(chǔ)類型相當(dāng)全面,支持各種 整數(shù),浮點(diǎn)數(shù),字符串,復(fù)數(shù)
復(fù)合類型支持 tuple, list, set, dict, numpy.ndarray 等,
對(duì)應(yīng) C++ 代碼的類型實(shí)現(xiàn)在 pythran/pythonic/include/types/ 下面,可以看到比如 dict 實(shí)際就是封裝了一下 std::unordered_map
https://pythran.readthedocs.io/en/latest/SUPPORT.html
可以看到支持的 python 基礎(chǔ)庫(kù),其中常用于機(jī)器學(xué)習(xí)的 numpy 支持算比較完善。
五、pythran 的基本原理
和常見的編譯器/解釋器類似, pythran 的架構(gòu)是分成 3 層:
python 代碼解析成抽象語(yǔ)法樹 AST 。用 python 標(biāo)準(zhǔn)庫(kù)自帶的的 ast 模塊實(shí)現(xiàn)
代碼優(yōu)化。
在 AST 上做優(yōu)化,有多種 transformation pass,比如 deadcode_elimination 死代碼消除,loop_full_unrolling 循環(huán)展開 等。還有 Function/Module/Node 級(jí)別的 Analysis,用來(lái)遍歷 AST 供 transformation 利用。
后端,實(shí)現(xiàn)代碼生成。目前有 2 個(gè)后端,Cxx / Python, Cxx 后端可以把 AST 轉(zhuǎn)成 C++ 代碼( Python 后端用來(lái)調(diào)試)。
目前看起來(lái) ,pythran 還欠缺的:
字符串處理能力欠缺,缺少 str.encode()/str.decode() 對(duì) utf8 的支持
缺少正則表達(dá)式 regex 支持
看文檔要自己加也不麻煩,看業(yè)務(wù)需要可以加。
六、相關(guān)文章
《京東電商推薦系統(tǒng)實(shí)踐》
https://www.infoq.cn/article/1OkKmb_gEYNR3YqC9RcW
《自主研發(fā)、不斷總結(jié)經(jīng)驗(yàn),美團(tuán)搜索推薦機(jī)器學(xué)習(xí)平臺(tái)》
https://cloud.tencent.com/developer/article/1357309
《推薦系統(tǒng)中模型訓(xùn)練及使用流程的標(biāo)準(zhǔn)化》
https://www.infoq.cn/article/2E6LCqb1GeqFRAjkkjX3
numba
http://numba.pydata.org
總結(jié)
以上是生活随笔為你收集整理的还能这样?把 Python 自动翻译成 C++的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 万字长文带你深入浅出 Golang Ru
- 下一篇: 「推荐系统」 领域的最新进展你知道么?