Mojo官方文档中文版:为什么选择Mojo🔥

为什么选择Mojo🔥

当我们开始Modular时,我们无意构建一种新的编程语言。但是,当我们构建平台以统一全球的ML / AI基础架构时,我们意识到整个堆栈的编程过于复杂。另外,我们手写了很多MLIR,玩得并不开心。

我们想要的是一种创新且可扩展的编程模型,可以针对加速器和人工智能领域普遍存在的其他异构系统。这意味着编程语言具有强大的编译时元编程、自适应编译技术的集成、整个编译流程的缓存以及现有语言不支持的其他功能。

尽管加速器很重要,但最普遍且有时被忽视的“加速器”之一是主机CPU。如今,CPU拥有许多类似张量核心的加速器块和其他AI加速单元,但它们也可以作为专用加速器无法处理的操作的“后备”,例如数据加载,预处理和后处理以及与外部系统的集成。因此,很明显,我们不能仅用一种仅适用于特定处理器的“加速器语言”来提升AI。

应用人工智能系统需要解决所有这些问题,我们认为没有理由不能只用一种语言来完成。因此,Mojo诞生了。

下一代编译器技术的语言

当我们意识到没有现有的语言可以解决人工智能计算的挑战时,我们开始重新思考如何设计和实现编程语言来解决我们的问题。由于我们需要对各种加速器的高性能支持,因此传统的编译器技术(如LLVM和GCC)不适合(任何基于它们的语言和工具都不够)。尽管它们支持各种 CPU 和一些常用的 GPU,但这些编译器技术是几十年前设计的,无法完全支持现代芯片架构。如今,专用机器学习加速器的标准技术是 MLIR。

MLIR是一个相对较新的开源编译器基础设施,始于Google(其领导转移到Modular),已在整个机器学习加速器社区中广泛采用。MLIR的优势在于它能够构建特定于领域的编译器,特别是对于不是传统CPU和GPU的奇怪领域,例如AI ASICS,量子计算系统,FPGA和定制芯片。

鉴于我们在 Modular 的目标是构建下一代 AI 平台,我们已经将 MLIR 用于我们的一些基础设施,但我们没有一种编程语言可以释放 MLIR 在整个堆栈中的全部潜力。虽然许多其他项目现在都使用MLIR,但Mojo是第一个专门为MLIR设计的主要语言,这使得Mojo在为AI工作负载编写系统级代码时具有独特的功能。

Python家族的成员

我们对Mojo的核心任务包括编译器内部的创新以及对当前和新兴加速器的支持,但认为没有必要在语言语法或社区方面进行创新。所以我们选择拥抱Python生态系统,因为它被广泛使用,受到AI生态系统的喜爱,并且因为我们相信它是一种非常好的语言。

Mojo语言有崇高的目标:我们希望与Python生态系统完全兼容,我们需要可预测的低级性能和低级控制,我们需要能够将代码子集部署到加速器。此外,我们不想创建一个碎片化的软件生态系统——我们不希望采用Mojo的Python用户将痛苦的从Python 2迁移到3进行比较。这些目标不小!

幸运的是,虽然Mojo是一个全新的代码库,但我们并没有真正从概念上从头开始。采用 Python 极大地简化了我们的设计工作,因为大多数语法已经指定。相反,我们可以将精力集中在构建Mojo的编译模型和系统编程功能上。我们还受益于从其他语言(如 Rust、Swift、Julia、Zig、Nim 等)中学到的大量经验教训,以及我们之前将开发人员迁移到新编译器和语言的经验,以及我们利用现有的 MLIR 编译器生态系统。

此外,我们决定Mojo的正确长期目标是提供Python的超集(即使Mojo与现有的Python程序兼容),并接受CPython实现以支持长尾生态系统。如果你是一个Python程序员,我们希望Mojo立即熟悉,同时也提供新的工具来开发安全和高性能的系统级代码,否则这些代码需要低于Python的C和C++。

