任务
在本地部署大模型,调用大模型进行对话。
添加库:
1、Transformer
Transformers
是由 Hugging Face 开发的一个开源库,广泛应用于自然语言处理(NLP)任务。其主要功能是简化了对大型预训练语言模型的加载和使用。它提供了数百种预训练的模型,涵盖了多种 NLP 任务。Transformers 支持多种不同类型的 Transformer 模型架构,涵盖了近年来最先进的 NLP 模型。以下是一些知名模型架构:
- BERT (Bidirectional Encoder Representations from Transformers):双向编码器,用于生成上下文的词向量。
- GPT (Generative Pretrained Transformer):生成型预训练模型,擅长生成流畅的文本。
- T5 (Text-To-Text Transfer Transformer):将所有任务转换为文本生成问题,支持多任务学习。
- RoBERTa:BERT 的改进版本,通过更多的数据和计算资源训练,性能更好。
- DistilBERT:BERT 的简化版,参数更少、速度更快,但仍能保持高性能。
- XLNet:结合了自回归和自编码器的优点,擅长生成任务。
- Bart:适合文本生成、摘要等任务,双向编码、左到右生成。
2、streamlit
Streamlit 是一个开源的 Python 库,专为快速构建和分享数据应用(data apps)而设计。通过 Streamlit,开发者可以使用非常简洁的 Python 代码将数据分析或机器学习模型可视化,并创建交互式的 Web 应用程序。Streamlit 的主要目标是降低开发和部署数据应用的复杂性,使得数据科学家和工程师可以专注于业务逻辑,而不需要深度了解前端开发。
简而言之就是提供了一个用户交互页面,不需要前端代码。
Streamlit 提供了许多用于构建用户界面的组件,使用户能够与数据进行交互。以下是一些常用的组件:
st.write()
: 通用的输出函数,支持文字、数据框、图表等的输出。st.title()
: 用于创建应用的标题。st.text()
和st.markdown()
: 显示文本,支持 Markdown 格式。st.image()
: 显示图片。st.button()
: 创建一个按钮,用户点击后触发事件。st.slider()
: 滑块,允许用户选择数值范围。st.selectbox()
: 下拉选择框。st.file_uploader()
: 文件上传组件,支持用户上传文件。st.form()
: 用于处理表单输入,用户可以提交多个字段。
主要添加的库如下:
from transformers import AutoTokenizer, AutoModelForCausalLM # 大模型加载必要的函数
import torch
import streamlit as st
# 源大模型下载
from modelscope import snapshot_download # 阿里的魔塔涵盖了很多大模型,下载速度超级快,而且qwen系列模型也挺好用的,算是国内数一数二的开源模型了
注意:
1、运行使用命令:streamlit run xxx.py
2、可能需要下载的包:einops、sentencepiece
3、使用魔塔modelscope下载模型,模型可以去魔塔社区寻找。
from modelscope import snapshot_download
model_dir = snapshot_download('模型ID', cache_dir='您希望的下载路径', revision='版本号')
加载大模型
大模型加载最重要的就是tokenizer和model,
1. Tokenizer(分词器)
Tokenizer
是将自然语言文本转换为模型可理解的数字化表示的工具。它负责将输入的文本转化为词(或子词)ID,然后传递给模型。具体来说,Tokenizer
的作用包括:
- 分词:将文本拆分成词或子词(这取决于模型的分词方式,比如 BERT 使用的 WordPiece,GPT 使用的 Byte-Pair Encoding (BPE))。
- 编码:将分词后的文本转换为词汇表中的唯一标识(IDs)。
- 填充与截断:确保输入的长度符合模型的要求(通常是固定长度),通过在短于要求的序列后添加填充(padding),或者截断超长的序列。
- 特殊标记处理:如开始标记 (
[CLS]
)、结束标记 ([SEP]
) 等,这些标记通常在处理输入序列时是必须的,尤其是在任务如分类和生成中。
示例
from transformers import AutoTokenizer
# 加载 Tokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
# 将文本转换为输入 ID
inputs = tokenizer("Hello, how are you?", return_tensors="pt")
2. Model(模型)
Model
是预训练的大型神经网络模型,通常是 Transformer 架构,用于执行特定的任务(如语言建模、文本生成、问答、翻译等)。模型的任务可以包括:
- 生成文本(如 GPT 模型)
- 进行分类(如 BERT 在情感分析、分类任务中)
- 生成摘要(如 T5 或 Bart 模型)
- 回答问题(如 BERT 在问答系统中)
示例
from transformers import AutoTokenizer, AutoModelForCausalLM
# 加载 tokenizer 和 model
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2").cuda()
# 编码输入文本,将字符转为ID
inputs = tokenizer("Hello, how are you?", return_tensors="pt").to('cuda')
# 模型生成文本
outputs = model.generate(inputs['input_ids'], max_length=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
注意:
1、generate()
是 transformers
库中用于文本生成的函数。它会根据输入的 token ID(即 inputs['input_ids']
)生成一段新的文本。
2、inputs['input_ids']
:这是模型输入的 token ID 序列,来自于上一步 tokenizer
处理后的结果。模型会根据这些 token 来生成下一个 token。
3、tokenizer.decode(outputs[0], skip_special_tokens=True)
:
outputs[0]
:outputs
是一个 batch,其中outputs[0]
是我们关心的第一条生成结果。tokenizer.decode()
:将模型生成的 token ID 序列转换回人类可读的文本字符串。skip_special_tokens=True
:告诉tokenizer
在解码时忽略特殊的 token,比如[CLS]
、[SEP]
等。某些模型在处理过程中会加入这些特殊的 token,但它们通常不需要出现在最终的输出文本中。
4、AutoTokenizer负责加载预训练的分词器, AutoModelForCausalLM负责加载语言模型。AutoTokenizer.from_pretrained函数的相关参数可参考AutoTokenizer.from_pretrained参数说明,AutoModelForCausalLM.from_pretrained函数的相关参数可参考AutoModelForCausalLM.from_pretrained参数说明
示例
1、Yuan2-2B-Mars-hf模型
源2.0 是浪潮信息发布的新一代基础语言大模型。我们开源了全部的3个模型源2.0-102B,源2.0-51B和源2.0-2B。并且我们提供了预训练,微调,推理服务的相关脚本,以供研发人员做进一步的开发。源2.0是在源1.0的基础上,利用更多样的高质量预训练数据和指令微调数据集,令模型在语义、数学、推理、代码、知识等不同方面具备更强的理解能力。
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import streamlit as st
# 创建一个标题和一个副标题
st.title("AI助手")
# 源大模型下载
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)
运行结果:
显存占用情况:
2、qwen2-1.5b-instruct模型
Qwen2 是 Qwen 大型语言模型系列的新篇章。对于 Qwen2,我们发布了从 0.5 到 720 亿参数不等的基础语言模型与指令调优语言模型,其中包括混合专家(Mixture-of-Experts)模型。本仓库包含了 1.5B 参数的 Qwen2 指令调优模型。
用原来的的代码运行会出问题,运行结果如下:
猜测是因为不同模型的运行规则有所不同,因此按照qwen文档说明修改代码:
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import streamlit as st
# 源大模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('qwen/Qwen2-1.5B-Instruct', cache_dir='./')
# 创建一个标题和一个副标题
st.title("AI助手")
# 定义模型路径
path = './qwen/Qwen2-1___5B-Instruct'
# path = './IEITYuan/Yuan2-2B-Mars-hf'
# 定义一个函数,用于获取模型和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>','<|im_end|>'], special_tokens=True)
print("Creat model...")
model = AutoModelForCausalLM.from_pretrained(path, torch_dtype=torch.bfloat16, 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)
# 调用模型
messages = [
{"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},
]
for msg in st.session_state.messages:
messages.append(msg)
print(messages)
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=1024) # 设置解码方式和最大生成长度
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(inputs.input_ids, outputs)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# 将模型的输出添加到session_state中的messages列表中
st.session_state.messages.append({"role": "assistant", "content": response})
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(response)
输出结果如下:
这下没啥问题了,所以对不同模型,要根据对应文档编写使用程序。qwen2-1.5b-instruct显存占用如下:
参考文献:
1、Streamlit完全指南:交互式应用开发从入门到精通 - 知乎 (zhihu.com)
2、Task3:源大模型RAG实战 - 飞书云文档 (feishu.cn)