【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

Boa: 在 Node.js 中使用 Python

  • 2020-04-21
  • 本文字数:3072 字

    阅读完需:约 10 分钟

Boa: 在 Node.js 中使用 Python

Hello,大家好,有一段时间不见了。


这次主要给大家带来一个好东西,它的主要用途就是能让大家在 Node.js 中使用 Python 的接口和函数。可能你看到这里会好奇,会疑惑,会不解,我 Node.js 大法那么好,干嘛要用 Python 呢?如果你之前尝试了解过一些机器学习的 JavaScript 的应用,就会比较清楚这背后的原因。


现状是机器学习生态几乎是捆绑在 Python 这门语言在高速迭代着的,而 JavaScript 只能望其项背,如果我们期望从零做到 Python 如今的规模,需要付出的工作量是巨大的,这个我在几年前写了 tensorflow-nodejs 的时候,就已经这么觉得了。


所以,我们就必须换一个思路,既然无法超越你,那么就利用你。对于脚本语言的开发者来说,其实并不在意底层是如何实现的,只要上层的语言和接口是我熟悉的就好,因此 Boa 就是为此而诞生的一个 Node.js 库,它通过桥接 CPython 来让 JavaScript 具备访问 Python 生态的能力,另外又借助于 ES6 新特性,来为使用者提供无缝的开发体验,那么到底是如何的体验呢?


下面来看一个简单的例子:


const boa = require('@pipcook/boa');const os = boa.import('os');console.log(os.getpid()); // prints the pid from python.
// using keyword arguments namely `kwargs`os.makedirs('..', boa.kwargs({ mode: 0x777, exist_ok: false,}));
// using bult-in functionsconst { range, len } = boa.builtins();const list = range(0, 10); // create a range arrayconsole.log(len(list)); // 10console.log(list[2]); // 2
复制代码


是不是很简单呢,只需要通过 boa.import 将 Python 的对象加载进来后,剩下的对象访问、函数调用以及数组访问都与我们使用 JavaScript 毫无区别。


const boa = require('@pipcook/boa');const { len, tuple, enumerate } = boa.builtins();const torch = boa.import('torch');const torchtext = boa.import('torchtext');const { nn, optim } = torch;
class TextSentiment extends nn.Module { constructor(sizeOfVocab, dimOfEmbed, numOfClass) { super(); this.embedding = nn.EmbeddingBag(sizeOfVocab, dimOfEmbed, boa.kwargs({ sparse: true, })); this.fc = nn.Linear(dimOfEmbed, numOfClass); this.init_weights(); } init_weights() { const initrange = 0.5 this.embedding.weight.data.uniform_(-initrange, initrange); this.fc.weight.data.uniform_(-initrange, initrange); this.fc.bias.data.zero_(); } forward(text, offsets) { const embedded = this.embedding(text, offsets); return this.fc(embedded); }}
复制代码


上面的例子除了示例了如何从 JavaScript 中继承自一个 Python 的类之外,还展示了我们如何使用 PyTorch 来创建一个模型,这是不是很 JavaScript 呢?


值得一提的是,在 Boa 的代码中,没有对 PyTorch 做过任何的封装,只要你在本地通过 Python 安装了对应的包就可以像上面的代码一样使用了,所以理论上你可以对任何 Python 包做上面所做的事情。


接下来,我们分别介绍一些主要的方法。

builtins()

Python 会内置一些常用的方法在 builtin 中,具体的 API 列表在:


https://docs.python.org/3.7/library/functions.html


那么 Boa 也提供了对应的方法:


const { len, list, range } = boa.builtins();
复制代码

import(name)

除了内置的方法外,最重要的功能便是加载 Python 包,那么 import 就是做这个事儿的。


const np = boa.import('numpy');
复制代码

kwargs(map)

接下来是 Python 中的关键字参数(Keyword Arguments),在 Python 中,提供了一种使用 Map 的方式来表示参数,如:


foobar(100, x=10, y=20)
复制代码