我们并不是要让世界相信“静态是最好的”或“动态是最好的”。相反,我们相信两者都在用于正确的应用程序时是好的,所以我们设计了Mojo,让你,程序员,决定何时使用静态或动态。

为什么我们选择Python

Python是ML和无数其他领域的主导力量。它易于学习,被重要的程序员群体所熟知,拥有一个了不起的社区,拥有大量有价值的软件包,并且拥有各种各样的优秀工具。Python通过其动态编程功能支持美观且富有表现力的API的开发,这导致TensorFlow和PyTorch等机器学习框架将Python作为其C++年实现的高性能运行时的前端。

对于今天的模块化来说,Python 是我们 API 表面堆栈中不可协商的一部分——这是由我们的客户决定的。鉴于我们堆栈中的其他所有内容都是可以协商的,因此我们应该从“Python优先”的方法开始。

更主观地说,我们认为Python是一种美丽的语言。它采用简单且可组合的抽象设计,它避免了不必要的标点符号,这些标点符号在实践中与缩进是多余的,并且它构建了强大的(动态)元编程功能。所有这些都为我们提供了一条跑道,可以将语言扩展到我们在Modular所需要的。我们希望Python生态系统中的人们看到我们对Mojo的方向是将Python提升到一个新的水平 - 完成它 - 而不是与它竞争。

与python的兼容性

我们计划与Python生态系统完全兼容,但实际上有两种类型的兼容性,所以这是我们目前对它们的立场:

就您导入现有Python模块并在Mojo程序中使用它们的能力而言,Mojo是100%兼容的,因为我们使用CPython进行互操作性。

就您将任何Python代码迁移到Mojo的能力而言,它还不完全兼容。Mojo已经支持Python的许多核心功能,包括async/await,错误处理,variadics等。然而,Mojo还很年轻,缺少Python的许多其他功能。Mojo甚至还不支持课程!

还有很多工作要做,但我们相信我们会实现这一目标,并且我们以团队的经验为指导,通过他们自己的兼容性之旅构建其他主要技术:

Clang编译器(C,C++,Objective-C,CUDA,OpenCL等编译器)的旅程,它是GCC,MSVC和其他现有编译器的“兼容替代品”。很难进行直接比较,但Clang问题的复杂性似乎比实现兼容的Python替代品大一个数量级。

Swift 编程语言之旅,它拥抱了 Objective-C 运行时和语言生态系统,并逐步迁移了数百万程序员(以及大量代码)。通过 Swift,我们学到了如何“运行时兼容”以及与遗留运行时协作的经验教训。

在你想要混合Python和Mojo代码的情况下,我们希望Mojo直接与CPython运行时合作,并且对与CPython类和对象集成具有类似的支持,而无需编译代码本身。这提供了与现有代码的庞大生态系统的插件兼容性,并且它支持渐进式迁移方法,其中增量迁移到Mojo会产生增量收益。

总的来说,我们相信,通过专注于语言设计和与Python完全兼容的渐进式进展,我们将及时到达我们需要的地方。

但是,重要的是要了解,当您编写纯Mojo代码时,实现,编译或运行时中没有任何内容使用任何现有的Python技术。就其本身而言,它是一种全新的语言,具有全新的编译和运行时系统。

与Python的差异

虽然Python兼容性和可迁移性是Mojo成功的关键,但我们也希望Mojo成为一流的语言(这意味着它是一种独立的语言,而不是依赖于另一种语言)。它不应仅仅为了保持兼容性而限制引入新关键字或语法产品的能力。因此,我们的兼容性方法是双重的:

我们利用CPython运行所有现有的Python 3代码而不加修改,并使用其运行时,未经修改,与整个生态系统完全兼容。以这种方式运行代码不会从Mojo带来任何好处,但是这个生态系统的存在和可用性将迅速加速Mojo的启动,并利用Python已经非常适合高级编程的事实。

我们将提供一个机械迁移工具,为想要将代码从 Python 迁移到 Mojo 的人提供非常好的兼容性。例如,为了避免使用与Mojo关键字匹配的标识符名称的Python代码出现迁移错误,Mojo提供了一个反引号功能,允许任何关键字充当标识符。

