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编写——当您想使用机器学习来确定某笔信用卡交易是合法的还是欺诈的时,您可以制作一个对Python微服务的POST请求。数据科学家和机器学习工程师用Python进行模型探索的日子已经一去不复返了,现在我们将一切交给“生产团队”,由他们用公司选择的语言完全重写逻辑。DevOps你构建,你运行-WernerVogels(亚马逊首席技术官)由于我们在谈论业务,因此必须强调机器学习模型不存在于真空中,它们是公司想要的产品或流程的一部分启动、优化或改进。因此,认为单靠一个数据科学家团队就能取得显著成果的想法是天真的。你需要的远不止这些。如果你想获得成功,你需要具备从产品到软件工程的多种技能。那么这样的团队应该使用哪种编程语言呢?记住JavaScript的起源:同时使用JavaScript和NodeJS,同一个人可以在系统的前端和后端工作(“全栈”)。Python作为一种通用编程语言提供了同样的便利。您可以使用其科学堆栈进行机器学习开发,利用其框架(Django、Flask、FastAPI等)进行模型部署,并通过REST或gRPCAPI提供预测。很好,不是吗?涟漪效应Python拥有庞大的机器学习生态系统;你希望你的机器学习算法或机器学习框架被采用:所以你用Python编写代码(或使用FFI为其提供Python绑定);Python生态系统变得更加强大。反复。答案我们明天可能仍在用Python编写机器学习软件。我们会永远使用它吗?不太可能,这就像问自己10年后计算机行业的未来会是什么样子。但我不敢打赌我们会在未来5年内看到Python的日落。所以呢?这篇文章不是关于Rust的吗?这是正确的!但更重要的是,在开始工作之前消除所有可能的误解。我不相信Rust会取代Python成为机器学习的首选语言——无论是现在还是将来,绝对没有这种情况发生的迹象。两种语言迎合的不是同一群人,它们针对不同的约束,做不同的优化,解决不同的问题集。但Rust在机器学习世界中占有一席之地。Rust有很大的潜力取代C和C++作为机器学习工作负载的首选Python后端。为什么生锈?没有比这本书的序言更好的答案了:例如,内存管理、数据表示和并发的低级细节的“系统级”处理。这个编程领域历来被视为一个神秘的领域,只有少数花足够时间学习它以避免其臭名昭著的陷阱的人才能进入。即使是那些实践它的人也要谨慎行事,以免他们的代码容易受到攻击,容易崩溃或损坏。Rust消除了那些旧陷阱,并提供了一套友好而优雅的工具来帮助您导航和打破这些障碍。需要“深入”到较低级别控制的程序员可以使用Rust做到这一点,而不会出现通常的崩溃或安全??漏洞风险,也不会出现变化无常的工具链的细微差别。更好的是,该语言旨在引导您自然地编写可靠的代码,这些代码在性能和内存使用方面都很高效。Rust提供与C和C++相当的性能,并且具有绝对的置信度。您相信编译器知道您不知道的内容:换句话说,您从“这到底是什么?”出发。到“让我们在生产环境中运行这段代码!”安全线。这大大降低了进入门槛。让更多的人(包括我?)写出高性能的机器学习算法。越来越多的人可以为他们每天使用的那些项目的后端做出贡献。这会导致更大的社区、更多的实验和更可持续的项目——换句话说,一个更健康、更多样化的生态系统。回到我之前提到的那些趋势,你会再次发现全栈带来的力量:负责模型探索的人(使用Python)可以向下钻取并在Rust中重写它的热路径以优化最终解决方案。.但在实践中做到这一点有多难呢?在Rust中可以多快地实现聚类算法?我为RustFest2019准备了一个研讨会:我们使用ndarray(Rust等价于NumPy)从头开始实施K-Means聚类算法。几周前,我写了一些关于研讨会的笔记,这些材料可以在GitHub上找到:它由一系列测试驱动的练习组成,每个步骤都有助于最终解决方案。我不能忽视这个问题:与scikit-learn相比,Rust中K-Means的范式实现有多快?我在RustFest上和一群对这个问题也很陌生的人一起度过了两天的实施时间,最终得出了答案。如果没有@sitegui、@dunnock和@ThomAub,这个过程会花费更长的时间:非常感谢您的帮助!实施我使用Rustcrate发布了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在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.2ScikitLearn604.7(慢1.3倍)总体而言,它们的速度相对接近-由于分配步骤被并行化,linfa可能稍快一些。如果您对这个结果感到疑惑,请再想一想:我们正在比较仅用了两天时间的教学研讨会实施与目前最复杂的机器学习框架所使用的实施。太疯狂了。从基准代码中可以看出,linfaK-Means实现提供了一个类似于scikit-learn的接口。fromsklearn.datasetsimportmake_blobsimportpytestfromlinfaimportKMeansfromsklearn.clusterimportKMeansassk_KMeans@pytest.fixture(scope="session",autouse=True)defmake_data():returnmake_blobs(n_samples=1000000)deftest_k_means_rust(benchmark,make_data):数据集,cluster_index=make_datamodel=31,0_means(max_means),tol=1e-4)labels=benchmark(model.fit_predict,dataset)assertlen(labels)==len(clu??ster_index)deftest_k_means_python(benchmark,make_data):dataset,cluster_index=make_data#Usingthesamealgorithmmodel=sk_KMeans(3,init="随机",algorithm="full",max_iter=100,tol=1e-4,n_init=1)labels=benchmark(model.fit_predict,dataset)assertlen(labels)==len(clu??ster_index)我也想介绍一下Rust版本对你来说——界面看起来略有不同(出于某种原因,我可能会在另一篇博文中讨论这个),但你可以很容易地找出相同的步骤:uselinfa::clustering::{generate_blobs,KMeans,KMeansHyperParams};usendarray::array;usendarray_rand::rand::SeedableRng;userand_isaac::Isaac64Rng;fnmain(){//我们的随机数生成器,seededforreproducibilityletmutrng=Isaac64Rng::seed_from_u64(42);//Foreachhourexpectedcentroids,generate1000datapointsaroundit(a"blob")letexpected_centroids=array![[10.,10.],[1.,12.],[20.,30.],[-20.,30.]];letdataset=generate_blobs(10000,&expected_centroids,&mutrng);//配置我们的训练算法letn_clusters=4;lethyperparams=KMeansHyperParams::new(n_clusters).max_n_iterations(200).tolerance(1e-5).build();//基于训练数据分布的Inferan最佳质心集=model.predict(&数据集);学习模型来提供服务是业界的既定模式,但在这些微服务中,往往很少或根本没有业务逻辑:它们无非是远程函数调用。给定序列化机器学习模型,我们能否完全自动化/抽象API生成?随着TensorflowServing越来越流行,我的想法得到了验证。所以我决定对三种场景进行基准测试:在PythongRPC服务器上运行的scikit-learn的K-means;linfa的K-means(Python包装器)在PythongRPC服务器上运行;linfa的K-means(Rust)在Rust的gRPC服务器(tonic,https://github.com/hyperium/tonic)上运行。我还没有对这些gRPCWeb服务器进行任何类型的调整:我们正在评估开箱即用的性能。我再次邀请您查看源代码(Rust/Python)。RustWeb服务器上的linfa每秒处理的请求数是scikit-learn的25倍,是pythongRPC服务器上的linfa(Python包装器)的7倍。延迟(提供响应所需的时间)也是如此,其中RustWeb服务器上的linfa始终比scikit-learn快25倍,比PythonWeb服务器上的linfa(Python包装器)快6倍。Rustweb服务器上的linfa在重负载下的错误率也是最低的。新工作流程这个实验规模太小,无法得出明确的结论,我相信您可以找到更快的K-MeansLloyds算法实现。但我希望这些结果足以让你相信Rust确实可以在机器学习开发中发挥重要作用。每个人只要学会一些ndarray的用法就可以写出这样的Rust实现(可以试试研讨会提供的资料)——但是因为C和C++的入门门槛,多少潜力被大量的机器学习白白浪费了从业者?如果这还不够,我想告诉您Rust不仅取代了Python的C和C++后端——它还利用其不断发展的异步生态系统来处理部署。这很容易做到:使用基于Rust的Python库识别候选模型;序列化最终模型;提供最终模型的路径和输入数据的预期模式作为配置;收获果实。这绝对是一个值得在2020年探索的想法。继续如前所述,linfa-clustering是linfa的一个子集,linfa是我计划在2020年重点关注的Rust通用机器学习框架。现在将其称为框架还为时过早:linfa-clustering之外别无他法😀.实现其大胆的使命宣言还有很长的路要走,但机器学习和相关领域对Rust生态系统的兴趣越来越大:https://github.com/rust-ml/discussion/issues/1,https//github.com/rust-lang/wg-governance/issues/11,https://github.com/rust-lang/wg-governance/issues/11。有时您只需要点燃火花并期望它点燃。事实上,我坚信,只有社区大力推动,才能培育、构建和维持Rust机器学习生态系统——没有捷径可走。Rust生态系统确实包含大量的机器学习crate——只要看看在crates.io上搜索机器学习会返回多少。我们不需要从头开始重写所有内容:我将linfa视为元数据包,是Rust生态系统中算法实现的精选集合。它是您满足机器学习需求的第一站,就像Python中的scikit-learn一样。如果这篇文章引起您的共鸣,请查看路线图(https://github.com/LukeMathWalker/linfa/issues)-我期待您的贡献!
