QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

性能提升 25 倍:Rust 有望取代 C 和 C++,成为机器学习首选 Python 后端

  • 2020-01-21
  • 本文字数:6146 字

    阅读完需:约 20 分钟

性能提升25倍:Rust有望取代C和C++,成为机器学习首选Python后端

在机器学习开发领域,如果我们纵观全局,撇除所有微小的细节,那么就可以提炼出机器学习开发中的两大不变步骤:模型训练和预测(或推断)。如今,机器学习的首选语言是 Python(除非你的工作环境有一些不寻常的约束才会有所不同),而这篇文章会带你走过一段新的旅程。希望当你看到最后会发现,使用 Rust 作为训练后端部署平台的主意并不像听起来那样疯狂或令人困惑(除了标题提到的性能提升外,这种做法的好处其实还有很多)。


为什么选择 Python?

我们可以花很多时间讨论机器学习开发中使用的各种工作流,但如果说我们通常是以一种探索性的方式来训练模型,这通常是没有争议的。你有一组数据,然后把它们切成许多片段从而更好地理解它们,接着尝试各种方法来解决你所关注的特定问题。(在谷歌街景图片中识别出小猫?天气预报?抑或是作物产量优化?做什么你来定!)


这一路上会有很多陷阱,最后你尝试使用的大多数技术都不是开箱即用的,因此重点在于快速的原型设计迭代改进。


对于像 Python 这样的动态编程语言,这是一个理想的使用场景。


更重要的是,你要考虑到大多数机器学习实践者会有统计学、数学、物理或类似学位的背景,却不是计算机科学专家,也就是说他们(我也一样✋)几乎没有接受过软件工程实践和工具方面的训练。


虽说 Python 同时支持函数式和面向对象的模式,但你可以使用命令式风格,凭借其脚本功能来快速上手。它的入门门槛很低,随着你的经验提升,越来越精于此道,Python 也会与你一同成长。


但是,仅仅易用是远远不够的:训练机器学习模型需要大量的繁琐运算,而 Python 绝对不是最快的编程语言。


于是我们看到 NumPy(1995/2006)、SciPy(2001)、Pandas(2008)和 Scikit-learn(2007)鱼贯入场。如果没有这样一个用于机器学习和科学计算的、高质量且覆盖全面的工具包,Python 就不会取得今天的地位。


然而,如果你深入背后探究一番,就会发现那里没有多少 Python 的位置:你正在使用 Python 来编排和利用一个 C 和 C++例程的强大内核


Python 是这些系统的前端,用户用 Python 这个用户界面将它们轻松地粘合在一起。C 和 C++ 才是你的后端,是幕后的魔力源泉。



确实,这是 Python 经常被忽略的特性:使用其外函数接口(FFI)与其他编程语言互操作相当容易。特别是,Python 库可以将需要大量数字运算的程序代码委派给 C 和 C++,这是 Python 科学生态系统中所有基础库都在使用的策略。


当然,技术永远无法决定一切。社会学因素对于大多数项目的成功(或消亡)都是至关重要的,即使有些人觉得这难以接受。


因此我们应该再补充一些背景:Python 是一个开放源代码项目(嗨,MATLAB!),它在学术机构中的渗透水平是不可忽略的;而且事实上,当深度学习走进聚光灯下时,与它相关的多数科学生态系统已经建立完毕了。


事后看来,将 Python 视为会在机器学习领域占据统治地位的强大候选者是很自然的事情,结果也并不出人意料。

我们今后还应该继续使用 Python 吗?

前面我们简要地介绍了将 Python 作为机器学习开发首选编程语言的部分原因。


但世界并不是静止不变的:背景环境的变化可以大大改变人们对哪种工具是“最佳工作工具”的认识。


一些最新趋势可能会加强 Python 在机器学习领域的地位。

微服务

微服务架构目前在架构设计方法中占主导地位:公司用松散的容器化服务集合来运行他们的业务,这些服务通过网络相互通信。


运行一个 Polyglot 堆栈从未如此简单:你的主应用程序和业务逻辑的精华都可以用 Java 编写——当你想利用机器学习来确定某笔信用卡交易是合法还是欺诈时,你可以发出一个 POST 请求到一个 Python 微服务上。


