一、前言
现在,我们已经成功以最低成本运行起了qwen大模型。然而,我们希望进一步探索并提升模型输出结果的符合度,以满足业务需求。
二、术语
2.1. system prompt(系统提示)
是指在生成对话或文本的任务中,为了引导模型产生合适的响应或输出,对模型进行输入的开头部分或系统提供的指令。系统提示通常包含一些关键信息,如对话的背景、任务的要求或期望的回答风格等,以帮助模型理解上下文并生成相关的响应。通过精心设计和调整系统提示,可以引导模型产生更准确、连贯且符合预期的输出。
2.2. temperature(温度)
是用于控制生成模型输出的多样性和随机性的一个参数。当温度较高时,模型会更加随机地选择输出,使得生成结果更加多样化和创造性,但可能会牺牲一些准确性和一致性。相反,当温度较低时,模型会更加确定性地选择输出,使得生成结果更加集中和可控。较低的温度值会使概率分布更尖峰,使得高概率的词或标记更容易被选中。
2.3. top_p
是一种用于控制生成模型输出的参数。在生成文本或对话的任务中,模型通常会输出一个概率分布,表示每个可能的词或标记的概率。top_p参数用于指定一个概率的阈值,模型将从概率累积最高的词开始逐步选择,直到累积概率超过阈值为止。通过设置top_p参数,我们可以控制生成模型输出的多样性和可控性。较小的top_p值会限制模型选择的候选词的数量,使得模型的输出更加集中和可控。较大的top_p值会增加模型选择的候选词的数量,使得模型的输出更加多样化和创造性。
2.4. repetition_penalty
是一种用于控制生成模型输出中重复内容的参数。在生成文本或对话的任务中,模型有时候可能会倾向于产生重复的词语、短语或句子,导致生成结果的质量下降或显得不够自然。为了解决这个问题,可以使用重复惩罚机制。重复惩罚参数可以调整模型对已经生成过的内容的偏好程度。较高的重复惩罚值会使模型更加抑制生成已经出现过的内容,以鼓励生成更多新颖的内容。较低的重复惩罚值则会相对宽容,允许模型生成一定程度的重复内容。
2.5. history
"历史上下文"是指在处理当前文本或对话时,与之前的文本或对话相关的信息和语境。历史上下文包括了之前的句子、段落或对话中的内容,以及前文中提到的实体、事件和语义关系等。它提供了理解当前文本的重要背景信息,帮助我们更准确地解释和推断文本的含义。处理历史上下文时,模型需要能够捕捉并记忆之前的信息,并将其与当前文本进行关联,以产生有意义的输出。
三、前置条件
3.1. windows操作系统(不需要GPU)
3.2. 下载Qwen-1_8B-Chat模型
四、技术实现
4.1. 设置system prompt
# system prompt设置为:你是一只乐意助人叮当猫,擅长解决人类的各种问题!不论什么事,只要你有疑问都可以来问我哦~
def chat(model,tokenizer,message):
position = 0
result = []
try:
for response in model.chat_stream(tokenizer, message, system='你是一只乐意助人叮当猫,擅长解决人类的各种问题!不论什么事,只要你有疑问都可以来问我哦~',history=None):
result.append(response[position:])
position = len(response)
yield "".join(result)
except Exception:
traceback.print_exc()
输出:
4.2. 设置模型参数
# 方式一,在模型调用时指定参数
def chat(model,tokenizer,message,config):
position = 0
result = []
try:
for response in model.chat_stream(tokenizer, message, system='你是一位乐于助人的人工智能助手,愿意解决人类提出的各种问题',history=None,
generation_config=config):
result.append(response[position:])
position = len(response)
yield "".join(result)
except Exception:
traceback.print_exc()
调用:
message = "广州有什么好玩的地方啊?"
config = GenerationConfig.from_pretrained(modelPath,trust_remote_code=True,top_p=0.9,temperature=0.9,repetition_penalty=1.1, do_sample=True, max_new_tokens=8192)
response = chat(model,tokenizer,message,config)
结果:
1) 第一次调用结果
2) 第二次调用结果
PS: 模型生成的内容更具有多样性
将 temperature=0.9调整为temperature=0.1
1) 第一次调用结果
PS: 模型生成的内容更具有确定性
# 方式二,在模型加载时指定参数
def loadModel(config):
model = AutoModelForCausalLM.from_pretrained(modelPath, device_map="cpu", trust_remote_code=True).eval()
model.generation_config = config
return model
调用:
config = GenerationConfig.from_pretrained(modelPath, trust_remote_code=True, top_p=0.9, temperature=0.9, repetition_penalty=1.1, do_sample=True, max_new_tokens=8192)
model = loadModel(config)
tokenizer = loadTokenizer()
message = "广州有什么好玩的地方啊?"
response = chat(model,tokenizer,message)
结果:
1) 第一次调用结果
2) 第二次调用结果
PS: 模型生成的内容更具有多样性
将 temperature=0.9调整为temperature=0.1
1) 第一次调用结果
2) 第二次调用结果
PS: 模型生成的内容更具有确定性
4.3. 设置历史上下文
def chat(model,tokenizer,message,history):
position = 0
result = []
try:
for response in model.chat_stream(tokenizer, message, system='你是一位乐于助人的人工智能助手,愿意解决人类提出的各种问题',history=history):
result.append(response[position:])
position = len(response)
yield "".join(result)
except Exception:
traceback.print_exc()
调用
config = GenerationConfig.from_pretrained(modelPath, trust_remote_code=True, top_p=0.9, temperature=0.1,repetition_penalty=1.1, do_sample=True, max_new_tokens=8192)
model = loadModel(config)
tokenizer = loadTokenizer()
message = "帮我介绍一下我家的特产?"
history = [('hi,你好','你好!有什么我可以帮助你的吗?'),('我家在广州,很好玩哦','广州是一个美丽的城市,有很多有趣的地方可以去。'),]
response = chat(model,tokenizer,message,history)
结果:
PS:
1) 根据模型参数的配置和prompt的差异,有可能导致模型出现幻觉并忘记之前的对话记录的情况。如下图所示:
五、完整代码
import traceback
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import time
modelPath = "E:\\pycharm\\gpt\\model\\qwen-1_8b-chat"
def chat(model,tokenizer,message,history):
position = 0
result = []
try:
for response in model.chat_stream(tokenizer, message, system='你是一位乐于助人的人工智能助手,愿意解决人类提出的各种问题',history=history):
result.append(response[position:])
position = len(response)
yield "".join(result)
except Exception:
traceback.print_exc()
def generate(model,tokenizer,message):
try:
inputs = tokenizer(message, return_tensors='pt')
pred = model.generate(**inputs)
return tokenizer.decode(pred.cpu()[0], skip_special_tokens=True)
except Exception:
traceback.print_exc()
def loadTokenizer():
tokenizer = AutoTokenizer.from_pretrained(modelPath, trust_remote_code=True)
return tokenizer
def loadModel(config):
model = AutoModelForCausalLM.from_pretrained(modelPath, device_map="cpu", trust_remote_code=True).eval()
model.generation_config = config
return model
if __name__ == '__main__':
config = GenerationConfig.from_pretrained(modelPath, trust_remote_code=True, top_p=0.9, temperature=0.1,repetition_penalty=1.1, do_sample=True, max_new_tokens=8192)
model = loadModel(config)
tokenizer = loadTokenizer()
start_time = time.time()
message = "帮我介绍一下我家的特产?"
history = [('hi,你好','你好!有什么我可以帮助你的吗?'),('我家在广州,很好玩哦','广州是一个美丽的城市,有很多有趣的地方可以去。'),]
response = chat(model,tokenizer,message,history)
result = []
for r in response:
result.append(r)
print(result[-1])
end_time = time.time()
print("执行耗时: {:.2f}秒".format(end_time-start_time))