2024 年 3 月 29 日,Modular Inc. 宣布开源 Mojo 的核心组件。
Mojo 是一种专为编写人工智能软件设计的编程语言,去年 8 月份正式发布,迄今为止已经积累了超过 17.5 万名开发者和 5 万个组织。
人工智能模型通常使用多种编程语言编写。开发者会用 Python 实现神经网络最简单的部分,这种语言易于学习,但运行速度相对较慢。其余部分的代码通常使用 C++ 编写,C++ 的运行速度比 Python 更快,但学习难度也更大。
Modular 将 Mojo 定位为一种更方便的替代方案。它提供了一种易于使用的语法,类似于 Python,但运行速度可以快上数千倍。因此,开发者可以编写快速的 AI 模型,而无需学习 C++ 等复杂的语言。
去年,Mojo 推出后,一些开发者对它的出现表现得非常兴奋,但当被问及开源日期时, Chris Lattner 在 Discord 上是这样说的:“如果我知道的话我会告诉你的。”于是在这一年左右的时间里,很多开发者一直处于观望和质疑的状态:
“宣传非常好,但如果不是开源的,我不会花任何时间来尝试。”
“它显然是一种被夸大的编程语言,它不是开源的!Chris Lattner 想要欺骗数百万 Python 开发人员!”
“我不能花时间在可能开源也可能不开源的语言上,特别是考虑到当前 OSS 的商业环境……”
现在,Mojo 终于开源了!
而且在短时间内,就已经达到了 17.6k 颗 star,并有了 2.1k 分支!
Mojo 开源的第一步
Modular 今天开源的是 Mojo 标准库的核心部分。标准库是编程语言的核心部分,它包含了语言的基本语法元素和一些重要特性。Mojo 的标准库包含用于优化 AI 超参数的功能,这些超参数决定了神经网络处理数据的方式。
“Mojo 标准库还处于大力开发阶段,变化迅速,因此我们首先开源其核心模块。这是我们开源之旅的一个重要起点,而不是终点。”
该公司表示,开源能让他们获得更多开发者的反馈,从而让 Mojo 得到更好的发展。另外,开源代码的方式有很多:有些项目提供源代码但不接受贡献;有些提供不透明的贡献流程,无法了解目标和路线图;有些虽然开源但不积极维护。Modular 表示他们选择了更彻底的开源方式:允许通过 GitHub pull request 提交外部贡献,鼓励开发者参与到 Mojo 的开发和完善中来,促进社区的壮大。
而且 Modular 的诚意非常足,他们还分享了完整的 commit 历史记录,从第一次 commit 开始!开放标准库的修订历史,可以使开发者能够追踪代码的演变过程,更好地理解代码含义。
此外,他们还会发布每日编译版本(nightly builds)的 Mojo 编译器,方便开发者快速尝试最新的编译器功能,并进行持续集成测试。
Modular 去年年底推出了商用 AI 平台 MAX,这是一套统一的工具和库,用于构建可跨多个硬件平台高效部署的高性能 AI 应用程序,如在 Kubernetes 环境中运行 AI 应用。该公司今天透露,未来他们也计划开源 MAX 的一些组件。
另外,特别值得一提的是他们选择了 Apache 2 LLVM 许可证进行开源。
这是一种定制版的 Apache 2 许可证。同时为了方便与遵循 GPL2 许可证的软件结合使用,Modular 做出了相应调整。GPL2 是另一流行的开源许可证,知名项目 Linux 内核即采用该许可证。在宣布开源的博客文章中,Modular 写道:
Apache 2 许可证是一个很好的起点,但我们在 LLVM 项目中使用许可证的经验告诉我们,它存在两个小问题。有些人担心 Apache 2 许可证可能无法与 GPL2 代码(例如 Linux 内核)很好地混合使用,并且 Apache 2 许可证要求你在衍生项目中确认使用该代码。我们希望你能够在不强制承认 Modular 或 Mojo 的情况下使用 Mojo。因此,我们加入了专门为解决这些问题而设计的 LLVM 例外条款。
未来 50 年里,
最适合 AI 编程的语言?
去年 5 月,Mojo 刚发布时,Modular 宣称,在运行 Mandelbrot 等算法时它比原始 Python 快 3.5 万倍。
去年 9 月,Modular 再次表示 “Mojo 将动态与静态语言的优点结合起来,一举将性能提升达 Python 的 68000 倍”。
去年 10 月,Mojo 登陆 Mac,Modular 再次提高了这个性能对比数据:“比 Python 快 90,000 倍”。
在谈到 Mojo 时,Modular 创始人兼首席执行官 Chris Lattner 表示:“可以这样理解,Mojo 是 Python 家族的一员,它汲取了所有这些酷炫的语言、编译器和其他技术,让 Python 向前迈进了一大步。我们认为它增强了 Python 的能力,赋予 Python 程序员超能力,让熟悉 Python 的人能够学习新知识,探索并征服新领域,而无需转用 C++。”
Mojo 基于 MLIR 中最新的编译器技术构成而成,所谓 MLIR 则是 LLVM 的演变产物,因此速度表现更好。只要程序员技术水平达标,又有充分优化的意愿,也完全可以让代码跑得飞快。Mojo 语言的目标在于既满足 Python 开发者的需求,又提供一系列新的代码优化技巧来充分发掘硬件设备的性能极限。
另一方面,Mojo 团队对 Rust 高度赞赏,并公开表示“Mojo 的设计也在很大程度上受 Rust 启发”。
在性能上,Modular 公司做了很多跟 Python 的比较,让大家有了清晰的对比,但比 Rust 快多少大家并没有概念。刚好在上个月,他们特地回应了“Mojo 是不是比 Rust 更快”的问题。
今年 2 月份的时候,Netflix 工程师兼 Rust 倡导者 @ThePrimeagen 发布了一段视频:用 Mojo 以超越 Rust50% 的速度解析 DNA 序列。这篇博文引发了大量的关注和讨论,毕竟 Rust 被定位为 AI 领域主导语言的潜在继任者(目前话事的主要是 Python 和 C++)。
@ThePrimeagen 对于 Mojo 和 Rust 在 AI 编程领域的未来展望:
如果 Mojo 正式加入战局,那我相信 Mojo 无疑将最终胜出。Mojo 取胜的原因,在于无需改变任何开发者已经熟知的范式。只需要稍加学习,就能获得惊人的性能表现。首先 Mojo 的编译速度很快,而且使用感受跟大家已经熟悉的语言非常接近,性能也跟 Rust 不相上下。唯一的问题就是怎么让更多人接受它。
在发表评论后,在业界颇有声望的 Rust 贡献者兼《Rust:从入门到生产(Zero to Production in Rust)》一书的作者 Luca Palmieri 在 X 上回应称:
昨天在 Mojo vs Rust 上看到了 @ThePrimeagen 的直播:他说的没错。如果 Mojo 能够全面落地,那么对于从事 AI 工作的朋友们来说,我们再也不用在“userspace”里看到 Rust 了。Mojo 的价值主张对于熟悉 Python 的机器学习工程师和数据科学家们都是种福音。
Rust 拥有系统编程语言领域最出色的高级人体工学设计,但其在 AI 应用领域存在两大问题:
编译速度慢,而 AI 特别强调实验与快速迭代;
大多数有 Python 经验的 AI 研究人员不愿花时间从零开始学习一门新语言。
Mojo 的目标是让 Python 开发者能够直观轻松地加以掌握。正如 Mohamed 所展示,他在几周之内就以业余项目的形式学会了 Mojo 并使用到 SIMD 优化算法(第一次实现只用了 200 行代码)。
对于关注 AI 开发的朋友们来说,目前确实存在三种语言选择其一的难题。
Mojo 与 Rust 都允许开发者在较低层级进行优化。以 Rust 为例,大家当然也可以把所有内容都打包在 Arc、Mutex 或者 Box 当中,以避免与借用检查器发生冲突,但这也会相应牺牲掉一部分性能。如果我们是在编写应用程序代码,这点性能差异可能没什么重大影响;但对于库或者其他性能敏感的代码,由此带来的开销可能会迅速增加。具体如何选择,取决于程序员对减少开销和优化性能的关注程度。
这两种语言都可以使用 LLVM 来优化代码生成,也都允许使用内联汇编(当然,相信没人会真这么做),所以理论上二者在传统硬件上的性能潜力基本相当。
基于最先进的编译器技术
Rust 于 2006 年启动,Swift 则诞生于 2010 年,二者主要构建在 LLVM IR 之上。Mojo 则亮相于 2022 年,基于 MLIR 构建而成——MLIR 是比 Rust 上使用的 LLVM IR 方法更加现代的“下一代”编译器堆栈。值得注意的是, Chris Lattner 于 2000 年 12 月在大学里创立了 LLVM,并从其多年来的演变和发展中学到了很多。他随后加入谷歌领导 MLIR 的开发,旨在支持公司的 TPU 及其他 AI 加速器项目。接下来,他继续利用从 LLVM IR 中学到的知识开启了下一步探索。
Modular 公司表示,Mojo 是首个充分利用到 MLIR 先进特性的编程语言,既可以生成优化度更高的 CPU 代码,也能支持 GPU 和其他加速器,而且统计速度也比 Rust 快得多。这是目前其他语言无法实现的优势,也是 AI 和编译器爱好者们痴迷 Mojo 的核心原因。
他们还重点解析了两个方面:
出色的 SIMD 人体工学设计:CPU 通过特殊的寄存器与指令来同时处理多位数据,这就是 SIMD(单指令、多数据)。但从历史上看,此类代码的编写体验在人体工学层面来看非常丑陋且难以使用。这些特殊指令已经存在多年,但大多数代码仍未针对其进行过优化。所以谁能解决这种复杂性并编写出可移植的 SIMD 优化算法,谁就能在市场上脱颖而出,例如 simd_json。
Mojo 的原语在设计之初就考虑到了 SIMD 优先:UInt8 实际上是一个 SIMD[DType.uint8, 1],即 1 元素的 SIMD。以这种方式表示它不会产生性能开销,同时允许程序员轻松将其用于 SIMD 优化。例如,我们可以将文本拆分成 64 字节块,将其表示为 SIMD[DType.uint8, 64],再将其与单个换行符进行比较,从而找到每个换行符的索引。由于机器上的 SIMD 寄存器可以同时计算 512 位数据的运算,因此这种操作就能将此类运算的性能提高 64 倍!
或者举个更简单的例子,假设大家有一个 SIMDDType.float64, 8,那么只需简单将其乘以 Float64(2),就能轻松提高性能。与单独将每个元素相乘比较,这种方法在大多数机器上能够将性能提高 8 倍。
LLVM(也就是 Rust)具有自动向量化优化通道,但由于无法更改 SIMD 的内存布局和其他重要细节,所以其性能表现永远达不到理论层面的开发优化极限。但 Mojo 在设计之初就考虑到 SIMD 特性,因此编写 SIMD 优化的感受与编写普通代码非常相似。
Eager Destruction 急切销毁:Rust 的设计灵感来自 C++ 的 RAII(资源获取即初始化),就是说一旦对象超出范围,应用程序开发者不必分心释放内存,编程语言本身会自行处理。这是个非常好的范例,能在保障动态语言人体工学的前提下回避垃圾收集机制带来的性能缺陷。
Mojo 则更进一步,它不会等待末尾作用域,而在最后一次使用对象时释放内存。这对 AI 场景非常有利,因为提前释放对象意味着提前释放 GPU 张量,因此可以在等量 GPU RAM 中拟合更大的模型。这是 Mojo 的独特优势,程序员无需费心设计即可获得最佳性能。Rust 借用检查器最初会将全部内容的生命周期延长至其作用域的末尾,借此匹配解构函数(destructor)的行为,但这会给用户带来一些令人困惑的后果。Rust 随后添加了一些非词汇生命周期功能以简化开发者的工作。但凭借 Mojo 中的急切销毁(eager destructor)机制,这种简化效果可以直接实现,而且其与对象的实际销毁方式保持一致,因此不会引发令人难以理解的极端情况。
Rust 中的另一种开销来自 Drop 的实现方式。它使用 Drop Flags 标记跟踪是否应该在运行时删除对象。Rust 在某些情况下能够实现优化,但 Mojo 可通过明确定义消除一切情况下的额外开销。
不管怎么说,开发人员都必须在 Mojo 以及 Python 的易用性、 C、C++ 或 Rust 的高性能之间做出选择。对此,Mojo 团队向开发者喊话说:“如果各位好奇心旺盛并更多面向未来,希望掌握一门可能在未来 50 年内对 AI 发展有所助益的语言,那不妨给 Mojo 个机会!”
参考链接:
https://www.modular.com/blog/the-next-big-step-in-mojo-open-source
https://twitter.com/clattner_llvm?lang=en
https://github.com/modularml/mojo
https://www.modular.com/blog/mojo-vs-rust-is-mojo-faster-than-rust
https://www.modular.com/blog/mojo-lightning-talk
https://www.infoq.cn/article/exdkqs3bhvwj6jlxuixy
https://www.reddit.com/r/ProgrammingLanguages/comments/135tfrc/mojo_a_programming_language_for_all_ai_developers/