【Datawhale AI 夏令营】动手学大模型应用开发Task1 Baseline 精读
开源大模型文件预览
Baseline
1.导入库
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import streamlit as st
2.模型下载
# 源大模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='./')
snapshot_download 函数进行模型下载,第一个参数为模型名称,第二个参数为模型保存路径(./ 为当前路径)
3.模型加载
# 定义一个函数,用于获取模型和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
streamlit
库中装饰器 @st.cache_resource
用于缓存好的模型和tokenizer,后续不需要重新执行函数内容
使用 transformers.AutoTokenizer
中的 from_pretrained
函数加载预训练模型的分词器
使用 transformers.AutoModelForCausalLM
中的 from_pretrained
函数加载与训练好的模型
.cuda()
可以将模型部署在GPU上
4.用户消息读取
# 如果用户在聊天输入框中输入了内容,则执行以下操作
if prompt := st.chat_input():
# 将用户的输入添加到session_state中的messages列表中
st.session_state.messages.append({"role": "user", "content": prompt})
# 在聊天界面上显示用户的输入
st.chat_message("user").write(prompt)
if prompt := st.chat_input():
赋值表达式,st.chat_input()
用于获取用户输入),则将其赋值给变量prompt
,并且如果输入不为空(即用户确实输入了内容),则执行紧接着的缩进块内的代码。
# 询问用户输入
user_input = st.chat_input()
# 检查用户是否输入了内容
if user_input:
prompt = user_input
5.拼接对话历史
prompt = "<n>".join(msg["content"] for msg in st.session_state.messages) + "<sep>" # 拼接对话历史
msg["content"] for msg in st.session_state.messages
遍历 st.session_state.messages 列表中的每个元素 msg ,提取 msg 字典中的 content 键值,这样可以创建一个新的列表。
"<n>".join()
将消息列表中的每个元素连接成单一的字符串,每个消息之间用作为分隔符,所有的消息内容形成一个连续的字符串,标识整个对话历史记录。
+ "<sep>"
作为对话历史结束的标记
6.模型调用
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>", '')
输入的 prompt 需要先经过 tokenizer
切分成 token,转化为对应的 id,并通过 .cuda()
部署在 GPU 上。调用 model_generate
生成输出的 id,并通过 tokenizer.decode()
将id转成对应的字符串。最后从字符串中提取模型生成的内容(即 <sep>
之后的字符串),并删除末尾的 <eod>
,得到最终的回复内容。
7.显示模型输出
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(response)
源码
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import streamlit as st
# 创建一个标题和一个副标题
st.title("💬 Yuan2.0 智能编程助手")
# 源大模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='./')
# 定义模型路径
path = './IEITYuan/Yuan2-2B-Mars-hf'
# 定义模型数据类型
torch_dtype = torch.bfloat16 # A10
# torch_dtype = torch.float16 # P100
# 定义一个函数,用于获取模型和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
# 加载model和tokenizer
tokenizer, model = get_model()
# 初次运行时,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"])
# 如果用户在聊天输入框中输入了内容,则执行以下操作
if prompt := st.chat_input():
# 将用户的输入添加到session_state中的messages列表中
st.session_state.messages.append({"role": "user", "content": prompt})
# 在聊天界面上显示用户的输入
st.chat_message("user").write(prompt)
# 调用模型
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>", '')
# 将模型的输出添加到session_state中的messages列表中
st.session_state.messages.append({"role": "assistant", "content": response})
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(response)