DataLearner logoDataLearnerAI
Latest AI Insights
Model Evaluations
Model Directory
Model Comparison
Resource Center
Tool Directory

加载中...

DataLearner logoDataLearner AI

A knowledge platform focused on LLM benchmarking, datasets, and practical instruction with continuously updated capability maps.

产品

  • Leaderboards
  • 模型对比
  • Datasets

资源

  • Tutorials
  • Editorial
  • Tool directory

关于

  • 关于我们
  • 隐私政策
  • 数据收集方法
  • 联系我们

© 2026 DataLearner AI. DataLearner curates industry data and case studies so researchers, enterprises, and developers can rely on trustworthy intelligence.

隐私政策服务条款
navigation.items.llm-tutorials

大模型教程

学习如何使用各种大语言模型,包括模型部署、微调、推理等实用教程

3篇教程
手把手教你用4090部署面壁智能开源的20亿参数大语言模型MiniCPM-2B-SFT

手把手教你用4090部署面壁智能开源的20亿参数大语言模型MiniCPM-2B-SFT

MiniCPM-2B-DPO阅读 0

<p>MiniCPM面壁智能开源的一系列小规模大语言模型,参数在20亿左右。在30亿参数及以下的模型中表现很好。也可以在手机上运行。MiniCPM分为好几个版本,包括纯粹的语言模型和针对图像理解的多模特模型。基座模型暂未开源,语言模型开源了SFT(有监督微调,Supervised Fine-Tuned)和DPO(直接偏好优化,Direct Preference Optimization)两类,直接偏好优化(DPO)可以理解为类似RLHF过程的对齐技术,有更好的效果。</p> <p>本教程代码主要是部署测试验证OpenBMB开源的MiniCPM-2B-DPO-FP16模型的,即做过DPO优化的半精度版本。其它版本模型直接替换模型文件位置即可,没有区别。</p> <p>关于MiniCPM-2B模型的介绍可以参考DataLearnerAI的模型信息卡介绍:<a href="https://www.datalearner.com/ai-models/pretrained-models/MiniCPM-2B-SFT">https://www.datalearner.com/ai-models/pretrained-models/MiniCPM-2B-SFT</a></p> <p>关于MiniCPM-2B的运行速度和其它信息可以参考上述模型信息卡的内容。</p> <center><img src="https://www.datalearner.com/resources/blog_images/2da7dcb4-0587-4c54-8c37-f379602ce494.png" alt=""></center> <div class="markdown-toc editormd-markdown-toc">[TOC]</div><h4 id="h4-u4E0Bu8F7Du5B89u88C5u5347u7EA7u4F9Du8D56u7684u5E93"><a name="下载安装升级依赖的库" class="reference-link"></a><span class="header-link octicon octicon-link"></span>下载安装升级依赖的库</h4><p>需要注意的是MiniCPM需要使用Flash Attention的库,而Flash Attention2只支持部分GPU显卡以及Linux系统,所以没办法在Windows以及较老的GPU上运行(英伟达架构中Ampere, Ada, 或者 Hopper 架构的 GPUs (如 A100, RTX 3090, RTX 4090, H100,而图灵GPUs (T4, RTX 2080)系列只支持Flash Attention 1.x版本)。</p> <pre><code>!pip install -U transformers !pip install flash_attn !pip install accelerate </code></pre><h4 id="h4--minicpm-"><a name="载入MiniCPM模型" class="reference-link"></a><span class="header-link octicon octicon-link"></span>载入MiniCPM模型</h4><pre><code>def init_model(): path = &#39;/home/datalearner/MiniCPM-2B-dpo-fp16&#39; tokenizer = AutoTokenizer.from_pretrained(path, local_files_only=True) tokenizer.pad_token_id = tokenizer.eos_token_id model = AutoModelForCausalLM.from_pretrained( path, torch_dtype=torch.float16, device_map=&#39;cuda&#39;, trust_remote_code=True) streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) return model, streamer, tokenizer </code></pre><p>注意,这里我们已经下载好了MiniCPM-2B-dpo-fp16精度的模型,位置:<code>/home/datalearner/MiniCPM-2B-dpo-fp16</code>。所以不需要等待下载。</p> <p>另外,为了支持流式输出,我们这里使用了transformer库中的<code>TextIteratorStreamer</code>类。</p> <h4 id="h4--gradio-"><a name="创建Gradio的聊天界面" class="reference-link"></a><span class="header-link octicon octicon-link"></span>创建Gradio的聊天界面</h4><p>这里使用Gradio创建对话界面的原型,代码如下:</p> <pre><code>with gr.Blocks() as demo: mini_cpm_model, mini_cpm_streamer, mini_cpm_tokenizer = init_model() chatbot = gr.Chatbot( height=900, avatar_images=(user_avatar, bot_avatar) ) msg = gr.Textbox() clear = gr.ClearButton([msg, chatbot]) cpm_history = [] def clear_history(): global cpm_history cpm_history = [] def respond(message, chat_history): cpm_history.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: message}) history_str = mini_cpm_tokenizer.apply_chat_template(cpm_history, tokenize=False, add_generation_prompt=False) inputs = mini_cpm_tokenizer(history_str, return_tensors=&#39;pt&#39;).to(&quot;cuda&quot;) chat_history.append([message, &quot;&quot;]) generation_kwargs = dict(**inputs, streamer=mini_cpm_streamer, max_new_tokens=4096, pad_token_id=mini_cpm_tokenizer.eos_token_id, num_beams=1, do_sample=True, top_p=0.8, temperature=0.3) thread = Thread(target=mini_cpm_model.generate, kwargs=generation_kwargs) thread.start() for new_text in mini_cpm_streamer: chat_history[-1][1] += new_text yield &quot;&quot;, chat_history cpm_history.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: chat_history[-1][1]}) clear.click(clear_history) msg.submit(respond, [msg, chatbot], [msg, chatbot]) </code></pre><p>这里需要注意的是,MiniCPM本身的历史对话参数是字典结构的数组,需要指定角色,格式如下:</p> <pre><code>[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;hey&quot;}, {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: &quot;hello&quot;}] </code></pre><p>但是这种格式是无法被Gradio的ChatBot作为返回值参数装入chat_history中,所以我们使用了全局的历史对话变量<code>cpm_history</code>。</p> <h4 id="h4-minicpm-2b-gradio-"><a name="MiniCPM-2B的Gradio对话程序流式输出完整的代码" class="reference-link"></a><span class="header-link octicon octicon-link"></span>MiniCPM-2B的Gradio对话程序流式输出完整的代码</h4><p>所有代码已经在GitHub开源,大家可以在<a href="https://github.com/DataLearnerAI/LLMPractice/tree/main/llm_code/mini_cpm">https://github.com/DataLearnerAI/LLMPractice/tree/main/llm_code/mini_cpm</a> 找到。</p> <h4 id="h4--minicpm-"><a name="使用仙宫云的MiniCPM的镜像一键部署运行" class="reference-link"></a><span class="header-link octicon octicon-link"></span>使用仙宫云的MiniCPM的镜像一键部署运行</h4><p>仙宫云提供了按照分钟租赁4090显卡(24GB,一个小时2块多),我们已经将上述代码依赖的库以及代码本身写好。大家可以注册仙宫云之后一键部署即可看到效果,适合大家自己上手操作学习。这里简单说一下如何启动MiniCPM的程序。</p> <h5 id="h5--minicpm-"><a name="一键部署MiniCPM的镜像" class="reference-link"></a><span class="header-link octicon octicon-link"></span>一键部署MiniCPM的镜像</h5><p>大家也可以直接一键部署我们在仙宫云发布的镜像。部署完成之后,可以打开“终端”使用ssh启动这个Gradio程序,直接对话:</p> <pre><code># 进入代码目录 cd /home/datalearner # 启动minicpm的gradio程序 python mini_cpm_stream.py </code></pre><p>按照上述代码即可打开网页。</p> <center><img src="https://www.datalearner.com/resources/blog_images/7dcf21eb-040f-42e8-9e9b-8e5a6e053a19.png" alt=""></center><br><center></center> <h5 id="h5--web-"><a name="打开浏览器的镜像web地址体验" class="reference-link"></a><span class="header-link octicon octicon-link"></span>打开浏览器的镜像web地址体验</h5><p>由于我们绑定了80端口,大家可以直接打开镜像的web地址浏览。</p> <center><img src="https://www.datalearner.com/resources/blog_images/9eac0e06-a838-4519-86d2-e6a6930c92cf.png" alt=""></center><br><center></center> <p>直接点击WebUI即可访问,可以共享给他人使用哦~</p> <p>启动之后在界面输入测试:</p> <center><img src="https://www.datalearner.com/resources/blog_images/9fbcaaef-ffac-48c2-b602-c555c3651dc5.png" alt=""></center><br><center></center>

