Transformers.js 文档

构建 Vanilla JavaScript 应用程序

您正在查看 main 版本,该版本需要从源代码安装。如果您想要常规的 npm 安装,请查看最新的稳定版本 (v3.0.0)。
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> 标签,我们将使用它在下载和运行模型时向用户提供状态更新,因为这两个操作都需要一些时间。

接下来,在 style.css 文件中添加以下 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

我们终于准备好创建我们的物体检测 pipeline 了!提醒一下,pipeline 是库提供的高级接口,用于执行特定任务。在我们的例子中,我们将使用 pipeline() 辅助函数实例化一个物体检测 pipeline。

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

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

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

我们现在可以调用我们在文件顶部导入的 pipeline() 函数,以创建我们的物体检测 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 更新为“分析中”,我们就准备好执行推理,这只是意味着使用一些数据运行模型。这通过从 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);
}

边界框和标签 span 也需要一些样式,因此将以下内容添加到 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

该应用程序在以下 URL 上线:https://huggingface.co/spaces/Scrimba/vanilla-js-object-detector

< > 在 GitHub 上更新