- 作者:老汪软件技巧
- 发表时间:2024-11-09 07:01
- 浏览量:
大家好,我是electrolux,这篇文章带大家看看前端怎么直接离线调用huggingface的模型
代码在这里: /electroluxc…
路由是: /transformer
在开始文章之前。首先咱们来聊一下huggingface吧
简单的来说huggingface 可以理解为对于AI开发者的GitHub,提供了模型,数据集等ai的物料。并且提供了一个名为 transformers 的库,这个库结合了多种模型,使得用户可以快速地学习和使用这些模型
然后回归咱们的文章,咱们这篇文章也会用到 transformerjs, 通过这个库,我们可以调用huggingface里面的模型。对比transformer其他服务端的package,主要少了视频的输出能力和表格任务。具体可以参考
这篇文章会用 transformerjs 用 30行代码左右带你实现一个ai翻译助手,下面是成品,接着预告一下,下一篇文章我会用langchan+transformerjs实现一个带rag(目标检索增强)的llm助手,有兴趣的可以follow一下。话不多说,直接开始
1.1 选择模型和下载模型
说实话,这一步可能就是咱们这个教程最难的地方了,由于众所皆知的原因,咱们不能直接连接huggingface,所以这一步我们可以选择他的镜像站点
/
现在是第二步,我们要清楚前端不是每一个模型都能够直接调用的,只有是onnx的格式才能够进行调用,因此 我们可以在hf中搜两个作者。 onnx-community 和 Xenova 。这两者的模型可以直接在前端调用。里面加起来的模型大概有1000来个,大家可以根据需求自己选择
地址如下
好,现在我们到第三步了,怎么把模型下载到我们本地。在前端项目中,public文件夹一般是可访问的。我们可以考虑将大模型下载到这里。这里我们采用的是nllb模型,一个ai翻译的简单模型,由于文件较大,这里提供三个方法下载。然后在咱们的源码示例中,也不会携带模型的。大家自己选择方法下载即可
git submodule add https://hf-mirror.com/Xenova/nllb-200-distilled-600M public/nllb-200-distilled-600M
# 后续可能需要 git lfs pull
1.2 指定环境变量
这一步是离线调用的关键,默认transformer 是 会加载 huggingface网站 的线上模型,我们可以通过改变环境变量来让前端去加载自己本地的模型
import { env } from '@xenova/transformers';
env.useCustomCache = false
env.useFSCache = false
// 会加载public下的模型
env.localModelPath = "/"
1.3 调用模型输出
transformer核心是一个 pipeline 方法,然后 可以参照对应模型文件的readme来查看使用示例。
核心代码如下
import { pipeline } from '@xenova/transformers';
let dataGet = async () => {
const translator = await pipeline('translation', 'nllb-200-distilled-600M');
let input = '你好,今天天气怎么样'
const output = await translator(input, {
src_lang: 'zho_Hans', // Chinese
tgt_lang: 'eng_Latn', // English
});
console.log({
output, input
});
}
dataGet();
这是加载模型和自定义环境的完整代码,26行就实现了,aw。确实简单。然后在控制台中输出
import React from 'react'
import { useEffect } from 'react'
import { pipeline, env } from '@xenova/transformers';
env.useCustomCache = false
env.useFSCache = false
env.localModelPath = "/model"
export default function index() {
let dataGet = async () => {
const translator = await pipeline('translation', 'nllb-200-distilled-600M');
let input = '你好,今天天气怎么样'
const output = await translator(input, {
src_lang: 'zho_Hans', // Chinese
tgt_lang: 'eng_Latn', // English
});
console.log({
output, input
});
}
useEffect(() => {
dataGet();
})
return (
<div>transformerdiv>
)
}
1.4 代码简单加个ui
简单装饰一下
css文件
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.bg-black{
background-color: #000;
}
.bg-blue-1{
background-color: #e6f2ff;
}
.bg-blue-3{
background-color: #007bff;
}
.bg-white{
background-color: #fff;
}
.bg-black-1{
background: #585a5d
}
.color-white-1{
color: #c3c3c3
}
.color-blue-1{
color: #a6d2ff;
}
.color-blue-3{
color: #007bff;
}
.color-white{
color: #fff;
}
.chat-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.chat-move{
position: relative;
top: -100px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.messages-container {
width: 80%;
max-height: 60%;
overflow-y: auto;
padding: 20px;
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 255, 0.2);
}
.message {
padding: 12px;
border-radius: 10px;
margin-bottom: 15px;
word-break: break-word;
}
.user {
border: 1px solid #c2e0ff;
align-self: flex-end;
}
.bot {
border: 1px solid #c2e0ff;
display: flex;
flex-direction: row-reverse;
align-self: flex-start;
}
.input-area {
display: flex;
gap: 10px;
width: 80%;
margin-top: 20px;
}
input {
flex-grow: 1;
border: 1px solid #007bff;
border-radius: 10px;
}
input:focus {
outline: none;
border: 1px solid #007bff;
}
button {
padding: 10px 20px;
border: none;
border-radius: 10px;
cursor: pointer;
}
tsx文件示例,路由在 /Transformer
import React from 'react'
import { useState} from 'react'
import { pipeline, env } from '@xenova/transformers';
env.useCustomCache = false
env.useFSCache = false
env.localModelPath = "/"
export default function index() {
const dataGet = async (inputValueTemp) => {
setAnswer("加载中");
const translator = await pipeline('translation', 'nllb-200-distilled-600M');
const output = await (translator as any)(inputValueTemp, {
src_lang: 'zho_Hans', // Chinese
tgt_lang: 'eng_Latn', // English
}) ;
setAnswer(output[0].translation_text);
}
const [quesion, setQuestion] = useState('提问区');
const [answer, setAnswer] = useState('回答区');
const [inputValue, setInputValue] = useState('');
const handleSendMessage = () => {
if (inputValue.trim() !== '') {
setQuestion(inputValue)
setInputValue('');
dataGet(inputValue)
}
};
return (
<div className="chat-container bg-black-1">
<div className="chat-move">
<div className="title">
<h1 className='color-white-1'>AI翻译助手h1>
div>
<div className="messages-container bg-white">
<div
className="message user"
>
{quesion}
div>
<div
className="message bot"
>
{answer}
div>
div>
<div className="input-area">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button className='bg-blue-3 color-white' onClick={handleSendMessage}>发送button>
div>
div>
div>
);
}
1.5 感叹一下
transformerjs确实是个好框架,可惜的是transformerjs并不支持训练,虽然也没几个会在客户端进行训练哈哈。
并且现在如果要web端加载几个g的模型对性能是个大挑战
因此这个玩意工程化之路道阻且长, 但是我相信也不会有多久的,
目前唯一感觉可以使用的场景是在手机端,可以模仿王者荣耀资源包的形式引入模型,让用户自主选择。
顺便一提,最近看 到一个 MobileLLM(Optimizing Sub-billion Parameter Language Models for On-Device Use Cases),算是近期优化的比较好的一个开源模型,是为了移动端性能考虑的量化模型,但是文件堪堪也有800M,虽然也挺大的,但是在动则3,4G的模型中算还可以