使用Gradio配合transformers的text streamer实现Llama3-8B-Instruct的网页聊天机器人,流式输出

使用Gradio配合transformers的text streamer实现Llama3-8B-Instruct的网页聊天机器人,流式输出

Llama3-8B-Instruct阅读 0

<p>Llama3系列是MetaAI最新开源的大语言模型,相比第二代模型,它的性能提升很高。其中700亿参数版本在上线2天后就在ChatBot Arena大模型匿名竞技场获得了2700多个匿名投票,得分超过此前最强的开源模型Command R+,登顶开源模型第一。相比较其它模型,Llama3在更多的数据训练,其模型架构也有了新的变化。关于Llama3系列模型的信息可以参考DataLearnerAI的介绍:<a href="https://www.datalearner.com/blog/1051713454866102">https://www.datalearner.com/blog/1051713454866102</a> </p> <center><img src="https://www.datalearner.com/resources/blog_images/3fdd784a-2c73-4cb1-b063-209ddf8a075a.png" alt=""></center><br><center></center> <p>本教程的主要目的是通过Gradio提供的ChatBot组件做web版的大模型聊天页面原型。然后通过transformers库提供TextStreamer工具实现流式输出。所有的代码均只在一个py文件中实现,搭建好环境之后,直接运行脚本即可绑定服务到80端口,实现web版本的Llama3的聊天应用。</p> <p>注意,这里的Llama3-8B-Instruct模型本身需要约15GB显存才可以推理,如果你本身已经有资源可以自己尝试部署。本教程的模型文件和代码已经打包成镜像,上架仙宫云的镜像市场,想一键体验或者低成本学习可以参考我们的仙宫云合作信息。</p> <div class="markdown-toc editormd-markdown-toc">[TOC]</div><h4 id="h4-llama3-"><a name="Llama3模型下载" class="reference-link"></a><span class="header-link octicon octicon-link"></span>Llama3模型下载</h4><p>首先需要注意的是,我们需要自己去申请拿到Llama3的预训练结果。目前看,尽量不要用个人邮箱申请,速度很快。DataLearnerAI的童鞋用企业邮箱注册申请,官网申请秒批,在HuggingFace申请也只需要几分钟即可。</p> <p>另外,需要注意的是,GitHub下载脚本下载需要审批通过的链接。HuggingFace上审批通过后需要配合access token下载。这部分可以用git命令也可以用HuggingFace的transformers库在python中下载认证。我们推荐自己手动下载。</p> <h4 id="h4--0-llama3-8b-instruct-"><a name="步骤0:安装Llama3-8B-Instruct的依赖" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤0:安装Llama3-8B-Instruct的依赖</h4><p>Llama3模型本身比较新,采用了一些比较新的架构。我们这里考虑使用transformers库做推理,同时使用accelerate加速,并最终使用gradio创建聊天界面,因此,在安装了torch的cuda版本前提下还需要安装上述三个库(升级到新版本):</p> <pre><code>pip install -U transformers pip install -U accelerate pip install -U gradio </code></pre><h4 id="h4--1-"><a name="步骤1:定义全局变量" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤1:定义全局变量</h4><p>为了初始化模型,以及设置一些Gradio聊天的界面头像,我们先定义几个全局变量,便于后续使用。</p> <pre><code>bot_avatar = &quot;/home/datalearner/dl_logo_rect.png&quot; # 聊天机器人头像位置 user_avatar = &quot;/home/datalearner/user_avatar.png&quot; # 用户头像位置 model_path = &quot;/home/datalearner/Meta-Llama-3-8B-Instruct&quot; # 已下载的模型位置 # 存储全局的历史对话记录,Llama3支持系统prompt,所以这里默认设置! llama3_chat_history = [ {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant trained by MetaAI! But you are running with DataLearnerAI Code.&quot;} ] # 初始化所有变量,用于载入模型 tokenizer = None streamer = None model = None terminators = None </code></pre><p>这里需要注意2点:一个是llama3_chat_history,这个变量用来保存历史对话信息,尽管Gradio的Chatbot组件有内置的变量chat_history管理对话记录。但是最新的模型的历史消息一般都包含了系统指令、不同角色区分等。所以我们用一个新的变量保存这些历史记录。也因为引入了这个变量,在清理历史消息的时候也需要增加清理机制。另一个变量是terminators,是模型停止输出的标记。在Llama3中,结束标记是它们自己设置的,这个变量如果没有或者设置错误,即使是Insturct指令优化模型也会出现不断生成内容的现象,也就是说模型不知道什么时候该停止生成。</p> <h4 id="h4--2-llama3-8b-instruct-"><a name="步骤2:初始化Llama3-8B-Instruct模型" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤2:初始化Llama3-8B-Instruct模型</h4><p>我们单独定义一个函数,用来初始化并加载Llama3-8B-Instruct模型,只需要启动时候初始化,后续对话直接使用即可:</p> <pre><code class="lang-python">def init_model(): &quot;&quot;&quot;初始化模型,载入本地模型 &quot;&quot;&quot; global tokenizer, model, streamer, terminators tokenizer = AutoTokenizer.from_pretrained( model_path, local_files_only=True) model = AutoModelForCausalLM.from_pretrained( model_path, torch_dtype=torch.float16, device_map=device, trust_remote_code=True ) terminators = [ tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids(&quot;&lt;|eot_id|&gt;&quot;) ] streamer = TextIteratorStreamer( tokenizer, skip_prompt=True, skip_special_tokens=True ) </code></pre> <p>初始化方法很简单,与常规的transformers写法一致,只是注意Llama3独有的停止标记即可。</p> <h4 id="h4--3-gradio-"><a name="步骤3:基于Gradio创建聊天机器人" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤3:基于Gradio创建聊天机器人</h4><p>接下来我们就可以使用Gradio来创建聊天机器人了。大致的代码框架如下:</p> <pre><code class="lang-python"> with gr.Blocks() as demo: # step1: 载入模型 init_model() # step2: 初始化gradio的chatbot应用,并添加按钮等信息 chatbot = gr.Chatbot( height=900, avatar_images=(user_avatar, bot_avatar) ) msg = gr.Textbox() clear = gr.ClearButton([msg, chatbot]) # 清楚历史记录 def clear_history(): global llama3_chat_history llama3_chat_history = [] # 用于回复的方法 def respond(message, chat_history): &quot;&quot;&quot;用Llama3回复用户消息的处理,后面展开&quot;&quot;&quot; # 点击清楚按钮,触发历史记录清楚 clear.click(clear_history) msg.submit(respond, [msg, chatbot], [msg, chatbot]) </code></pre> <p>这是非常常规的Gradio聊天机器人应用写法。除了清楚历史记录外,其它都与官方代码一致。这里加的的清楚历史记录是在最后<code>clear.click</code>时候触发的,clear是清楚历史对话的按钮,我们前面说了,我们引入了自定义变量,那就要这里记住清楚。</p> <p>接下来我们来加入推理代码即可,即代码中<code>用于回复的方法</code>注释部分的具体内容。</p> <h4 id="h4--4-transformers-"><a name="步骤4:增加用transformers库推理回复用户消息的内容" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤4:增加用transformers库推理回复用户消息的内容</h4><p>这部分就是拿到用户的输入之后,怎么用流式方法推理。在步骤2中,我们已经初始化了Llama3-8B-Instruct模型相关的变量。那么流式推理的代码主要如下:</p> <pre><code class="lang-python">def respond(message, chat_history): # 引入全局变量 global llama3_chat_history, tokenizer, model, streamer # 拼接对话历史 llama3_chat_history.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: message}) # 使用Llama3自带的聊天模板,格式化对话记录 history_str = tokenizer.apply_chat_template( llama3_chat_history, tokenize=False, add_generation_prompt=True ) # 对历史记录进行tokenization inputs = tokenizer(history_str, return_tensors=&#39;pt&#39;).to(device) # 这个历史记录是Gradio的Chatbot自带的变量,用来控制页面显示逻辑的,我们必须也要对齐操作,保证页面展示正常 chat_history.append([message, &quot;&quot;]) # 拼接推理参数 generation_kwargs = dict( **inputs, streamer=streamer, max_new_tokens=4096, num_beams=1, do_sample=True, top_p=0.8, temperature=0.3, eos_token_id=terminators ) # 启动线程,用以监控流失输出结果 thread = Thread(target=model.generate, kwargs=generation_kwargs) thread.start() # 循环推理streamer,每次得到新增的推理部分都附到历史记录末尾,Gradio会监控这个变量在页面展示 for new_text in streamer: chat_history[-1][1] += new_text yield &quot;&quot;, chat_history # 所有的输出完毕之后,我们自己的历史记录也要更新,把模型输出的完整结果加进来。 llama3_chat_history.append( {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: chat_history[-1][1]} ) </code></pre> <p>可以看到,这部分内容是最多的。但也不是很复杂。把前面所有内容拼接好就是完整的代码了。这个代码放到一个py脚本中,后面直接执行这个脚本即可。唯一需要注意的是安装的transformers等依赖的版本,以及要提前把模型文件下载好。</p> <h4 id="h4--5-gradio-80-web-"><a name="步骤5:绑定Gradio应用到80端口,运行web访问" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤5:绑定Gradio应用到80端口,运行web访问</h4><p>这一步很简单,常规操作,但是没有就无法启动了:</p> <pre><code>if __name__ == &quot;__main__&quot;: demo.launch(server_name=&quot;0.0.0.0&quot;, server_port=80) </code></pre><h4 id="h4-u5728u4ED9u5BABu4E91u955Cu50CFu4E2Du8FD0u884C"><a name="在仙宫云镜像中运行" class="reference-link"></a><span class="header-link octicon octicon-link"></span>在仙宫云镜像中运行</h4><p>最后,我们简单总结一下如何运行。首先,这里的运行并不是一定要在仙宫云进行。只要你在超过15G显卡的机器上就可以跑了。</p> <p>我们的代码文件和模型文件都放在了<code>/home/datalearner</code>目录下的<code>run_llama3_gradio.py</code>,所以,我们执行如下命令即可:</p> <pre><code>cd /home/datalearner python run_llama3_gradio.py </code></pre><p>接下来可以看到如下界面提示:</p> <center><img src="https://www.datalearner.com/resources/blog_images/c641e0ae-695c-44c8-9668-eb898eaa966e.png" alt=""></center> <p>这个提示说明成功拉起模型,并启动了gradio的界面。通过运行<code>nvidia-smi</code>命令也可以看到4090的显存已经消耗了15GB左右。说明半精度的Llama3-8B-Instruct已经拉起来了。</p> <center><img src="https://www.datalearner.com/resources/blog_images/ae828167-0db8-4dc7-880f-269843e59b50.png" alt=""></center><br><center></center> <p>启动完成之后,本地可以通过http:/127.0.0.1 访问,如果是仙宫云,则直接可以通过外网访问。可以通过仙宫云控制台访问web地址:</p> <center><img src="https://www.datalearner.com/resources/blog_images/9eac0e06-a838-4519-86d2-e6a6930c92cf.png" alt=""></center><br><center></center> <p>Llama3-8B-Instruct简单测试:</p> <center><img src="https://www.datalearner.com/resources/blog_images/9676b6fa-4f92-4a12-9031-5def43a4deca.png" alt=""></center><br><center></center>

