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 functions
const { range, len } = boa.builtins();
const list = range(0, 10); // create a range array
console.log(len(list)); // 10
console.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.5this.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 作为不错的开始:

alibaba/pipcook​github.com

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

boa支持https_Boa: 在 Node.js 中使用 Python相关推荐

  1. 在node.js中,使用基于ORM架构的Sequelize,操作mysql数据库之增删改查

    Sequelize是一个基于promise的关系型数据库ORM框架,这个库完全采用JavaScript开发并且能够用在Node.JS环境中,易于使用,支持多SQL方言(dialect),.它当前支持M ...

  2. node/js 漏洞_6个可用于检查Node.js中漏洞的工具

    node/js 漏洞 Vulnerabilities can exist in all products. The larger your software grows, the greater th ...

  3. node mongoose_如何使用Express,Mongoose和Socket.io在Node.js中构建实时聊天应用程序

    node mongoose by Arun Mathew Kurian 通过阿伦·马修·库里安(Arun Mathew Kurian) 如何使用Express,Mongoose和Socket.io在N ...

  4. node.js中模块_在Node.js中需要模块:您需要知道的一切

    node.js中模块 by Samer Buna 通过Samer Buna 在Node.js中需要模块:您需要知道的一切 (Requiring modules in Node.js: Everythi ...

  5. 修改js文件需要重启服务器,关于Node.js中频繁修改代码重启服务器的问题

    我们可以使用一个第三方命名行工具,nodemon 来帮我们解决频繁修改代码重启服务器问题. nodemon 是一个基于 Node.jsNode.js 开发的第三方命令行工具,我们使用的时候需要独立安装 ...

  6. 如何在node.js中发出HTTP POST请求?

    如何在node.js中使用数据发出出站HTTP POST请求? #1楼 如果您使用请求库,这会变得更容易. var request = require('request');request.post( ...

  7. c语言socket句柄函数传递,通过源码解析 Node.js 中进程间通信中的 socket 句柄传递...

    在 Node.js 中,当我们使用 child_process 模块创建子进程后,会返回一个 ChildProcess 类的实例,通过调用 ChildProcess#send(message[, se ...

  8. [原] 探索 EventEmitter 在 Node.js 中的实现

    你有没有想过,为什么浏览器的 div 上可以绑定多个 onclick 事件,点击一下 div 可以触发全部的事件,jquery 的 .on(),.off(),one() 又是如何实现的?Node.js ...

  9. import export php,import与export在node.js中的使用方法

    import与export是es6中模块化的导入与导出,node.js现阶段不支持,需要通过babel进行编译,使其变成node.js的模块化代码.(关于node.js模块,可参考其他node.js模 ...

最新文章

  1. android 应用间共享数据,调用其他app数据资源
  2. links下c语言中for的作用是,C语言开发注意事项
  3. Qt多线程 TCP 服务端
  4. Visual studio代码行数统计
  5. Project FreeEIM 2.0:重现失落的飞鸽传书
  6. c++primer 第2章 练习题答案 (尚未完善 陆续补充中 基本上已经完成)
  7. binwalk 提取bootimg_boot.img的解包与打包
  8. python 读取csv_Python实现CSV数据的读取--两种方法实现
  9. 记录利用CSS完美解决前端图片变形问题
  10. MT4系统自带指标代码
  11. 面试常考的7道智力题,再也不怕面试官刁难
  12. 初窥 RAP:如何使用 RAP 进行接口文档管理
  13. SQL,从熟练到掌握
  14. java获取手机通讯录权限_Android读取手机通讯录联系人到自己项目
  15. 测试人员应看重「业务测试能力」
  16. 1GB等于多少MB?
  17. STM32如何快速驱动一款12864LCD液晶模块 3分钟点亮 STM32例程
  18. java课程设计qq_Java课程设计(qq聊天程序)
  19. PHP array_filter无法传变量过滤的小坑
  20. emqx broker安装

热门文章

  1. JavaScript兼容HTML代码的注释
  2. python常见的错误总结
  3. CentOS6.X 系统安装图文教程,超详细
  4. 安卓平台运行python_在 android 上运行 python 的方法
  5. python os 获取当前路径的绝对路径的上层目录_os 模块常用函数
  6. SQL优化|Java面试题
  7. jQuery的$.fn使用
  8. python looper_入门级python线程问题
  9. log4j写入mysql数据库_log4j日志写入数据库
  10. linux下创建多进程,linux之多进程fork:进程创建