TensorFlow.js 入门

2025-06-07

TensorFlow.js 入门

如果您像我一样,一直想知道什么是机器学习(又名 ML),并且摆脱了所有那些数学术语,那么这是一个激动人心的时刻,因为它TensorFlow.js可以为您提供帮助。

您可以在此处找到此帖子的代码

简介

我从事前端开发多年,也对机器学习和人工智能充满好奇。然而,由于我一直很忙,而且大多数机器学习框架都是用我从未接触过的语言编写的,所以一直没有机会深入研究。

如今,情况已经发生了变化,人们现在在移动设备或浏览器中使用机器学习。TensorFlow.js它是一个允许我们在浏览器或 中创建、训练和部署 ML 模型的库Node.js。说实话,我对此感到非常兴奋,因为它让我可以玩转模型和神经网络,而无需深入底层或学习一门新语言🤯。

别误会,我并不害怕学习一门新语言,事实上,学习语言也是我的爱好之一。但由于我最近忙于各种事务,根本没时间深入研究这个领域。

这个库的好处在于,您不需要具备 ML 方面的先验知识,您只需处理一些为您简化了很多概念的高级 API,这样您就可以专注于部署模型和解决问题,而不是重新发明轮子🔥。

但还有更多选择,为我们带来了更多机会。基本上你可以:

  • 导入预先训练的模型并使用它(预测或部署它)
  • 导入预先训练的模型(Keras 或 Python)并使用数据集进行训练
  • 创建、训练、预测和部署隐私友好模型(数据永远不会离开应用程序)
  • 可能还有更多我不知道的事情🤷‍。

核心概念

在进一步了解如何使用它之前,我们需要熟悉一些基本概念,以便达成共识。

张量

数据的核心单位TensorFlow.js是张量:一组数值,被塑造成一个或多个维度的数组。Tensor实例具有一个shape属性,该属性定义数组shape(即数组每个维度上有多少个值)。

变量

变量用一个张量值来初始化。然而,与张量不同的是,变量的值是可变的。

运营(Ops)

张量允许您存储数据,而操作 (ops) 允许您操作这些数据。TensorFlow.js提供了各种适用于线性代数和机器学习的可在张量上执行的操作。由于张量是不可变的,这些操作不会改变其值;相反,操作会返回新的张量。

模型和层

从概念上讲,模型是一个函数,给定一些输入,它将产生一些期望的输出。TensorFlow.js创建模型有两种方法。你可以直接使用操作符 (ops) 来表示模型所做的工作。

或者您可以使用高级 APItf.model来构建层模型,这是深度学习中流行的抽象。

警告:由于TensorFlow.js使用 GPU 加速数学运算,因此在处理张量和变量时需要管理 GPU 内存。它提供了两个函数来帮助实现这一点:disposetf.tidy。我们稍后会深入探讨这两个函数。

如何使用预先训练的模型

您可以使用广受欢迎的Keras Python 库中的预训练模型进行预测。这意味着您无需成为数据科学家即可使用这些模型,甚至可以构建强大的机器学习应用。

幸运的是,有许多可用且随时可用的模型,它们通过 公开TensorFlow.js。为此,您需要使用TensorFlow.js converter一个开源库,将预先训练的模型加载到 可以理解的格式中TenserFlow.js

注意:为此,您需要了解一点Python知识并将其安装在本地。

您需要执行两个操作才能获得一个可立即使用的模型。首先,将模型保存在本地,然后运行转换器进行转换。但我找到了一种更简单的方法,不需要运行转换。转换逻辑已经在tensorflowjsPython 包中实现了😁,所以我就直接用它吧。

保存模型

让我们来看一个例子,假设我们要导入MobileNet网络(用于检测图像中的物体)并将其保存在本地。首先,按照此处的说明安装先决条件

然后我们可以编写下面的代码将模型保存在本地:

from keras.applications import mobilenet
import tensorflowjs as tfjs

mobilenet = mobilenet.MobileNet()

