文章来源:why swift on tensorflow

    Swift for TensorFlow的核心图程序提取算法自动微分Python语言互操作特性可以在其他编程语言中实现,我们偶尔会被问到为什么我们没有在这个项目中使用其他语言。
    该项目的工程师以前熟悉Swift(和其他几种语言),但选择是以我们项目的目标为指导的,该目标规定了具体的技术要求(如下所述)。这个选择也被广泛讨论,与同事和其他感兴趣的工程师进行了辩论,我们得出结论,斯威夫特是最好的方向。在这份文件中,我们与社区分享我们的审议过程,以帮助解释我们的决定。
    也就是说,虽然我们的语言选择是由我们的具体项目目标指导的,但我们希望看到这些技术和思想在其他编程语言的上下文中得到更广泛的应用!如果您有兴趣从事类似的项目,请与我们联系,我们将乐于分享我们的专业知识。

    这个项目是怎么来的
    正如设计概述文档中所讨论的,我们的项目目标是提高TensorFlow的可用性。我们很快意识到,由于Python具有高度的动态性,我们基于核心静态分析的图形程序提取算法不适合Python。这导致我们不得不选择另一种语言来工作,我们希望有条不紊地处理这个问题。因此,我们为项目定义了目标,探索了编程语言的哪些属性对于实现这些目标是重要的,然后根据这些属性评估了许多语言。你已经知道结果了——我们最终决定了swift。

    下面我们将解释我们的项目目标,讨论有助于实现这些目标的编程语言属性,提供针对这些目标的特定语言的简短评估,并具体讨论Swift的优缺点

    项目目标
    TensorFlow是一个世界级的机器学习框架,被广泛的不同的人用于很多不同的事情。我们的项目目标是为TensorFlow提供一个基于TensorFlow的能力和能力的新接口,同时将其可用性提升到一个全新的水平。我们的目标是让机器学习研究人员(理论和应用)、大规模部署的生产工程师,以及任何使用TensorFlow的人在不牺牲任何已经使TensorFlow变得伟大的东西的情况下,更加高效和快乐。

    我们围绕在系统中维护和改进的重要属性定义了目标:

    • 表现性:我们需要一个define-by-run模型,感觉像是直接针对一个数字API和宿主语言(比如NumPy)进行编程,没有显式的图形抽象。我们不应该对本机控制流、使用本机数据结构(如字典)或其他感觉自然的东西施加约束。

    • 高性能:我们希望充分利用我们的硬件和加速器,包括CPU、GPU、云TPU,以及整个行业正在开发的未来加速器。性能对于节省兆瓦的生产部署非常重要,但对于那些希望在实验中获得快速周转时间的研究人员来说同样重要。

    • 硬件抽象:应该可以在不嵌入硬件特定信息的情况下构建一个模型,并从硬件中获得“良好”的性能。我们应该提供(opt-in)能力,为特定的加速器进一步优化模型,以实现全峰值性能,并确保这是一个低摩擦路径,不需要重写模型。

    • 大型、动态和自我修改的模型:我们不知道ML模型在5年后会是什么样子,但很明显它们会更大、更稀疏、结构也不那么严格。我们应该解决今天的问题,拥抱下一代,随着计算机价格的不断降低,研究人员将提出这一代。我们应该完全支持动态模型,如注意模型,大型模型,如专家混合模型,以及需要与真实或模拟环境(如Atari游戏)频繁交互的强化学习模型

    • 性能可预测性:使大型且灵活的系统可用的一个关键方面是使其可预测:虽然它应该可以表达任何内容,但是应该很容易预测哪些内容将有效运行,并且工具应该提供有关性能悬崖的反馈。简单且可预测的工具比试图解决最常见问题的魔法层更可取。

    • 快速迭代时间:我们需要启用高效的研究人员工作流,在那里工具会消失,允许用户专注于数据和数学。

    • 可调试性和自省性:研发的一个重要部分是找出模型中发生了什么,诊断故障,并找出要更改的内容。一个更早诊断更多错误的系统(例如编译时的形状不匹配)比一个只在运行时捕获错误的系统更有用。

    • 高端用户体验:无论用户是喜欢UI、控制台还是批处理体验,我们都应该满足他们的需求。我们应该支持终端用户(例如,使用解释器/REPL)、Jupyter笔记本、喜欢UNIX的用户!脚本和其他常见模式。

    • 灵活部署:除了支持在gpu和云tpu等高端加速器上进行推理外,我们还需要能够通过TFLite部署到只推理移动目标。我们需要支持需要最小依赖性的生产团队,例如,能够为CPU生成一个.o文件。

    • 快速部署:ML空间的移动非常快:我们应该尽可能消除研究和生产部署之间的障碍。需要对“研究代码”进行重大重写以将其“投入生产”将是有害的,这既是因为它减慢了这一速度,也是因为它使迭代改进生产模型变得非常困难。重写也会引入非常微妙和有害的错误。

    • 一流的自动微分(AD):AD是TensorFlow的一个关键特性,但我们可以改善它的用户体验,并从广告社区引入更先进的技术。我们应该支持更高阶的AD,以及最好的类内实现,如专用的伴随、雅可比的简单计算、每个示例的梯度、检查点等。

    • 拥抱TensorFlow图形生态系统:GraphDef(和SavedModel)是交换、传输、部署、与可视化工具集成等的关键。

    正如你所看到的,这不是一个简短的目标列表,而且这并不容易实现。也就是说,我们相信我们可以在一个单一的相干系统中做到这一点,而TensorFlow成熟的技术为我们处理了很多事情。
    值得注意的是,自2018年4月发布以来,Swift for TensorFlow尚未解决其中一些目标(例如改进部署和自我修改模型),但我们有一些想法,我们预计这些想法将发展为向前迈出的伟大一步,并随着时间的推移涵盖每一个目标。

    程序设计语言的性质
    编程语言是一组基本上正交的设计决策(及其结果)的集合,这些决策(及其结果)表现为一个不可分割的工件。每种语言在每个轴上提供不同的折衷,因此选择一种语言类似于解决一个高度多维的稀疏优化问题。为了增加挑战,许多编程语言可以得到增强,因此我们需要考虑通过增强语言和编译器来克服某些缺陷的可能性(以及社区接受这种更改的可能性)。
    本节讨论其中一些轴,并将它们与上面的项目目标列表联系起来。这些特性中很少有是“绝对必需的”,但其中一个方面的弱点可能会造成后续影响。当我们将具体的语言权衡讨论推迟到下一节时,我们将确定在某些情况下对于给定目标有问题的各种语言类。

    Python的优点
    首先,让我们从Python希望没有争议的优点开始,我们不能破坏这些优点:

    • 社区:拥有一个庞大的用户社区是很重要的:社区驱动书籍、教程和所有的小东西,直到它们消失之前,没有人会想到它们(我们需要emacs和vim支持。。。:-). 这一要求通常排除了大多数研究语言,也排除了为TensorFlow构建新语言的可能性。
    • 开源和跨平台:TensorFlow是开源的,在每个可以想象的平台上都有用户。我们希望能够扩展到支持所有这些。
    • 美学与设计:语法是一种语言的“用户界面”,对可用性和用户使用系统的方式有着深刻的影响。好的设计是很辛苦的工作,但它很重要-这不仅仅是一个问题的“自行车擦身”。
    • “主流”语法:TensorFlow是一个主流系统,它的大多数用户都在使用Python,我们的目标是吸引广泛的用户群。这意味着过度的“非主流”语言将损害我们技术的采用。也就是说,我们对其他社区探索这些技术非常感兴趣。
    • 浅学习曲线:我们希望新用户花时间学习TensorFlow,而不是与一种具有高学习曲线的语言作斗争。陡峭的学习曲线也降低了现有TensorFlow用户切换到我们新系统的可能性。
    • 高生产率:人们喜欢Python,因为它的模板和低“仪式”。当许多人觉得他们是在浪费时间安抚编译器或大量生产模板时,他们会感到沮丧。
    • 调试器:TensorFlow的目标之一是让人们能够更有效地调试他们的模型,因此我们需要调试经验。这通常不包括没有调试器的研究语言。
    • 交互性:批量编译在生产中占有重要地位,但REPLs,#!脚本、笔记本环境等广泛应用于各个研究团队。
    • 可预测的语义:类型系统(无论是动态的还是静态的)应该有合理的行为,并且组合起来没有令人惊讶的行为。
    • 内存安全:我们不希望TensorFlow用户花时间在他们的模型中寻找悬而未决的指针错误和未定义的行为。这个要求一般不包括C、C++和FORTRAN语言。另一方面,值得注意的是,与现有C代码的互操作性对于大型系统非常有用。
    • pythonapi:TensorFlow用户受益于并依赖于TensorFlow产品之外的大量pythonapi集合,例如可视化和数据科学方面的东西。如果我们忽视这一现实,采用我们的新制度(无论它有多伟大)将非常缓慢。

    Python挑战

    Python在以上几点上很好,但它也有一些挑战。以下是一些改进后TensorFlow会更好的地方:

    • 性能:性能是Python的一个长期问题,对于TensorFlow核心来说,它会导致大量的额外工作:在Python层编写东西是最自然的,但是由于性能原因,很多事情不能在那里完成。这导致用户不得不在C++中编写TysFooFPS,只是为了处理Python性能。这使得Tensorflow的低性能成为一个重要的可用性问题。
    • 并发性:吉尔的存在在大规模设置中增加了堆栈中的复杂性:它防止模型作者对某些事情(没有自己编写C++ +CUDA)实现合理的性能,并且防止模型中并发算法的自然表达。
    • 部署:Python解释器及其包生态系统在mobile上是非入门的。它也被认为是一个重要的责任,为产品团队,希望密封低依赖性建设。生产用户经常在Python中进行训练,但是编写它们的推理逻辑来对抗TunSoFraseC++ API的生产,这损害了我们的目标,缩小了研发和生产部署之间的差距。
    • 定制的OPS:建立一个定制的OP当前需要编写C++和Eigen /CUDA——这是一个巨大的复杂的悬崖跳跃,在某些情况下,一个屏障减少了模型的自由交换(因为它们现在依赖于他们的源之外的东西),并且可以将ML模型锁定到某些硬件供应商。如果有一条路径可以用与模型相同的语言编写高性能内核,那就更好了。

    Python的这些众所周知的问题使得TensorFlow编程模型比理想情况下更加复杂。他们需要先进的TysFraseUp用户学习和处理堆栈的C++和CUDA层。他们减慢了研究人员的速度,他们经常是那些尝试新事物并突破当前系统极限的人。

    图程序提取所需的性质
    我们用来自动识别和提取程序图形的基本算法是基于代码的静态分析。这意味着我们需要能够“静态地”查看代码(即,不运行它),并且能够可靠地识别张量操作以及它们之间的数据流和控制流依赖关系。为了实现图形的性能,我们需要能够将大量的张量代码连接在一起——最好是具有与手动使用类似于张量流会话API的API相同的粒度。我们还需要允许用户能够使用高层api,比如层和估计器(以及构建他们自己的抽象!)不破坏我们的分析能力。
    在证明系统中,众所周知,很难进行既完整又合理的静态分析,这意味着可以选择1)有时产生错误结果但处理所有程序的不健全模型,2)始终正确但处理有限程序集的声音模型。因为我们使用静态分析来生成代码,所以我们要求分析是正确的!让我们来探索一个保守正确但不完整的模型。
    如果我们把分析局限于一个我们知道可以可靠分析的有界计算模型,我们就可以证明是正确的。在我们的图形转换中,这种方法很有效,因为我们有一个保守的正确回退来处理任何超出分析能力的情况:我们可以将数据从图形复制回主机CPU,并动态执行任意逻辑来确定下一步要做什么,然后将数据发送回图形计算。
    要使这种方法在实践中发挥作用,我们需要做两件事:首先,我们需要处理的案例子集足够大,以便包含有趣的内容——包括高级用户抽象。其次,我们需要生成的模型足够简单,让普通人能够理解它:许多特殊情况和依赖场景的行为破坏了系统的可用性。
    以一种可用的方式使其工作有一些微妙但关键的方面,许多著名的编程语言(包括Python和其他以OOP为中心的语言)强制进行不可接受的折衷,使其在实践中无法很好地工作。这个问题影响到任何基于动态调度和可变状态的语义调度模型的面向对象语言。为了解释这个问题,我们在伪Swift语法中使用了一个故意简化的示例(注意:这不是惯用代码!):

    屏幕快照 2020-04-13 下午2.40.26.png
    本例使用一个假设的层库来设置来自剩余网络的块。这是一个合理的代码,使用Java或Python程序员(例如)将使用的抽象类型。
    然而,上面代码的明显简单性是许多复杂性的基础:像conv1这样的属性可以在设置块之后重新分配。对层(未显示)上forward()和backward()的方法调用是动态调度的,这意味着调用的目标依赖于代码的动态属性。指向层的“指针”甚至可能被别名为其他引用,这使得很难对每个对象的读写进行数据流分析。这些可能的行为使得编译器很难静态地证明程序的结果——这是可靠地提取图形的先决条件。

    回到上面的选择,我们有几个选择:

    • 一个可预测的、可解释的和有限的模型:Java有一个(非常小的)子集,我们可以以完全可靠的方式进行静态分析:如果所有代码都在静态方法或最终基类的方法中,那么我们知道所有调用都是静态调度的。如果所有变量都保证一次分配,那么我们可以进行积极的指针跟踪。这个选项的问题是,我们失去了拥有高层次抽象的能力,至少没有到处来回复制。

    • 一个不可预测、难以解释、但更为普遍的模型:众所周知,虽然许多OOP语言在理论和技术上是动态调度的,但是类层次分析过程间别名分析等技术可以静态地发现其中的许多。我们可以使用这样的启发式技术来扩展我们可以处理的情况。不幸的是,这些技术通常需要“整个程序分析”,而程序中某个部分的细微更改可能会导致“远处的怪异操作”,因为分析会变得混乱。这意味着对程序的一个部分的微小更改可能会导致发送和接收被添加到模型的其他部分,从而导致难以或不可能为用户解释模型。

    我们的项目目标是提供一个高度可用的体验,这需要编程模型的可预测性和可解释性。这一点尤其重要,因为发送和接收可能对性能产生重大影响:所涉及的数据大小可能是千兆字节!因此,我们拒绝基于启发式的方法,坚持可预测、可解释但有限的模型。

    但并非所有的编程语言都以同样的方式受到限制。例如,如果您比较C和Java,在C中引入结构可以让它可靠地处理比Java更广泛的情况。一个极为极端的是C++,它有一个100%静态的图灵完整模板元编程系统。Swift介于两者之间,它提供了大量的表达能力(特别是由于其面向协议编程的方法),我们在图形程序抽取中对此进行了深入的解释。

    图程序提取所需的附加属性
    除了可靠的静态分析,我们还受益于语言的其他一些特性:

    • 限制指针别名:只有在图形程序提取能够可靠地在操作之间建立数据流定义使用链时,图形程序提取才能工作。允许对C/C++等指针和引用进行不混叠的语言将迫使我们的静态分析过于保守,在它们的存在下复制到主机。

    • 已知的张量操作:由于我们要将主机代码中的张量操作提取到一个图中,所以我们需要知道它们是什么-通过指定的语法、静态类型系统或其他钩子。

    • 合适的编译器IR:图程序提取是一个非常重要的编译器转换,它需要合适的中间表示(IR)来处理。这个IR必须足够高层次,以支持我们使用的去语法糖转换,并且能够编译成TensorFlow图而不丢失基本信息。图程序提取所需的技术理论上可以在一个好的AST上执行,但在SSA形式的控制流图上更容易实现。

    静态与动态类型系统
    最后,还有静态和动态类型的主题。静态类型提供了许多与我们的用例特别相关的优点。静态类型:

    • 可以在编译时而不是运行时捕获错误。当一个愚蠢的错误导致长时间的训练失败时,人们会非常沮丧。
    • 直接改善工具体验,如代码完成/智能感知、跳转到定义等。
    • 使我们很容易知道什么是张量运算。

    另一方面,静态类型语言可能需要大量的仪式和样板,这会激怒并直接损害生产力。不过,也有一些很有前途的中间点,例如静态类型的语言,但在普通情况下使用类型推断来消除显式类型。

    哪些语言符合我们的项目要求?
    这是一长串的目标,而且有很多语言要考虑。因此,这里我们选择处理相关语言的集群,而不是逐个构建和评估这些语言的完整交叉乘积。如果我们对下面的任何语言或社区做出了错误的描述,请提前向我们报错,让我们知道,我们将很高兴地纠正任何错误!

    • 一种新的语言:创造一种语言是一项荒谬的工作。您不仅需要一个解析器,还需要一个调试器、所有工具、书籍和教材,以及构建和支持一个大型社区所需的所有其他东西。此外,即使我们愿意投入必要的资金来做这件事,也需要很多年才能做好,而且机器学习进展得太快了。
    • Python:考虑到TensorFlow社区的大多数人已经在使用Python,因此将其用于这项工作是理想的。然而,Python的动态特性并不适合我们所依赖的可靠的静态分析和图形程序提取方法。Python的某些子集可能会被编译(Tangent就是这么做的),但是还不清楚如何用这种方法支持像Python类这样的高级抽象。
    • Ruby/Javascript/R/Typescript/etc:这些语言在静态分析方面与Python有相同的问题。我们经常被特别问到TypeScript:虽然它引入了一个非常好的类型系统,但它并没有改善Python带来的基本动态分派和对象别名挑战。
    • Java/C#/Scala(以及其他具有普适动态分派的OOP语言):这些语言与Python一样共享大多数静态分析问题:它们的主要抽象特性(类和接口)构建在高度动态的构造上,这意味着张量运算的静态分析依赖于“最大努力”技术,如别名分析类层次分析。此外,由于它们普遍基于引用,因此很难可靠地消除指针别名的歧义。

    与Python一样,我们的方法可能适用于这类语言,但这样的系统要么会迫使模型开发人员使用非常低的抽象api(例如,所有代码都必须在最后一个类中),要么系统将依赖于启发式的静态分析技术,这些技术在某些情况下有效,但在其他情况下无效。

    • Go:Go是一种很好的语言,它的社区不断壮大,许多Go程序员都曾是Python程序员。不幸的是,Go不太适合这种方法:它允许非结构化的别名,抽象通常是根据动态接口分派、对reflect()的调用以及从接口{}到具体类型的动态转换来实现的。这些动态特性中的每一个都会破坏可靠的大规模抽象解释,因此用户将被迫只使用Go的静态函数和结构特性,从这些特性中构建高层层和估计抽象是不现实的(除非它们被构建到语言中)。

    另一个重要的问题是,Go的本质需要在Go语言中添加重要的语言增强,比如内置的张量类型,某种方式能够表示在张量元素类型上通用的抽象,自动区分支持,以及核心提取算法的实现。Go社区更倾向于保持语言的小型化,在这个项目中使用它需要违背这些核心原则。

    • Rust:我们相信Rust支持实现本文所述技术所需的所有成分:它有很强的静态性,并且它的traits系统支持零成本抽象,可以被编译器证明是可以消除的。它有一个很棒的指针别名模型,一个合适的中级IR,一个充满活力和参与性的社区,以及一个很棒的开放式语言进化过程

    使用Rust的一个关注点是,这个项目的一个强大目标是吸引整个TensorFlow社区,这个社区目前普遍基于Python。我们喜欢生锈,但它有一个陡峭的学习曲线,可能会排除数据科学家和其他经常使用TensorFlow的非专家程序员。所有权模型非常棒,但与当今用Python实现的机器学习代码所面临的问题几乎无关。

    • C++:与RISE一样,我们相信C++支持实现我们工作所需的所有必要的组件,包括一个成熟的编译器前端和一个活动的标准委员会。然而,C++中经常存在未定义的行为,并且它的静态合成系统大部分依赖于C宏和模板元编程,这不是特别有用。此外,因为C++通常并不吸引Python程序员,我们担心选择它会阻止一个重要社区采纳我们的工具。

    • Julia:Julia是另一种伟大的语言,有一个开放和活跃的社区。他们目前正在投资机器学习技术,甚至与pythonapi具有良好的互操作性。Julia社区与我们的项目有许多共同的价值观,在我们的项目顺利进行后,他们在一篇非常相似的博客文章中发表了这些价值观。我们不是Julia的专家,但是由于它的编译方法是基于类型专门化的,因此它可能有足够的表示和基础设施来承载我们所依赖的图形程序提取技术。

    最后决定
    最后,我们把技术优势的列表缩小到SWIFT、RIST、C++和潜在朱丽亚。接下来,由于可用性问题,我们排除了C++和生锈,并选择了Swift来代替朱丽亚,因为Swift有一个更大的社区,语法上更接近Python,并且因为我们更熟悉它的内部实现细节——这使得我们能够更快地实现原型。
    根据我们的语言属性评估Swift
    看看我们如何根据文档顶部的逐点语言属性来评估Swift可能会很有趣。以下是这些要点的简要总结—从Python擅长的主题开始。最后,我们还公开讨论了Swift的具体限制和挑战。
    与Python的优势相比Swift

    • 社区:Swift是一种快速发展的语言,在最近的调查中名列前十位,据信有超过一百万的程序员使用它。它拥有一个庞大而充满活力的开源社区和一个开发良好的工具生态系统。Swift的大本营是移动开发,但有几个社区正在推动Swift的服务器和云应用。
    • 开源和跨平台:是的。
    • 美学与设计:这是一个主观的话题,很难衡量,但这是Swift 3的一个主要焦点。Swift得益于开源社区一年来致力于改进语法以确保一致性和优雅性。现在很难对语言进行源代码突破性的更改,但Swift肯定得益于没有过早锁定。
    • “主流”语法:Swift是为了适应编程语言的“扩展C族”而设计的,它有意让人感觉“熟悉”。
    • 浅学习曲线:Swift的一个关键设计目标是逐步揭示语言的复杂性,使其成为一种极易教的语言。这是一个使得在Swift Playgrounds iPad应用程序中将Swift代码作为第一种编程语言(针对初中、七年级和八年级)教给孩子的东西。
    • 高生产率:Swift的目标是最大限度地提高代码的清晰度,因此它努力减少样板文件。Swift的最高目标是优化编写和维护一个运行中的应用程序所需的时间,包括调试时间和其他一些超出仅仅是敲出代码的事情。
    • 调试器:Swift有一个完整的调试器,它支持命令行和IDE。
    • 交互性:Swift支持批量编译、强大的REPL(与完整的调试器集成)和#!剧本。笔记本电脑环境可免费用于Mac(Xcode Playgrounds)、iOS(Swift Playgrounds)和web版本。
    • 可预测语义:是的。
    • 内存安全:Swift的目标是成为“默认安全”的语言,不仅在内存安全方面,而且有助于及早捕获逻辑错误。它还提供显式的“不安全”api来与C代码交互和直接访问硬件。
    • pythonapi:当我们开始这个项目的时候,答案是“不”,这就是为什么我们优先考虑构建一个新的方法来表达Swift/Python的互操作性。现在的答案是“是”。

    与Python的挑战相比Swift
    接下来,Python现在有一些问题:

    • 性能:Swift有很好的底层性能和内存使用,而且由于它在移动设备上的应用非常广泛,所以有一个很大的社区的人在不断改进它。当添加显式内存所有权支持时,SWIFT将成为C++的许多应用的可信替代。
    • 并发性:Swift还不包括对并发性的语言支持,但是可以很好地与pthreads之类的本地API一起工作,它还附带了一个很好的工作队列API Dispatch(也称为“GCD”)。一级并发模型是Swift未来可能的特性,它可以基于async/await和Actors。
    • 部署:Swift可以编译成简单的本地机器代码,如C,并且不依赖于垃圾收集器或其他繁重的运行时。使用Swift将ML模型编译成.o/.h文件是完全合理的。
    • 自定义操作:Swift构建在LLVM之上,可以直接访问所有LLVM内部函数,LLVM可以为Nvidia/PTX和AMD卡生成GPU内核。原则上,有人可以为Swift构建一个嵌入式的“CUDA/OpenCL”DSL。我们有兴趣在长期内对此进行探索,因为这将导致模型更加独立(因此更容易共享),并允许高级用户使用单一语言。

    图程序提取所需的性质
    接下来,我们将从以下几个方面来构建我们在这里描述的图形程序提取模型:

    • 通过高级抽象进行可靠的静态分析:Swift具有高度动态的特性(类、存在性和转义闭包),但它也有一个开发良好的静态方面,即围绕结构和枚举旋转。结构和枚举可以是泛型的,有方法,并且符合协议(它们提供“类接口”特性、mixin和其他称为面向协议编程的功能)。Swift依赖于这些可删除的静态特性,因为它的基本类型(如Int和Bool)实际上是在标准库中实现的,而不是内置在编译器中。由于这些特性,Swift为开发人员提供了一个简单可靠的概念模型:只要您不使用类、存在性或其他动态特性,抽象解释就一定会成功,并给您带来出色的性能。这在图形程序提取文档中有详细的说明。
    • 已知张量运算:Swift有一个静态类型系统,它给我们一个简单的启发:把任何张量类型的东西放在加速器上。我们还选择给张量ops一个不同的句法形式(目前拼写为tfop(…)),这不是必需的,但可以简化一些事情。
    • 合适的编译器IR:Swift完全可以完成我们需要的转换,因为它有一个名为SIL的高级IR。这用控制流图表示SSA中的代码,保留源级类型信息(因此我们知道什么值是张量),并提供我们需要的关键转换,如内联、泛型专门化等。SIL的存在使构建原型的编译器块变得非常便宜。SIL包括IR序列化、“模块间优化”、“模块间优化”、内联、泛型专门化和所有其他基本的过程间优化基础设施,我们需要在不重新创建基本编译器基础设施轮子的情况下完成这项工作。
    • 受限指针别名:Swift有一个模糊但重要的特性,称为内存独占性,它是作为正在进行的工作的一部分而构建的,目的是将受信任启发的内存所有权模型引入Swift。Swift的别名支持意味着,即使对于inout参数,基于静态分析的分析和转换也可以依赖非常强的内存来源保证。这为C.Swift中的Fortran引用和限制指针提供了类似的分析能力。Swift对值语义的关注也是我们分析数组和其他值类型的主要帮助。

    使用Swift的已知缺点
    如上所述,Swift非常适合这个项目,原因有很多。也就是说,它不是完美的任何一个想象力延伸。为了抓住讨论的消极面,以下是使用Swift进行本项目最常见的问题:

    • 它(相对而言)是新的:Swift自2010年开始开发,2014年首次公开发布。因此,它还是相对较新的,因此工具和周围的生态系统没有Python成熟,Python已经有25年的历史了。
    • Windows支持:Swift是跨平台的,在类UNIX系统上比较成熟,包括Apple平台、Linux、BSD和其他UNIX-y的东西。也就是说,Windows的支持还比较早,但至少有一个活跃的社区正在进行这方面的工作。
    • 太大的依赖性:Swift依赖于LLVM和Clang,这意味着它是TensorFlow的一个重要依赖性。另一方面,所有备选方案(包括Python)都引入了一组非常重要的依赖项。Swift还与TensorFlow很好地结合在一起,因为它已经依赖LLVM(通过XLA编译器后端)。
    • 小型数据科学社区:Swift在数据科学社区方面没有太多的障碍。它有一个我们希望参与的小社区,但是与现有的NumPy、SciPy、scikit learn和Python可用的其他生态系统相比,它非常小。考虑到这些Python库中的大多数都是用Python包装的C代码实现的,Swift生态系统最终可能会增长为包含相同库的Swift包装器。不过,从短期来看,我们认为Python互操作性方法是一种非常实用和非常通用的解决方案,可以满足TensorFlow用户的需求。
    • 错误消息需要改进:类型推断的一个缺点是,有时得到的错误消息(特别是在使用高阶泛型函数编程结构时)可能会产生误导。这通常通过将表达式分解为子表达式来解决。
    • 构建时间可以改进:拥有大型应用程序(例如超过10万行代码)的开发人员对构建时间不满意。这仍然是快速开发社区的一个焦点,并有望随着时间的推移而改进,但鉴于机器学习模型的规模相对较小,这不应该是一个问题。
    • 随着项目的发展,可能会出现其他挑战。如果是的话,告诉我们,我们会把他们加入名单。

    结论
    回想起来,Swift非常适合这个项目的需要,这并不奇怪。斯威夫特是由一个紧密的团队设计和建造的。该团队先前建立了高度模块化和可组合的编译器基础结构(LLVM)、编译器和运行时,用于高度动态的SimalTalk派生语言(ObjuleC),具有强大的泛型语言的编译器和一个可编程的泛型系统(C++),以及一个路径敏感的静态分析引擎(CLAN静态分析器)。此外,Swift的设计目标是构建一种像脚本语言一样易于学习和使用,但又有足够能力用作系统编程语言的东西。

    您可以看到Swift for TensorFlow项目是如何使用这些东西的:

    • 可用性目标在两个项目之间是直接一致的
    • 高度动态的特性允许与pythonapi的自然互操作性
    • 强大的静态端允许语言支持静态分析,这是图形程序提取和自动区分的基础
    • 泛型系统对于使自动区分成为用户可扩展的语言特性至关重要
    • 支持路径敏感静态分析的目标促成了构建承载此工作的SIL中间表示的原因
    • 模块化和可组合性的文化允许我们在TensorFlow库中定义许多“语言”特性(比如Tensor类型),而不必对语言和编译器进行侵入性的更改

    Swift for TensorFlow特性和功能的实现还没有完成,但是我们对项目在实践中的进展感觉良好。也就是说,我们非常希望看到我们正在探索的算法被其他语言和社区应用!