Pipcook 1.0开源!前端开发者的机器学习工具箱
希望大家在阅读后,能够了解到 Pipcook 现在已经做了哪些,后面想要做什么?Pipcook 对社区正式发布的 1.0 版本,都有哪些功能?也欢迎对前端智能化有想法的同学加入。
什么是机器学习?
在开始正式介绍 Pipcook 之前,我们先为一些新手同学科普下什么是机器学习,若你已经了解,可以直接跳过。
机器学习发展至今,已经成为了一种全新的思维模式,不同于我们传统的编程思维,因为后者在思考和工作的过程中,虽然有明确的计算机分层,但最终从上至下的逻辑都是清晰可见的,也是易于解释的,而对于应用程序本身,要么是按照 OO 的思想在设计虚拟世界中的每一个实体和抽象,亦或者 FP 中的输入与输出,总而言之,我们在设计时,必须对细节了然于胸。
但对于机器学习来说,其思维方式更像是通过代码构建了一个在通用与不通用之间的数据结构(即模型),然后将真实的数据输入到这个数据结构中,不同的数据输入就能产生不同的结果,而我们把这个产生的过程称为训练。对于一个问题而言,已经不需要我们将具体的操作步骤完全定义出来了,我们让机器取代我们的思考过程,从数据中去学习潜在的规律,这样的方式更适合一些更为复杂的问题,比如当很多数据产生时,人脑已经很难进行归纳和抽象时,往往使用机器学习会取得更好的效果。
所以,可以看得出来,机器学习并非是为了完全取代人类。相反,正如一开始蒸汽革命与电气革命一样,机器学习是取代那部分对于人类来说繁琐,难以归纳和抽象的工作,而人类将借助于机器学习,可以站在更高的角度去解决遇到的问题。
为了理解方便,可以把机器学习分为了视觉和文本两大类,其中每一类都包括了对应的一些任务,如下:
比如在前端智能化最常见的设计稿生成代码的场景中,就使用了图片分类和目标检测来提取设计稿的信息,提供给代码生成器。
AI ❤️ JavaScript
机器学习正在高速发展的过程中,无论是推荐系统、计算机视觉、自然语言处理、还是各种语音识别和自动驾驶技术,在机器学习的加持下,都在不断地变得越来越好用和可靠。
但作为前端工程师的我们,尽管社区内已经有了 Tensorflow.js、ONNX.js 等前辈存在,但机器学习离 JavaScript 开发者仍然很远,原因有二:
JavaScript 自身所沉淀的机器学习生态仍然不够成熟和稳定;
JavaScript 对于机器学习/深度学习最前沿的算法和模型的支持总是滞后的;
那么 Pipcook 究竟是如何解决以上两个问题并让 AI 爱 JavaScript 的呢?答案之一就是 —— Boa,在 Pipcook 的设计哲学中,我们并不迷信所谓的 JavaScript 邪教 —— “任何能被 JavaScript 重写的都将会使用 JavaScript 重写”,Pipcook 开发团队更在意用户的使用体验,而非使用何种语言去实现它。
从上图可以看出来,我们在构建 Pipcook 的过程中,使用了多种编程语言和技术,其中 TypeScript 和 JavaScript 加起来仅不到 25%。
在 Pipcook 中,通过 Boa 提供了无缝使用 Python 生态的能力,解决了机器学习与 JavaScript 的物理距离,但还剩下所谓的“理论”距离 —— 让前端工程师进化为机器学习软件工程师。
如果说通过 Node.js,能帮助前端工程师转职成为服务端工程师,那么 Pipcook 在这方面,也希望成为前端工程师们进阶为机器学习软件工程师的利器。
为什么会有 Pipcook?
imgcook、idaecook、reviewcook ......统称为前端智能化项目,比如 ideacook,解决的是如何从产品文档生成产品代码的场景、imgcook 解决的是如何从视觉稿生成业务代码的问题,而 reviewcook 则是帮助我们解决一些代码上线前的智能化回归验证。
Pipcook 的定位就是为上述这些智能化项目提供夯实可靠的机器学习平台,让前端人员就能完成上面提到的那些事情。
那么,在了解了为什么会有 Pipcook 之后,就来看看 Pipcook 本身的项目定义:
Pipcook 是一个为前端工程师打造的机器学习工具集
与此同时,Pipcook 引入了两个不算太新的概念:
Pipeline 作为目前 Pipcook 最核心的功能提供,用于描述(JSON)并构建单个机器学习模型;
PipApp 作为实验性质的功能提供,它通过提供更高级的使用方式,屏蔽了模型部署和训练的细节,让工程师只需关注机器学习的“业务逻辑”;
另外,Pipcook 分别提供了 Pipcook Tools(命令行工具)和 Pipboard(GUI 工具)来让用户使用 Pipeline 和 Pipboard。
什么是 Pipeline
在了解了机器学习与 Pipcook,接下来就可以学习 Pipcook 中的 Pipeline 了。
整个过程我们通过下图来做一个简单的说明:
这条 Pipeline 是从左下方开始的:
data collect 插件按照机器学习任务的类型(视觉/文本),将输入的数据集转成 Pipcook 内部标准的数据格式,PascalVoc 与 CSV;
data access 插件则负责将 Pipcook 标准数据集格式转换为模型需要的 UniDataset,当中,如果配置了 data process 流程,会将数据集中的每一行数据通过 data process 进行预处理;
处理好的 UniDataset 就分为元信息和训练集两个部分,分别传到 model define 和 model train 插件;
model define 插件通过数据集的元信息来定义模型的形状和结构,定义完成后进入下一阶段;
model train 插件通过将 UniDataset 中的训练集输入到定义的模型中进行训练,完成后进入下一个阶段;
model evaluate 插件将 UniDataset 中的测试集输入到训练好的模型中,以此来对模型最终的效果进行评估,若结果满足要求,则输出可以使用的模型;
以上就是一个基本的 Pipeline 流程,那么我们来看看 Pipeline 具体是长什么样子:
{
"plugins": {
"dataCollect": {
"package": "@pipcook/plugins-mnist-data-collect",
"params": {
"trainCount": 8000,
"testCount": 2000
}
},
"dataAccess": {
"package": "@pipcook/plugins-pascalvoc-data-access"
},
"dataProcess": {
"package": "@pipcook/plugins-image-data-process",
"params": {
"resize": [224, 224]
}
},
"modelDefine": {
"package": "@pipcook/plugins-tensorflow-mobilenet-model-define",
"params": {
"batchSize": 8,
"freeze": true
}
},
"modelTrain": {
"package": "@pipcook/plugins-image-classification-tensorflow-model-train",
"params": {
"epochs": 15
}
},
"modelEvaluate": {
"package": "@pipcook/plugins-image-classification-tensorflow-model-evaluate"
}
}
}
从上图可以看到 Pipeline 十分简单,只需要按照预先定义的字段配置你需要的插件及参数即可,然后再通过 Pipcook Tools 来运行它就行了:
$ pipcook run https://foobar.xzz/mobilenet-classification.json
Pipcook Tools 支持运行本地和远程的 Pipeline,这意味着开发者可以通过 CDN、GitHub 或者任意 HTTP 服务来分享你的 Pipeline。
在经过一定时间的训练之后,就会在当前目录下的 output 文件夹下看到生成的模型文件和相关的 JavaScript 库了:
生成的模型包
生成后的使用方式也十分简单:
$ cd ./output && npm install
$ node -e "require('./output')('input data')"
除此之外,你也可以通过 Pipboard 随时下载历史的训练结果,如下图所示:
为了方便开发者使用,Pipcook 已经内置了一些任务类型的 Pipeline:
文本类
文本分类:text-bayes-classification(基于朴素贝叶斯的分类)、fasttext-classification(基于 FastText 的文本分类)
文本创作:chinese-poem-creation(生成中国诗歌)
视觉类
图片分类:mobilenet-image-classification(基于 mobilenet 的图片分类)
目标检测:object-detection(基于 detectron2 开发的目标检测)
图片风格迁移:image-generation-cycle-gan(基于 CycleGAN 的图片生成)
如何开发插件
通过上面的介绍,读者基本已经了解了 Pipcook 主要的使用场景了,对,那就是 —— Pipeline,但要说到 Pipeline 却离不开插件,我们为 Pipcook 的 Pipeline 生态构建了一套开放的插件机制,通过这套机制,任何开发者都可以随时随地基于 Node.js 为 Pipcook 拓展插件。
首先,一个插件,也是一个 NPM 包,在 NPM 包的基础上,Pipcook 增加了一些拓展字段,即在 package.json 中增加了一些额外的定义,下面就是一个简单的定义:
{
"name": "my-own-pipcook-plugin",
"version": "1.0.0",
"description": "my own pipcook plugin",
"dependencies": {
"@pipcook/pipcook-core": "^0.5.0"
},
"pipcook": {
"category": "dataCollect",
"datatype": "image"
},
"conda": {
"python": "3.7",
"dependencies": {
"tensorflow": "2.2.0"
}
}
}
首先,每个插件都必须依赖 @pipcook/pipcook-core,它包含了实际定义插件所依赖的类型定义和一些工具函数。然后是 "pipcook" 节点,它定义了插件的基本信息,比如类别和数据类型,它用于 Pipcook 对插件本身做归类和整理,接下来就是 "conda" 节点(可选),如果插件依赖 Python 环境,那么开发者可以通过这个字段配置 Python 的依赖,比如上述就表示插件依赖 Python 版 tensorflow@2.2.0,在 Pipcook 安装插件时就会自动进行安装。
定义好这些基本信息后,就可以开始写具体的插件代码了,还记得前面在说明 Pipeline 流程时的那张图吗?每一种插件类型的写法都是不一样的,比如一个简单的 data collect 插件如下:
const collectTextline: DataCollectType = async (args: ArgsType): Promise<void> => {
const { uri, dataDir } = args;
await fs.copy(uri, dataDir + '/my-own-dataset.csv');
return null;
};
export default collectTextline;
插件的输入是 ArgsType,输出是 void,那么来看看 data process 插件:
const doubleSize: DataProcessType = async (sample: Sample, metadata: Metadata, args?: ArgsType): Promise<void> => {
// double the data
sample.data = sample.data * 2;
};
export default doubleSize;
看,无论是输入的参数还是函数返回值,都不一样了。但读者也不需要害怕,Pipcook 中的插件类型都是固定的,并且每一种插件的写法和类型定义也都定义好了,具体可以阅读 Pipcook 的插件规范文档。
另外,正如在开篇所说的,Pipcook 通过 Boa 提供了无缝接入 Python 生态的能力,也正因为这种能力,才帮助 JavaScript 社区解决了机器学习生态成熟度和前沿技术使用的问题,那么究竟如何开始使用 Boa 呢?
首先,在 package.json 中的依赖中添加 @pipcook/boa 及对应版本,另外在 "conda.dependencies" 中添加依赖的 Python 包,然后就能在插件中使用了:
const boa = require('@pipcook/boa');
const tensorflow = boa.import('tensorflow');
PipApp(实验功能)
Pipcook 开发团队一直在思考什么样的编程方式,能让前端工程师更容易地使用机器学习,未来机器学习究竟会在前端领域是什么样的呢?因此我们开发了 PipApp,为开发者屏蔽掉了更多技术细节,让开发者只需要关注机器学习的“业务逻辑”。
下面我们来看看一个 PipApp 长什么样:
import { createLearnable, nlp } from '@pipcook/app';
const isCooking = createLearnable(async function(sentence: string) {
return (await nlp.classify(sentence));
});
const isBooking = createLearnable(async function(sentence: string) {
return (await nlp.classify(sentence));
});
(async () => {
console.log(await isCooking('test'));
console.log(await isBooking('booking test'));
})();
上面的例子,首先通过 createLearnable 创建了一个机器学习上下文,你可以把它理解成一种特殊的 async function,只有在 Learnable 函数块中才能使用 PipApp 提供的机器学习 API。上面的例子,分别创建了两个机器学习流程,在其中都使用了 nlp.classify 来完成一个文本分类的任务。
与运行 Pipeline 不同,PipApp 需要创建一个完整的项目目录,因此在开始之前,我们需要从初始化一个 Node.js 项目开始。
$ npm init
$ npm install @pipcook/app --save
创建好项目以及完成代码之后,就可以开始编译项目了,它的主要目的是分析项目代码并生成对应的 Pipeline 和项目文件。
$ pipcook app compile /path/to/your/project/script.ts
generated 2 pipelines, please click the following links to config them:
(nlp.classify) > http://localhost:6927/index.html#/pipeline/info?pipelineId=1a287920-b10e-11ea-a743-792a596edff1
(nlp.classify) > http://localhost:6927/index.html#/pipeline/info?pipelineId=1a287921-b10e-11ea-a743-792a596edff1
执行完命令后,会提示配置 Pipeline,通过链接点击进去去配置即可,开发者需要根据不同的调用接口来配置不同的数据,比如第一个分类是为了对产品进行分类,那么我们配置 Pipeline 的时候,就要准备跟产品分类相关的数据集。
当配置完成后,保存 Pipeline,就可以开始训练了:
$ pipcook app train /path/to/your/project/script.ts
当所有模型训练完成后,就可以开始构建最终的应用包了,构建完成后,会在目录下生成 {filename}.ml.js 文件,使用 Node.js 运行即可:
$ pipcook app build /path/to/your/project/script.ts
$ node /path/to/your/project/script.ml.js
简单地说,当用户希望将多个模型放在一起使用时,PipApp 能更加方便地将这些模型的使用逻辑与调用关系结合在一起,就好像现在在 Node.js 中调用 API 一样,唯一的不同在于写好的代码仍然不能立即执行,需要将所有生成的模型训练完成后才可以运行。
ROADMAP
如果说 Pipcook 1.0 是开发团队对于前端智能化的一次社区输出,那么接下来,就是 Pipcook 会积极采纳社区的输入,一起将 Pipcook 变得更易于使用,易于分享和易于理解,围绕着这些“易于”,开发团队将会在下面几个方面努力:
让插件安装变得更稳定、快速
让插件开发变得更方便
让插件分享变得更容易
让 Pipeline 的执行更快,资源占用更少
让 Pipboard 变得更有用、好用
在接下来的3个月内,我们也会和阿里菜鸟的同学一起合作,将强化学习的能力拓展到 Pipcook 工具集中,相信有了强化学习的加持,无论是 PipApp 还是 Pipeline,都能完成更加自然和完整的机器学习工程,为前端智能化带来不一样的感受。
最后,Pipcook 前端智能化的目标与阿里云负责机器学习前端的小伙伴一拍即合,因此我们也会与阿里云合作,推出针对前端工程师的机器学习解决方案,并且努力为机器学习新手们争取到尽量免费的训练资源,节省入门的算力成本。
淘系技术部 - FX Team
目前团队有较多高校和海外背景的技术小二,专业领域涉及前端、算法、全栈等。
我们在 D2C(Design to Code) 领域开放了 Imgcook 平台,在逐步释放阿里生态的前端生产力;我们也与 Google 的 tensorflow 团队保持长线合作,基于 tfjs-node 之上,开源了我们的前端算法工程框架 Pipcook,在引领前端行业向智能化时代迈进。
简历投递📮:suchuan.cyf@alibaba-inc.com