共计 5161 个字符,预计需要花费 13 分钟才能阅读完成。
我们很高兴宣布Polynote的开源发布:一个新的多语言笔记本,具有一流的Scala支持,Apache Spark集成,包括Scala,Python和SQL在内的多语言互操作性,按需输入自动完成功能等等。
Polynote为数据科学家和机器学习研究人员提供了一个笔记本环境,使他们可以自由地将我们基于JVM的ML平台(大量使用Scala)与Python生态系统的流行机器学习和可视化库无缝集成。它已经在Netflix的个性化和推荐团队中得到了广泛采用,并且现已与我们的其他研究平台集成在一起。
在Netflix,我们一直对与开源社区共享充满信心,并相信Polynote在满足Netflix之外的类似需求方面具有巨大的潜力。
功能概述
重现性
Polynote通过设计提高笔记本的可重复性。通过在执行笔记本时考虑单元在笔记本中的位置,Polynote有助于防止使笔记本难以从顶部重新运行的不良做法。
编辑改进
Polynote提供了类似IDE的功能,例如交互式自动完成和参数提示,内联错误突出显示以及具有LaTeX支持的富文本编辑器。
能见度
Polynote UI通过显示内核状态,突出显示当前正在运行的单元代码以及显示当前正在执行的任务,提供对内核状态的快速了解。
多种语言
笔记本中的每个单元格都可以用不同的语言编写,并且它们之间共享变量。目前支持Scala,Python和SQL单元格类型。
依赖性和配置管理
Polynote提供了保存在笔记本本身中的配置和依赖关系设置,并有助于解决Spark开发人员通常遇到的一些依赖关系问题。
数据可视化
本地数据探索和可视化功能可帮助用户了解更多有关其数据的信息。与matplotlib和Vega集成,使高级用户可以通过精美的可视化工具与他人进行通信
重新定义Scala使用体验
在Netflix个性化基础架构团队中,我们的工作是通过构建可消除痛点并使研究人员专注于研究的工具来加速机器学习创新。Polynote源自对现有笔记本工具缺点的不满,尤其是在对Scala的支持方面。
例如,虽然Python开发人员习惯于在使用具有相对较少数量依赖关系的程序包管理器构建的环境中工作,但Scala开发人员通常在基于项目的环境中使用构建工具来管理数百个(通常)冲突的依赖关系。借助Spark,开发人员可以在集群计算环境中工作,无论使用哪个节点,都必须确保他们的分布式代码在一致的环境中运行。最后,我们发现用户对笔记本电脑中的代码编辑体验也感到沮丧,尤其是习惯于使用IntelliJ IDEA或Eclipse。
一些问题是笔记本电脑体验所特有的。记事本执行是在特定环境中的特定时间点运行的特定代码段的记录。将代码,数据和执行结果组合到一个文档中,使notebook功能强大,但也难以复制。的确,科学计算界已经记录了一些notebook的可复制性问题以及可复制笔记本的一些最佳实践。
最后,ML空间可能特有的另一个问题是需要多语言支持。机器学习研究人员通常使用多种编程语言工作-例如,研究人员可能使用Scala和Spark生成训练数据(清理,二次采样等),而实际的训练可能是使用流行的Python ML库(例如tensorflow或scikit-learn)完成的。
接下来,我们将更深入地了解Polynote的功能。
通过设计可复制
Polynote的两个指导原则是可复制性和可见性。为了实现这些目标,我们最早的设计决策之一是从头开始构建Polynote的代码解释,而不是像传统笔记本一样依赖REPL。
我们认为,虽然REPL总体上不错,但它们根本不适合notebook。为了了解REPL和notebook,让我们看一下典型notebook环境的设计。
notebook是单元格的有序集合,每个单元格可以保存代码或文本。每个单元格的内容可以独立修改和执行。单元格可以重新排列,插入和删除。它们还可以取决于notebook中其他单元的输出。
将此与REPL环境进行对比。在REPL会话中,用户一次将一个表达式输入提示。一旦评估,表达式及其评估结果是不变的。评估结果将附加到下一个表达式可用的全局状态。
不幸的是,这两个模型之间的脱节意味着在使用REPL会话评估单元代码的典型笔记本环境中,当用户与notebook交互时会导致隐藏状态的产生。单元可以以任何顺序执行,从而使此全局隐藏状态发生变化,进而影响其他单元的执行。通常,notebook无法从顶部可靠地重新运行,这使得它们很难复制和与他人共享。隐藏状态还使用户难以推理笔记本中发生的事情。
从头开始编写Polynote的代码解释可以使我们摆脱这种全局的可变状态。通过跟踪每个单元格中定义的变量,Polynote会基于在其上方运行的单元格为给定单元格构建输入状态。使单元格的位置在其执行语义中很重要,可以强制执行最小意外原则,从而允许用户从上至下阅读notebook。通过使顺序运行notebook更有可能工作来确保可重复性。
编辑人性化
让我们面对现实吧-对于曾经使用过IDE的人来说,在notebook中编写大量的代码就像回到几十年前。我们已经看到用户更喜欢在IDE中编写代码,然后将其粘贴到notebook中以便运行。提供成熟的现代IDE的所有功能并不是我们的目标,但代码编辑方面的一些增强功能对改善可用性大有帮助。
能见度
如前所述,可见性是Polynote的指导原则之一。我们希望可以轻松地在任何给定时间查看内核的功能,而无需深入研究日志。为此,Polynote提供了各种UI处理方法,可让用户知道发生了什么。
这是代码执行过程中Polynote的快照。
一次浏览此UI即可为用户提供大量信息。首先,从笔记本视图和任务列表都可以清楚地看到单元1当前正在运行。我们还可以看到,单元2到4按此顺序排队运行。
我们还可以看到当前正在运行的确切语句以蓝色突出显示-定义了值sumOfRandomNumbers的行。最后,由于评估该语句会启动Spark作业,因此我们还可以在任务列表中看到作业级和阶段级的Spark进度信息。
这是该执行过程的动画,因此我们可以看到Polynote如何使跟踪内核状态变得容易。
符号表提供了对notebook内部状态的了解。选择一个单元格后,符号表会在黑线上方显示当前单元格执行所产生的任何值,并在该线下方显示该单元格可用的任何值(来自先前的单元格)。在动画的结尾,我们显示符号表在依次单击每个单元格时更新。
最后,内核状态区域提供有关内核执行状态的信息。在下面,我们以内核的状态从空闲和连接状态(绿色)变为繁忙(黄色)的状态变化的特写视图。其他状态包括灰色的断开连接,红色的死机或未启动。
多种语言
您可能已经在前面显示的屏幕快照中注意到,每个单元格的工具栏中都有一个语言下拉列表。这是因为Polynote支持真正的多语种笔记本,其中每个单元格都可以用不同的语言编写!
运行单元格时,内核将可用的类型化输入值提供给单元格的语言解释器。反过来,解释器将结果输入的输出值提供回内核。这使Polynote notebook中的单元可以在相同的上下文中运行,并使用相同的共享状态,而与它们定义的语言无关,因此用户可以为手头的工作选择最佳工具。
这是一个使用python库scikit-learn来计算使用Scala生成的数据集的等渗回归的示例。该代码改编自scikit-learn网站上的等渗回归示例。
如该示例所示,Polynote使用户可以在同一笔记本中流畅地从一种语言切换到另一种语言。
依赖和配置管理
为了更好地促进可重复性,Polynote将配置和相关性信息直接存储在笔记本本身中,而不是依赖于外部文件或群集/服务器级别的配置。我们发现直接在notebook 代码中管理依赖项比较麻烦,并且可能会使用户感到困惑。而是,Polynote提供了一个用户友好的“配置”部分,用户可以在其中为每个笔记本设置依赖性。
通过这种配置,Polynote可以为notebook构造一个环境。它在本地获取依赖关系(使用Coursier或pip从存储库获取依赖关系),并将Scala依赖关系加载到隔离的ClassLoader中,以减少与Spark库发生类冲突的机会。Python依赖项被加载到隔离的virtualenv中。在Spark模式下使用Polynote时,它将为使用提供的配置的笔记本计算机创建Spark Session。Python和Scala依赖关系会自动添加到Spark Session。
数据可视化
笔记本电脑最重要的用例之一是能够浏览和可视化数据。Polynote与两个最受欢迎的开源可视化库Vega和Matplotlib集成。
尽管matplotlib集成在notebook中是非常标准的,但是Polynote还具有对数据浏览的本机支持-包括数据模式视图,表检查器,图构造器和Vega支持。
我们将使用Kaggle的Wine Reviews数据集,通过使用上述工具的简单数据示例,进行一些数据分析和探索。首先,这是一个简单的示例,仅将数据加载到Spark中,查看Schema,对其进行绘制并将其保存在笔记本中。
让我们专注于我们在这里看到的一些内容。
如果单元格的最后一条语句是表达式,则会将其分配给单元格的Out变量。Polynote将以其数据类型确定的方式显示结果的表示形式。如果是类似表格的数据类型,例如DataFrame或case类的集合,Polynote会显示快速检查器,使用户可以一目了然地看到架构和类型信息。
快速检查器还提供了两个用于调出完整数据检查器的按钮-左侧的按钮调出表格视图,而右侧的按钮调出绘图构造器。该动画还显示了绘图构造器,以及用户如何拖放度量和尺寸以创建不同的绘图。
我们还将展示如何将绘图作为自己的单元格保存到notebook中。由于Polynote本身支持Vega规格,因此保存图仅需插入具有生成规格的新Vega单元。与任何其他语言一样,Vega规范可以利用多语言支持来引用以前单元格中的值。在这种情况下,我们使用Out值(一个DataFrame)并对其执行附加聚合。这样就可以进行有效的绘图,而不必将数百万个数据点带给客户端。Polynote的Vega规范语言提供了一个API,用于聚集和修改类似表格的数据流。
Vega单元不需要使用plot构造函数进行创作-可以将任何Vega规范放入Vega单元中并直接绘制,如下所示。
除了单元格结果值,还可以单击一下来检查符号表中的任何变量。
未来
我们在这里描述了Polynote的一些关键功能。我们很荣幸通过开放源代码广泛共享Polynote,我们很高兴听到您的反馈。立即访问我们的网站或直接访问代码,开始尝试一下,让我们知道您的想法!看一下我们当前未解决的问题,看看我们正在计划什么,当然,始终欢迎PR!Polynote仍处于起步阶段,因此您可能会遇到一些粗糙的边缘。它也是一个强大的工具,可以执行任意代码(“功能强大,责任重大”),因此请在环境中使用时意识到这一点。
前方还有许多激动人心的工作。我们对Polynote的潜力非常乐观,我们希望向社区学习,就像我们希望他们将从Polynote中获得价值一样。如果您有兴趣从事Polynote或其他机器学习研究,工程和基础设施问题,请访问Netflix Research网站以及一些最新的职位。
致谢
Netflix的许多同事在Polynote开发的早期阶段就为我们提供了帮助。我们要对Aish Fenton,Hua Jiang,Kedar Sadekar,Devesh Parekh,Christopher Alvino和许多其他早期采用Polynote的人提供深思熟虑的反馈表示由衷的感谢。