AIGC前端工程师——JS如何运行AI模型+图片识别

前言

大家好,今日我们将深入探讨如何在前端环境中,利用JavaScript执行AI模型。随着人工智能技术的飞速发展,越来越多的开发者开始尝试在Web应用中集成AI功能,而JavaScript作为前端开发的主力军,也扮演着越来越重要的角色。那么,前端执行AI模型的复杂程度究竟如何呢?让我们一探究竟,揭开这一领域的神秘面纱。

总流程

  1. AI模型库导入
  2. 模型加载
  3. 数据预处理
  4. 推理执行
  5. 输出处理

AI模型库导入

Ⅰ、AI模型库的选择

首先,你需要选择一个适合你的需求并且能够在JavaScript环境下运行的AI模型库。常见的选择包括:TensorFlow、Brain、Synaptic等。它们各有所长,可以根据您的具体需求来挑选。接下来,让我们通过简介来了解这些模型库的主要使用场景

  1. TensorFlow: 是一个由Hugging Face开发的深度学习库,主要用于自然语言处理(NLP)。它提供了大量预训练模型,如BERT、GPT、RoBERTa、T5等,适用于处理文本生成、情感分析、智能问答系统等自然语言处理任务的库,提供了各种预训练模型,适合处理文本相关的复杂任务。
  2. Brain:是一个简单的JavaScript库,适用于处理简单预测和基础图像识别任务,易于入门和使用,适合初学者和小型项目。
  3. Synaptic:是一个灵活的JavaScript神经网络库,主要用于学术研究和小型项目,支持自定义网络结构,适合探索性实验和研究。
  4. ConvNetJS:专注于浏览器端的图像识别任务,特别擅长处理基础的图像分类任务,无需服务器端支持,适合简单的图像识别应用。
  5. ml5: 基于TensorFlow.js的JavaScript库,旨在简化机器学习的复杂性,适合艺术创作和教育项目,提供高级API用于快速原型开发和教学。

在本篇文章中,我们将以目前应用最为广泛的TensorFlow库作为示例进行讲解。

Ⅱ、模型库引入方式

模型库的引入方式多样,每种方式都有其优缺点。以下是两种常见引入方式的比较,以及示例代码:

  1. Script 标签引入

    • 优点

      • 简单易用 :只需在 HTML 文件中添加 <script> 标签即可引入库文件,无需配置额外的工具或加载器。
      • 兼容性好:适用于各种浏览器和环境,无需担心兼容性问题。
      • 直接访问全局变量:库文件加载后会在全局作用域中定义相关的对象或函数,可以直接在任何地方访问。
    • 缺点

      • 依赖本地文件:需要下载并存储库文件,增加了项目体积和维护成本。
      • 版本控制困难:更新和管理库文件需要手动处理,无法利用包管理工具进行版本控制。
    • 示例

html 复制代码
<!-- 使用 Script 标签引入库文件 -->
<script src="path/to/transformers/dist/transformers.min.js"></script>
  1. ES Module 引入

    • 优点

      • 模块化管理 :支持模块化开发,可以使用 importexport 语法来管理模块之间的依赖关系,易于维护和管理。
      • 版本控制简单:可以直接指定所需的库版本,无需下载和管理本地文件,依赖于包管理工具。
      • 可靠缓存:浏览器会对 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 函数时,需要传递两个参数:任务类型和模型标识符。

  1. 任务类型字符串:这是一个描述所需任务的字符串。它告诉模型应该执行什么类型的任务。在本次示例中,任务类型是 "object-detection"(物体检测),表示我们希望进行对象检测。其他任务类型还包括文本生成(text-generation)、文本分类(text-classification)、问答(question-answering)等。
  2. 模型标识符:这是一个指定要使用的模型的字符串。模型标识符通常由模型的创建者定义,并且用于唯一标识一个特定的模型。在本次示例中,模型标识符是 "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);
  1. const reader = new FileReader();:创建一个新的FileReader对象。
  2. reader.onload = function (e2) { ... }:当文件加载完成时,执行这个函数。e2参数是一个事件对象,其中包含了加载完成的文件数据。
  3. const image = document.createElement('img'):创建一个新的<img>元素,用于显示加载的图片。
  4. image.src = e2.target.result;:将加载的文件数据(Data URL)赋值给图片元素的src属性,这样就将图片加载到了DOM中。
  5. imageContainer.appendChild(image);:将图片元素添加到名为imageContainer的HTML元素中。imageContainer(一个用于显示图片的容器元素)。
  6. detect(image);:调用detect函数,并传递加载的图片作为参数。启动图像检测任务的函数,利用功能模块化思想,对功能进行封装。
  7. 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)
}
  1. const detect = async (image) => { ... }:定义了一个名为 detect 的异步箭头函数,它接收一个图片对象作为参数,用于图签检测。
  2. status.textContent = "分析中...";:这行代码设置了页面中一个元素的文本内容为 "分析中...",为了提升用户体验,以便用户知道当前正在进行对象检测。
  3. const detector = await pipeline("object-detection", "Xenova/detr-resnet-50");:不清楚请移步"加载模型"部分。
  4. const output = await detector(image.src, { threshold: 0.1, percentage: true });:这里调用了 detector 函数对象,传递了图片的源数据和一个包含参数的对象。threshold 参数设置了阈值,用于过滤检测结果的置信度阈值,这里设置为 0.1;percentage 参数设置为 true,指示返回的置信度以百分比形式。当然除了这两种参数外,该模型还提供了其它参数,详情请查阅官方文档
  5. 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应用赋予一种独特的魔力,同时也极大地丰富了用户的互动体验。祝大家在探索人工智能的道路上不断前行,创造出更多令人惊艳的作品!✨🚀

相关推荐
Martin -Tang9 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发10 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
扫地的小何尚4 小时前
NVIDIA RTX 系统上使用 llama.cpp 加速 LLM
人工智能·aigc·llama·gpu·nvidia·cuda·英伟达
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html