数据科学家和机器学习工程师用 Python 执行模型探索的日子已经一去不复返了,如今我们将所有内容移交给“生产团队”,后者会用公司选择的语言全面重写逻辑。

DevOps

你构建,你运行——Werner Vogels(亚马逊 CTO)


既然我们谈论的是业务,那就必须强调一点:机器学习模型不是凭空存在的,它们是公司要启动、优化或改进的产品或过程的一部分。


因此,由数据科学家组成的团队就能取得显著的成绩——是很天真的想法。你需要的东西远不止这些。


如果要获得成功的机会,则需要从产品到软件工程的各种技能的组合。


那么这样的团队应该使用哪种编程语言?


记住 JavaScript 的兴起历程:同一个人使用 JavaScript 和 NodeJS,就可以同时处理系统的前端和后端工作(“全栈”)。


作为通用编程语言的 Python 提供了相同的便利。你可以将其科学堆栈用于机器学习开发,并利用其框架(Django、Flask 和 FastAPI 等)进行模型部署,再通过 REST 或 gRPC API 提供预测。


很好,不是吗?

连锁效应

  1. Python 拥有一个庞大的机器学习生态系统;

  2. 你希望自己的机器学习算法或机器学习框架能被采纳:所以你使用 Python 编写代码(或使用 FFI 为它提供 Python 绑定);

  3. Python 生态系统变得更强大了。


循环往复。

答案

明天我们可能还是会用 Python 来编写机器学习软件。


我们会永远使用它吗?不太可能,这就像在问自己,从现在起 10 年后计算机产业的未来会是什么样。


但是我不会押注说未来 5 年我们就能看到 Python 的落日。

所以呢?这篇文章不是要谈 Rust 的吗?


没错!


但更重要的是,在开始谈论正题之前消除所有可能的误解。


我不相信 Rust 会取代 Python 成为机器学习的首选语言——这事完全没有任何苗头,不管是今天还是未来,这都不是什么趋势。


这两门语言无法迎合相同的人群,并且它们针对的是不同的约束条件,做了不同的优化工作,解决的是一系列不同的问题。


但是 Rust 在机器学习世界中有自己的一席之地


Rust 具有取代 C 和 C++,成为机器学习负载首选的 Python 后端的巨大潜力。

为什么是 Rust?

没有比这本书的序言更好的答案了:


例如,“系统级”地处理内存管理、数据表示和并发性的底层细节。传统上,这种编程领域被视为是神秘的王国,只有少数一些已经花了足够的时间学习,以避免其臭名昭著陷阱的人们才能踏入其中。即使是实践它的那些人们也要谨慎行事,以免他们的代码易受攻击、容易崩溃或损坏。

Rust 消除了那些旧有的陷阱,并提供了一套友好而精致的工具来帮助你披荆斩棘,打破这些障碍。那些需要“深入”到较底层控制的程序员可以使用 Rust 来做到这一点,而不必承担崩溃或出现安全漏洞的常见风险,也不必领悟多变的工具链的精髓所在。更好的是,这种语言旨在引导你自然地开始使用在性能和内存使用方面效率出色的可靠代码。


Rust 以彻底领先的信心水平提供了与 C 和 C++相当的性能。


你相信编译器知道你所不知道的内容:换句话说,你从“这到底是什么?”安全地转到了“让我们在生产中运行这些代码!”的这条路线上。


这大大降低了入门的门槛。


让更多的人(又包括我✋)可以编写高性能的机器学习算法。


越来越多的人可以为他们每天使用的那些项目的后端做出贡献。


这会催生一个更大的社区、更多的实验和更可持续的项目——换句话说,催生一个更健康、更多样化的生态系统。


回到我之前提到的那些趋势,你会再次发现全栈带来的强大力量:负责模型探索的那个人(使用 Python)可以深入研究并使用 Rust 重写其热路径,来优化最终解决方案。。


但在实践中这样做的难度如何呢?


用 Rust 实现聚类算法能快多少?

