十、tensorflow.js 入门

在前一章中,您已经了解了机器学习 ( ML )的基础知识,并学习了一些构建和使用 ML 模型所需的理论基础。

在本章中,我们将向您介绍一个高效且流行的 JavaScript 中的 ML 库,名为 TensorFlow.js,到本章结束时,您将了解如何安装和使用 TensorFlow.js,如何创建 tensor,如何使用 Core 应用编程接口 ( API )对 tensor 进行操作,以及如何使用 TensorFlow.js 的 Layer API 构建回归模型。

在本章中,我们将涵盖以下主题:

  • 什么是 TensorFlow.js?
  • 安装和使用 TensorFlow.js
  • 张量和张量上的基本运算
  • 用 TensorFlow.js 建立一个简单的回归模型

技术要求

要完成本章,您应该拥有以下工具或资源:

什么是 TensorFlow.js?

TensorFlow.js(tfjs)是一个用于在浏览器或 Node.js 中创建、训练和部署 ML 模型的 JavaScript 库,由 Nikhil Thorat 和 Daniel Smilkov 在谷歌创建,最初名为 Deeplearn.js,2018 年被合并到 TensorFlow 团队,更名为 TensorFlow . js。

TensorFlow.js 提供了两个主要层,概述如下:

  • CoreAPI :这是直接处理张量的低级 API——tensorflow . js 的核心数据结构。
  • layer rapi:构建在 CoreAPI 层之上的高级层,用于轻松构建 ML 模型。

在后面的章节中,张量以及张量上的基本运算使用 TensorFlow.js 构建一个简单的回归模型,您将了解到关于 CoreAPI 和 LayerAPI 层的更多细节。

使用 TensorFlow.js,您可以执行以下操作:

  • 执行硬件加速的数学运算
  • 为浏览器或 Node.js 开发 ML 模型
  • 使用转移学习(T1)重新训练现有的 ML 模型
  • 重用用 Python 训练的现有 ML 模型