总之,这使得Mojo可以很好地集成到一个主要是CPython的世界中,但允许Mojo程序员逐步将代码(一次一个模块或文件)移动到Mojo。这是苹果执行的从Objective-C到Swift迁移的行之有效的方法。

构建 Mojo 的其余部分和迁移支持需要一些时间,但我们相信这种策略使我们能够集中精力并避免分心。我们还认为与CPython的关系可以在两个方向上建立 - 如果CPython团队最终在Mojo而不是C中重新实现解释器,那不是很酷吗?🔥

Python的问题

通过使Mojo成为Python的超集,我们相信我们可以解决Python的许多现有问题。

Python有一些众所周知的问题 - 最明显的是低级性能和CPython实现细节,如全局解释器锁(GIL),这使得Python成为单线程。虽然有许多正在进行的项目来改善这些挑战,但Python带来的问题更深入,在人工智能领域尤其有影响。我们将在 2023 年详细讨论这些技术限制,而是讨论它们的影响。

请注意,我们在本节中提到的Python所指的都是CPython实现。我们稍后将讨论其他实现。

两世界问题

由于各种原因,Python不适合系统编程。幸运的是,Python 作为胶水层具有惊人的优势,与 C 和 C++ 的低级绑定允许在 C、C++ 和许多其他具有更好性能特征的语言中构建库。这就是NumPy,TensorFlow,PyTorch和生态系统中大量其他库成为可能的原因。

不幸的是,虽然这种方法是构建高性能 Python 库的有效方法,但它是有代价的:构建这些混合库非常复杂。它需要对CPython的内部进行低级理解,需要C/C++(或其他)编程的知识(首先破坏了使用Python的原始目标之一),使得发展大型框架变得困难,并且(在ML的情况下)将世界推向“基于图”的编程模型,其基本可用性比“渴望模式”系统差。TensorFlow和PyTorch在这方面都面临着重大挑战。

除了两个世界问题如何造成系统复杂性的基本性质之外,它还使生态系统中的其他一切都变得更加复杂。调试器通常不能跨 Python 和 C 代码,而那些可以跨 Python 和 C 代码的代码也不会被广泛接受。令人痛苦的是,除了Python之外,Python包生态系统还必须处理C / C++代码。像PyTorch这样的项目,拥有大量的C++投资,有意尝试将更多的代码库迁移到Python,因为他们知道它获得了可用性。

三世界和N世界问题

整个Python生态系统中普遍存在两个世界的问题,但对于机器学习框架的开发人员来说,情况更糟。人工智能正在普遍加速,这些加速器使用定制的编程语言,如CUDA。虽然 CUDA 是C++的亲戚,但它有自己的特殊问题和局限性,并且它没有调试器或分析器等一致的工具。它也有效地锁定在单个硬件制造商中。

人工智能世界在硬件方面拥有令人难以置信的创新,因此,复杂性正在失控。现在有几次尝试为加速器(OpenCL,Sycl,OneAPI等)构建有限的编程系统。这种复杂性爆炸式增长正在继续增加,这些系统都没有解决工具和生态系统中严重伤害行业的根本碎片化问题——它们正在增加碎片化。

移动和服务器部署

Python生态系统面临的另一个挑战是部署。这有很多方面,包括如何控制依赖关系,如何部署密封编译的“a.out”文件,以及如何改进多线程和性能。在这些领域,我们希望看到Python生态系统向前迈出重要的一步。

相关工作

我们知道还有许多其他改进Python的努力,但它们并没有解决我们旨在通过Mojo解决的基本问题。

一些正在进行的改进Python的努力包括加速Python和取代GIL,构建看起来像Python但作为其子集的语言,以及构建与Python集成但不是一流语言的嵌入式领域特定语言(DSL)。虽然我们不能提供所有努力的详尽清单,但我们可以谈谈这些项目中面临的一些挑战,以及为什么它们不能解决Mojo所做的问题。

改进 CPython 和 JIT 编译 Python

