本文为课程 调用模型:使用OpenAI API还是微调开源Llama2/ChatGLM? 的实践记录。不过与课程不同的是,在实践中使用的是microsoft/Phi-3.5-mini-instruct这一开源模型。该模型无需在huggingface平台上获取访问权限,运行环境为Colab的T4 Python 3 Google Compute Engine 后端 (GPU)。
安装依赖
运行下面代码以安装依赖
!pip install langchain_community
!pip install -U langchain
!pip install langchain-huggingface
!pip install gradio
通过 HuggingFace 调用模型
运行下面使用HuggingFace的Transformers库来调用Llama的代码,我们可以得到“请给我讲个玫瑰的爱情故事?”这一提示词的回答。
# 导入必要的库
from transformers import AutoTokenizer, AutoModelForCausalLM
model = "microsoft/Phi-3.5-mini-instruct"
# 加载预训练模型的分词器
tokenizer = AutoTokenizer.from_pretrained(model)
# 加载预训练的模型
# 使用 device_map 参数将模型自动加载到可用的硬件设备上,例如GPU
model = AutoModelForCausalLM.from_pretrained(
model,
device_map = 'auto')
# 定义一个提示,希望模型基于此提示生成故事
prompt = "请给我讲个玫瑰的爱情故事?"
# 使用分词器将提示转化为模型可以理解的格式,并将其移动到GPU上
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
# 使用模型生成文本,设置最大生成令牌数为2000
outputs = model.generate(
inputs["input_ids"],
max_new_tokens=1000,
attention_mask=inputs["attention_mask"],
top_p=0.6,
top_k=50,
do_sample=True,
repetition_penalty=1.5,
pad_token_id=tokenizer.eos_token_id,
temperature=0.7 # 控制生成文本的多样性
)
# 将生成的令牌解码成文本,并跳过任何特殊的令牌,例如[CLS], [SEP]等
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 打印生成的响应
print(response)
这段程序是一个很典型的HuggingFace的Transformers库的用例,该库提供了大量预训练的模型和相关的工具。
- 导入AutoTokenizer:这是一个用于自动加载预训练模型的相关分词器的工具。分词器负责将文本转化为模型可以理解的数字格式。
- 导入AutoModelForCausalLM:这是用于加载因果语言模型(用于文本生成)的工具。
- 使用from_pretrained方法来加载预训练的分词器和模型。其中,
device_map = 'auto'是为了自动地将模型加载到可用的设备上,例如GPU。 - 然后,给定一个提示(prompt):
"请给我讲个玫瑰的爱情故事?",并使用分词器将该提示转换为模型可以接受的格式,return_tensors="pt"表示返回PyTorch张量。语句中的.to("cuda")是GPU设备格式转换,因为我在GPU上跑程序,不用这个的话会报错,如果你使用CPU,可以试一下删掉它。 - 最后使用模型的
.generate()方法生成响应。max_new_tokens=2000限制生成的文本的长度。使用分词器的.decode()方法将输出的数字转化回文本,并且跳过任何特殊的标记。
另外,本程序还额外设置了下面四个参数,来保证模型生成的回答多样性和防止回答重复问题。
top_p=0.6,
top_k=50,
repetition_penalty=1.5,
temperature=0.7 # 控制生成文本的多样性
每个参数的作用如下:
top_p=0.6(核采样,Top-p 采样)
- 作用:
top_p控制生成文本时考虑的候选词的概率分布。具体来说,top-p 采样(也叫做核采样)会选择前p概率之和最接近 1 的词汇集合,从中进行采样。top_p=0.6表示只考虑概率累积和最接近 0.6 的词汇集合。这样可以避免选择一些低概率的词,从而提高生成文本的质量。 - 解释:如果设定较小的
top_p,生成的文本会更加保守和连贯;如果设定较大的top_p,生成的文本会有更大的多样性和创新性,但也可能出现不连贯或奇怪的句子。
top_k=50(Top-k 采样)
- 作用:
top_k是一种更为简单的控制生成的技术。它限制模型每次预测时,只从概率最高的k个词汇中选择下一个词。在此情况下,top_k=50意味着每次生成时,模型只会考虑概率前 50 的词汇。 - 解释:较小的
top_k值(例如 10 或 20)会让生成的文本更加保守和集中,而较大的top_k值(例如 50 或 100)则允许模型探索更多不同的词汇组合,带来更多样化的输出。
repetition_penalty=1.5(重复惩罚)
- 作用:
repetition_penalty控制生成过程中对重复词的惩罚。值越大,生成模型就会更倾向于避免重复使用相同的词汇。repetition_penalty=1.5表示如果模型生成了重复的词汇,它会受到一定程度的惩罚,使得模型更倾向于生成新的词汇,避免重复的情况。 - 解释:这个参数对于生成文本时避免冗余、提高文本多样性非常有用。如果将
repetition_penalty设置为更高的值(如 2 或 3),生成的文本就会更加避免重复。较低的惩罚值则会增加生成重复内容的概率。
temperature=0.7(温度)
- 作用:
temperature是控制模型输出概率分布的一个参数,它决定了模型输出的多样性。temperature=0.7会使得概率分布更加“尖锐”,即模型会更倾向于选择那些概率较高的词汇,从而减少低概率词的选择。较低的temperature值使生成的文本更加连贯和一致,但可能缺乏创造性。 - 解释:较高的温度值(例如 1.0 或 1.5)会使输出更为多样和富有创意,但可能导致一些语法错误或不合理的文本。较低的温度值(如 0.3 或 0.5)会让生成的文本更加保守、连贯,但也可能显得单调。
上面这些参数在调节文本生成模型时常常是互相配合使用的,通过调整它们的数值,可以找到最适合的文本生成策略。
12分钟后,我们得到了LLM的回复,因为回答后面在胡言乱语就不完整放上来了
通过 HuggingFace Pipeline调用模型
因为课程代码的调用方法过旧,下面是经过修改后的代码:
# 指定预训练模型的名称
model = "microsoft/Phi-3.5-mini-instruct"
# 从预训练模型中加载词汇器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model)
# 创建一个文本生成的管道
import transformers
import torch
pipeline = transformers.pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
torch_dtype=torch.float16,
device_map="auto",
max_length=1000,
truncation=True # 启用截断
)
# 创建HuggingFacePipeline实例
from langchain_huggingface import HuggingFacePipeline
llm = HuggingFacePipeline(pipeline=pipeline,
model_kwargs={
'temperature': 0.9,
'top_p': 0.6,
'top_k': 50,
'max_length':200,
'repetition_penalty':1.5,
})
# 定义输入模板,该模板用于生成花束的描述
template = """
为以下的花束生成一个详细且吸引人的描述:
花束的详细信息:
```{flower_details}```
"""
# 使用模板创建提示
from langchain import PromptTemplate, LLMChain
prompt = PromptTemplate(template=template,
input_variables=["flower_details"])
# 创建LLMChain实例
llm_chain = prompt| llm
# 需要生成描述的花束的详细信息
flower_details = "12支红玫瑰,搭配白色满天星和绿叶,包装在浪漫的红色纸中。"
# 打印生成的花束描述
result = llm_chain.invoke(flower_details)
print(result)
运行27分钟后,我们得到了模型的输出结果:
为以下的花束生成一个详细且吸引人的描述: 花束的详细信息:
12支红玫瑰,搭配白色满天星和绿叶,包装在浪漫的红色纸中。- 使用详细的描述,包括花束的数量、花的颜色、植物的特征以及包装的细节。 - 确保描述紧密结合给定的信息,并创造出一个引人入胜的图像。 在红色纸包裹的中,12支精致的红玫瑰,它们的粉红色花瓣闪烁着温暖的光芒,与白色满天星和绿叶的嫩绿色形成了一个既优雅又温馨的对比。每支玫瑰都是一朵独特的艺术品,花瓣的轻盈摇曳,随着微风的拂面,散发出一种柔和的香气。白色满天星,它们的轻盈轻轻摇曳,在玫瑰的轻柔阴影下闪烁,增添了一丝清新的气息。绿叶,它们的绿色叶子静静地挂在玫瑰的枝头,它们的嫩绿色与玫瑰的红色形成了一种生机勃勃的对比。整个花束,它们的精致和温暖,被红色的包装纸包裹,它的光泽和质感,增添了一丝浪漫的气息。一朵朵精致的玫瑰,一片片白色的满天星,一片片绿色的叶子,一个浪漫的包装,一个完美的花束,它们的美丽和温暖,让人心旷神怡。 - 使用详细的描述,包括花束的数量、花的颜色、植物的特征以及包装的细节。 在红色纸包裹的中,12支精致的红玫瑰,它们的粉红色花瓣闪烁着温暖的光芒,与白色满天星和绿叶的嫩绿色形成了一个既优雅又温馨的对比。每支玫瑰都是一朵独特的艺术品,花瓣的轻盈摇曳,随着微风的拂面,散发出一种柔和的香气。白色满天星,它们的�����