save_path = "output\\mobilenet"
tfjs.converters.save_keras_model(mobilenet, save_path)
Enter fullscreen mode Exit fullscreen mode

mobilenet运行此程序后,文件夹中应该有一个output包含以下文件的文件夹:

以 TensorFlow.js 格式保存的 keras 模型

猜猜看,您已经准备好使用它并编写您的第一个TensorFlow.js应用程序了。

如果您热衷于使用 CLI 命令转换模型,请查看本教程

在您的应用程序中使用模型

我在示例中使用了Angular ,但您可以随意使用您喜欢的任何框架,甚至是原始 JS 🙃。

创建应用程序

我已经安装了 Angular CLI,因此我只需打开命令提示符并创建一个新的应用程序:

ng new mobilenet

cd mobilenet
Enter fullscreen mode Exit fullscreen mode

安装 TensorFlow.js

这需要一些时间(创建应用并安装所有 npm 包)。完成后,TensorFlow.js也添加以下包:

npm install @tensorflow/tfjs --save
Enter fullscreen mode Exit fullscreen mode

完成后,将保存的模型的内容复制到资产文件夹中,然后使用您选择的编辑器(VS Code😁)打开该文件夹。

您还需要图像类别用于预测。因此,请在项目中的某个位置创建一个文件,并将该文件的内容添加到其中。我已将其放在我的 assets 文件夹中。

导入模型并使用它

打开app.component.ts文件并添加导入语句:

import * as tf from '@tensorflow/tfjs';
import { IMAGENET_CLASSES } from '../assets/imagenet-classes';
Enter fullscreen mode Exit fullscreen mode

我们需要一些变量来保存我们的数据和一些我们必须使用的 HTML 元素的引用:

model: tf.Model;
classes: any[];
imageData: ImageData;

@ViewChild('chosenImage') img: ElementRef;
@ViewChild('fileUpload') fileUpload: ElementRef;
Enter fullscreen mode Exit fullscreen mode

该模型将具有我们的模型,类用于我们的预测结果,并imageData用于将我们的文件上传文件转换为它并在页面上的图像中显示它。

还有两个全局变量,图像大小是模型训练的大小,以及我们想要从预测结果中选择的预测数量(因为它是一个数组):

const IMAGE_SIZE = 224;
const TOPK_PREDICTIONS = 5;
Enter fullscreen mode Exit fullscreen mode

是时候添加一个方法来加载模型并在其中调用它了ngOnInit

ngOnInit() {
  this.loadModel();
}

async loadModel() {
  this.model = await tf.loadModel('/assets/model.json');
}
Enter fullscreen mode Exit fullscreen mode

我们需要在 HTML 中上传文件和添加图像,所以让我们添加它们:

<div class="container">
  <h2>
    Using MobileNet neural network in Angular
  </h2>
  <div class="upload" [hidden]="!model">
    Upload an image:
    <input
      #fileUpload
      type="file"
      id="files"
      name="files[]"
      (change)="fileChangeEvent($event)"
    />
  </div>
  <div>
    <img
      #chosenImage
      width="224"
      height="224"
      class="sample-image"
    />
    <div class="predictions">
      <div
        *ngFor="let class of classes"
        class="row"
      >
        <div class="col-sm-6">
          {{class.className}}
        </div>
        <div class="col-sm-6">
          {{class.probability.toFixed(3)}}
        </div>
      </div>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

再用一点 CSS 让它更漂亮:

.container {
  padding: 200px;

  .sample-image {
    margin: 20px;
  }

  .predictions {
    margin-top: 20px;
    width: 100%;
  }
}
Enter fullscreen mode Exit fullscreen mode

HTML 中的预测部分将包含预测结果,我们假设它存储在名为的变量中classes

现在让我们回到TypeScript文件并添加预测代码。首先,为文件输入创建一个处理程序,它将触发我们的预测逻辑:

