web开发者踏入人工智能的利器_Tensorflow.js
前言
最近公司向员工搜集公司杂志的文章,刚好最近学习了机器学习相关课程。为了赚取购买课程的费用,所以写了如下文章投稿赚取稿费。
如下文章可能涉及一些我所购买课程的内容,所以不便将所有资源进行展示。
当初写这篇文章的目的除了赚取公司的稿费外,还有就是给现有web开发的同事提供一些新的开发方向,认识新的开发领域。
一、人工智能、机器学习、Tensorflow三者关系
人工智能是近几年火热的话题,同时人工智能也是一门很庞大的学科。那么如何实现人工智能?机器学习就是其中一种实现方式。
机器学习又是什么?“机器学习”如同字面意思,让计算机自己学习提供的数据特征,最终达到识别相应的类似数据。
那么如何以编程的形式使程序拥有机器学习能力?Tensorflow库是一款很好的机器学习的编程库。而本文的Tensorflow.js是Tensorflow的JS版本。除了JS版本,Tensorflow还有Python、C++、Java等多种语言版本。
综上所述可以下图总结这三者关系:
二、为什么要学习机器学习
学习机器学习并不是为了蹭人工智能的热度,而是为了更好的迎接未来的发展趋势。现有绝大多数开发人员面向的是规则编程。根据规则写固定规则程序。但是需求的复杂性提高就无法再通过编写规则来编程。
比如产品需求要让程序识别猫的图片筛选出来做专题,那么程序猿不可能将所有猫的图片进行编写规则来识别,因为每新增一张图片就意味着要修改代码增加一个判断规则。这就是传统编程的短板。
学习人工智能,学习机器学习编程就是为了弥补这个短板,让程序能更好的适应未来复杂多变的需求。
三、为什么选择Tensorflow.js
本文主要是针对web开发者认识机器学习这个领域,而web开发者必备的语言技能就是Javascript。Tensorflow.js就是以纯Javascript来编写机器学习程序的开发库,而且运行环境可以选择浏览器,可以很好的可视化程序的训练过程。这就是本文选择Tensorflow.js的最重要原因。
除了这个重要原因,Tensorflow.js还有如下优势:
1、Tensorflow.js是开箱即用的开发库,开发者无需花精力去编写基础复杂的数学问题。
2、由于可运行于浏览器,减少服务器的运算,提高服务器资源利用,增强客户端响应运算结果的速度。
3、使用语言就是Javascript,前端工程师不需要学习其他后端语言,降低入门门槛。
4、由于浏览器的WebGL可调用GPU,所以Tensorflow.js会使用GPU加速模型的运算,提高运算效率。
5、由于Node和Python一样都是使用C++编写的环境,所以在Node环境进行运算的速度目前与Python速度不相上下。
6、Tensorflow.js的模型可以跟Python等其他语言模型进行互转。就是js写了一个机器模型可以转换模型到Python环境下使用。
7、浏览器可以很好可视化机器训练过程,同时浏览器可调用设备的摄像头、麦克风等增加机器学习的应用场景,让机器学习跟接近用户。
有优势比如有它的劣势:
1、部署在浏览器,js就是公开的,那么训练模型就是公开的,商业保密性低。
2、浏览器端不适合部署体积过大的训练模型,不然用户加载页面会相当耗时。
3、在Node环境目前无法做到分布式训练,使用多台服务器对一个模型进行大规模训练。
4、Tensorflow.js的社区活跃度、资源等方面都不如Python社区,但是可以从Python社区去寻找资源运用到js平台。
综合上面优劣,选择Tensorflow.js是为了进入机器学习领域,让web开发者体验到机器学习编程和传统的规则编程两者之间的不同。深入学习之后可以平滑过度到其他人工智能开发的开发库。
四、体验Tensorflow.js开箱即用编程
(一)安装和引用Tensorflow.js
在html页面中可直接引用一个js文件即可。cdn地址是:
https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js
npm安装使用:npm i @tensorflow/tfjs即可。
以上是浏览器端的安装方式,如果运行在node环境可选择安装node版本,
npm安装:npm i @tensorflow/tfjs-node。因为node版本是运行c++环境,所以在执行这个命令前需要下载很多c++环境的安装包。
(二)第一个TF程序:
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js " type="text/javascript"></script>
<script type="text/javascript">
var a=tf.tensor([1,2]);
a.print();
console.log(a)
</script>
就是这么简单,跟使用jquery这些库是一样的。
(三)体验机器学习编程思想,初识Tensorflow.js的API
上图代码:
const model = tf.sequential();
model.add(tf.layers.dense({
units: 4,
inputShape: [2],
activation: 'relu'
}));
model.add(tf.layers.dense({
units: 1,
activation: 'sigmoid'
}));
model.compile({
loss: tf.losses.logLoss,
optimizer: tf.train.adam(0.1)
});
const inputs = tf.tensor(data.map(p => [p.x, p.y]));
const labels = tf.tensor(data.map(p => p.label));
await model.fit(inputs, labels, {
epochs: 10
});
window.predict = (form) => {
const pred = model.predict(tf.tensor([[form.x.value * 1, form.y.value * 1]]));
alert(`预测结果:${pred.dataSync()[0]}`);
};
上面代码是使用Tensorflow.js分析XOR数据集的部分代码。代码描述了从创建神经网络到训练神经网络最终进行预测。
从代码中可以看出,没有写一句IF判断语句,全部都是在使用Tensorflow.js提供的API进行构建神经网络。所以机器学习的编程是通过构建神经网络来实现程序,而不是通过规则判断来编写程序。
于此同时可以看出使用Tensorflow.js构建神经网络相当容易,只需要调用API设置你想要的构建元素即可完成。无需编写过多的数学理论方法。比如激活函数sigmoid,你无需重新编写实现sigmoid数学函数,TF已经提供了该函数,设置调用即可。
途中的注释中描述了很多名词,比如:神经元、损失函数、优化器、神经层、激活函数等等,这些名词都是学习机器学习的一些基础知识。本文不对这些基础知识做一一详解,如有机会再详细对这些基础知识做一次整合讲解。
五、使用Tensorflow.js解决问题
下面我们看下Tensorflow.js如何进行机器学习编程的实例,除了上面介绍需要npm安装@tensorflow/tfjs这个包外,还需要额外安装@tensorflow/tfjs-vis可视化包。这个包不影响机器训练,功能是为了将训练过程可视化到浏览器当中。
(一)线性回归问题:
已知x轴值1、2、3、4对应y轴值为1、3、5、7,可得如下坐标图:
传统的规则编程也可轻松完成这样的线性回归函数,并且还能准确预测,比方说x轴为100.5时对应的y值是多少。下面我们看下在Tensorflow.js中如何用机器学习的编程方式实现。
import * as tf from '@tensorflow/tfjs';
import * as tfvis from '@tensorflow/tfjs-vis'; window.onload = async () => {
const xs = [1, 2, 3, 4];
const ys = [1, 3, 5, 7]; tfvis.render.scatterplot(
{ name: '线性回归训练集' },
{ values: xs.map((x, i) => ({ x, y: ys[i] })) },
{ xAxisDomain: [0, 5], yAxisDomain: [0, 8] }
); const model = tf.sequential();
model.add(tf.layers.dense({ units: 1, inputShape: [1] }));
model.compile({ loss: tf.losses.meanSquaredError, optimizer: tf.train.sgd(0.1) }); const inputs = tf.tensor(xs);
const labels = tf.tensor(ys);
await model.fit(inputs, labels, {
batchSize: 4,
epochs: 200,
callbacks: tfvis.show.fitCallbacks(
{ name: '训练过程' },
['loss']
)
}); const output = model.predict(tf.tensor([5]));
alert(`如果 x 为 5,那么预测 y 为 ${output.dataSync()[0]}`);
};
以上代码将输入值[1,2,3,4]和输出结果[1,3,5,7]作为训练集,这个训练集只有4组个数据,但是通过机器反复学习这4个数据集,就能预测出很接近的最终值。
这里使用sequential模型构建学习的神经网络,模型损失函数采用均方误差即代码中的tf.losses.meanSquaredError,优化器使用随机梯度下降即tf.train.sgd(0.1)。
最后将训练数据集给model进行训练,也就是调用了model.fit方法。batchSize是指每次训练数据个数,epochs是指训练次数。代码中表示每次训练4个数据,一共训练200次。
运行程序,浏览器中会显示整个训练过程:
由图可以看出loss也就是训练损失已平滑的曲线不断降低,损失越低表示训练结果越接近真实结果。
最终训练完毕会执行model.predict方法进行预测,代码中预测x为5时y值是多少,根据人类的大脑对这个简单函数的预测应该是为9,而程序实际输出是:
无限接近于9。这虽然没有完全等于9,但是已经相当有参考价值,因为训练损失是很难降低到0,而且这段机器学习程序只重复训练4个数据集。
(二)解决逻辑回归问题:
如图,我们要输入xy的坐标轴,然后预测该坐标属于黄色还是蓝色。这张图中,黄色和蓝色之间有少许的杂音而且还有很多空白地区没有显示出对应数据,图表也不可能显示完全部数据,这个时候就无法使用传统的规则编程进行书写。
我们看下Tensorflow.js如何解决这逻辑回归问题:
import * as tf from '@tensorflow/tfjs';
import * as tfvis from '@tensorflow/tfjs-vis';
import { getData } from './data.js'; window.onload = async () => {
const data = getData(400);
tfvis.render.scatterplot(
{ name: '逻辑回归训练数据' },
{
values: [
data.filter(p => p.label === 1),
data.filter(p => p.label === 0),
]
}
);
const model = tf.sequential();
model.add(tf.layers.dense({
units: 1,
inputShape: [2],
activation: 'sigmoid'
}));
model.compile({
loss: tf.losses.logLoss,
optimizer: tf.train.adam(0.1)
}); const inputs = tf.tensor(data.map(p => [p.x, p.y]));
const labels = tf.tensor(data.map(p => p.label));
await model.fit(inputs, labels, {
batchSize: 40,
epochs: 20,
callbacks: tfvis.show.fitCallbacks(
{ name: '训练效果' },
['loss']
)
}); window.predict = (form) => {
const pred = model.predict(tf.tensor([[form.x.value * 1, form.y.value * 1]]));
alert(`预测结果:${pred.dataSync()[0]}`);
};
};
这种逻辑回归问题比上面的线性回归问题明显复杂很多,但是使用Tensorflow.js进行编程却没有复杂多少,用的API是一样的。只是将损失函数从均方误差meanSquaredError变成了对数损失函数logLoss,因为逻辑回归问题无法使用均方误差进行很好的训练(这是一个数学问题,需要理解对数函数)。优化器采用了adam,当然优化器也可以使用随机梯度下降(至于优化器函数的选择也是一个数学问题)。
除了这两块有明显的区别,其他代码基本和线性回归的使用的API没有差别。
执行代码后我们可以看到整个训练过程的损失变化:
在页面输入框可以输入我们想要预测的坐标:
此例中预测结果接近0的是黄点,接近于1的是蓝点,如果预测值是0.5左右,那么所预测结果应该是两块区域之间的临界点。
(三)卷积神经网络的编写
卷积神经网络是一个伟大的发明,它可以让机器更加高效的学习图片、声音这些文件特征。
我们来看下Tensorflow.js如何构建卷积神经网络来识别手写数字的。在编写之前需要在网络上找到mnist数据集,这是经典的手写数字数据集,为我们节约了收集手写数字的图片集。下面看下代码的具体实现:
import * as tf from '@tensorflow/tfjs';
import * as tfvis from '@tensorflow/tfjs-vis';
import { MnistData } from './data'; window.onload = async () => {
const data = new MnistData();
await data.load();
const examples = data.nextTestBatch(20);
const surface = tfvis.visor().surface({ name: '输入示例' });
for (let i = 0; i < 20; i += 1) {
const imageTensor = tf.tidy(() => {
return examples.xs
.slice([i, 0], [1, 784])
.reshape([28, 28, 1]);
}); const canvas = document.createElement('canvas');
canvas.width = 28;
canvas.height = 28;
canvas.style = 'margin: 4px';
await tf.browser.toPixels(imageTensor, canvas);
surface.drawArea.appendChild(canvas);
} const model = tf.sequential();
model.add(tf.layers.conv2d({
inputShape: [28, 28, 1],
kernelSize: 5,
filters: 8,
strides: 1,
activation: 'relu',
kernelInitializer: 'varianceScaling'
}));
model.add(tf.layers.maxPool2d({
poolSize: [2, 2],
strides: [2, 2]
}));
model.add(tf.layers.conv2d({
kernelSize: 5,
filters: 16,
strides: 1,
activation: 'relu',
kernelInitializer: 'varianceScaling'
}));
model.add(tf.layers.maxPool2d({
poolSize: [2, 2],
strides: [2, 2]
}));
model.add(tf.layers.flatten());
model.add(tf.layers.dense({
units: 10,
activation: 'softmax',
kernelInitializer: 'varianceScaling'
}));
model.compile({
loss: 'categoricalCrossentropy',
optimizer: tf.train.adam(),
metrics: ['accuracy']
}); const [trainXs, trainYs] = tf.tidy(() => {
const d = data.nextTrainBatch(1000);
return [
d.xs.reshape([1000, 28, 28, 1]),
d.labels
];
}); const [testXs, testYs] = tf.tidy(() => {
const d = data.nextTestBatch(200);
return [
d.xs.reshape([200, 28, 28, 1]),
d.labels
];
}); await model.fit(trainXs, trainYs, {
validationData: [testXs, testYs],
batchSize: 500,
epochs: 20,
callbacks: tfvis.show.fitCallbacks(
{ name: '训练效果' },
['loss', 'val_loss', 'acc', 'val_acc'],
{ callbacks: ['onEpochEnd'] }
)
}); const canvas = document.querySelector('canvas'); canvas.addEventListener('mousemove', (e) => {
if (e.buttons === 1) {
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(255,255,255)';
ctx.fillRect(e.offsetX, e.offsetY, 25, 25);
}
}); window.clear = () => {
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(0,0,0)';
ctx.fillRect(0, 0, 300, 300);
}; clear(); window.predict = () => {
const input = tf.tidy(() => {
return tf.image.resizeBilinear(
tf.browser.fromPixels(canvas),
[28, 28],
true
).slice([0, 0, 0], [28, 28, 1])
.toFloat()
.div(255)
.reshape([1, 28, 28, 1]);
});
const pred = model.predict(input).argMax(1);
alert(`预测结果为 ${pred.dataSync()[0]}`);
};
};
上面代码中,有一大半是canvas画布的操作代码,可以不进行研究。在创建模型model之前的代码是将20张实例图片挂载到页面显示,也可以不进行研究。而Tensorflow.js的实际书写代码比线性回归相比之多了十来行。我们来解析下这部分代码。
这个卷积神经网络构建一共就分了5层,2层2D卷积层,2层池化层,1层输出层。tf.layers.conv2d创建的是2d卷积层,卷积层之后创建一个tf.layers.maxPool2d最大池化层对上一次卷积特征进行优化。进行两次卷积提取特征和池化后使用了tf.layers.flatten将立体数据平铺,最后根据平铺数据通过tf.layers.dense全链接层作为预测输出。这样一个简单的卷积神经网络就构建完成。
后面是将图片数据读取1000张图片转换成Tensorflow.js可运算的数据Tensor(张量),以及随机读取这1000张以外的200张验证数据。
model.fit方法进行模型的训练,这里将训练集和验证集都放入训练过程。验证集的目的是为了验证模型训练效果是否偏离了轨道,也就是是否出现过拟合或者欠拟合的情况。
运行代码后的结果如图:
我们可以看到loss训练损失在平滑下降,acc是训练准确度。val_loss和val_acc是验证集的损失值和准确度。这里的模型我们只训练了1000张图片,然后只训练了20次。在如此小的数据集以及训练次数的情况下已经可以达到惊人的效果。
我们在页面画布上可以随意写数字0-9,模型就可以进行判断我们写的是什么数字。如图效果:
案例使用小结:
上面例子只是让大家通过具体案例和代码实现来更加深入了解机器学习是如何编程的,以及Tensorflow.js的强大。
机器学习的编程和传统编程有着思维上的不同。传统编程要求程序逻辑缜密,对条件判断做出人为认定。而机器学习编程不在拘泥于规则编写,而是构建神经网络让计算机进行特征的学习。
而Tensorflow给我们程序猿封装了很多构建神经网络、训练模型的API。
六、本篇小结
上述简要介绍了人工智能、机器学习这些AI领域的概念,以及让大家感受了一下Tensorflow.js在机器学习上是如何编程的。本篇文章主要目的是带大家认识人工智能编程的世界。
Tensorflow.js并不是最热门最高效的机器学习框架,但是由于它使用的语言是Javascript以及开箱即用的API,这些条件可以让WEB开发者们用比较低的学习成本进行人工智能编程领域的学习。
如今很多大厂对人工智能的研发都投入了大量的人力资金,Tensorflow.js在移动端也出现很多应用,最近比较有名的实时彩妆就是使用Tensorflow.js进行编写的小程序。至于未来AI的发展是迅猛的,人工智能编程未来很可能是每个程序猿的必修课。所以在此勉励程序猿任重而道远,大家共勉之。
七、其他拓展
人工智能是一门庞大的学科,机器学习只是它的一个分支,它的分支可以用网上的下面这张图来描述:
从上图中可以看到机器学习也有庞大的分支,其中Deep Learning(深度学习)是近年来最火热的课题,深度学习训练的效果会更加智能。Tensorflow可以进行深度学习的编程。不过深度学习需要庞大的数据量以及强大的计算量,传统的机器学习不需要庞大的数据量。所以两者有着不可分割的关系。
下面是一些有关人工智能的一些学习网站,这些网站不仅限于Tensorflow.js,更多是关于机器学习的基础知识:
Tensorflow模拟:http://playground.tensorflow.org
谷歌机器学习速成教程:https://developers.google.cn/machine-learning/crash-course
机器学习算法课程:http://wiki.fast.ai/index.php/Main_Page
卷积神经网络原理:https://setosa.io/ev/image-kernels/
以上就是在公司投稿有关tensorflow.js的文章,希望对人工智能有兴趣的朋友有所帮助。
web开发者踏入人工智能的利器_Tensorflow.js的更多相关文章
- web开发者谷歌浏览器常用插件
1.Allow-Control-Allow-Origin 安装此插件解决跨域问题,在本地起服务器可访别的域的数据. 需在Access-Control-Expose-Headers加上Allow- ...
- 蒲公英 · JELLY技术周刊 Vol.16 谷歌首个线上 Web 开发者大会
蒲公英 · JELLY技术周刊 Vol.16 近期,谷歌有史以来的第一次线上谷歌 Web 开发者大会,Web Vitals.PWA.DevTools 和 Lighthouse 6.0 等一系列特性或产 ...
- 在Linux系统下运行微信Web开发者工具
微信Web开发者工具只有window版本和mac版本,如果想要在Linux系统下运行微信Web开发者工具,需要花费很大周折. 注:带 * 的步骤或文件为不确定是否管用的步骤或文件.本人系统为Linux ...
- 微信小程序IDE(微信web开发者工具)安装、破解手册
1.IDE下载 微信web开发者工具,本人是用的windows 10 x64系统,用到以下两个版本的IDE安装工具与一个破解工具包: wechat_web_devtools_0.7.0_x64.exe ...
- mac版微信web开发者工具(小程序开发工具)无法显示二维码 解决方案
微信小程序概念的提出,绝对可以算得上中国IT界惊天动地的一件大事,这可能意味着一场新的开发热潮即将到来, 我也怀着激动的心情准备全身心投入其中,不过截止目前,在官方网站上下载的最新版本都无法使用,打开 ...
- Web开发者的六个代码调试平台
代码调试平台是Web开发者进行开发.测试.分享.协作和交流的网络应用,它们支持实时的编辑.预览HTML.CSS和JavaScript的客户端代码.这些代码调试平台最值得称道的地方在于,它们中的大多数都 ...
- Web开发者和设计师必须要知道的 iOS 8 十个变化
原文出处: mobilexweb 译文出处:罗磊(@罗罗磊磊) 欢迎分享原创到伯乐头条 喜大普奔,喜极而泣,喜当爹,随着iPhone 6和iPhone 6 plus的上市,ios 8终于在上周 ...
- Web开发者不可不知的15条编码原则
HTML已经走过了近20的发展历程.从HTML4到XHTML,再到最近十分火热的HTML5,它几乎见证了整个互联网的发展.但是,即便到现在,有很多基础的概念和原则依然需要开发者高度注意.下面,向大家介 ...
- 7 个面向Web开发者的实用CSS3教程推荐
通过CSS来创建精细.复杂的效果,成为了Web前端开发的未来趋势.世界各地的设计师认为CSS3是一项非常具有潜力的技术,未来将会创造更多不可思议的美妙设计. 本文为Web开发者带来了一些与CSS3相关 ...
随机推荐
- MySQL第一讲概论
MySQL 后期内容 Python 今日内容概要 MySQL的概念 数据库软件的安装及使用 配置文件介绍 数据库常用命令(库操作.表操作.记录操作) 今日内容详细 什么是数据库 1.单机游戏 本地保存 ...
- 基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
在我的各种开发框架中,数据访问有的基于微软企业库,有的基于EFCore的实体框架,两者各有其应用场景,不过多的去比较.最近在使用SqlSugar的时候,觉得这个数据访问处理的组件确实很灵活,据说性能也 ...
- JVM垃圾回收阅读笔记
Java内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭,栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作. 每一个栈帧中分配多少内存基本上是 ...
- laravel 终端命令
创建模块及控制器
- 无法加载文件 **.ps1,系统中禁止执行脚本
控制台执行命令后出现 无法加载文件 ******.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 "get-help about_signing" 在控制台执行命令: s ...
- vant中tab标签切换时会改变内容滚动高度
vant的tabs标签页,标签切换时会改变内容区的滚动高度,这是因为内容区共用同一个父元素为滚动区域引起的,解决办法:在tabs的内容区域嵌套一层滚动区域,让每个内容区域使用单独的滚动元素就行了. ...
- IEAD关于git配置以及拉代码和提交代码
1.提前安装git客户端,注册码云帐号 注册地址:https://gitee.com/signup 2.新建仓库 3.修改仓库信息 4.从IDEA拉git项目,下面两个地方都可以配置 首次创建需要输入 ...
- Intellij IDEA远程debug线上项目记录
远程调试,特别是当你在本地开发的时候,你需要调试服务器上的程序时,远程调试就显得非常有用. JAVA 支持调试功能,本身提供了一个简单的调试工具JDB,支持设置断点及线程级的调试同时,不同的JVM通过 ...
- AQS 详解之共享锁模式
概括 AQS框架数据结构是一个先进先出的双向队列,当多个线程进行竞争资源时,那些竞争失败的线程会加入到队列中.他向上层提供了很多接口,其中一个是acquireShared获取共享模式的接口.本文将会根 ...
- Tomcat高级配置(应用场景总结及示例)
前言 本文将解决以下问题: 如何将Linux下任意位置的项目(虚拟目录)部署到tomcat? 如何将项目部署到服务器特定端口? 如何在一个服务器上部署多个web应用? 本例中 系统:Linux ver ...