在本章中,我们将介绍使用 TensorFlow.js 执行硬件加速的数学运算和开发 ML 模型。如果您想了解最后两个用例——再培训和重用 ML 模型——那么官方 TensorFlow.js 文档(https://www.tensorflow.org/js/guide)是一个很好的起点。

现在我们已经有了介绍,在下一节中,我们将向您展示如何在浏览器和 Node.js 环境中安装和使用 TensorFlow.js。

安装和使用 TensorFlow.js

正如我们前面提到的一样,TensorFlow.js 可以在浏览器和 Node.js 环境中安装和运行。在下面的段落中,我们将向您展示如何实现这一点,首先从浏览器开始。

在浏览器中设置 TensorFlow.js

安装 TensorFlow 有两种方式。浏览器中的 js。这些概述如下:

  • 通过脚本标签
  • 使用包管理器,如节点包管理器 ( npm )或纱线

通过脚本标签安装

通过script标签安装 TensorFlow.js 很容易。只需将标签放入您的超文本标记语言 ( HTML )文件的头文件中,如以下代码片段所示:

<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.6.0/dist/tf.min.js"></script>

要确认安装了 TensorFlow.js,请在浏览器中打开 HTML 文件,并检查网络选项卡。你应该看到名称tf.min.js和一个200的状态码,如下图截图所示:

Figure 10.1 – Network tab showing the successful installation of tfjs

图 10.1–显示 tfjs 成功安装的网络选项卡

您可以在您的 HTML 文件的正文中添加一个简单的脚本来确认tfjs的成功安装。在 HTML 文件的script部分,添加以下代码:

...
<script>
         tf.ready().then(()=>{
            console.log("Tensorflow.js loaded successfully!");
        })
 </script>
...

一旦 TensorFlow.js 在页面上加载并准备好,前面的代码片段就会将文本Tensorflow.js loaded successfully!记录到浏览器控制台。要查看输出,请在浏览器中打开 HTML 文件并检查控制台输出。你应该会看到一个输出结果,如下图截图所示:

Figure 10.2 – Tensor output from add operation

图 10.2–加法运算的张量输出

接下来,让我们看看如何通过包管理器安装tfjs

通过包管理器安装

可以通过npmyarn等包管理器安装tfjs。当您需要在客户端项目(如 React 和 Vue 项目)中使用tfjs时,这非常有用。

要使用npm进行安装,请在您的命令行界面 ( 命令行界面)中运行以下命令:

npm install @tensorflow/tfjs

要使用yarn进行安装,也只需在命令行界面中运行以下命令:

yarn add @tensorflow/tfjs

注意

在通过命令行界面使用npmyarn成功安装软件包之前,您必须在系统中安装它们中的任何一个,最好是全局安装。如果你安装了 Node.js,那么你已经有了npm。安装yarn可以按照这里的步骤:https://classic.yarnpkg.com/en/docs/install/#mac-stable

在安装成功后,您可以导入并使用tfjs,如以下代码片段所示:

import * as tf from '@tensorflow/tfjs';
const x = tf.tensor2d([1, 2, 3, 4], [2, 2]);
const y = tf.tensor2d([1, 3, 5, 7], [2, 2]);
const sum = x.add(y)
 sum.print()

运行前面的代码片段将在控制台中产生以下输出:

Figure 10.3 – Output from testing tfjs installed with package managers

图 10.3–测试安装了包管理器的 tfjs 的输出

通过遵循前面代码块中的步骤,您应该能够在浏览器或客户端框架中安装和使用tfjs。在下一节中,我们将向您展示如何在 Node.js 环境中安装tfjs

在 Node.js 中安装 TensorFlow.js

在节点中安装tfjs。 js 很简单,但是首先要保证你的系统上安装了 node . js、npm或者yarn

Node.js 中的 TensorFlow.js 有三个选项,安装的选择将取决于您的系统规格。在下面的小节中,我们将向您展示这三个选项。

使用本机 C++绑定安装 TensorFlow.js

@tensorflow/tfjs-node()版本的tfjs直接连接到 TensorFlow 的原生 C++绑定。这使得它速度很快,并且与 Python 版本的 TensorFlow 性能相当。这意味着tfjs-nodetf.keras在引擎盖下使用相同的 C++绑定。

要安装tfjs-node,只需通过命令行界面运行以下命令:

npm install @tensorflow/tfjs-node

或者,如果使用yarn,通过命令行界面运行以下命令:

yarn add @tensorflow/tfjs-node

在 GPU 支持下安装 TensorFlow.js

tfjs@tensorflow/tfjs-node-gpu版本支持在图形处理单元 ( GPU )启用的 硬件上运行操作。使用tfjs-node-gpu运行的操作通常比tfjs-node运行的更快,因为操作可以很容易地矢量化。

要安装tfjs-node-gpu,只需通过命令行界面运行以下命令:

npm install @tensorflow/tfjs-node-gpu

或者,如果使用yarn,通过命令行界面运行以下命令:

yarn add @tensorflow/tfjs-node-gpu

安装普通 TensorFlow.js

@tensorflow/tfjs版本是tfjs的纯 JavaScript 版本。在性能方面是最慢的,应该很少使用。

要安装此版本,只需通过命令行界面运行以下命令:

npm install @tensorflow/tfjs

或者,如果使用yarn,通过命令行界面运行以下命令:

yarn add @tensorflow/tfjs

如果您按照前面的步骤操作,那么您应该至少安装了一个版本的tfjs。您可以使用以下代码示例测试安装是否成功:

const tf = require('@tensorflow/tfjs-node')
// const tf = require('@tensorflow/tfjs-node-gpu') GPU version
// const tf = require('@tensorflow/tfjs') Pure JS version
const xs = tf.randomNormal([100, 10])
const ys = tf.randomNormal([100, 1])
const sum = xs.add(ys)
const xsSum = xs.sum()
const xsMean = xs.mean()

console.log("Sum of xs and ys")
sum.print()
console.log("Sum of xs")
xsSum.print()
console.log("Mean of xs")
xsMean.print()

注意

当我们想要查看底层数据时,我们在张量上调用print()函数。如果我们使用默认的console.log,我们会得到Tensor对象。

运行前面的代码应该会在控制台中输出以下内容:

Figure 10.4 – Output from testing tfjs installed in Node.js

图 10.4–测试安装在 Node.js 中的 tfjs 的输出

现在你已经在你的项目中成功安装了tfjs,在下一节中,我们将向你介绍tfjs的核心数据结构——张量。

张量和张量上的基本运算

张量是tfjs中基本的数据结构。你可以认为张量是向量、矩阵或高维数组的推广。我们在中介绍的 CoreAPI 是什么?部分,展示了创建和使用张量的不同功能。

下面的截图显示了标量、向量和带有张量的矩阵之间的简单比较:

Figure 10.5 – Comparison between simple n-dimensional arrays and a tensor

图 10.5–简单 n 维数组和张量之间的比较

小费

一个矩阵是一个由m x n个数字组成的网格,其中m代表行数,n代表列数。矩阵可以是一维或多维的,相同形状的矩阵支持相互之间的直接数学运算。

另一方面,向量是具有形状(1,1)的一维矩阵;也就是说,它只有一行和一列,例如,[2,3],[3,1,4]。

我们之前提到张量更像是一个广义矩阵——也就是说,它扩展了矩阵的概念。张量可以用它们的等级来描述。等级类似于形状的概念,但由单个数字表示,而不是形状。在下面的列表中,我们通过示例看到了不同类型的张量等级:

  • 秩为 0 的张量是标量,例如 1、20 或 100。
  • 秩为 1 的张量是向量,例如[1,20]或[20,100,23.6]。
  • 秩为 2 的张量是矩阵,例如[[1,3,6],[2.3,5,7]]。

请注意,我们可以有等级为 4 或更高的张量,这些张量被称为高维张量,很难可视化。请参见下面的截图,以更好地理解张量:

Figure 10.6 – Comparison of tensors with different ranks

图 10.6–不同等级张量的比较

除了等级外,张量还有dtypedataaxisshape等属性。这些在这里有更详细的描述:

  • dtype属性(数据类型)是张量持有的数据类型,例如,具有以下数据[2.5,3.8]的秩 1 张量的数据类型为float32。默认情况下,数字张量的数据类型为float32,但这可以在创建过程中更改。TensorFlow.js 支持float32int32boolcomplex64string数据类型。
  • data属性是张量的内容。这通常存储为数组。
  • axis属性是张量的特定维度,例如, m x n 张量的轴为 mn 。该轴可用于指定在哪个维度上执行操作。
  • shape属性是张量的维数。把形状想象成张量每个轴上的元素数量。

现在您已经对张量有了基本的了解,在下一小节中,我们将向您展示如何创建张量,并对它们执行一些基本操作。

创造张量

可以用tf.tensor()方法创建张量,如下面的代码片段所示:

const tf = require('@tensorflow/tfjs-node')

const tvector = tf.tensor([1, 2, 3, 4]);
console.log(tvector)
//output
Tensor {
  kept: false,
  isDisposedInternal: false,
  shape: [ 4 ],
  dtype: 'float32',
  size: 4,
  strides: [],
  dataId: {},
  id: 0,
  rankType: '1'
}

在前面的代码片段中,我们将一个平面数组(向量)传递给tf.tensor()方法来创建一个tfjs张量。创建这个之后,我们现在可以使用不同的属性和函数来操纵或变换张量。

其中一个属性是shape属性,我们可以调用它,如下面的代码片段所示:

console.log('shape:', tvector.shape);
//outputs: shape: [ 4 ]

注意,当你用console.log记录张量时,你会得到一个张量对象。如果需要查看底层张量数组,可以调用张量上的print()函数,如下面代码片段中的所示:

tvector.print();
//outputs
Tensor
    [1, 2, 3, 4]

如果需要访问张量的底层数据,可以调用array()arraySync()方法。两者的区别在于array()异步运行并返回解析到底层数组的承诺,而arraySync()同步运行。你可以在这里看到一个例子:

const tvectorArray = tvector.array()
const tvectorArraySync = tvector.arraySync()
console.log(tvectorArray)
console.log(tvectorArraySync)
//outputs
Promise { <pending> }
[ 1, 2, 3, 4 ]

也可以通过指定shape参数来创建张量。例如,在下面的代码片段中,我们从一个平面数组创建一个 2×2(二维 ( 2D ))张量:

const ts = tf.tensor([1, 2, 3, 4], [2, 2]);
console.log('shape:', ts.shape);
ts.print();
//outputs
shape: [ 2, 2 ]
Tensor
    [[1, 2],
     [3, 4]]

或者,我们可以创建一个 1×4(一维 ( 1D )张量,如下面的代码片段所示:

const ts = tf.tensor([1, 2, 3, 4], [1, 4]);
console.log('shape:', ts.shape);
ts.print();
//outputs
shape: [ 1, 4 ]
Tensor
     [[1, 2, 3, 4],]

然而,请注意,形状必须与元素的数量相匹配——例如,您不能从具有四个元素的平面阵列创建2 x 5维张量。以下代码将引发形状错误:

const ts = tf.tensor([1, 2, 3, 4], [2, 5]);

输出如下所示:

Figure 10.7 – Error thrown from shape mismatch

图 10.7–形状不匹配引发的错误

Tfjs 明确提供功能用于创建 1D、2D、三维 ( 3D )、四维 ( 4D )、五维 ( 5D )、六维 ( 6D )张量。您可以使用它来代替指定shape参数。你可以从官方的tfjs应用编程接口这里阅读更多关于创建张量的信息:https://js.tensorflow.org/api/latest/#Tensors-Creation

默认情况下,张量具有float32dtype属性,因此您创建的任何张量都将具有float32dtype。如果这不是期望的dtype,您可以指定张量创建的类型,如我们在下面的代码片段中所演示的:

const tsInt = tf.tensor([1, 2, 3, 4], [1, 4], 'int32');
console.log('dtype:', tsInt.dtype);
//outputs
dtype: int32

现在你知道如何创建张量,我们将继续操作张量。

在张量上操作

张量,正如我们前面所说的,将数据存储在网格中,并允许大量操作来操纵或转换这些数据。tfjs为线性代数和 ML 提供了很多算子。

tfjs中的操作分为不同的部分。以下是一些常见操作的解释:

您可以在这里的官方 API 中看到支持操作的完整列表:https://js.tensorflow.org/api/3.7.0/#Operations

现在您已经对可用的张量算子有了基本的了解,我们将展示一些代码示例。

在张量上应用算术运算

我们可以通过在第一个张量上直接调用add()方法并传递第二个张量作为参数来添加两个张量,如下面的代码片段所示:

const tf = require('@tensorflow/tfjs-node')
const a = tf.tensor1d([1, 2, 3, 4]);
const b = tf.tensor1d([10, 20, 30, 40]);
a.add(b).print();
//outputs
Tensor
    [11, 22, 33, 44]

请注意,您也可以通过在tf对象上调用运算符来直接添加或应用任何运算符,如以下代码片段所示:

const tf = require('@tensorflow/tfjs-node')
const a = tf.tensor1d([1, 2, 3, 4]);
const b = tf.tensor1d([10, 20, 30, 40]);
const sum = tf.add(a, b)
sum.print()
//outputs
Tensor
    [11, 22, 33, 44]

利用这些知识,您可以执行其他算术运算,如减法、乘法、除法和幂运算,如我们在以下代码片段中演示的那样:

const a = tf.tensor1d([1, 2, 3, 4]);
const b = tf.tensor1d([10, 20, 30, 40]);

const tfsum = tf.add(a, b)
const tfsub = tf.sub(b, a)
const tfdiv = tf.div(b, a)
const tfpow = tf.pow(b, a)
const tfmax = tf.maximum(a, b)

tfsum.print()
tfsub.print()
tfdiv.print()
tfpow.print()
tfmax.print()
//outputs
Tensor
    [11, 22, 33, 44]
Tensor
    [9, 18, 27, 36]
Tensor
    [10, 10, 10, 10]
Tensor
    [10, 400, 27000, 2560000]
Tensor
    [10, 20, 30, 40]

值得一提的是,传递给算符的张量的顺序很重要,因为顺序的改变会导致结果不同。例如,如果我们将前面div操作的顺序从const tfsub = tf.sub(b, a)交换到const tfsub = tf.sub(a, b),那么我们会得到一个否定的结果,如下输出所示:

Tensor
    [-9, -18, -27, -36]

注意所有涉及两个张量的运算只有在两个张量形状相同的情况下才会起作用。例如,以下操作将引发无效的形状错误:

const a = tf.tensor1d([1, 2, 3, 4]);
const b = tf.tensor1d([10, 20, 30, 40, 50]);
const tfsum = tf.add(a, b)

Figure 10.8 – Invalid shape error when performing an operation on tensors with a different shape

图 10.8–对不同形状的张量执行运算时出现无效形状错误

在下一小节中,我们看一些张量的基本数学运算的例子。

在张量上应用基本数学运算

遵循上一小节中的示例格式,在张量上应用算术运算,我们给出了在张量上计算数学运算的一些示例,如下所示:

const tf = require('@tensorflow/tfjs-node')

const x = tf.tensor1d([-1, 2, -3, 4]);
x.abs().print();  // Computes the absolute values of the tensor
x.cos().print(); // Computes the cosine of the tensor
x.exp().print(); // Computes the exponential of the tensor
x.log().print(); // Computes the natural logarithm  of the tensor
x.square().print(); // Computes the sqaure of the tensor

输出如下所示:

Tensor
    [1, 2, 3, 4]
Tensor
    [0.5403023, -0.4161468, -0.9899925, -0.6536436]
Tensor
    [0.3678795, 7.3890562, 0.0497871, 54.5981522]
Tensor
    [NaN, 0.6931472, NaN, 1.3862944]
Tensor
    [1, 4, 9, 16]

正如我们前面提到的,你可以直接从tf对象调用操作符——例如,x.cos()变成了tf.cos(x)

在张量上应用归约运算

我们也可以对张量进行meanminmaxargMinargMax等归约运算。下面是以下代码片段中meanminmaxargMinargMax的一些示例:

const x = tf.tensor1d([1, 2, 3]);
x.mean().print();  // or tf.mean(x)  Returns the mean value of the tensor
x.min().print();  // or tf.min(x) Returns the smallest value in the tensor
x.max().print();  // or tf.max(x) Returns the largest value in the tensor
x.argMax().print();  // or tf.argMax(x) Returns the index of the largest value
x.argMin().print();  // or tf.argMin(x) Returns the index of the smallest value

输出如下所示:

Tensor 2
Tensor 1
Tensor 3
Tensor 2
Tensor 0

掌握了 ML、张量以及可以在张量上执行的操作的基本知识,现在就可以构建一个简单的 ML 模型了。在本章的下一节中,我们将巩固您在这一节中学到的所有知识。

用 TensorFlow.js 建立简单的回归模型

在前一章第九章机器学习基础中,你被介绍了 ML 的基础知识,尤其是回归和分类模型的理论方面。在本节中,我们将向您展示如何使用tfjslayer rapi创建和训练回归模型。具体来说,到本节结束时,您将拥有一个可以根据超市数据预测销售价格的回归模型。

在本地设置环境

在构建回归模型之前,您必须在本地设置您的环境。在本节中,我们将在 Node.js 环境中工作。这意味着我们将使用 TensorFlow.js 和 Danfo.js 的node版本。

按照以下步骤设置您的环境:

  1. 在新的工作目录中,为项目创建一个文件夹。我们将创建一个名为sales_predictor的,如下面的代码片段所示:

    js mkdir sales_predictor cd sales_predictor

  2. 接下来,在文件夹目录中打开一个终端,通过运行以下命令初始化一个新的npm项目:

    js npm init

  3. 接下来,安装Danfo.js节点包,如下所示:

    js yarn add danfojs-node or if using npm npm install danfojs-node

  4. Also from the terminal, create an src folder and add train.js, model.js, and data _proc.js files. You can create these folders/files manually from your code editor or by running the following command in the terminal:

    js mkdir src && cd src && touch train.js && touch data_proc.js && touch model.js

    注意

    请注意,在前面的代码片段中,我们在src文件夹中创建了三个文件(train.jsdata_proc.jsmodel.js)。这些文件将分别包含用于处理数据、创建tfjs模型和模型训练的代码。

现在您已经设置了您的项目和文件,我们将进入下一节的数据检索和处理步骤。

检索和处理训练数据集

我们将用于模型训练的数据集被称为大润发销售数据集(https://www . kaggle . com/devash 0507/big-mart-sales-prediction)。它作为公共数据集在数据科学竞赛平台 Kaggle 上提供。

您可以直接从本章的代码库中下载数据集:https://github . com/PacktPublishing/Building-Data-Driven-Applications-with-danfo . js-/blob/main/chapter 10/sales _ predictor/src/dataset/train . CSV。下载成功后,在项目目录中创建一个名为dataset的文件夹,并将数据集复制到其中。

为了确认一切正常,您的项目src文件夹应该具有以下文件结构:

|-data-proc.js
|-dataset
|   └── Train.csv
|-model.js
|-train.js

与所有数据科学问题一样,一般问题陈述可用于指导您解决问题。就 BigMart 销售数据集而言,问题陈述如下:

BigMart 收集了 2013 年不同城市 10 家门店 1559 款产品的销售数据。此外,还定义了每个产品和商店的某些属性。目的是建立一个预测模型,并找出每种产品在特定商店的销售额。

从前面的问题陈述中,你会注意到,建立这个模型的目的是帮助 BigMart 有效地预测每种产品在特定商店的销量。现在,这里的销售价格意味着连续的价值,因此,我们有一个回归问题。

现在您已经访问了数据并理解了问题陈述,您将使用Danfo.js加载数据集并执行一些数据处理和清理。

注意

我们在这里的代码库中提供了一个单独的 Danfo Notebook(Dnotebook)文件:https://github . com/PacktPublishing/Building-Data-Driven-Applications-with-Danfo . js-/blob/main/chapter 10/sales _ predictor/src/big mart % 20 sales % 20 Notebook . JSON。在笔记本中,我们对销售数据集进行了一些数据探索和分析,其中大部分将帮助我们完成以下处理步骤。

在代码编辑器中打开data_proc.js文件后,按照这里给出的步骤处理 BigMart 销售数据集:

  1. 首先我们导入danfojs-node,如下:

    js const dfd = require("danfojs-node")

  2. 然后,我们创建一个名为processData的函数,接受数据集路径,如下所示:

    js async function processData(trainDataPath) {     //… process code goes here }

  3. 接下来,在processData函数的主体中,我们使用read_csv函数加载数据集并打印标题,如下所示:

    js const salesDf = await dfd.read_csv(trainDataPath) salesDf.head().print()

  4. 为了确保数据加载工作,您可以将数据集的路径传递给processData函数,如以下代码片段所示:

    js processData("./dataset/train.csv")

  5. And in your terminal, run the data_proc.js file using the following command:

    js node data_proc.js

    这将输出以下内容:

    Figure 10.9 – Displaying the head value of the BigMart sales dataset

    图 10.9–显示 BigMart 销售数据集的头部值

  6. 从 Dnotebook 文件的分析中,我们注意到两列Item_WeightOutlet_Sales缺少值。在下面的代码片段中,我们将分别使用平均值和模态值来填充这些缺失值:

    js ...    salesDf.fillna({         columns: ["Item_Weight", "Outlet_Size"],         values: [salesDf['Item_Weight'].mean(), "Medium"],         inplace: true     }) ...

  7. 正如我们已经注意到的,数据集是分类(字符串)列和数值(float32int32)列的混合。这意味着我们必须将所有分类列转换为数字形式,然后才能将它们传递给我们的模型。在下面的代码片段中,我们使用 Danfo.js 的LabelEncoder将每个分类列编码为一个数字:

    js ...      let encoder = new dfd.LabelEncoder()      let catCols = salesDf.select_dtypes(includes = ['string']).column_names // get all categorical column names      catCols.forEach(col => {         encoder.fit(salesDf[col])         enc_val = encoder.transform(salesDf[col])         salesDf.addColumn({ column: col, value: enc_val })      })      ...

  8. 接下来,我们将从训练数据集中分离目标。正如我们从问题陈述中注意到的,目标是销售价格。这对应于最后一列Item_Outlet_Sales。在下面的代码片段中,我们将使用iloc函数分割数据集:

    js ...       let Xtrain, ytrain;       Xtrain = salesDf.iloc({ columns:         [`1:${salesDf.columns.length - 1}`] })       ytrain = salesDf['Item_Outlet_Sales']       console.log(`Training Dataset Shape: ${Xtrain.shape}`) ...

  9. 接下来,我们将标准化我们的数据集。标准化我们的数据集迫使每一列都在比例中,因此改进了模型训练。在下面的代码片段中,我们使用 Danfo.js 的StandardScaler来标准化数据集:

    js       ... let scaler = new dfd.MinMaxScaler()       scaler.fit(Xtrain)       Xtrain = scaler.transform(Xtrain) ...

  10. Finally, to complete the processData function, we'll return the raw tensors, as shown in the following code snippet:

    js ...        return [Xtrain.tensor, ytrain.tensor] ...

    注意

    在这里可以看到代码库中的完整代码:https://github . com/PacktPublishing/Building-Data-Driven-Applications-with-danfo . js/blob/main/chapter 10/sales _ predictor/src/Data-proc . js

执行并打印最终data_proc.js文件中的张量,应该会得到如下截图所示的张量:

Figure 10.10 – Final BigMart data tensors after processing

图 10.10–处理后的最终 BigMart 数据张量

现在您有了一个可以处理原始数据集并返回张量的函数,让我们继续使用tfjs创建模型。

用 TensorFlow.js 创建模型

正如我们前面提到的,tfjs提供了一个图层应用编程接口,可以用来定义和创建 ML 模型。图层应用编程接口类似于流行的 Keras 应用编程接口,因此,已经熟悉 Keras 的 Python 开发人员可以轻松地将其代码移植到tfjs

图层应用编程接口提供了两种创建模型的方式——顺序和模型格式。我们将在下面的小节中简要解释并给出这些例子。

创建模型的顺序方式

这是最简单也是最常见的建模方式。它只是多个模型层的堆栈,其中堆栈中的第一层定义输入,最后一层定义输出,而中间层可以根据需要任意多。

下面的代码片段显示了一个两层顺序模型的示例:

const model = tf.sequential();
// First layer must have an input shape defined.
model.add(tf.layers.dense({units: 32, inputShape: [50]}));
model.add(tf.layers.dense({units: 24})); 
model.add(tf.layers.dense({units: 1}));

您将从前面的代码片段中注意到,序列中的第一层提供了一个inputShape参数。这意味着模型需要一个带有50列的输入。

您也可以通过传递一系列层来创建一个顺序层,如下面的代码片段所示:

const model = tf.sequential({
   layers: [tf.layers.dense({units: 32, inputShape: [50]}),
           tf.layers.dense({units: 24}),
           tf.layers.dense({units: 1})]
});

接下来,让我们看看模型格式。

创建模型的模型方式

创建模型的模型格式在创建模型时提供了更多的灵活性。不是简单地接受线性层的堆叠,用模型层定义的模型可以是非线性的、循环的,并且可以根据您的需要进行高级或连接。

例如,在下面的代码片段中,我们使用模型格式创建了一个两层网络:

const input = tf.input({ shape: [5] });
const denseLayer1 = tf.layers.dense({ units: 16, activation: 'relu' });
const denseLayer2 = tf.layers.dense({ units: 8, activation: 'relu' });
const denseLayer3 = tf.layers.dense({ units: 1 })
const output = denseLayer3.apply(denseLayer2.apply(denseLayer1.apply(input)))
const model = tf.model({ inputs: input, outputs: output });

从前面的示例代码中,您可以看到我们正在显式调用apply函数,并将我们想要连接的图层作为参数传递。通过这种方式,我们可以构建具有图形连接的混合和高度复杂的模型。

您可以从这里的官方tfjs文档中了解更多关于图层应用编程接口的信息:https://js.tensorflow.org/api/latest/#Models

现在您知道了如何使用 Layer API 创建模型,我们将在下一节创建一个简单的三层回归模型。

创建简单的三层回归模型

回归模型,正如我们在前一章第九章机器学习基础所解释的,是一个具有连续输出的模型。为了用tfjs创建一个回归模型,我们定义了层的堆叠,在最后一层,我们将units的数量设置为1。例如,打开代码库中的model.js文件。在第 7-11 行中,您应该会看到以下顺序模型定义:

...
const model = tf.sequential();
model.add(tf.layers.dense({ inputShape: [11], units: 128, kernelInitializer: 'leCunNormal' }));
model.add(tf.layers.dense({units: 64, activation: 'relu' }));
model.add(tf.layers.dense({units: 32, activation: 'relu' }));
model.add(tf.layers.dense({units: 1}))
...

注意在第一层,我们将inputShape参数设置为11。这是因为我们的大集市数据集中有11训练列。您可以通过打印处理过的张量的形状来确认这一点。在最后一层,我们将units属性设置为1,因为我们想要预测单个连续值。

中间的层可以是我们想要的任何数量,并且单元可以采用任何数量。因此,本质上,在两者之间增加更多的层会给我们一个更深的模型,而增加更多的单元会给我们一个更宽的模型。要使用的层的选择不仅取决于问题,还取决于执行多个实验和训练。

仅仅用这几行代码,你就成功地在tfjs中创建了一个三层回归模型。

创建模型后,通常要做的下一件事是编译模型。那么,编译是做什么的?嗯,编译是为训练和评估准备模型的过程。这意味着,在编译阶段,我们必须设置模型的优化器、损失和/或训练度量。

必须先编译一个tfjs模型,然后才能开始训练。那么,我们如何在tfjs中编译模型呢?这可以通过在已定义的模型上调用compile函数并设置您想要计算的优化器和度量来完成。

model.js文件的第 13-17 行中,我们通过将优化器设置为Adam,将lossmetrics属性设置为meanSquaredError来编译我们的回归模型。查看下面的代码片段:

...
    model.compile({
        optimizer: tf.train.adam(LEARNING_RATE),
        loss: tf.losses.meanSquaredError,
        metrics: ['mse']
    });
...

值得一提的是有不同类型的优化器可供选择;查看 https://js.tensorflow.org/api/latest/#Training-Optimizers 的完整列表。选择使用哪种优化器将取决于您的经验以及多次实验。

就损失而言,问题将通知您使用哪个损失函数。在我们的例子中,由于这是一个回归问题,我们可以使用均方误差 ( 均方误差)函数。要查看可用损耗功能的完整列表,请访问https://js.tensorflow.org/api/latest/#Training-Losses

最后,就模型训练期间计算和显示的指标而言,我们可以指定多个选项,就像损失一样,指定的指标将取决于您试图解决的问题。在我们的例子中,我们也可以计算一个均方误差。要查看支持指标的完整列表,请访问https://js.tensorflow.org/api/latest/#Metrics

现在您已经定义并编译了模型,我们将进入本章的下一部分,也是最后一部分,这是关于训练模型的。

用处理后的数据集训练模型

train.js文件包含代码,用于在处理后的数据集上训练三层回归模型。在以下步骤中,我们将引导您完成模型培训的整个过程:

  1. 首先,让我们使用processData函数加载和处理数据集,如下所示:

    js … const data = await processData("./dataset/train.csv") const Xtrain = data[0] const ytrain = data[1] …

  2. 接下来,我们使用getModel功能加载模型,如下所示:

    js … const model = getModel() …

  3. Next, and very importantly, we call the fit function on the model, pass the training data, the target, and a couple of parameters such as the epoch, batchSize, and validationSplits parameters, and a callback function called onEpochEnd, as follows:

    js …     await model.fit(Xtrain, ytrain, {         batchSize: 24,         epochs: 20,         validationSplit: 0.2,         callbacks: {             onEpochEnd: async (epoch, logs) => {                 const progressUpdate = `EPOCH (${epoch + 1}): Train MSE: ${Math.sqrt(logs.mse)}, Val MSE:  ${Math.sqrt(logs.val_mse)}\n`                 console.log(progressUpdate);             }         }     }); ...

    让我们理解我们传递给fit函数的参数的作用,如下所示:

    • Xtrain:训练数据。
    • ytrain:目标数据。
    • epoch:历元大小是迭代训练数据的次数。
    • batchSize:批次大小是计算一次梯度更新时使用的数据点或样本数。
    • validationSplit:验证分割是一个方便的参数,它告诉tfjs保留指定百分比的数据进行验证。当我们不想手动将数据集分割成训练集和测试集时,可以使用这种方法。
    • callbacks:回调,顾名思义,接受在模型训练的不同生命周期中调用的函数列表。回调在监控模型训练中很重要。查看完整的回调列表:https://js.tensorflow.org/api/latest/#tf.。
    • 最后,我们保存模型,以便在进行新的预测时使用,如下所示:

    js       ...       await model.save("file://./sales_pred_model") ...

运行train.js文件将加载和处理数据集,加载模型,并针对指定数量的时期运行模型训练。我们指定的回调(onEpochEnd)会打印出每个历元后的损失和根 MSE,如下图截图所示:

Figure 10.11 – Model training logs showing loss and root MSE

图 10.11–显示损失和根均方误差的模型训练日志

就这样!您已经成功地创建、训练并保存了一个回归模型,该模型可以使用 TensorFlow.js 预测销售价格。在本章的下一部分也是最后一部分,我们将向您展示如何加载您保存的模型并使用它进行预测。

用训练好的模型进行预测

为了做出预测,我们必须加载保存的模型,并在其上调用predict 函数。TensorFlow.js 提供了一个loadLayersModel函数,可以用来从文件系统加载保存的模型。在以下步骤中,我们将向您展示如何实现这一点:

  1. 创建一个名为predict.js的新文件。
  2. In the predict.js file, add the following code:

    js const dfd = require("danfojs-node") const tf = dfd.tf async function loadModel() {     const model = await tf.loadLayersModel('file://./sales_pred_model/model.json');     model.summary()     return model } loadModel()

    前面的代码从文件路径加载保存的模型并打印摘要。摘要的输出应该类似于下面屏幕截图中显示的内容:

    Figure 10.12 – Model summary of the saved model

    图 10.12–已保存模型的模型摘要

  3. Now, create a new function called predict that uses the saved model to make a prediction, as shown in the following code snippet:

    ```js ... async function predict() {     //You'll probably have to do some data pre-processing as we did before training     const data = [0.1, 0.21, 0.25, 0.058, 0.0, 0.0720, 0.111, 1, 0, 0.5, 0.33] //sample processed test data     const model = await loadModel()     const value = model.predict(tf.tensor(data, [1, 11])) //cast data to required shape     console.log(value.arraySync());

    } predict() ```

    输出如下所示:

    js [ [ 738.65380859375 ] ] ...

    在前面的函数中,我们在模型上调用predict函数,并传递一个具有我们的模型所期望的正确形状(batch,11)的张量。这返回预测的张量,从这个张量,我们得到基础值。由此,我们可以看出,具有这些特定价值的产品售价约为 739 美元 ( 美元)。

    注意

    在现实世界的应用中,您通常会从另一个逗号分隔值 ( CSV )文件中加载一个测试数据集,并应用与我们在培训期间相同的数据处理步骤。该示例使用内联数据点,只是为了演示如何使用保存的模型进行预测。

这就把我们带到了这一章的结尾!祝贺你走到这一步。我相信你学到了很多。在下一章中,我们将通过构建一个更实际的应用——一个推荐系统来深入探讨!

总结

在本章中,我们向您介绍了 TensorFlow.js 的基础知识,具体来说,您学习了如何在浏览器和 Node.js 环境中安装 TensorFlow.js,您学习了 tensors 和tfjs的核心数据结构,您学习了 core 和 Layer APIs,最后,您学习了如何构建、训练和保存回归模型。

在下一章中,我们将深入到一个更加实用和动手的项目中,这里获得的知识将帮助您使用 TensorFlow.js 和 Danfo.js 构建出色的产品。