27

模型转代码:XGBoost等模型也能快速转纯C或Java代码

 5 years ago
source link: https://www.jiqizhixin.com/articles/2019-03-06-6?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

你是否常训练炫酷的机器学习模型,用来分析数据或执行某些新奇的任务?你是否发现你的模型只能在一定开发环境上才能跑起来,很难部署也很难加入其它程序?今天我们将介绍一个炫酷的工具,它可以把构建在 scikit-learn 或XGBoost等库上的 ML 模型直接转化为不需要任何依赖项的 Java/Python/C 源代码。

  • 项目地址:https://github.com/BayesWitnesses/m2cgen/

那么转化为 Java/Python/C 源代码有什么用呢?想象一下如果我们使用 ML 框架(scikit-learn\XGBoost\LightGBM)训练了一个模型,现在我们希望把这个模型做成应用或嵌入到已有的模型中,那么我们肯定需要考虑这些问题:

  • 如果产品环境并没有 Python 运行时怎么办?

  • 如果产品不能通过云服务器进行计算,只能在本地进行怎么办?

  • ML 模型的推断速度太慢又怎么办?

这些问题都很难解决,也是开发者在做自己项目时常遇到的问题。如果我们能将用 Python 和 ML 库构建的模型转换一下,变成纯 Java 或 C 写的代码,且这些代码不会依赖各种库,那么部署或嵌入不就简单了么。在 m2cgen 这个项目中,它就可以将 ML 模型转化为不带有依赖项的纯代码。

m2cgen(Model 2 Code Generator)是一个轻量级的 Python 库,它能快速便捷地将已训练统计模型转化为 Python、C 和 Java 代码。目前 m2cgen 已经支持各种分类模型与回归模型,包括 支持向量机 决策树 随机森林 和梯度提升树等,注意这些都是统计机器学习模型,深度神经网络还是老老实实使用 DL 框架吧。

模型转换效果

我们可以通过几个简单案例了解 m2cgen 是如何转换为纯代码的,简单而言即把模型架构和权重显化了。如下所示如果我们简单地训练一个线性回归模型,当然代码看着简单是因为我们直接调用了 scikit-learn 库中的模型。

from sklearn.datasets import load_boston
from sklearn import linear_model
import m2cgen as m2c

boston = load_boston()
X, y = boston.data, boston.target

estimator = linear_model.LinearRegression()
estimator.fit(X, y)

code = m2c.export_to_java(estimator)

上面最后一行将 scikit-learn 中的线性回归模型转化为 Java 代码,注意这个模型已经拟合了训练数据,或者说已经完成了训练。转化后的代码如下所示:

public class Model {

    public static double score(double[] input) {
        return (((((((((((((36.45948838508965) + ((input[0]) * (-0.10801135783679647))) + ((input[1]) * (0.04642045836688297))) + ((input[2]) * (0.02055862636707<mark data-type="institutions" data-id="e6402476-9c73-4340-b0c8-2b470157ce64">360</mark>8))) + ((input[3]) * (2.6867338193449406))) + ((input[4]) * (-17.76661122830004))) + ((input[5]) * (3.8098652068092163))) + ((input[6]) * (0.0006922246403454562))) + ((input[7]) * (-1.475566845600257))) + ((input[8]) * (0.30604947898516943))) + ((input[9]) * (-0.012334593916574394))) + ((input[10]) * (-0.9527472317072884))) + ((input[11]) * (0.009311683273794044))) + ((input[12]) * (-0.5247583778554867));
    }
}

如上 return 后面的语句,它就是一个线性回归的表达式,每一个 input[ * ] 都是一种特征,它后面的数值就是训练后的权重。所以整个线性模型有 13 个特征及对应权重,以及另外一个偏置项。

我们还可以找到更多的案例,如果我们用XGBoost训练一个简单的分类模型,我们可以看到转化的代码会大量使用 if-else 大法,不过我们本身也不用维护生成的代码,所以这种结构也没什么关系了。

import numpy as np
def score(input):
    if (input[2]) >= (2.5999999):
        var0 = -0.0731707439
    else:
        var0 = 0.142857149
    if (input[2]) >= (2.5999999):
        var1 = -0.0705206916
    else:
        var1 = 0.12477719
    var2 = np.exp(((0.5) + (var0)) + (var1))
    if (input[2]) >= (2.5999999):
        if (input[2]) >= (4.85000038):
            var3 = -0.0578680299
        else:
            var3 = 0.132596686
    else:
        var3 = -0.0714285821
    if (input[2]) >= (2.5999999):
        if (input[2]) >= (4.85000038):
            var4 = -0.0552999191
        else:
            var4 = 0.116139404
    else:
        var4 = -0.0687687024
    var5 = np.exp(((0.5) + (var3)) + (var4))
    if (input[2]) >= (4.85000038):
        if (input[3]) >= (1.75):
            var6 = 0.142011836
        else:
            var6 = 0.0405405387
    else:
        if (input[3]) >= (1.6500001):
            var6 = 0.0428571403
        else:
            var6 = -0.0730659068
    if (input[2]) >= (4.85000038):
        if (input[3]) >= (1.75):
            var7 = 0.124653712
        else:
            var7 = 0.035562478
    else:
        if (input[3]) >= (1.6500001):
            var7 = 0.0425687581
        else:
            var7 = -0.0704230517
    var8 = np.exp(((0.5) + (var6)) + (var7))
    var9 = ((var2) + (var5)) + (var8)
    return np.asarray([(var2) / (var9), (var5) / (var9), (var8) / (var9)])

不过上面这种代码也非常合理,本身决策树就可以视为一种 if-else 的规则集合,不同输入特征 input[ * ] 满足不同的条件就能得到不同的值,这些值最后能联合计算分类结果。

项目细节

工具的安装很简单,直接用 pip 就行了:

pip install m2cgen

除了前面那样在代码中调用转换工具,我们还能通过命令行使用序列化的模型目标(pickle protocol)生成代码:

$ m2cgen <pickle_file> --language <language> [--indent <indent>]
         [--class_name <class_name>] [--package_name <package_name>]
         [--recursion-limit <recursion_limit>]

目前项目支持以下分类和回归模型的转换:

NBRZFfr.png!web

分类模型输出结果:

NF7jiqZ.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK