Transformers.js 文档

构建一个 Vanilla JavaScript 应用程序

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

以开始

构建一个 Vanilla JavaScript 应用程序

在本教程中,您将构建一个简单的 Web 应用程序,使用 Transformers.js 检测图像中的物体!要跟随学习,您只需要一个代码编辑器、一个浏览器和一个简单的服务器(例如,VS Code Live Server)。

以下是它的工作原理:用户点击“上传图片”并使用输入对话框选择一张图片。在使用目标检测模型分析图像后,预测的边界框会叠加在图像之上,如下所示

Demo

有用链接

步骤 1:HTML 和 CSS 设置

在我们开始使用 Transformers.js 构建之前,我们首先需要用一些标记和样式来打基础。创建一个名为 index.html 的文件,包含一个基本的 HTML 骨架,并将以下 <main> 标签添加到 <body>

<main class="container">
  <label class="custom-file-upload">
    <input id="file-upload" type="file" accept="image/*" />
    <img class="upload-icon" src="https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/upload-icon.png" />
    Upload image
  </label>
  <div id="image-container"></div>
  <p id="status"></p>
</main>
点击这里查看此标记的细分。

我们添加了一个 <input> 元素,其 type="file" 属性接受图像。这允许用户使用弹出对话框从本地文件系统中选择图像。此元素的默认样式看起来很糟糕,所以让我们添加一些样式。实现这一点最简单的方法是将 <input> 元素包装在一个 <label> 中,隐藏输入,然后将标签样式化为按钮。

我们还添加了一个空的 <div> 容器来显示图像,还有一个空的 <p> 标签,我们将用它来在下载和运行模型时向用户提供状态更新,因为这两个操作都需要一些时间。

接下来,将以下 CSS 规则添加到 style.css 文件中,并将其链接到 HTML

html,
body {
    font-family: Arial, Helvetica, sans-serif;
}

.container {
    margin: 40px auto;
    width: max(50vw, 400px);
    display: flex;
    flex-direction: column;
    align-items: center;
}

.custom-file-upload {
    display: flex;
    align-items: center;
    gap: 10px;
    border: 2px solid black;
    padding: 8px 16px;
    cursor: pointer;
    border-radius: 6px;
}

#file-upload {
    display: none;
}

.upload-icon {
    width: 30px;
}

#image-container {
    width: 100%;
    margin-top: 20px;
    position: relative;
}

#image-container>img {
    width: 100%;
}

以下是 UI 在此阶段的样子

Demo

步骤 2:JavaScript 设置

完成这些无聊的部分后,让我们开始编写一些 JavaScript 代码!创建一个名为 index.js 的文件,并通过在 <body> 末尾添加以下内容将其链接到 index.html

<script src="./index.js" type="module"></script>

type="module" 属性很重要,因为它将我们的文件转换为一个JavaScript 模块,这意味着我们将能够使用导入和导出。

转到 index.js,让我们通过在文件顶部添加以下行来导入 Transformers.js

import { pipeline, env } from "https://cdn.jsdelivr.net.cn/npm/@huggingface/transformers";

由于我们将从 Hugging Face Hub 下载模型,因此我们可以通过设置以下内容跳过本地模型检查

env.allowLocalModels = false;

接下来,让我们创建对我们将在稍后访问的各种 DOM 元素的引用

const fileUpload = document.getElementById("file-upload");
const imageContainer = document.getElementById("image-container");
const status = document.getElementById("status");

步骤 3:创建目标检测管道

我们终于可以创建目标检测管道了!提醒一下,管道 是库提供的用于执行特定任务的高级接口。在本例中,我们将使用 pipeline() 辅助函数实例化一个目标检测管道。

由于这可能需要一些时间(特别是第一次,因为我们必须下载约 40MB 的模型),所以我们首先更新 status 段落,以便用户知道我们即将加载模型。

status.textContent = "Loading model...";

为了使本教程保持简单,我们将在主(UI)线程中加载和运行模型。不建议在生产应用程序中这样做,因为在执行这些操作时 UI 会冻结。这是因为 JavaScript 是一种单线程语言。要克服这个问题,您可以使用 Web Worker 在后台下载和运行模型。但是,在本教程中我们不会介绍这一点……

我们现在可以调用我们在文件顶部导入的 pipeline() 函数来创建我们的目标检测管道

const detector = await pipeline("object-detection", "Xenova/detr-resnet-50");

我们向 pipeline() 函数传递了两个参数:(1)任务和(2)模型。

  1. 第一个告诉 Transformers.js 我们想要执行什么类型的任务。在本例中,是 object-detection,但库支持许多其他任务,包括 text-generationsentiment-analysissummarizationautomatic-speech-recognition。有关完整列表,请参见此处

  2. 第二个参数指定我们想使用哪个模型来解决给定的任务。我们将使用 Xenova/detr-resnet-50,因为它是一个相对较小(约 40MB)但功能强大的模型,用于检测图像中的物体。