我为RustFest 2019准备了一个研讨会:我们使用 ndarray(一个 NumPy 的 Rust 等效方案)从零开始实现了 K-Means 聚类算法。


几周前,我写了一些关于研讨会的笔记相关材料可以在 GitHub 上找到:它由一系列测试驱动的练习构成,每个步骤都为最终解决方案作出了贡献。


我不能忽视这个问题:与 scikit-learn 相比,Rust 中 K-Means 的范例实现有多快?


我和一群同样对此问题刚到好奇的人在 RustFest 度过了两天实现日,最后给出了答案。


如果没有 @sitegui、@dunnock和 @ThomAub,这个过程会花费更长的时间:非常感谢你们的帮助!

实现

我用 Rust crate 发布了一个清理过的 K-Means 实现:linfa-clustering(https://crates.io/crates/linfa-clustering)。linfa-clustering 是 linfa(https://crates.io/crates/linfa)的一个子集——我们稍后会详细讨论后者。


从源代码中你可以看出来,重点在于清晰易懂的优化配置:它是Lloyd算法的实现范例。


大多数提速机会都没有得到利用,并且肯定还有进一步调优和打磨的空间——例如,它只将多线程用于分配步骤,而更新步骤还是单线程的。


为了进行正面比较,我为此编写了 Python 绑定(https://github.com/LukeMathWalker/linfa-python):linfa is on PyPi(https://pypi.org/project/linfa/),作为 Python 库。


我想重点对比一下:


  • 训练时间

  • 推理时间,模型作为一个 gRPC 微服务公开时所测得的时间。


我们测量将模型作为微服务公开来提供预测需要的时间,这更接近在实际生产环境中使用此代码的表现。


你可以在 GitHub 上获得重现基准测试的说明、结果和代码(https://github.com/LukeMathWalker/clustering-benchmarks)。

训练基准测试

使用pytest-benchmark)在一个 100 万点的数据集上训练 K-Means 模型时,linfa 的训练速度是 scikit-learn 的 1.3 倍。


平均训练时间(毫秒)
Linfa(Rust上的Python包装器)467.2
Scikit Learn604.7(慢1.3倍)


总体而言,它们的速度比较接近——由于分配步骤是并行的,linfa 可能会稍微快一些。


如果你对这个结果感到疑惑,请再想一想:我们正在将一个只花了两天时间的教学研讨会实现与目前最完善的机器学习框架所使用的实现进行比较。


太疯狂了。


从基准测试代码中可以看到,linfa K-Means 实现提供了一个类似于 scikit-learn 的界面。


from sklearn.datasets import make_blobsimport pytestfrom linfa import KMeansfrom sklearn.cluster import KMeans as sk_KMeans
@pytest.fixture(scope="session", autouse=True)def make_data():return make_blobs(n_samples=1000000)
def test_k_means_rust(benchmark, make_data): dataset, cluster_index = make_data model = KMeans(3, max_iter=100, tol=1e-4) labels = benchmark(model.fit_predict, dataset) assert len(labels) == len(cluster_index)
def test_k_means_python(benchmark, make_data): dataset, cluster_index = make_data # Using the same algorithm model = sk_KMeans(3, init="random", algorithm="full", max_iter=100, tol=1e-4, n_init=1) labels = benchmark(model.fit_predict, dataset) assert len(labels) == len(cluster_index)
复制代码


我也想给你介绍 Rust 版本——界面看起来略有不同(出于某种原因,我可能会在另一篇博客文章中谈论此事),但是你可以轻松地找出相同的步骤:


 use linfa::clustering::{generate_blobs, KMeans, KMeansHyperParams}; use ndarray::array; use ndarray_rand::rand::SeedableRng; use rand_isaac::Isaac64Rng;  fn main() {     // Our random number generator, seeded for reproducibility     let mut rng = Isaac64Rng::seed_from_u64(42);     // For each our expected centroids, generate 1000 data points around it (a "blob")    let expected_centroids = array![[10., 10.], [1., 12.], [20., 30.], [-20., 30.]];    let dataset = generate_blobs(10000, &expected_centroids, &mut rng);
// Configure our training algorithm let n_clusters = 4; let hyperparams = KMeansHyperParams::new(n_clusters) .max_n_iterations(200) .tolerance(1e-5) .build();
// Infer an optimal set of centroids based on the training data distribution let model = KMeans::fit(hyperparams, &dataset, &mut rng);
// Assign each point to a cluster using the set of centroids found using `fit` let labels = model.predict(&dataset); }
复制代码

推理基准测试

如前所述,使用一个专用微服务为机器学习模型提供服务,在业界已是一种既定模式。


但在这些微服务中,往往很少或几乎没有业务逻辑:它们无非就是一个远程函数调用而已。


给定一个序列化的机器学习模型,我们是否可以完全自动化/抽象 API 生成?随着Tensorflow Serving越来越受欢迎,我的想法得到了验证。


因此我决定针对三种场景进行基准测试:


  • scikit-learn 的 K-means 运行在 Python 的 gRPC 服务器上;

  • linfa 的 K-means(Python 包装器)运行在 Python 的 gRPC 服务器上;

  • linfa 的 K-means(Rust)运行在 Rust 的 gRPC 服务器(tonic,https://github.com/hyperium/tonic)上。


我尚未在这些 gRPC Web 服务器上做任何形式的调优:我们要评价的是开箱即用的性能。我再次邀请你查看源代码(Rust/Python)。


Rust Web 服务器上的 linfa 每秒处理的请求数是 scikit-learn 的 25 倍,是 python gRPC 服务器上的 linfa(Python 包装器)的 7 倍。



延迟(提供响应需要多长时间)也是如此,其中 Rust Web 服务器上的 linfa 始终比 scikit-learn 快 25 倍,比 Python Web 服务器上的 linfa(Python 包装器)快 6 倍。



Rust Web 服务器上的 linfa 在重负载下的错误率也是最低的。


新的工作流

这项实验规模太小,无法得出确切的结论,而且我相信你可以找到针对 K-Means 的 Lloyds 算法的更快实现。


但我希望这些结果足以说服你,Rust 确实可以在机器学习开发中发挥重要作用。所有人只要学一些 ndarray 的用法(可以试试研讨会提供的材料),就可以写出这样的 Rust 实现——可就因为 C 和 C++的入门门槛,大批机器学习从业者浪费了多少潜能?


如果这还不够,我还想告诉你,Rust 不仅可以替换掉 Python 的 C 和 C++后端——它还可以利用其不断发展的异步生态系统来处理部署工作。


做起来很简单:


  • 使用基于 Rust 的 Python 库识别候选模型;

  • 序列化最终模型;

  • 提供最终模型的路径和输入数据的预期模式作为配置;

  • 收获果实吧。



这绝对是一个值得在 2020 年探索的想法。

走下去

如前所述,linfa-clustering 是 linfa 的子集,后者是 Rust 中的通用机器学习框架,我计划在 2020 年专注研究这个框架。


甚至在此时将其称为一个框架还为时过早:linfa-clustering 之外就没什么东西了😀。


要实现其大胆的使命宣言还有很长的路要走,但在机器学习及其相关领域,对 Rust 生态系统的兴趣愈加浓厚:https://github.com/rust-ml/discussion/issues/1https://github.com/rust-lang/wg-governance/issues/11https://github.com/rust-lang/wg-governance/issues/11


有时你只需点燃星星之火,即可期待它熊熊燎原。


实际上,我坚信只有社区努力推动,才能在 Rust 中扶持、建立和维持一个机器学习生态系统——并没有捷径可言。


Rust 生态系统确实包含丰富的机器学习 crates——看看在 crates.io 上搜索 machine learning 会返回多少东西吧。


我们无需从头开始重写所有内容:我将 linfa 视为一个元包,一个 Rust 生态系统中精选的算法实现的集合。它是满足你机器学习需求的第一站,就像是 Python 中的 scikit-learn 一样。


如果这篇文章引起了你的共鸣,请看一看路线图——我期待你的贡献!


非常欢迎你提供关于本文的注释、建议和反馈:你可以在 Twitter 上 @algo_luca,在 GitHub 上 @LukeMathWalker,或通过电子邮件 rust@lpalmieri.com 与我联系。


原文链接


https://www.lpalmieri.com/posts/2019-12-01-taking-ml-to-production-with-rust-a-25x-speedup/


2020-01-21 09:0013074
用户头像
蔡芳芳 InfoQ主编

发布了 801 篇内容, 共 563.9 次阅读, 收获喜欢 2794 次。

关注

评论

发布
暂无评论
发现更多内容

视频实时自然美颜, 无惧素颜上镜

HarmonyOS SDK

HMS Core

甩掉容量规划炸弹:用 AHPA 实现 Kubernetes 智能弹性伸缩

阿里巴巴中间件

阿里云 Kubernetes 云原生 AHPA

华为云Stack新版发布:构筑行业云底座,共创行业新价值

华为云开发者联盟

云计算 后端 华为云 企业号 1 月 PK 榜

软件测试/测试开发 | AppCrawler 自动遍历测试工具实践(一)

测试人

软件测试 自动化测试 测试开发 自动遍历 AppCrawler

TDengine 公布 2022 年度中国时序数据应用创新奖,33 个科技企业创新应用脱颖而出

TDengine

数据库 tdengine 时序数据库

硬实力,高潜力!旺链科技当选“2022德勤中国高科技高成长50强”

旺链科技

区块链 区块链技术

ISV生态合作伙伴体系多领域赋能,开拓市场赛道

元年技术洞察

数据中台 数据 数字化转型 ISV 方舟平台

react源码中的hooks

flyzz177

React

总有一个你能用上的29个IDEA小技巧

风铃架构日知录

Java 程序员 IDEA IT 开发工具

要避免的自动化实践

FunTester

Java高手速成 | 高质量代码编写最佳实践

TiAmo

编程好习惯 设计原则 Java’

牛啊!长这么大还是头一次见24W字的SpringBoot从入门到实战文档

程序知音

Java spring 微服务 springboot 后端技术

行业分析| 交通综合执法对讲系统

anyRTC开发者

指挥调度 快对讲 语音对讲 视频对讲 综合执法

赞赞赞!融云收获行业媒体「组团打 Call」

融云 RongCloud

使用 NineData 高效编写 SQL

NineData

数据库 sql 数据库开发 数据管理工具 NineData

Diffie-Hellman密钥协商算法探究

百度Geek说

数据安全 企业号 1 月 PK 榜

学术加油站|机器学习应用在数据库调优领域的前沿工作解读

OceanBase 数据库

数据库 oceanbase

【Redis 技术探索】「数据迁移实战」手把手教你如何实现在线 + 离线模式进行迁移 Redis 数据实战指南(数据检查对比)

洛神灬殇

redis 1月日更 数据对比 Redis-full-check

信用卡APP评测系列:科技赋能信用卡APP创新升级,助力客户体验提升

易观分析

金融 信用卡

HDI压合设计准则作业规范

华秋PCB

PCB PCB设计 HDI

文末领资料 | 研发效能领域的三个年度关键词

思码逸研发效能

研发管理 研发效能

【等保小知识】等保四级是最高级别吗?等保四级适用于哪些领域?

行云管家

等保 等保测评 等保四级

react源码中的fiber架构

flyzz177

React

火山引擎 DataLeap 通过中国信通院测评,数据管理能力获官方认可!

字节跳动数据平台

大数据 数据治理

大咖说·对话开源|与Tapdata论道数据技术开放生态

大咖说

开源

为什么网络I/O会被阻塞

华为云开发者联盟

后端 开发 华为云 企业号 1 月 PK 榜

一文总结ACE代码框架

OpenHarmony开发者

OpenHarmony

无监控,不运维!深入浅出介绍ChengYing监控设计和使用

袋鼠云数栈

编程的终结;展望2023年AI系统方向;AI的下一个阶段

OneFlow

人工智能 深度学习

【等保小知识】等保3.0就是等保三级吗?

行云管家

等保 等保2.0 等保3.0

react hook 源码完全解读

flyzz177

React

性能提升25倍:Rust有望取代C和C++,成为机器学习首选Python后端_语言 & 开发_lpalmieri_InfoQ精选文章