本次夏令营意在使参与者通过学习大模型部署、大模型检索增强生成(Retrieval Augmented Generation, RAG)实战、大模型微调实战,掌握大模型应用全栈开发
一.跑通baseline
对于像我这样的初学者而言,跑通baseline是关键的第一步,帮助熟悉比赛流程的同时在大脑里形成对大语言模型基本使用方法和功能的直观印象。官方在此贴心地提供了详细的baseline速通指南:Datawhale 大致可以划分为以下几点:
- 开通阿里云PAI-DSW试用
- 在魔塔社区开通PAI实例
- 创建demo
- 对话体验
相关步骤官方文档解释的非常清晰,按照文档一步步来就能搞定。
二.理解baseline代码
相信有不少uu像我一样,或多或少接触过大模型开发,脑海中也有一些大模型的相关理论知识,各种高大上的名词也都听闻过一点,但是缺乏实操经验,相关开发工作不知从何处入手,那么借这次夏令营的机会,读懂官方baseline代码是一个良好的开始。
1.文件下载、环境安装、启动demo部分代码
git lfs install
git clone https://www.modelscope.cn/datasets/Datawhale/AICamp_yuan_baseline.git
pip install streamlit==1.24.0
streamlit run AICamp_yuan_baseline/Task\ 1:零基础玩转源大模型/web_demo_2b.py --server.address 127.0.0.1 --server.port 6006
将项目git clone下来后安装streamlit,streamlit是一个开源python库,允许开发者快速构建和部署数据应用和网络应用,能够使开发者将数据分析、模型可视化以及原型设计快速转化为可分享的Web应用程序。它主要具有以下优点:
- 交互性高:Streamlit支持创建高度交互性的应用,用户可以通过滑块、下拉菜单、文本输入等方式与应用进行交互,可用于动态调整参数
- 实时性:通过提供的接口,用户可以将数据发送到后台服务器,实时获取推理结果
- 简单易用:可以通过通过编写简单的Python脚本,快速构建应用。它采用命令式编程范式,使得代码的编写和调试更加直观。通过Streamlit,开发者可以轻松地将应用分享给他人,只需将代码仓库分享。
最后运行web_demo_2b.py脚本,并使用server.address和server.port指定服务器地址和端口号,成功运行后就可以打开页面啦,效果如下:
2.demo代码解析
导入相关库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import streamlit as st
首先导入的是Hugging Face的
transformers
库中的
AutoTokenizer
和
AutoModelForCausalLM
类。这些类用于加载预训练的语言模型及其分词器。然后是torch和streamlit。
使用streamlit创建标题
st.title("💬 Yuan2.0 智能编程助手")
使用streamlit的title函数来设置页面标题
源大模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='./')
- modelscope是一个开源模型即服务平台,由阿里提供
- 导入了
modelscope
库的snapshot_download
函数,该函数用于下载预训练的模型 - 使用
snapshot_download
函数下载名为IEITYuan/Yuan2-2B-Mars-hf
的模型,并将其缓存到当前目录下
定义模型下载后存储路径
path = './IEITYuan/Yuan2-2B-Mars-hf'
定义模型数据类型
torch_dtype = torch.bfloat16 # A10
- 这行代码定义了模型的数据类型为
torch.bfloat16
,这是针对特定硬件(如A10 GPU)的数据类型 - 如果使用不同的硬件(如P100 GPU),可以切换到
torch.float16
数据类型
加载语言模型和分词器(Tokenizer)
@st.cache_resource
def get_model():
print("Creat tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(path, add_eos_token=False, add_bos_token=False, eos_token='<eod>')
tokenizer.add_tokens(['<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>','<commit_before>','<commit_msg>','<commit_after>','<jupyter_start>','<jupyter_text>','<jupyter_code>','<jupyter_output>','<empty_output>'], special_tokens=True)
print("Creat model...")
model = AutoModelForCausalLM.from_pretrained(path, torch_dtype=torch_dtype, trust_remote_code=True).cuda()
print("Done.")
return tokenizer, model
- @st.cache_resource:这是streamlit的一个装饰器,用于缓存函数的输出。好处就在于get_model只会被执行一次,其结果会被缓存起来,之后调用函数可以直接返回缓存的结果。这样可以显著提升应用性能,对于加载模型这种耗时操作。
- tokenizer = AutoTokenizer.from_pretrained():从path路径加载分词器,add_eos_token=False、add_bos_token=False表示不自动添加句子结束和开始的标志,eos_token='<eod>'定义了自定义的句子结束标志
- tokenizer.add_tokens():向分词器中加入自定义的token
- model = AutoModelForCausa1LM.from_pretrained():从指定路径加载模型,torch_dtype指定了模型的数据类型,trust_remote_code=True表示信任远程代码(随模型加载被下载,默认为False),.cuda()表示将模型移动到gpu上
创建聊天列表并在页面显示聊天记录
# 初次运行时,session_state中没有"messages",需要创建一个空列表
if "messages" not in st.session_state:
st.session_state["messages"] = []
# 每次对话时,都需要遍历session_state中的所有消息,并显示在聊天界面上
for msg in st.session_state.messages:
st.chat_message(msg["role"]).write(msg["content"])
- st.session_state是streamlit的一个核心属性,是一个字典,允许开发者访问在用户访问期间保持不变的数据,也就是只要用户步关闭标签页,保存在st.session_state的数据就会持续存在。
- 在st.session_state中设置一个键为"message"的条目,其对应的值为[],即一个空列表。
- st.chat_message创建一个聊天信息的显示容器,并在其中显示内容。.write()是streamlit的一个方法,用于在界面上显示文本或其他可渲染的对象。这里显示的内容为msg['role'],及其对应的msg['content']
添加并显示用户输入和模型处理后的输出
# 如果用户在聊天输入框中输入了内容,则执行以下操作
if prompt := st.chat_input():
# 将用户的输入添加到session_state中的messages列表中
st.session_state.messages.append({"role": "user", "content": prompt})
# 在聊天界面上显示用户的输入
st.chat_message("user").write(prompt)
..............................................
# 将模型的输出添加到session_state中的messages列表中
st.session_state.messages.append({"role": "assistant", "content": response})
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(response)
- 将用户输入赋值于prompt,并将"user"及"user"对应的prompt添加到st.settion_state.messages,后将以上内容通过st.chat_message()在页面显示
- 将模型处理后的输出添加到session_state.message中并调用st.chat_message()函数显示
调用模型处理用户输入
# 调用模型
prompt = "<n>".join(msg["content"] for msg in st.session_state.messages) + "<sep>" # 拼接对话历史
inputs = tokenizer(prompt, return_tensors="pt")["input_ids"].cuda()
outputs = model.generate(inputs, do_sample=False, max_length=1024) # 设置解码方式和最大生成长度
output = tokenizer.decode(outputs[0])
response = output.split("<sep>")[-1].replace("<eod>", '')
- 将消息的所有内容拼接为一个字符串,取出st.session_state.message列表中键"content"对应的所有的值,使用“<n>”分割并以“<seq>结尾”
- 使用tokenizer处理所有prompt,设置返回值类型为“pt”(pytorch张量格式),获取所有输入id(代表文本中的单词、标点符号和其他语言元素),然后放在gpu上
- 使用model.generate()处理inputs,do_sample=False表示不使用随机采样,max_length设置最大输出长度
- output[0]是模型生成的文本序列的张量,包含所有生成文本的ID,tokenizer.decode()是分词器的解码方法,将生成的ID序列转化为原始文本
- 最后提取最后一个
"<sep>"
之后的内容作为响应,同时移除"<eod>"
(对话结束标记)
三、总结
通过跑通并阅读官方baseline,了解了大模型应用全栈开发的一些工具和流程,比如前端工具streamlit,处理用户输入、调用语言模型、最后输出到界面的流程,合理使用这些工具和方法将会使搭建自己的大模型应用更加从容。
版权归原作者 动手学深度睡眠 所有, 如有侵权,请联系我们删除。