一旦函数返回,我们将告诉用户应用程序已准备好使用。

status.textContent = "Ready";

步骤 4:创建图像上传器

下一步是支持上传/选择图像。为此,我们将监听 fileUpload 元素的“change”事件。在回调函数中,我们使用 FileReader() 来读取选定图像的内容(如果没有选择则不读取)。

fileUpload.addEventListener("change", function (e) {
  const file = e.target.files[0];
  if (!file) {
    return;
  }

  const reader = new FileReader();

  // Set up a callback when the file is loaded
  reader.onload = function (e2) {
    imageContainer.innerHTML = "";
    const image = document.createElement("img");
    image.src = e2.target.result;
    imageContainer.appendChild(image);
    // detect(image); // Uncomment this line to run the model
  };
  reader.readAsDataURL(file);
});

图像加载到浏览器后,将调用 reader.onload 回调函数。在其中,我们将新的 <img> 元素追加到 imageContainer 中,以供用户查看。

不用担心 detect(image) 函数调用(已注释掉) - 我们稍后会解释。现在,尝试运行应用程序并上传一个图像到浏览器。您应该会看到您的图像像这样显示在按钮下方。

Demo

步骤 5:运行模型

我们终于准备好开始与 Transformers.js 交互了!让我们从上面的代码段中取消 detect(image) 函数调用的注释。然后我们将定义该函数本身。

async function detect(img) {
  status.textContent = "Analysing...";
  const output = await detector(img.src, {
    threshold: 0.5,
    percentage: true,
  });
  status.textContent = "";
  console.log("output", output);
  // ...
}

注意:detect 函数需要是异步的,因为我们将 await 模型的结果。

status 更新为“Analysing”后,我们就可以进行 *推理* 了,这仅仅意味着用一些数据运行模型。这是通过 pipeline() 返回的 detector() 函数完成的。我们传递的第一个参数是图像数据(img.src)。

第二个参数是选项对象。

  • 我们将 threshold 属性设置为 0.5。这意味着我们希望模型至少有 50% 的信心才能声称它在图像中检测到对象。阈值越低,它检测到的对象就越多(但可能会误识别对象);阈值越高,它检测到的对象就越少(但可能会错过场景中的对象)。
  • 我们还指定了 percentage: true,这意味着我们希望将对象的边界框以百分比形式返回(而不是像素)。

如果您现在尝试运行应用程序并上传图像,您应该会看到以下输出记录在控制台中。

Demo

在上面的示例中,我们上传了一张两头大象的图像,所以 output 变量包含一个有两个对象的数组,每个对象都包含一个 label(字符串“elephant”)、一个 score(表示模型对其预测的信心)和一个 box 对象(表示检测到的实体的边界框)。

步骤 6:渲染方框

最后一步是将 box 坐标显示为围绕每头大象的矩形。

在我们的 detect() 函数的末尾,我们将使用 .forEach()output 数组中的每个对象上运行 renderBox 函数。

output.forEach(renderBox);

以下是 renderBox() 函数的代码,其中包含一些注释以帮助您理解正在发生的事情。

// Render a bounding box and label on the image
function renderBox({ box, label }) {
  const { xmax, xmin, ymax, ymin } = box;

  // Generate a random color for the box
  const color = "#" + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, 0);

  // Draw the box
  const boxElement = document.createElement("div");
  boxElement.className = "bounding-box";
  Object.assign(boxElement.style, {
    borderColor: color,
    left: 100 * xmin + "%",
    top: 100 * ymin + "%",
    width: 100 * (xmax - xmin) + "%",
    height: 100 * (ymax - ymin) + "%",
  });

  // Draw the label
  const labelElement = document.createElement("span");
  labelElement.textContent = label;
  labelElement.className = "bounding-box-label";
  labelElement.style.backgroundColor = color;

  boxElement.appendChild(labelElement);
  imageContainer.appendChild(boxElement);
}

边界框和标签跨度也需要一些样式,所以将以下内容添加到 style.css 文件中。

.bounding-box {
    position: absolute;
    box-sizing: border-box;
    border-width: 2px;
    border-style: solid;
}

.bounding-box-label {
    color: white;
    position: absolute;
    font-size: 12px;
    margin-top: -16px;
    margin-left: -2px;
    padding: 1px;
}

就这样!

您现在已经构建了自己的功能齐全的 AI 应用程序,它可以检测图像中的对象,并且完全在您的浏览器中运行:没有外部服务器、API 或构建工具。太酷了!🥳

Demo

该应用程序的实时网址如下:https://huggingface.co/spaces/Scrimba/vanilla-js-object-detector

< > 在 GitHub 上更新