最近,社区花费了大量精力来提高CPython性能和其他实现问题,这显示出巨大的成果。这项工作非常棒,因为它逐步改进了当前的CPython实现。例如,Python 3.11 通过内部改进将性能提高了 Python 10.60 3-10%,Python 3.12 旨在通过跟踪优化器走得更远。许多其他项目都在试图驯服GIL,像PyPy这样的项目(以及其他许多项目)已经使用JIT编译和跟踪方法来加速Python。

虽然我们是这些伟大努力的粉丝,并且觉得它们对社区有价值和令人兴奋,但不幸的是,它们不能满足我们在 Modular 的需求,因为它们不能帮助在加速器上提供统一的语言。如今,许多加速器支持非常有限的动态功能,或者性能很差。此外,系统程序员不仅追求“性能”,而且他们通常还希望对计算方式进行大量的可预测性和控制。

我们希望消除在 Python 库中使用 C 或 C++ 的需要,我们寻求尽可能高的性能,并且在某些情况下我们根本无法接受动态功能。因此,这些方法无济于事。

Python子集和其他类似Python的语言

有很多尝试来构建一个“可部署的”Python,比如来自PyTorch项目的TorchScript。这些非常有用,因为它们通常提供低依赖项部署解决方案,有时具有高性能。因为它们使用类似Python的语法,所以它们比新语言更容易学习。

另一方面,这些语言还没有被广泛采用——因为它们是 Python 的一个子集,它们通常不与 Python 生态系统互操作,没有出色的工具(如调试器),并且经常单方面改变 Python 中的不方便行为,这破坏了兼容性并进一步分裂了生态系统。例如,其中许多更改了简单整数包装的行为,而不是生成与 Python 兼容的数学。

这些方法的挑战在于它们试图解决Python的一个弱点,但它们并不擅长Python的强项。充其量,这些可以提供C和C++的新替代方案,但如果不解决Python的动态用例,它们就无法解决“两个世界的问题”。这种方法会导致碎片化,不兼容使得迁移变得困难甚至不可能 - 回想一下从 Python 2 迁移到 Python 3 是多么具有挑战性。

与C兼容的Python超集

由于Mojo被设计为具有改进的系统编程能力的Python超集,因此它与其他Python超集(如Pyrex和Cython)共享一些高级思想。与Mojo一样,这些项目定义了自己的语言,也支持Python语言。它们允许您为 Python 编写性能更高的扩展,以便与 Python 和 C 库互操作。

这些 Python 超集非常适合某些类型的应用程序,并且它们已被一些流行的 Python 库应用,效果很好。然而,他们不能解决Python的两世界问题,因为他们依赖CPython作为他们的核心语义,所以没有它就无法工作,而Mojo只在必要时使用CPython来提供与现有Python代码的兼容性。Pure Mojo代码不使用任何预先存在的运行时或编译器技术,而是使用基于MLIR的基础架构在各种硬件上实现高性能执行。

Python中的嵌入式 DSL

另一种常见的方法是在Python中构建嵌入式领域特定语言(DSL),通常与Python装饰器一起安装。有很多这样的例子(TensorFlow中的装饰器,OpenAI的Triton编程模型中的装饰器等)。这些系统的一个主要好处是,它们保持了与Python工具生态系统的兼容性,并本机集成到Python逻辑中,允许嵌入式迷你语言与Python的优势共存,用于动态用例。@tf.function@triton.jit

不幸的是,这些系统提供的嵌入式迷你语言通常具有令人惊讶的局限性,不能与调试器和其他工作流工具很好地集成,并且不支持我们寻求的统一异构计算的语言的本地语言集成级别,并且是编写大规模内核和系统的主要方式。

通过Mojo,我们希望通过简化事情并使其更加一致来推动整个系统的可用性。嵌入式DSL是启动和运行演示的便捷方式,但我们愿意付出额外的努力,为我们的用例提供更好的可用性和可预测性。

要查看到目前为止我们使用Mojo构建的所有功能,请参阅Mojo编程手册。