Transformers.js 文档

构建 Vanilla JavaScript 应用

您正在查看的是需要从源码安装。如果你想使用常规的 npm install,请查看最新的稳定版本 (v3.0.0)。
Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

构建 Vanilla JavaScript 应用

在本教程中,你将使用 Transformers.js 构建一个简单的 Web 应用来检测图像中的物体!要跟着做,你只需要一个代码编辑器、一个浏览器和一个简单的服务器(例如,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 的文件,并在 index.html 中链接它,方法是在 <body> 的末尾添加以下内容

<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) task 和 (2) model。

  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() 函数的末尾,我们将对 output 数组中的每个对象运行 renderBox 函数,使用 .forEach()

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 上更新