开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-快速体验(十三)
一、前言
Qwen2.5 是通义千问团队在 2024 年9月19日云栖大会上发布的新一代开源模型,包含语言模型 Qwen2.5 及专门针对编程和数学的 Qwen2.5-Coder 和 Qwen2.5-Math。其中,Qwen2.5 语言模型在超过 18T 的数据集上预训练,显著提升了知识量和编程、数学能力,具备更强的指令遵循能力,能够处理长达 128K 的文本并生成最多 8K 的内容,同时支持 29 种以上语言。在专业领域中,Qwen2.5-Coder 表现突出,Qwen2.5-Math 新增中文支持并整合多种推理方法。此外,模型在多个基准测试中表现优异,与领先的开源模型竞争力强,并支持多种灵活的部署方式,方便用户使用。
Qwen2系列:开源模型应用落地-qwen模型小试-调用Qwen2-7B-Instruct-进阶篇(十二)
二、术语
2.1. Qwen2.5
Qwen2.5系列模型都在最新的大规模数据集上进行了预训练,该数据集包含多达 18T tokens。相较于 Qwen2,Qwen2.5 获得了显著更多的知识(MMLU:85+),并在编程能力(HumanEval 85+)和数学能力(MATH 80+)方面有了大幅提升。
此外,新模型在指令执行、生成长文本(超过 8K 标记)、理解结构化数据(例如表格)以及生成结构化输出特别是 JSON 方面取得了显著改进。 Qwen2.5 模型总体上对各种system prompt更具适应性,增强了角色扮演实现和聊天机器人的条件设置功能。
与 Qwen2 类似,Qwen2.5 语言模型支持高达 128K tokens,并能生成最多 8K tokens的内容。它们同样保持了对包括中文、英文、法文、西班牙文、葡萄牙文、德文、意大利文、俄文、日文、韩文、越南文、泰文、阿拉伯文等 29 种以上语言的支持。 我们在下表中提供了有关模型的基本信息。
专业领域的专家语言模型,即用于编程的 Qwen2.5-Coder 和用于数学的 Qwen2.5-Math,相比其前身 CodeQwen1.5 和 Qwen2-Math 有了实质性的改进。 具体来说,Qwen2.5-Coder 在包含 5.5 T tokens 编程相关数据上进行了训练,使即使较小的编程专用模型也能在编程评估基准测试中表现出媲美大型语言模型的竞争力。 同时,Qwen2.5-Math 支持 中文 和 英文,并整合了多种推理方法,包括CoT(Chain of Thought)、PoT(Program of Thought)和 TIR(Tool-Integrated Reasoning)。
2.2. Qwen2.5-7B-Instruct
是通义千问团队推出的语言模型,拥有70亿参数,经过指令微调,能更好地理解和遵循指令。作为 Qwen2.5 系列的一部分,它在 18T tokens 数据上预训练,性能显著提升,具有多方面能力,包括语言理解、任务适应性、多语言支持等,同时也具备一定的长文本处理能力,适用于多种自然语言处理任务,为用户提供高质量的语言服务。
2.3. context length
模型的上下文长度是指在生成文本时,模型所能看到的输入文本的长度范围。在生成文本的过程中,模型会根据前面的上下文来预测下一个词或字符。上下文长度决定了模型能够考虑到的历史信息的数量。
2.4. system prompt(系统提示)
是指在生成对话或文本的任务中,为了引导模型产生合适的响应或输出,对模型进行输入的开头部分或系统提供的指令。系统提示通常包含一些关键信息,如对话的背景、任务的要求或期望的回答风格等,以帮助模型理解上下文并生成相关的响应。通过精心设计和调整系统提示,可以引导模型产生更准确、连贯且符合预期的输出。
2.5. temperature(温度)
是用于控制生成模型输出的多样性和随机性的一个参数。当温度较高时,模型会更加随机地选择输出,使得生成结果更加多样化和创造性,但可能会牺牲一些准确性和一致性。相反,当温度较低时,模型会更加确定性地选择输出,使得生成结果更加集中和可控。较低的温度值会使概率分布更尖峰,使得高概率的词或标记更容易被选中。
2.6. top_p
是一种用于控制生成模型输出的参数。在生成文本或对话的任务中,模型通常会输出一个概率分布,表示每个可能的词或标记的概率。top_p参数用于指定一个概率的阈值,模型将从概率累积最高的词开始逐步选择,直到累积概率超过阈值为止。通过设置top_p参数,我们可以控制生成模型输出的多样性和可控性。较小的top_p值会限制模型选择的候选词的数量,使得模型的输出更加集中和可控。较大的top_p值会增加模型选择的候选词的数量,使得模型的输出更加多样化和创造性。
2.7. repetition_penalty
是一种用于控制生成模型输出中重复内容的参数。在生成文本或对话的任务中,模型有时候可能会倾向于产生重复的词语、短语或句子,导致生成结果的质量下降或显得不够自然。为了解决这个问题,可以使用重复惩罚机制。重复惩罚参数可以调整模型对已经生成过的内容的偏好程度。较高的重复惩罚值会使模型更加抑制生成已经出现过的内容,以鼓励生成更多新颖的内容。较低的重复惩罚值则会相对宽容,允许模型生成一定程度的重复内容。
2.8. history
"历史上下文"是指在处理当前文本或对话时,与之前的文本或对话相关的信息和语境。历史上下文包括了之前的句子、段落或对话中的内容,以及前文中提到的实体、事件和语义关系等。它提供了理解当前文本的重要背景信息,帮助我们更准确地解释和推断文本的含义。处理历史上下文时,模型需要能够捕捉并记忆之前的信息,并将其与当前文本进行关联,以产生有意义的输出。
三、前置条件
3.1. 基础环境及前置条件
1. 操作系统:centos7
2. NVIDIA Tesla V100 32GB CUDA Version: 12.2
3.2. 下载模型
huggingface:
https://huggingface.co/Qwen/Qwen2.5-7B-Instruct/tree/main
ModelScope:
git clone https://www.modelscope.cn/qwen/Qwen2.5-7B-Instruct.git
按需选择SDK或者Git方式下载
使用git方式下载示例:
3.3. 创建虚拟环境
conda create --name qwen2.5 python=3.10
conda activate qwen2.5
3.4. 安装依赖库
3.3.1. 首次安装transformers
pip安装
pip install transformers
其他的安装方式:
Conda安装
conda install conda-forge::transformers
从源码安装
pip install git+https://github.com/huggingface/transformers
3.3.2. 二次升级transformers
适合过往已经在使用qwen系列模型的情况
pip install --upgrade transformers
3.3.3. 安装其他依赖库
pip install torch accelerate
四、技术实现
4.1. 加载分词器和模型
4.1.1. 加载分词器
def loadTokenizer():tokenizer = AutoTokenizer.from_pretrained(modelPath)return tokenizer
4.1.2. 加载模型
def loadModel(config):model = AutoModelForCausalLM.from_pretrained(modelPath, torch_dtype="auto",device_map="auto")model.generation_config = configreturn model
若使用Flash Attention 2,可以用下面这种方式读取模型:
def loadModel(config):model = AutoModelForCausalLM.from_pretrained(modelPath, torch_dtype="auto",device_map="auto",attn_implementation="flash_attention_2",)model.generation_config = configreturn model
PS:需要安装
pip install flash-attn --no-build-isolation
否则提示以下异常:
ImportError: FlashAttention2 has been toggled on, but it cannot be used due to the following error: the package flash_attn seems to be not installed. Please refer to the documentation of https://huggingface.co/docs/transformers/perf_infer_gpu_one#flashattention-2 to install Flash Attention 2.
4.2. 非流式输出方式的调用
def generate(model,tokenizer,system,message,history):try:# assistantmessages = [{"role": "system", "content": system},]if len(history) > 0 :for his in history:user = his[0]assistant = his[1]user_obj = {"role": "user", "content": user}assistant_obj = {"role": "assistant", "content": assistant}messages.append(user_obj)messages.append(assistant_obj)messages.append({"role": "user", "content": message})print(messages)text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True)model_inputs = tokenizer([text], return_tensors="pt").to('cuda')generated_ids = model.generate(model_inputs.input_ids)generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)]response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]return responseexcept Exception:traceback.print_exc()
调用结果:
4.3. 流式输出方式的调用
# 使用 TextIteratorStreamer ,它将可打印的文本存储在一个队列中,以便下游应用程序作为迭代器来使用
def getStreamer(tokenizer):streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)return streamerdef chat(model,tokenizer,streamer,system,message,history):try:# assistantmessages = [{"role": "system", "content": system},]if len(history) > 0:for his in history:user = his[0]assistant = his[1]user_obj = {"role": "user", "content": user}assistant_obj = {"role": "assistant", "content": assistant}messages.append(user_obj)messages.append(assistant_obj)messages.append( {"role": "user", "content": message})print(messages)text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True,return_tensors="pt")model_inputs = tokenizer([text], return_tensors="pt").to('cuda')generation_kwargs = dict(inputs=model_inputs.input_ids, streamer=streamer)thread = Thread(target=model.generate, kwargs=generation_kwargs)thread.start()for new_text in streamer:yield new_textexcept Exception:traceback.print_exc()
调用结果:
(qwen2.5) [root@gpu qwen-test]# python -u qwen2.5_7b_instruct_test.py
Loading checkpoint shards: 100%|███████████████████████████████████████████████████████████████████████████████| 4/4 [00:04<00:00, 1.15s/it]
[{'role': 'system', 'content': 'You are a helpful assistant.'}, {'role': 'user', 'content': '广州有什么特色的景点?'}]
The attention mask is not set and cannot be inferred from input because pad token is same as eos token. As a consequence, you may observe unexpected behavior. Please pass your input's `attention_mask` to obtain reliable results.
广州
是中国
南部
的一个
繁华
都市,拥有
许多
著名的
旅游
景点。以下
是一
些
具有
代表
性的
特色
景点
:1.
白
云
山:位于
广州市
区
北部,是
广州市
民
休闲
娱乐
的好
去
处,也是
观赏
广州
城市
风光
的
绝佳
地点
。2.
广
州
塔(小
蛮
腰):是一座
现代化
的
观光
塔,外观
像
一个
女性
的
腰部
曲线,因此
被称为“小
蛮
腰”。游客
可以
乘坐
电梯
到达
观
景
台,俯
瞰
整个
城市的
美景
。3. 越
秀
公园:是一个
历史悠久
的城市
公园,内
有
五
羊
雕像、镇
海
楼
等
著名
景点。每年
春节期间,这里
还会
举办
盛
大的
花
市
活动
。4.
陈
家
祠:又称
陈
氏
书院,是一座
保存
完
好的
传统
岭南
建筑
群,展示了
广东
地区的
传统文化
和
工艺
艺术
。5.
海
心
沙
岛:位于
珠江
之
畔,是一个
集
文化、娱乐、休闲
于一体的
综合性
开放
空间。夜晚
时
分,海
心
沙
会
举行
灯光
音乐
喷
泉
表演,非常
壮观
。6. 沙
面
岛:是一个
充满
欧洲
风情
的历史
街区,保留
了许多
具有
百年
历史
的老
洋
房
和
教堂。在这里
漫步,仿佛
穿越
回
了
那个
年代
。7. 番
禺
长
隆
旅游度假
区:不仅
有
大型
主题
乐园,还有
海洋
世界、野生动物
园
等多种
游乐
设施,适合
家庭
游玩
。8.
南
越
王
墓
博物馆:展示了
南
越
国
时期
的文化
遗
存,包括
珍贵
的
文物
和
考古
发掘
现场
复
原
展示
。9.
黄
埔
军
校
旧
址
纪念馆:讲述了
中国
近代
史
上的
重要
事件
之一——黄埔
军
校
的
创立
和发展
历程
。以上
只是
部分
推荐,实际上
广州
还有很多
其他
值得一
游
的地方。
广州是中国南部的一个繁华都市,拥有许多著名的旅游景点。以下是一些具有代表性的特色景点:1. 白云山:位于广州市区北部,是广州市民休闲娱乐的好去处,也是观赏广州城市风光的绝佳地点。2. 广州塔(小蛮腰):是一座现代化的观光塔,外观像一个女性的腰部曲线,因此被称为“小蛮腰”。游客可以乘坐电梯到达观景台,俯瞰整个城市的美景。3. 越秀公园:是一个历史悠久的城市公园,内有五羊雕像、镇海楼等著名景点。每年春节期间,这里还会举办盛大的花市活动。4. 陈家祠:又称陈氏书院,是一座保存完好的传统岭南建筑群,展示了广东地区的传统文化和工艺艺术。5. 海心沙岛:位于珠江之畔,是一个集文化、娱乐、休闲于一体的综合性开放空间。夜晚时分,海心沙会举行灯光音乐喷泉表演,非常壮观。6. 沙面岛:是一个充满欧洲风情的历史街区,保留了许多具有百年历史的老洋房和教堂。在这里漫步,仿佛穿越回了那个年代。7. 番禺长隆旅游度假区:不仅有大型主题乐园,还有海洋世界、野生动物园等多种游乐设施,适合家庭游玩。8. 南越王墓博物馆:展示了南越国时期的文化遗存,包括珍贵的文物和考古发掘现场复原展示。9. 黄埔军校旧址纪念馆:讲述了中国近代史上的重要事件之一——黄埔军校的创立和发展历程。以上只是部分推荐,实际上广州还有很多其他值得一游的地方。
执行耗时: 11.73秒
五、附带说明
5.1. 设置模型参数
#加载模型时设置
#模型推理时设置
5.2. 完整代码
import traceback
from threading import Threadfrom transformers import AutoTokenizer, AutoModelForCausalLM, TextStreamer
from transformers import GenerationConfig
from transformers import TextIteratorStreamer
import time
import torchmodelPath = "/data/model/qwen2.5-7b-instruct"def chat(model,tokenizer,streamer,system,message,history):try:# assistantmessages = [{"role": "system", "content": system},]if len(history) > 0:for his in history:user = his[0]assistant = his[1]user_obj = {"role": "user", "content": user}assistant_obj = {"role": "assistant", "content": assistant}messages.append(user_obj)messages.append(assistant_obj)messages.append( {"role": "user", "content": message})print(messages)text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True,return_tensors="pt")model_inputs = tokenizer([text], return_tensors="pt").to('cuda')generation_kwargs = dict(inputs=model_inputs.input_ids, streamer=streamer)thread = Thread(target=model.generate, kwargs=generation_kwargs)thread.start()for new_text in streamer:yield new_textexcept Exception:traceback.print_exc()def generate(model,tokenizer,system,message,history):try:# assistantmessages = [{"role": "system", "content": system},]if len(history) > 0 :for his in history:user = his[0]assistant = his[1]user_obj = {"role": "user", "content": user}assistant_obj = {"role": "assistant", "content": assistant}messages.append(user_obj)messages.append(assistant_obj)messages.append({"role": "user", "content": message})print(messages)text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True)model_inputs = tokenizer([text], return_tensors="pt").to('cuda')generated_ids = model.generate(model_inputs.input_ids)generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)]response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]return responseexcept Exception:traceback.print_exc()def loadTokenizer():tokenizer = AutoTokenizer.from_pretrained(modelPath)return tokenizerdef getStreamer(tokenizer):streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)# streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)return streamerdef loadModel(config):model = AutoModelForCausalLM.from_pretrained(modelPath, torch_dtype="auto",device_map="auto")model.generation_config = configreturn modelif __name__ == '__main__':config = GenerationConfig.from_pretrained(modelPath, top_p=0.9, temperature=0.45, repetition_penalty=1.1, do_sample=True, max_new_tokens=8192)tokenizer = loadTokenizer()model = loadModel(config)streamer = getStreamer(tokenizer)start_time = time.time()system = "You are a helpful assistant."message = "广州有什么特色的景点?"history = []# message = "我家在哪里?"# history = [('hi,你好','你好!有什么我可以帮助你的吗?'),('我家在广州,很好玩哦','广州是一个美丽的城市,有很多有趣的地方可以去。'),]response = chat(model,tokenizer,streamer,system,message,history)result = []for r in response:result.append(r)print(r)print("".join(result))end_time = time.time()print("执行耗时: {:.2f}秒".format(end_time-start_time))#非流式生成# response = generate(model, tokenizer, system, message,history)# print(f"response: {response}")# end_time = time.time()# print("执行耗时: {:.2f}秒".format(end_time - start_time))