Transformers.js 文档
构建 Vanilla JavaScript 应用程序
并获得增强的文档体验
开始使用
构建 Vanilla JavaScript 应用程序
在本教程中,您将构建一个简单的 Web 应用程序,该应用程序使用 Transformers.js 检测图像中的物体!要继续学习,您只需要一个代码编辑器、一个浏览器和一个简单的服务器(例如,VS Code Live Server)。
以下是它的工作原理:用户单击“上传图像”并使用输入对话框选择图像。在使用物体检测模型分析图像后,预测的边界框将叠加在图像顶部,如下所示
实用链接
步骤 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 的外观
步骤 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)模型。
第一个参数告诉 Transformers.js 我们要执行的任务类型。在我们的例子中,它是
object-detection
,但该库支持许多其他任务,包括text-generation
、sentiment-analysis
、summarization
或automatic-speech-recognition
。有关完整列表,请参阅 此处。第二个参数指定我们想要使用哪个模型来解决给定的任务。我们将使用
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)
函数调用(已注释掉)——我们稍后会解释它!现在,尝试运行应用程序并上传图像到浏览器。您应该看到您的图像显示在按钮下方,如下所示
步骤 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
,这意味着我们希望物体的边界框以百分比(而不是像素)返回。
如果您现在尝试运行应用程序并上传图像,您应该看到以下输出记录到控制台
在上面的示例中,我们上传了两只大象的图像,因此 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 或构建工具。非常酷!🥳
该应用程序在以下 URL 上线:https://huggingface.co/spaces/Scrimba/vanilla-js-object-detector
< > 在 GitHub 上更新