手把手教你从0部署李开复零一万物公司开源的多模态大模型Yi-VL-6B,实现网页端的多模态聊天机器人应用

手把手教你从0部署李开复零一万物公司开源的多模态大模型Yi-VL-6B,实现网页端的多模态聊天机器人应用

Yi-VL-6B阅读 0

<p>Yi-VL-6B是由李开复旗下的大模型初创企业零一万物开源的一个多模态大模型。其基座语言模型是Yi-6B,具有良好的文本理解等能力。Yi-VL-6B的图像理解能力很好,在同等参数规模水平上非常优秀。Yi-VL-6B的图像部分采用了LLaVA模型类似的图片处理机制。但是从此前的情况看,Yi-VL-6B的代码依赖比较多,很难运行。本教程主要是采用了Gradio多模态Chatbot组件,可以在网页端实现多模态对话的功能。</p> <center><img src="https://www.datalearner.com/resources/blog_images/e64280ca-b6bc-44c6-8d84-2b34d5b8d310.png" alt=""></center><br><center></center> <p>官方提供的代码,包含vllm部分,但是我们测试过,它不支持多轮,我们提了一个feature request,官方当作bug修复了,本次教程依然采用原先的方案。使用vllm会更简单,后续我们考虑新增这部分教程。</p> <div class="markdown-toc editormd-markdown-toc">[TOC]</div><h4 id="h4--1-yi-vl-"><a name="步骤1:下载模型,安装Yi-VL官方代码库和模型文件" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤1:下载模型,安装Yi-VL官方代码库和模型文件</h4><p>Yi-VL系列代码在图像处理部分的部分逻辑与著名的LLaVA库差不多,但是与它也有一些区别。此前DataLearnerAI的童鞋测试过,使用transformers库拉起Yi-VL-6B会出现一些错误,例如<code>TypeError: expected str, bytes or os.PathLike object, not NoneType</code>。在官方的GitHub中提过这个issue,但是重现错误之后没有给出解决方案。所以,我们采用了官方提供的LLaVA接口来做测试。可以成功运行。</p> <h5 id="h5--huggingface-"><a name="从HuggingFace下载官方的模型预训练结果" class="reference-link"></a><span class="header-link octicon octicon-link"></span>从HuggingFace下载官方的模型预训练结果</h5><p>这个不多说,从<a href="https://huggingface.co/01-ai/Yi-VL-6B/tree/main">https://huggingface.co/01-ai/Yi-VL-6B/tree/main</a> 下载即可。不过这里提醒一下,虽然Yi-VL-6B模型本身是60亿参数规模,但是多模态模型是要外接视觉部分的。因此,这个库的vit文件也要下载,如果是手动下载,不要忘记这部分内容。</p> <p>模型文件下载完毕之后,就可以看到<code>/home/datalearner</code>目录下有了Yi-VL-6B的文件夹。</p> <h5 id="h5--yi-"><a name="从官方库下载Yi代码" class="reference-link"></a><span class="header-link octicon octicon-link"></span>从官方库下载Yi代码</h5><p>前面已经说了,完全使用transformers库会有一些问题。所以我们采用了官方的代码,将其改造成可以在Gradio运行即可。因此,需要下载官方代码库:</p> <pre><code># 先进入/home/datalearner目录,我们的代码和模型都在这里 cd /home/datalearner # 使用git下载官方代码 git clone https://github.com/01-ai/Yi.git # 安装Yi相关依赖 export PYTHONPATH=$PYTHONPATH:$(pwd) pip install -r requirements.txt </code></pre><p>注意,export那一步骤是把当前路径加入到环境变量中,必须执行,否则可能出现部分库找不到。</p> <p>代码下载安装完毕之后,就可以看到<code>/home/datalearner</code>目录下有了Yi的文件夹。</p> <p>经过上面两个步骤,我们可以看到下面的目录结构:</p> <center><img src="https://www.datalearner.com/resources/blog_images/cadbec21-e501-46b7-904d-67fcb2aa781d.png" alt=""></center><br><center></center> <p>这里红圈标识的是本次教程新增的代码部分,在这里执行即可。下面我们详细介绍部署代码。</p> <h4 id="h4--"><a name="步骤二:引入相关的库,并初始化变量" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤二:引入相关的库,并初始化变量</h4><p>这是最基本的步骤了,只是因为Yi-VL代码相对比较复杂,所以这里会引入比较多的官方提供的库。前面说了,我们的代码是嵌入在官方库的Yi/VL目录下的,本地IDE也需要把官方的llava目录包含进来,否则会提示找不到。所以代码位置一定要准确。</p> <p>引入依赖和初始化的部分代码如下:</p> <pre><code>import gradio as gr import os import torch from llava.conversation import conv_templates from llava.mm_utils import ( KeywordsStoppingCriteria, get_model_name_from_path, load_pretrained_model, process_images, tokenizer_image_token, ) from llava.model.constants import DEFAULT_IMAGE_TOKEN, IMAGE_TOKEN_INDEX, key_info from PIL import Image # 前两个是聊天的头像,可以换成任意的自己的,最后一个是模型目录 bot_avatar = &quot;/home/datalearner/dl_logo_rect.png&quot; user_avatar = &quot;/home/datalearner/user_avatar.png&quot; model_path = &quot;/home/datalearner/Yi-VL-6B&quot; # 这些变量都是模型初始化的时候赋值,推理时候使用,所以定义在这,作为全局变量 client = None conv = None model = None tokenizer = None image_processor = None image_tensor = None yi_chat_history = [] </code></pre><h4 id="h4--"><a name="步骤三:定义图像读取方法" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤三:定义图像读取方法</h4><p>在多模态大模型中,图像和文本类似,都是使用网络层读取数据。只是文本变成token id输入,图像则转成像素读取。这里使用Image库来读取图片:</p> <pre><code>def load_image(image_file): &quot;&quot;&quot;载入图片 &quot;&quot;&quot; if image_file is None: return None # 如果是网络图片,这部分代码需要改造,这里因为使用Gradio对话,没有单独的网路图片地址,所以不支持网络图片。改造很简单,参考Image库使用即可 image = Image.open(image_file).convert(&quot;RGB&quot;) return image </code></pre><p>非常基本的方法,在后续获得图像之后使用。</p> <h4 id="h4--gradio-chatbot-"><a name="步骤四:按照Gradio的多模态Chatbot消息处理历史数据" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤四:按照Gradio的多模态Chatbot消息处理历史数据</h4><p>这部分是通过读取用户提交的文本和图像附件消息来获得相应内容,然后让Yi-VL-6B模型进行推理。</p> <pre><code> def get_res_from_yi_vl(new_msg, image_file): &quot;&quot;&quot; 永远只取最新的一个图片作为输入 &quot;&quot;&quot; print(f&quot;new msg:{new_msg}&quot;) print(f&quot;new image:{image_file}&quot;) global conv, model, tokenizer, image_processor, image_tensor if image_file is None: image = None else: image = load_image(image_file) image_tensor = process_images([image], image_processor, model.config) image_tensor = image_tensor.to(model.device, dtype=torch.bfloat16) inp = new_msg if image is not None: inp = DEFAULT_IMAGE_TOKEN + &quot;\n&quot; + inp conv.append_message(conv.roles[0], inp) image = None else: conv.append_message(conv.roles[0], inp) conv.append_message(conv.roles[1], None) prompt = conv.get_prompt() input_ids = ( tokenizer_image_token( prompt, tokenizer, IMAGE_TOKEN_INDEX, return_tensors=&quot;pt&quot; ) .unsqueeze(0) .to(model.device) ) stop_str = conv.sep keywords = [stop_str] stopping_criteria = KeywordsStoppingCriteria(keywords, tokenizer, input_ids) with torch.inference_mode(): output_ids = model.generate( input_ids, images=image_tensor, do_sample=True, temperature=0.2, max_new_tokens=1024, use_cache=True, stopping_criteria=[stopping_criteria], ) input_token_len = input_ids.shape[1] outputs = tokenizer.batch_decode( output_ids[:, input_token_len:], skip_special_tokens=True )[0] outputs = outputs.strip() if outputs.endswith(stop_str): outputs = outputs[: -len(stop_str)] outputs = outputs.strip() print(outputs) conv.messages[-1][-1] = outputs return outputs def add_message(history, message): &quot;&quot;&quot; 处理输入的消息,多模态的数据处理需要区分用户输入的文本和附件,本部分的逻辑是来自于Gradio官方的接口 :param history: 历史消息,列表格式,即[&quot;msg1&quot;, &quot;msg2&quot;] :param message: 当前输入的消息,字典类型,其中可以一次放入多个文件。格式如下: { &#39;text&#39;: &#39;hello&#39;, &#39;files&#39;: [ { &#39;path&#39;: &#39;/home/datalearner/test.png&#39;, &#39;url&#39;: &#39;/file=/home/datalearner/test.png&#39;, &#39;size&#39;: 27599, &#39;orig_name&#39;: &#39;test.png&#39;, &#39;mime_type&#39;: &#39;image/png&#39;, &#39;is_stream&#39;: False, &#39;meta&#39;: {&#39;_type&#39;: &#39;gradio.FileData&#39;} } ] &quot;&quot;&quot; global yi_chat_history new_msg = { &quot;role&quot;: &quot;user&quot;, &quot;content&quot; : { &quot;image_files&quot;:[], &quot;text_msg&quot;: &quot;&quot;, } } image_file = [] for x in message[&quot;files&quot;]: history.append(((x,), None)) image_file.append(x) if message[&quot;text&quot;] is not None: history.append((message[&quot;text&quot;], None)) new_msg[&quot;content&quot;][&quot;text_msg&quot;] = message[&quot;text&quot;] if len(image_file)&gt;0: new_msg[&quot;content&quot;][&quot;image_files&quot;].extend(image_file) yi_chat_history.append(new_msg) return history, gr.MultimodalTextbox(value=None, interactive=False, file_types=[&quot;image&quot;]) </code></pre><p>这里的参数是Gradio提供的内置变量的历史数据和新增消息。Gradio本身是支持每次用户发送消息时候带图像附件的。但是当前模型在这块并不是很擅长,我们只读取第一次的图片,剩余的就忽略了。另外,我们这里也要根据这个数据构造Yi-VL-6B模型可以识别的历史消息格式,所以使用了全局变量进行拼接。</p> <h4 id="h4--yi-vl-6b-"><a name="步骤五:使用Yi-VL-6B模型进行推理" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤五:使用Yi-VL-6B模型进行推理</h4><p>这部分的核心代码是用官方提供的推理函数。但是需要配合改造成可以被Gradio接受的方法。用于后面的聊天机器人使用。</p> <h5 id="h5--yi-vl-6b-"><a name="用Yi-VL-6B模型做多模态推理的代码" class="reference-link"></a><span class="header-link octicon octicon-link"></span>用Yi-VL-6B模型做多模态推理的代码</h5><p>首先我们构造一个方法,让Yi-VL-6B模型对图片和文本做推理。代码如下:</p> <pre><code class="lang-python">def get_res_from_yi_vl(new_msg, image_file): &quot;&quot;&quot; 永远只取最新的一个图片作为输入 &quot;&quot;&quot; print(f&quot;new msg:{new_msg}&quot;) print(f&quot;new image:{image_file}&quot;) # 获取全局变量,这些应该是已经初始化了的模型相关变量,可以直接使用 global conv, model, tokenizer, image_processor, image_tensor # 如果输入有图片,需要对图片做tensor转换,也就是变成相应的transformers网络可以读取的向量 if image_file is None: image = None else: image = load_image(image_file) image_tensor = process_images([image], image_processor, model.config) image_tensor = image_tensor.to(model.device, dtype=torch.bfloat16) # 这部分代码主要用于拼接图像输入,图像需要特殊标记位 inp = new_msg if image is not None: inp = DEFAULT_IMAGE_TOKEN + &quot;\n&quot; + inp conv.append_message(conv.roles[0], inp) image = None else: conv.append_message(conv.roles[0], inp) conv.append_message(conv.roles[1], None) prompt = conv.get_prompt() # 将图像与文本输入的prompt拼接作为输入 input_ids = ( tokenizer_image_token( prompt, tokenizer, IMAGE_TOKEN_INDEX, return_tensors=&quot;pt&quot; ) .unsqueeze(0) .to(model.device) ) stop_str = conv.sep keywords = [stop_str] stopping_criteria = KeywordsStoppingCriteria(keywords, tokenizer, input_ids) # 构造完所有输入之后可以用模型进行推理 with torch.inference_mode(): output_ids = model.generate( input_ids, images=image_tensor, do_sample=True, temperature=0.2, max_new_tokens=1024, use_cache=True, stopping_criteria=[stopping_criteria], ) # 这里拿到的输出是token id,需要转成可读的文本 input_token_len = input_ids.shape[1] outputs = tokenizer.batch_decode( output_ids[:, input_token_len:], skip_special_tokens=True )[0] outputs = outputs.strip() if outputs.endswith(stop_str): outputs = outputs[: -len(stop_str)] outputs = outputs.strip() print(outputs) conv.messages[-1][-1] = outputs return outputs </code></pre> <p>这里的核心代码和步骤我们已经做了解释。其实这些代码正常情况应该可以由transformer提供工具帮助我们串联,这里我们只能通过相对原始一点的代码写,否则可能会报错。</p> <h5 id="h5--gradio-"><a name="构造适配Gradio的机器人回复方法" class="reference-link"></a><span class="header-link octicon octicon-link"></span>构造适配Gradio的机器人回复方法</h5><p>上面是用Yi-VL-6B做多模态推理的代码。这部分代码作为整个方法可以用来构造Gradio的Chatbot输出了。</p> <pre><code>def bot(history): &quot;&quot;&quot;Yi-VL-6B推理 &quot;&quot;&quot; global yi_chat_history print(f&quot;chat history: {yi_chat_history}&quot;) new_text_msg, new_image_list = yi_chat_history[-1][&quot;content&quot;][&quot;text_msg&quot;], yi_chat_history[-1][&quot;content&quot;][&quot;image_files&quot;] new_image_file = None if len(new_image_list)&gt;0: new_image_file = new_image_list[0] # bot_msg = get_res_from_yi_vl(new_text_msg, new_image_file) history[-1][1] = bot_msg yi_chat_history.append({&quot;role&quot;:&quot;assistant&quot;, &quot;content&quot;: bot_msg}) return history </code></pre><h4 id="h4--"><a name="步骤六:初始化模型方法" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤六:初始化模型方法</h4><p>接下来我们增加一个模型初始化的方法,用在启动Chatbot之前执行,可以一次性载入模型到GPU显存中,后面直接使用。这部分比较简单:</p> <pre><code class="lang-python"> def init_model(): &quot;&quot;&quot;Initialize Yi-VL-6B model &quot;&quot;&quot; global tokenizer, model, image_processor, conv, model_path model_path = os.path.expanduser(model_path) key_info[&quot;model_path&quot;] = model_path get_model_name_from_path(model_path) tokenizer, model, image_processor, _ = load_pretrained_model(model_path) conv = conv_templates[&quot;mm_default&quot;].copy() </code></pre> <h4 id="h4--gradio-chatbot-web-"><a name="步骤七:基于Gradio的多模态Chatbot构建完整的Web版多模态模型应用" class="reference-link"></a><span class="header-link octicon octicon-link"></span>步骤七:基于Gradio的多模态Chatbot构建完整的Web版多模态模型应用</h4><p>在准备完上面的核心方法之后,我们就可以按照Gardio官方提供的Multi Modal Chatbot来构建多模态聊天大模型应用了。代码如下:</p> <pre><code class="lang-python">with gr.Blocks() as demo: # 初始化代码 init_model() # 自定义历史消息清楚方法,由于我们创建了一个自定义历史消息变量,因此无法使用Gradio内置的方式清楚历史记录 def clear_history(): global yi_chat_history, conv yi_chat_history = [] conv = conv_templates[&quot;mm_default&quot;].copy() # 创建Chatbot应用 chatbot = gr.Chatbot( [], elem_id=&quot;chatbot&quot;, bubble_full_width=False, height=900, avatar_images=(user_avatar, bot_avatar) ) # 获取多模态输入,这部分和纯文本的Chatbot不一样 chat_input = gr.MultimodalTextbox(interactive=True, file_types=[&quot;image&quot;], placeholder=&quot;请输入文本或者上传图片&quot;, show_label=False) # 增加清楚历史记录按钮, clear = gr.ClearButton([chat_input, chatbot]) # 用户提交历史消息之后触发机器人回复 chat_msg = chat_input.submit(add_message, [chatbot, chat_input], [chatbot, chat_input], queue=False).then( bot, chatbot, chatbot, api_name=&quot;bot_response&quot; ) chat_msg.then(lambda: gr.Textbox(interactive=True), None, [chat_input], queue=False) # 点击清楚历史记录,触发自定义历史记录清楚方法 clear.click(clear_history) </code></pre> <p>核心步骤如上。这里相比官方的代码主要增加了一个自定义历史记录清楚方法。前面说过,大多数模型都有自定义的历史消息记录格式,与当前的Gradio内置的历史消息变量格式有差异。所以我们自己增加了一个变量存储与模型兼容的历史消息。带来的问题就是清楚历史按钮需要新增方法用来清楚这个数据。</p> <h4 id="h4--80-"><a name="绑定80端口,创建脚本入口" class="reference-link"></a><span class="header-link octicon octicon-link"></span>绑定80端口,创建脚本入口</h4><p>最后一步很简单,就是创建Gradio应用,绑定到80端口,并开启外部访问的功能,便于我们可以在其它机器上通过浏览器访问我们的应用。</p> <pre><code class="lang-python">if __name__ == &quot;__main__&quot;: demo.launch(server_name=&quot;0.0.0.0&quot;, server_port=80) </code></pre> <h4 id="h4--yi-vl-6b-"><a name="启动Yi-VL-6B多模态大模型聊天应用" class="reference-link"></a><span class="header-link octicon octicon-link"></span>启动Yi-VL-6B多模态大模型聊天应用</h4><p>最后我们说一下如何启动。如前所述,上面所有的代码都合并到一起放在一个py脚本(我们创建了一个<code>yi_vl_cli.py</code>文件)中方便大家运行。但是,与常规的方式不同我们需要把这个脚本放到官方下载的代码的VL目录下,因为我们引用了官方的部分库。位置放对之后可以直接启动即可。方法如下:</p> <pre><code>cd /home/datalearner/Yi/VL python yi_vl_cli.py </code></pre><p>等待一会上述代码执行之后,可以看到如下截图:</p> <center><img src="https://www.datalearner.com/resources/blog_images/d2b5998e-a5db-4fef-baa3-ec96e14f3b17.png" alt=""></center><br><center></center> <p>看到这些就算运行成功了,需要注意的是前面一大块告警是可以忽略的。Yi-VL的代码前期兼容性不太好,所以会有一些这样的告警。启动完成之后可以通过127.0.0.1本地访问。如果需要其他人可以通过互联网访问,那就需要外部IP了,或者如果你是在仙宫云上用我们的镜像启动,那就可以通过仙宫云提供的WebUI地址访问:</p> <center><img src="https://www.datalearner.com/resources/blog_images/9eac0e06-a838-4519-86d2-e6a6930c92cf.png" alt=""></center><br><center></center> <p>我们访问做了一个简单的测试:</p> <center><img src="https://www.datalearner.com/resources/blog_images/e3d9428f-d9a8-4587-a447-0d8db98bf106.png" alt=""></center><br><center></center> <p>很顺畅。不过需要注意的是,Yi-VL-6B经过DataLearnerAI测试效果一般。在图像描述方面或者理解总结方面很不错。但是做文本提取类似这样的任务则能力非常有限了。</p>