前言
大家好,今日我们将深入探讨如何在前端环境中,利用JavaScript执行AI模型。随着人工智能技术的飞速发展,越来越多的开发者开始尝试在Web应用中集成AI功能,而JavaScript作为前端开发的主力军,也扮演着越来越重要的角色。那么,前端执行AI模型的复杂程度究竟如何呢?让我们一探究竟,揭开这一领域的神秘面纱。
总流程
- AI模型库导入
- 模型加载
- 数据预处理
- 推理执行
- 输出处理
AI模型库导入
Ⅰ、AI模型库的选择
首先,你需要选择一个适合你的需求并且能够在JavaScript环境下运行的AI模型库。常见的选择包括:TensorFlow、Brain、Synaptic等。它们各有所长,可以根据您的具体需求来挑选。接下来,让我们通过简介来了解这些模型库的主要使用场景:
- TensorFlow: 是一个由Hugging Face开发的深度学习库,主要用于自然语言处理(NLP)。它提供了大量预训练模型,如BERT、GPT、RoBERTa、T5等,适用于处理文本生成、情感分析、智能问答系统等自然语言处理任务的库,提供了各种预训练模型,适合处理文本相关的复杂任务。
- Brain:是一个简单的JavaScript库,适用于处理简单预测和基础图像识别任务,易于入门和使用,适合初学者和小型项目。
- Synaptic:是一个灵活的JavaScript神经网络库,主要用于学术研究和小型项目,支持自定义网络结构,适合探索性实验和研究。
- ConvNetJS:专注于浏览器端的图像识别任务,特别擅长处理基础的图像分类任务,无需服务器端支持,适合简单的图像识别应用。
- ml5: 基于TensorFlow.js的JavaScript库,旨在简化机器学习的复杂性,适合艺术创作和教育项目,提供高级API用于快速原型开发和教学。
在本篇文章中,我们将以目前应用最为广泛的TensorFlow库作为示例进行讲解。
Ⅱ、模型库引入方式
模型库的引入方式多样,每种方式都有其优缺点。以下是两种常见引入方式的比较,以及示例代码:
-
Script 标签引入:
-
优点:
- 简单易用 :只需在 HTML 文件中添加
<script>
标签即可引入库文件,无需配置额外的工具或加载器。 - 兼容性好:适用于各种浏览器和环境,无需担心兼容性问题。
- 直接访问全局变量:库文件加载后会在全局作用域中定义相关的对象或函数,可以直接在任何地方访问。
- 简单易用 :只需在 HTML 文件中添加
-
缺点:
- 依赖本地文件:需要下载并存储库文件,增加了项目体积和维护成本。
- 版本控制困难:更新和管理库文件需要手动处理,无法利用包管理工具进行版本控制。
-
示例:
-
html
<!-- 使用 Script 标签引入库文件 -->
<script src="path/to/transformers/dist/transformers.min.js"></script>
-
ES Module 引入:
-
优点:
- 模块化管理 :支持模块化开发,可以使用
import
和export
语法来管理模块之间的依赖关系,易于维护和管理。 - 版本控制简单:可以直接指定所需的库版本,无需下载和管理本地文件,依赖于包管理工具。
- 可靠缓存:浏览器会对 ES Module 进行缓存,下次加载时可直接使用缓存,提高了加载速度。
- 模块化管理 :支持模块化开发,可以使用
-
缺点:
- 兼容性限制:部分较老版本的浏览器不支持 ES Module,需要使用构建工具进行转换或提供回退方案。
- 需要网络连接:需要在每次加载时从远程服务器获取库文件,如果网络不稳定可能会导致加载失败或延迟。
-
示例:
-
js
// 使用 ES Module 引入库文件
import { pipeline, env } from "https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0";
env.allowLocalModels = false;
根据项目需求、开发环境及技术偏好,选取合适的方式至关重要。下一步,本次示例使用的是"ES Module 引入方式"导入模型库。
模型加载
至此,我们进入了模型准备阶段。您可以选择使用所选模型库提供的模型,或将自己的模型转换为前端友好的格式。有些框架已提供预训练模型,既省时又省力。当然,针对特殊需求,自行训练模型也是可行的。本节中,我将选择transformers中用于object-detection(物体检测)的Xenova/detr-resnet-50模型进行图片识别。示例代码如下:
js
// model 图片对象检测
const detector = await pipeline("object-detection", "Xenova/detr-resnet-50");
当使用 pipeline
函数时,需要传递两个参数:任务类型和模型标识符。
- 任务类型字符串:这是一个描述所需任务的字符串。它告诉模型应该执行什么类型的任务。在本次示例中,任务类型是 "object-detection"(物体检测),表示我们希望进行对象检测。其他任务类型还包括文本生成(text-generation)、文本分类(text-classification)、问答(question-answering)等。
- 模型标识符:这是一个指定要使用的模型的字符串。模型标识符通常由模型的创建者定义,并且用于唯一标识一个特定的模型。在本次示例中,模型标识符是 "Xenova/detr-resnet-50",它指定了一个名为DETR ResNet-50的对象检测模型。
数据预处理
在将数据喂给模型之前,需要对数据进行恰当的预处理,这包括调整大小、归一化、标准化等操作,旨在确保模型得以准确解析数据。仿若施加了魔法,AI模型将展现出它神奇的能力!下面此项目相应的代码示例,用以对用户输入的图片进行预处理:
js
const reader = new FileReader();
reader.onload = function (e2) {
// 加载完成之后执行
const image = document.createElement('img'); //创建图片对象
image.src = e2.target.result;
imageContainer.appendChild(image);
detect(image); // 启动ai任务 功能模块化, 封装出去
}
reader.readAsDataURL(file);
const reader = new FileReader();
:创建一个新的FileReader对象。reader.onload = function (e2) { ... }
:当文件加载完成时,执行这个函数。e2
参数是一个事件对象,其中包含了加载完成的文件数据。const image = document.createElement('img')
:创建一个新的<img>
元素,用于显示加载的图片。image.src = e2.target.result;
:将加载的文件数据(Data URL)赋值给图片元素的src
属性,这样就将图片加载到了DOM中。imageContainer.appendChild(image);
:将图片元素添加到名为imageContainer
的HTML元素中。imageContainer
(一个用于显示图片的容器元素)。detect(image);
:调用detect
函数,并传递加载的图片作为参数。启动图像检测任务的函数,利用功能模块化思想,对功能进行封装。reader.readAsDataURL(file);
:开始读取指定的文件,并以Data URL的形式加载文件内容到内存中。
推理执行
在准备工作完成后,就可以利用框架提供的API执行推理过程了,即将预处理后的数据传递给模型,并接收模型生成的结果。以下为相关代码示例:
js
// 检测图片AI任务
const detect = async (image) => {
status.textContent = "分析中..."; //优化用户体验
// model导入 图片对象检测 实例化了一个对象
const detector = await pipeline("object-detection", "Xenova/detr-resnet-50");
const output = await detector(image.src, {
threshold: 0.1,
percentage: true
})
output.forEach(renderBox)
}
const detect = async (image) => { ... }
:定义了一个名为detect
的异步箭头函数,它接收一个图片对象作为参数,用于图签检测。status.textContent = "分析中...";
:这行代码设置了页面中一个元素的文本内容为 "分析中...",为了提升用户体验,以便用户知道当前正在进行对象检测。const detector = await pipeline("object-detection", "Xenova/detr-resnet-50");
:不清楚请移步"加载模型"部分。const output = await detector(image.src, { threshold: 0.1, percentage: true });
:这里调用了detector
函数对象,传递了图片的源数据和一个包含参数的对象。threshold
参数设置了阈值,用于过滤检测结果的置信度阈值,这里设置为 0.1;percentage
参数设置为true
,指示返回的置信度以百分比形式。当然除了这两种参数外,该模型还提供了其它参数,详情请查阅官方文档output.forEach(renderBox);
:这行代码对output
中的每个检测结果都调用了一个名为renderBox
的函数,用于在页面上渲染检测结果。
输出处理
最后,模型推理完成后,需要对输出进行后处理,比如解码分类标签、解析回归结果、可视化输出等操作。就像做完饭后,需要摆盘装饰一样,把成果展示得更加美味诱人!以下是代码示例 :
js
//输出渲染函数
function renderBox({ box, label }) {
//从 `box` 对象中解构出最大和最小的 x 和 y 坐标值,便于对各个检测结果对象添加边框
const { xmax, xmin, ymax, ymin } = box;
//用于表示边界框
const boxElement = document.createElement('div');
//添加一个 CSS 类名,用于样式控制
boxElement.className = 'bounding-box';
Object.assign(boxElement.style, {
borderColor: '#FF0000',
borderWidth: '1px',
borderStyle: 'solid',
left: 100 * xmin + '%',
top: 100 * ymin + '%',
width: 100 * (xmax - xmin) + '%',
height: 100 * (ymax - ymin) + '%'
})
//显示在页面上
imageContainer.appendChild(boxElement);
//显示标签文本
const labelElement = document.createElement('span');
labelElement.textContent = label;
labelElement.className = 'bounding-box-label';
//设置标签文本的背景颜色为黑红色。
labelElement.style.backgroundColor = '#FF0000';
//显示标签
boxElement.appendChild(labelElement);
imageContainer.appendChild(boxElement);
}
完整代码
以下是关于图片检测的完整示例代码:
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nlp之图片识别</title>
<style>
.container {
margin: 40px auto;
width: max(50vw, 400px);
display: flex;
flex-direction: column;
align-items: center;
}
.custom-file-upload {
display: flex;
align-items: center;
cursor: pointer;
gap: 10px;
border: 2px solid black;
padding: 8px 16px;
border-radius: 6px;
}
#file-upload {
display: none;
}
#image-container {
width: 100%;
margin-top: 20px;
position: relative;
}
#image-container>img {
width: 100%;
}
.bounding-box {
position: absolute;
box-sizing: border-box;
}
.bounding-box-label {
position: absolute;
color: white;
font-size: 12px;
}
</style>
</head>
<body>
<main class="container">
<label for="file-upload" class="custom-file-upload">
<!-- input#file-upload -->
<!-- <input type="text" id="file-upload"> -->
<input type="file" accept="image/*" id="file-upload">
上传图片
</label>
<div id="image-container"></div>
<p id="status"></p>
</main>
<script type="module">
// transformers nlp 任务
import { pipeline, env } from "https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0";
env.allowLocalModels = false;
const fileUplod = document.getElementById('file-upload');
const imageContainer = document.getElementById('image-container');
fileUplod.addEventListener('change', (e) => {
// console.log(e.target.files[0]);
const file = e.target.files[0];
// 新建一个FileReader 对象 01 序列
// 图片比较大
const reader = new FileReader();
reader.onload = function (e2) {
// 加载完成
const image = document.createElement('img'); //创建图片对象
// console.log(e2.target.result);
image.src = e2.target.result;
imageContainer.appendChild(image);
detect(image); // 启动ai任务 功能模块化, 封装出去
}
reader.readAsDataURL(file);
})
const status = document.getElementById("status")
// 检测图片AI任务
const detect = async (image) => {
status.textContent = "分析中...";
// 实例化了一个对象
const detector = await pipeline("object-detection", "Xenova/detr-resnet-50"); //model 图片对象检测
const output = await detector(image.src, {
threshold: 0.1,
percentage: true
})
// console.log(output);
output.forEach(renderBox)
}
function renderBox({ box, label }) {
console.log(box, label);
const { xmax, xmin, ymax, ymin } = box;
const boxElement = document.createElement('div');
boxElement.className = 'bounding-box';
Object.assign(boxElement.style, {
borderColor: '#FF0000',
borderWidth: '1px',
borderStyle: 'solid',
left: 100 * xmin + '%',
top: 100 * ymin + '%',
width: 100 * (xmax - xmin) + '%',
height: 100 * (ymax - ymin) + '%'
})
imageContainer.appendChild(boxElement);
const labelElement = document.createElement('span');
labelElement.textContent = label;
labelElement.className = 'bounding-box-label';
labelElement.style.backgroundColor = '#FF0000';
boxElement.appendChild(labelElement);
imageContainer.appendChild(boxElement);
}
</script>
</body>
</html>
运行结果:
当然,这段代码仍有需要改进的地方比如图像检测精度等。
总结
在前端直接部署和运行AI模型可能初听起来似乎颇为高深莫测,但若是跟随上述步骤一步步地执行,你将会意识到这一过程并不像最初预想的那样复杂。利用JavaScript来管理AI模型的执行,不仅能够为你的Web应用赋予一种独特的魔力,同时也极大地丰富了用户的互动体验。祝大家在探索人工智能的道路上不断前行,创造出更多令人惊艳的作品!✨🚀