TensorFlow.js 入门
原文博客文章:
https://aralroca.com/blog/first-steps-with-tensorflowjs
我想多写几篇文章,简单介绍一下机器学习和深度学习的基础知识。我虽然是这方面的初学者,但我希望尽快掌握这些概念,以便创建一些有趣的AI模型。不过,我们并不需要对机器学习有深入的了解才能使用一些现有的模型。我们可以使用一些库,例如Keras、TensorFlow或TensorFlow.js。本文将介绍如何创建基本的AI模型,以及如何使用TensorFlow.js创建更复杂的模型。虽然不需要很深的专业知识,但我们还是会解释一些基本概念。
什么是模型?
或许更好的问题应该是:“现实究竟是什么?”。是的,这个问题很难回答……我们需要简化它才能理解它!一种表示这种简化“现实”的方式是使用模型。模型种类繁多:世界地图、图表等等。
我们更容易理解那些无需机器辅助就能使用的模型。例如,如果我们想建立一个模型来表示巴塞罗那房价与房屋面积的关系:首先,我们可以收集一些数据:
| 房间数量 | 价格 |
|---|---|
| 3 | 131,000欧元 |
| 3 | 125,000欧元 |
| 4 | 235,000欧元 |
| 4 | 265,000欧元 |
| 5 | 535,000欧元 |
然后,我们将这些数据显示在二维图表中,每个参数(价格、房间数)占一维:
瞧!我们现在可以画一条线,开始预测拥有6个、7个或更多房间的房屋的价格了。这个模型叫做线性回归,它是机器学习领域最简单的入门模型之一。当然,这个模型还不够完善:
- 只有 5 个例子,所以可靠性不够。
- 虽然只有两个参数(价格、房间数),但还有更多因素可能会影响价格:例如,所在地区、房屋的房龄等等。
对于第一个问题,我们可以通过增加样本数量来解决,例如用 100 万个样本代替 5 个。对于第二个问题,我们可以增加维度……对吧?二维图表可以帮助我们理解数据并绘制线条,而三维空间中我们也可以使用平面:
但是,如何处理超过 3D 的情况呢?4D 或 100 万维呢?我们的大脑无法在图表上直观地呈现这些,但是……好消息!我们可以运用数学知识来计算超过 3D 的超平面,而神经网络正是实现这一目标的绝佳工具!顺便说一句,我还有一个好消息要告诉你:使用 TensorFlow.js,你不需要成为数学专家。
什么是神经网络?
在了解什么是神经网络之前,我们需要先了解什么是神经元。现实世界中的神经元看起来类似于这样:
神经元最重要的组成部分是:
- 树突:它是数据的输入端。
- 轴突:它是输出端。
- 突触(图中未显示):它是神经元之间进行通讯的结构。它负责在轴突末梢和邻近神经元的树突之间传递电信号。突触是学习的关键,因为它们会根据使用情况增强或减弱电活动。
- 输入:输入的参数。
- 权重:就像突触一样,它们的活动会增加或减少,以调整神经元,从而建立更好的线性回归。
- 线性函数:每个神经元都像一个线性回归函数,因此对于线性回归模型,我们只需要一个神经元!
- 激活函数:我们可以应用一些激活函数,将输出从标量转换为另一个非线性函数。比较常见的激活函数有:sigmoid、RELU 和 tanh。
- 输出:应用激活函数后的计算输出。
激活函数的作用非常重要,它是神经网络的强大之处。没有激活函数,就不可能构建一个智能的神经网络。原因在于,尽管网络中有多个神经元,但神经网络的输出始终是线性回归。我们需要某种机制将这些线性回归转化为非线性回归,从而解决非线性问题。正是由于激活函数的存在,我们才能将这些线性函数转换为非线性函数:
训练模型
就像二维线性回归示例那样,在图表中画一条线就足以让我们开始预测新数据。然而,“深度学习”的核心思想是让神经网络学习如何画出这条线。对于简单的直线,我们可以使用只有一个神经元的简单神经网络,但对于其他模型,我们可能需要执行更复杂的操作,例如对两组数据进行分类。在这种情况下,“训练”的目标是学习如何画出类似这样的图形:
请记住,这并不复杂,因为它是在二维空间中。每个模型都是一个独立的世界,但所有模型的“训练”概念都非常相似。第一步是画出一条随机线,然后通过迭代算法不断改进它,并在每次迭代中修正误差。这种优化算法被称为梯度下降(还有更复杂的算法,例如随机梯度下降或ADAM,它们的概念相同)。为了理解梯度下降,我们需要知道每种算法(线性回归器、逻辑回归器等)都有不同的成本函数来衡量误差。成本函数总是会收敛到某个点,它可以是凸函数,也可以是非凸函数。最低收敛点位于误差为 0% 的位置。我们的目标是达到这个点。
在使用梯度下降算法时,我们从成本函数上的某个随机点开始,但我们并不知道这个点在哪里!想象一下,你身处一座完全失明的山上,需要一步一步地走到最低点。如果地形崎岖不平(例如非凸函数),下降过程会更加复杂。
我不会深入解释梯度下降算法。你只需要记住,它是一种用于训练 AI 模型以最小化预测误差的优化算法。该算法需要时间和 GPU 来进行矩阵乘法运算。通常,第一次执行很难达到这个收敛点,因此我们需要调整一些超参数,例如学习率(下山的步长)或添加一些正则化项。经过梯度下降迭代后,当误差接近 0% 时,我们就更接近收敛点。此时,我们已经创建好了模型,可以开始进行预测了!
使用 TensorFlow.js 训练模型
TensorFlow.js 为我们提供了一种创建神经网络的简便方法。首先,我们将创建一个名为 LinearModel 的类,其中包含一个名为 trainModel 的方法。对于这种模型,我们将使用顺序模型。顺序模型是指任何一层的输出作为下一层输入的模型,也就是说,模型拓扑结构是一个简单的“堆叠”层,没有分支或跳层。在 trainModel 方法中,我们将定义各个层(由于线性回归问题只需要一层,因此我们只使用一层):
import * as tf from '@tensorflow/tfjs' ; /** * 线性模型类 */ export default class LinearModel { /** * 训练模型 */ async trainModel(xs, ys){ const layers = tf.layers.dense({ units: 1, // 输出空间的维度 inputShape: [1], // 只有一个参数 }); const lossAndOptimizer = { 损失函数:'均方误差' 优化器:'sgd',// 随机梯度下降 }; this.linearModel = tf.sequential(); this.linearModel.add (layers); // 添加层 this.linearModel.compile (lossAndOptimizer); // 开始模型训练! await this.linearModel.fit ( tf.tensor1d(xs), tf.tensor1d(ys) ); } ...更多的 }
使用此类:
const model = new LinearModel(); // xs 和 ys -> 数字数组(x 轴和 y 轴) await model.trainModel(xs, ys);
经过这次培训,我们就可以开始进行预测了!
使用 TensorFlow.js 进行预测
通常情况下,预测反而是最简单的部分!训练模型需要定义一些超参数……但即便如此,预测本身仍然非常简单。接下来,我们将把以下方法写入 LinearRegressor 类:
import * as tf from '@tensorflow/tfjs' ; export default class LinearModel { 训练代码 预测(值){ 返回Array.from ( this.linearModel .predict(tf.tensor2d([value], [1, 1])) .dataSync() ) } }
现在,我们可以在代码中使用预测方法了:
const prediction = model.predict(500); // 预测数字 500 的值 console.log(prediction) // => 420.423
使用 TensorFlow.js 的预训练模型
学习创建模型是最难的部分;例如,对训练数据进行归一化,正确设置所有超参数等等。如果你是这方面的新手(像我一样),并且想尝试一些模型,可以使用预训练模型。有很多预训练模型可以与 TensorFlow.js 一起使用。此外,你还可以导入使用 TensorFlow 或 Keras 创建的外部模型。例如,你可以使用 PoseNet模型(实时人体姿态估计)来做一些有趣的项目:
📕 代码: https ://github.com/aralroca/posenet-d3它非常易于使用:
import * as posenet from '@tensorflow-models/posenet' ; // 常量 const imageScaleFactor = 0.5; const outputStride = 16; const flipHorizontal = true ; const weight = 0.5; // 加载模型 const net = await posenet.load(weight); // 进行预测 const poses = await net .estimateSinglePose( imageElement, 图像缩放因子, 翻转水平, 输出步长 );
poses变量的 JSON 格式如下:
{
"score" : 0.32371445304906,
"keypoints" : [
{
"位置" : {
"y" : 76.291801452637,
"x" : 253.36747741699
},
“part” : “nose”,
“score” : 0.99539834260941
},
{
"位置" : {
"y" : 71.10383605957,
"x" : 253.54365539551
},
“part” : “leftEye”,
“score” : 0.98781454563141
},
// ……以及:右眼、左耳、右耳、左肩、右肩
// 左肘、右肘、左腕、右腕、左髋、右髋、
// 左膝、右膝、左踝、右踝
]
}
想象一下,仅用这个模型你就能开发出多少有趣的创意项目!
📕 代码: https://github.com/aralroca/fishFollow-posenet-tfjs
从 Keras 导入模型
我们可以将外部模型导入 TensorFlow.js。在本例中,我们将使用 Keras 模型进行数字识别(h5 文件格式)。为此,我们需要tfjs_converter。
使用 pip 安装 tensorflowjs
然后,使用转换器:
tensorflowjs_converter --input_format keras keras/cnn.h5 src/assets
最后,您就可以将模型导入到您的 JS 代码中了!
// 加载模型 const model = await tf.loadModel( './assets/model.json' ); // 准备图像 let img = tf.fromPixels(imageData, 1); img = img.reshape([1, 28, 28, 1]); img = tf.cast(img, 'float32' ); // 预测 const output = model.predict(img);
只需几行代码,即可将 Keras 中的数字识别模型集成到我们的 JS 代码中。当然,现在我们可以添加更多逻辑来实现更有用的功能,例如使用 canvas 绘制数字,然后捕获该图像以预测数字。📕
代码: https://github.com/aralroca/MNIST_React_TensorFlowJS
为什么是在浏览器中?
根据设备的不同,在浏览器中训练模型的效率可能非常低下。尽管 TensorFlow.js 利用 WebGL 在后台训练模型,但其速度仍然比 TensorFlow Python 慢 1.5 到 2 倍。然而,在 TensorFlow.js 出现之前,如果不通过 API 交互,就无法直接在浏览器中使用机器学习模型。现在,我们可以在应用程序中离线训练和使用模型。此外,由于无需向服务器发送请求,预测速度也大大加快。另一个优势是服务器成本降低,因为现在所有计算都在客户端进行。
结论
- 模型是一种表示现实简化部分的方式,我们可以利用模型来预测事物。
- 创建模型的一个好方法是使用神经网络。
- TensorFlow.js 是一个创建神经网络的好工具,而且使用起来也很方便。
参考:
- https://js.tensorflow.org
- https://en.wikipedia.org/wiki/Scientific_modelling
- https://www.quantstart.com/articles/Supervised-Learning-for-Document-Classification-with-Scikit-Learn
- https://en.wikipedia.org/wiki/Synapse
- https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5
- https://github.com/tensorflow/tfjs-models/tree/master/posenet
- https://www.youtube.com/watch?v=Y_XM3Bu-4yc
- https://ml4a.github.io/demos/confusion_mnist/