fileChangeEvent(event: any) {
  const file = event.target.files[0];
  if (!file || !file.type.match('image.*')) {
    return;
  }

  this.classes = [];

  const reader = new FileReader();
  reader.onload = e => {
    this.img.nativeElement.src = e.target['result'];
    this.predict(this.img.nativeElement);
  };

  reader.readAsDataURL(file);
}
Enter fullscreen mode Exit fullscreen mode

在这个方法中,我们所做的就是读取选定的文件,将其作为图像源放在页面上,以便页面能够看到所选的图像,然后调用预测方法。onload由于必须先读取文件,因此我们在事件处理程序中异步调用了该方法。

现在让我们编写预测代码:

async predict(imageData: ImageData): Promise<any> {
  this.fileUpload.nativeElement.value = '';
  const startTime = performance.now();
  const logits = tf.tidy(() => {
    // tf.fromPixels() returns a Tensor from an image element.
    const img = tf.fromPixels(imageData).toFloat();

    const offset = tf.scalar(127.5);
    // Normalize the image from [0, 255] to [-1, 1].
    const normalized = img.sub(offset).div(offset);

    // Reshape to a single-element batch so we can pass it to predict.
    const batched = normalized.reshape([1, IMAGE_SIZE, IMAGE_SIZE, 3]);

    // Make a prediction through mobilenet.
    return this.model.predict(batched);
  });

  // Convert logits to probabilities and class names.
  this.classes = await this.getTopKClasses(logits, TOPK_PREDICTIONS);
  const totalTime = performance.now() - startTime;
  console.log(`Done in ${Math.floor(totalTime)}ms`);
}
Enter fullscreen mode Exit fullscreen mode

如果你乍一看不懂这里的代码,没关系。既然我们已经导入了模型,那么就需要了解一下它的内部原理。

首先,我使用tidy前面提到的函数来确保我们没有任何内存泄漏。

然后我将图像转换为该模型所需的浮点数据类型。

完成后,我们需要将数据从 [0, 255] 范围归一化到 [-1, 1]。该scalar操作会创建一个具有指定值的张量。

最后,我们需要将输入重塑为 [1, IMAGE_SIZE, IMAGE_SIZE, 3] 张量并调用预测。

一旦我们得到结果,我们就必须x从结果中提取顶级类,所以让我们实现它:

async getTopKClasses(logits, topK): Promise<any[]> {
  const values = await logits.data();

  const valuesAndIndices = [];
  for (let i = 0; i < values.length; i++) {
    valuesAndIndices.push({ value: values[i], index: i });
  }
  valuesAndIndices.sort((a, b) => {
    return b.value - a.value;
  });
  const topkValues = new Float32Array(topK);
  const topkIndices = new Int32Array(topK);
  for (let i = 0; i < topK; i++) {
    topkValues[i] = valuesAndIndices[i].value;
    topkIndices[i] = valuesAndIndices[i].index;
  }

  const topClassesAndProbs = [];
  for (let i = 0; i < topkIndices.length; i++) {
    topClassesAndProbs.push({
      className: IMAGENET_CLASSES[topkIndices[i]],
      probability: topkValues[i]
    });
  }
  return topClassesAndProbs;
}
Enter fullscreen mode Exit fullscreen mode

好的,记得我们调用了这个方法,并将 predict 的结果设置为 a 的形状logit。Logits 通常是 a Tensor、一个数组或一个类型数组。

基本上,我们通过等待方法获取结果data。然后,我们使用该输出的值和索引创建一个新数组。

在此基础上,我们根据形成的数组计算出最终的类。同样,你不需要理解代码的作用,从高层次上讲,它只是将结果映射到我们之前从 GitHub 仓库获取的某个类上。

运行应用程序

您现在可以运行该应用程序并上传localhost:4200图像,看看您得到了什么预测😎。

入门就是这么简单。希望你喜欢这篇指南,并能激励你去看看。

再次,您可以在此处找到此帖子的代码

文章来源:https://dev.to/yashints/getting-started-on-tensorflow-js-4n5
PREV
删除未使用的 CSS
NEXT
你知道滚动到文本吗?📜