它能更好地帮助调用者了解每个参数的含义,为此,在 Boa 中增加了 kwargs 方法来支持这种用法:


foobar(100, boa.kwargs({ x: 10, y: 20 }));
复制代码

with(ctx, fn)

With 可能对于一些熟悉 JavaScript 历史的人会比较眼熟,但 Python 中的 with,用法和目的并不与 JavaScript 相同,Python 中的 with 语句有点类似于 JavaScript 中的 Block Scoping:


with(localcontext()) {  # balabala}
复制代码


上面的 Python 代码是将 localcontext() 的状态保存下来,然后开始执行 with 语句中的块代码,最后,将 localcontext() 的状态释放。


内部的实现机制就是每个传到 with 语句中的变量需要实现两个方法:enter 和 exit,然后分别在块代码执行前后调用,因此对于 Boa 中的用法,如下:


boa.with(torch.no_grad(), () => {  const output = model(text, offsets);  const loss = criterion(output, cls);  validLoss += loss.item();  validAcc += boa.eval`(${output.argmax(1)} == ${cls}).sum().item()`;});
复制代码


上面的例子是 PyTorch 中一个普通的计算模型效果的逻辑,首先通过 torch.no_grad() 设置了一个上下文,然后开始执行计算的代码,在块代码执行结束后,会自动将状态恢复。

eval(str)

最后一个要说的,就是动态的执行一些 Python 表达式(单行),为什么要提供这么一个方法呢?这还是要说回 Python 的优势,在一些很复杂的数据处理的场景,往往 Python 表达式还是能非常简单易懂地表达,这样就大大地减少了代码的复杂度,我们先来看一个例子:


const line = (boa.eval`'\t'.join([str(x) for x in ${vec}])`);
复制代码


上面的代码如果要换成 JavaScript 的话:


vec.map(x => x.toString()).join('\t');
复制代码


看着似乎差不多了多少是吧?那么再来看看下面的例子:


boa.eval`{u:i for i, u in enumerate(${vocab})}`;boa.eval`[${char2idx}[c] for c in ${text}]`boa.eval`${chunk}[:-1]`boa.eval`${chunk}[0:-1:2]`
复制代码


怎么样,是否是感觉上面的例子已经没法使用 JavaScript 简单的一行就能搞定了呢?


不过值得一提的是,JavaScript 在这方面也在渐渐地弥补,这里 是整理的一些 TC39 正在做的一些相关的标准,其中就包括上面的 Slice Notation。


说回到 eval 的定位,它像是对 JavaScript 的补充,它在一些标准还未落地和稳定之前,可以让我们使用 Python 表达式来更简单地表达,而所需要的仅仅是一些低成本的学习即可。


接下来就说说 eval 到底如何使用,它接受一个“字符串”,但我们一般在使用时都会通过 Template String,下来先看两个例子:


boa.eval('print("foobar")');boa.eval(`print("${txt}")`);
复制代码


看完上面两行代码,它们是比较少见的用法。真正常用,也是最能发挥出 eval 效果的是使用 Tagged Template String,这种用法就像我们一开始看到的一样,在 eval 后面直接跟模版字符串的内容,这样做的好处是 eval 函数会接收到所有的模版参数,这样我们便可以将 JavaScript 的对象和 Python 表达式打通,实现更平滑的使用体验,如下:


const chunk = range(0, 10);boa.eval`${chunk}[0:-1:2]`
复制代码


上面就是把 chunk 传到了表达式中,再通过 Python 的 Slice Notation 语法去取到对应的值,最后返回到 JavaScript 的世界中。

尾声

好了,简单的 API 介绍就先到这里,如果想了解更多 API 和 Boa 的能力,可以到 Boa 的文档了解:


https://github.com/alibaba/pipcook/blob/master/docs/tutorials/want-to-use-python.md


另外,Boa 作为 Pipcook 的一个子项目,也非常欢迎大家来加入进来,对于想加入的同学可以通过这些 Issue 作为不错的开始:


https://github.com/alibaba/pipcook/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22


最后再说一下 Boa 的初衷,就是希望能让 Node.js 开发者更无缝地使用 Python 中丰富的机器学习生态。可以说,从今天开始,你就可以开始看着 Python 的文档,使用 JavaScript 来“学习和使用”机器学习和深度学习了!


2020-04-21 15:532707

评论 1 条评论

发布
用户头像
「望其项背」一般以否定句式使用
2020-04-22 10:44
回复
没有更多了
发现更多内容

大厂面试题:有了G1还需要其他垃圾回收器吗?我教你怎么答

Java 程序员 后端

天真,居然还有人认为java的参数传递方式是引用传递(1)

Java 程序员 后端

太全了吧!阿里面试官纯手打:金三银四跳槽必会Java核心知识点笔记整理

Java 程序员 后端

太厉害了,终于有人把TCP-IP协议整合成864页学习笔记了

Java 程序员 后端

在外包公司从Java后端干到安卓开发,你醒醒吧!,阿里大师推荐的这份Java开发必读书单

Java 程序员 后端

架构实战营总结

Mr.He

架构实战营

大厂面试官:千万级数据量的表,如何进行快速查询,springmvc源码书籍

Java 程序员 后端

质量基础设施一站式平台建设,NQI一站式系统开发

电微13828808271

复习54天二战字节跳动,终获offer定级2-2【面试答案,springboot底层原理面试题

Java 程序员 后端

天真,居然还有人认为java的参数传递方式是引用传递,互联网java工程师面试突击训练网盘

Java 程序员 后端

基础面试3:内存溢出 vs 内存泄漏,java自学教程视频

Java 程序员 后端

NQI一站式线上平台搭建,质量基础设施一站式服务

电微13828808271

多线程—可能你会遇到的多线程面试题都在这里了(含答案

Java 程序员 后端

图解Redis:一套方案轻松搞定数据库与缓存数据不一致问题

Java 程序员 后端

图说线性表-搞懂链表从这篇文章开始,2021必看-Java高级面试题总结

Java 程序员 后端

基于springboot开发的国际物流管理系统,花费近一年时间整理的Java核心知识清单

Java 程序员 后端

备战金三银四吃透这些Spring Boot笔记文档,让你超过90%的Java面试者

Java 程序员 后端

多线程详解第3讲:线程状态,感悟分享

Java 程序员 后端

太强了!阿里大神亲码“SpringCloud核心手册,2021Java常见笔试题

Java 程序员 后端

天才第一步!Java架构速成笔记必备精品成就年薪百万,掌门一对一java面试流程

Java 程序员 后端

基于Java NIO框架区别对比,spring教程下载

Java 程序员 后端

大厂面试题中爱问的「调度算法」(1),java后端技术栈图谱

Java 程序员 后端

大学毕业年的找工作和学习总结,java中级开发工程师面试题

Java 程序员 后端

太为难我了,阿里面试了7轮(5年经验,java百度图像识别接口

Java 程序员 后端

天天阿里,不如先吃透阿里技术官私藏的分布式笔记,最少能到P6

Java 程序员 后端

在SQL SERVER中实现RSA加解密函数,java入门书籍推荐

Java 程序员 后端

堪称零瑕疵!仅用了330页直接封神,我要吹爆这份RocketMQ笔记

Java 程序员 后端

大厂面试算法到底有多重要?学会这份算法宝典,随便暴打头条面试官

Java 程序员 后端

基于DRBD的KVM动态迁移,Java开发需要学什么

Java 程序员 后端

大厂面试题中爱问的「调度算法」,分享一波阿里、字节、腾讯、美团等精选大厂面试题

Java 程序员 后端

大四实习生”都四面成功拿到字节跳动Offer了,你还有什么理由去摸鱼

Java 程序员 后端

Boa: 在 Node.js 中使用 Python_大前端_徐明强_InfoQ精选文章