第七节 调用模型:使用OpenAI API还是微调开源Llama2/ChatGLM?
一、基础知识点
(一)大预言模型发展史
Google 2018 年的论文名篇Attention is all you need,提出了Transformer架构,也给这一次AI的腾飞点了火。Transformer是几乎所有预训练模型的核心底层架构。基于Transformer预训练所得的大规模语言模型也被叫做“基础模型”(Foundation Model 或Base Model)。
(二)预训练+微调的模式
NLP应用人员可以对模型的头部或者部分参数根据自己的需要进行适应性的调整,这通常涉及在相对较小的有标注数据集上进行有监督学习,让模型适应特定任务的需求。微调过程相比于从头训练一个模型要快得多,且需要的数据量也要少得多,这使得作为工程师的我们能够更高效地开发和部署各种NLP解决方案。
图中的“具体任务”,其实也可以更换为“具体领域”。那么总结来说:
- 预训练:在大规模无标注文本数据上进行模型的训练,目标是让模型学习自然语言的基础表达、上下文信息和语义知识,为后续任务提供一个通用的、丰富的语言表示基础。
- 微调:在预训练模型的基础上,可以根据特定的下游任务对模型进行微调。现在你经常会听到各行各业的人说:我们的优势就是领域知识嘛!我们比不过国内外 大模型 ,我们可以拿开源模型做垂直领域嘛!做 垂类 模型! —— 啥叫垂类?指的其实就是根据领域数据微调开源模型这件事儿。
这种预训练+微调的大模型应用模式优势明显。首先,预训练模型能够将大量的通用语言知识迁移到各种下游任务上,作为应用人员,我们不需要自己寻找语料库,从头开始训练大模型,这减少了训练时间和数据需求;其次,微调过程可以快速地根据特定任务进行优化,简化了模型部署的难度;最后,预训练+微调的架构具有很强的可扩展性,可以方便地应用于各种自然语言处理任务,大大提高了NLP技术在实际应用中的可用性和普及程度,给我们带来了巨大的便利。
(三)用 HuggingFace 跑开源模型
- 注册并安装 HuggingFace
第一步,还是要登录 HuggingFace 网站,并拿到专属于你的Token。(如果你做了前面几节课的实战案例,那么你应该已经有这个API Token了)
第二步,用 pip install transformers 安装HuggingFace Library。详见这里。
第三步,在命令行中运行 huggingface-cli login,设置你的API Token。
# 导入HuggingFace API Token
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = '你的HuggingFace API Token'
2. 申请使用 Meta 的 Llama2 模型
在HuggingFace的Model中,找到 meta-llama/Llama-2-7b。注意,各种各样版本的Llama2模型多如牛毛,我们这里用的是最小的7B版。此外,还有13b\70b\chat版以及各种各样的非Meta官方版。选择meta-llama/Llama-2-7b这个模型后,你能够看到这个模型的基本信息。如果你是第一次用Llama,你需要申请Access,从申请到批准,大概是几分钟的事儿。
- 通过 HuggingFace 调用 Llama
# 导入必要的库
from transformers import AutoTokenizer, AutoModelForCausalLM
# 加载预训练模型的分词器
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
# 加载预训练的模型
# 使用 device_map 参数将模型自动加载到可用的硬件设备上,例如GPU
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-chat-hf",
device_map = 'auto')
# 定义一个提示,希望模型基于此提示生成故事
prompt = "请给我讲个玫瑰的爱情故事?"
# 使用分词器将提示转化为模型可以理解的格式,并将其移动到GPU上
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
# 使用模型生成文本,设置最大生成令牌数为2000
outputs = model.generate(inputs["input_ids"], max_new_tokens=2000)
# 将生成的令牌解码成文本,并跳过任何特殊的令牌,例如[CLS], [SEP]等
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 打印生成的响应
print(response)
- 导入AutoTokenizer:这是一个用于自动加载预训练模型的相关分词器的工具。分词器负责将文本转化为模型可以理解的数字格式。
- 导入AutoModelForCausalLM:这是用于加载因果语言模型(用于文本生成)的工具。
- 使用from_pretrained方法来加载预训练的分词器和模型。其中,
device_map = 'auto'是为了自动地将模型加载到可用的设备上,例如GPU。 - 然后,给定一个提示(prompt):
"请给我讲个玫瑰的爱情故事?",并使用分词器将该提示转换为模型可以接受的格式,return_tensors="pt"表示返回PyTorch张量。语句中的.to("cuda")是GPU设备格式转换,因为我在GPU上跑程序,不用这个的话会报错,如果你使用CPU,可以试一下删掉它。 - 最后使用模型的
.generate()方法生成响应。max_new_tokens=2000限制生成的文本的长度。使用分词器的.decode()方法将输出的数字转化回文本,并且跳过任何特殊的标记。
(四)LangChain 和 HuggingFace 的接口
- 通过 HuggingFace Hub
第一种集成方式,是通过HuggingFace Hub。HuggingFace Hub 是一个开源模型中心化存储库,主要用于分享、协作和存储预训练模型、数据集以及相关组件。我们给出一个HuggingFace Hub 和LangChain集成的代码示例。
# 导入HuggingFace API Token
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = '你的HuggingFace API Token'
# 导入必要的库
from langchain import PromptTemplate, HuggingFaceHub, LLMChain
# 初始化HF LLM
llm = HuggingFaceHub(
repo_id="google/flan-t5-small",
#repo_id="meta-llama/Llama-2-7b-chat-hf",
)
# 创建简单的question-answering提示模板
template = """Question: {question}
Answer: """
# 创建Prompt
prompt = PromptTemplate(template=template, input_variables=["question"])
# 调用LLM Chain --- 我们以后会详细讲LLM Chain
llm_chain = LLMChain(
prompt=prompt,
llm=llm
)
# 准备问题
question = "Rose is which type of flower?"
# 调用模型并返回结果
print(llm_chain.run(question))
2. 通过 HuggingFace Pipeline
HuggingFace 的 Pipeline 是一种高级工具,它简化了多种常见自然语言处理(NLP)任务的使用流程,使得用户不需要深入了解模型细节,也能够很容易地利用预训练模型来做任务。
# 指定预训练模型的名称
model = "meta-llama/Llama-2-7b-chat-hf"
# 从预训练模型中加载词汇器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model)
# 创建一个文本生成的管道
import transformers
import torch
pipeline = transformers.pipeline(
"text-generation",
model=model,
torch_dtype=torch.float16,
device_map="auto",
max_length = 1000
)
# 创建HuggingFacePipeline实例
from langchain import HuggingFacePipeline
llm = HuggingFacePipeline(pipeline = pipeline,
model_kwargs = {'temperature':0})
# 定义输入模板,该模板用于生成花束的描述
template = """
为以下的花束生成一个详细且吸引人的描述:
花束的详细信息:
```{flower_details}```
"""
# 使用模板创建提示
from langchain import PromptTemplate, LLMChain
prompt = PromptTemplate(template=template,
input_variables=["flower_details"])
# 创建LLMChain实例
from langchain import PromptTemplate
llm_chain = LLMChain(prompt=prompt, llm=llm)
# 需要生成描述的花束的详细信息
flower_details = "12支红玫瑰,搭配白色满天星和绿叶,包装在浪漫的红色纸中。"
# 打印生成的花束描述
print(llm_chain.run(flower_details))
(五)用 LangChain 调用自定义语言模型
在本机运行模型。此时应该如何利用LangChain的功能?
我们可以创建一个LLM的衍生类,自己定义模型。而LLM这个基类,则位于langchain.llms.base中,通过from langchain.llms.base import LLM语句导入。
这个自定义的LLM类只需要实现一个方法:
- _call方法:用于接收输入字符串并返回响应字符串。
以及一个可选方法:
- _identifying_params方法:用于帮助打印此类的属性。
下面,让我们先从HuggingFace的这里,下载一个llama-2-7b-chat.ggmlv3.q4_K_S.bin模型,并保存在本地。
# 导入需要的库
from llama_cpp import Llama
from typing import Optional, List, Mapping, Any
from langchain.llms.base import LLM
# 模型的名称和路径常量
MODEL_NAME = 'llama-2-7b-chat.ggmlv3.q4_K_S.bin'
MODEL_PATH = '/home/huangj/03_Llama/'
# 自定义的LLM类,继承自基础LLM类
class CustomLLM(LLM):
model_name = MODEL_NAME
# 该方法使用Llama库调用模型生成回复
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
prompt_length = len(prompt) + 5
# 初始化Llama模型,指定模型路径和线程数
llm = Llama(model_path=MODEL_PATH+MODEL_NAME, n_threads=4)
# 使用Llama模型生成回复
response = llm(f"Q: {prompt} A: ", max_tokens=256)
# 从返回的回复中提取文本部分
output = response['choices'][0]['text'].replace('A: ', '').strip()
# 返回生成的回复,同时剔除了问题部分和额外字符
return output[prompt_length:]
# 返回模型的标识参数,这里只是返回模型的名称
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {"name_of_model": self.model_name}
# 返回模型的类型,这里是"custom"
@property
def _llm_type(self) -> str:
return "custom"
# 初始化自定义LLM类
llm = CustomLLM()
# 使用自定义LLM生成一个回复
result = llm("昨天有一个客户抱怨他买了花给女朋友之后,两天花就枯了,你说作为客服我应该怎么解释?")
# 打印生成的回复
print(result)
二、学习心得
(一)引言
本次学习主要聚焦于使用OpenAI API与微调开源模型(如Llama2和ChatGLM)之间的选择与应用。通过深入了解大预言模型的发展史、预训练+微调的模式、HuggingFace开源模型的使用、以及LangChain与HuggingFace的接口,我对自然语言处理(NLP)领域的前沿技术有了更深入的理解。以下是我本次学习的几点心得。
(二)大预言模型与Transformer架构
- Transformer架构的重要性:Google在2018年提出的Transformer架构为当今AI的腾飞奠定了基础。这一架构已成为几乎所有预训练模型的核心,使得模型能够更高效地处理自然语言任务。
- 基础模型的概念:基于Transformer预训练所得的大规模语言模型被称为“基础模型”。这些模型通过在大规模无标注文本数据上的训练,学习到了自然语言的基础表达、上下文信息和语义知识。
(三)预训练+微调的模式
- 预训练的优势:预训练模型能够将大量的通用语言知识迁移到各种下游任务上,大大减少了训练时间和数据需求。这使得应用人员能够更高效地开发和部署各种NLP解决方案。
- 微调的应用:在预训练模型的基础上,根据特定的下游任务对模型进行微调。这种方法使得模型能够快速适应特定任务的需求,提高了模型的实用性和准确性。
- 垂类模型的理解:垂类模型是指根据领域数据微调开源模型所得到的模型。这种模型在特定领域内的表现通常优于通用模型,因为它们能够利用领域内的专业知识进行训练和优化。
(四)HuggingFace开源模型的使用
- HuggingFace平台的重要性:HuggingFace平台是一个开源模型中心化存储库,提供了丰富的预训练模型、数据集以及相关组件。这使得用户能够方便地获取和使用这些资源,加速了NLP技术的发展和应用。
- Llama2模型的使用:通过HuggingFace平台,我学习了如何申请和使用Meta的Llama2模型。通过微调这个模型,我可以将其应用于特定领域,提高模型的实用性和准确性。
- Pipeline工具的使用:HuggingFace的Pipeline工具简化了多种常见NLP任务的使用流程。通过创建文本生成的管道,我能够轻松地利用预训练模型来生成文本,提高了工作效率。
(五)LangChain与HuggingFace的接口
- LangChain平台的功能:LangChain平台提供了与HuggingFace等开源模型的接口,使得用户能够更方便地集成和使用这些模型。通过LangChain,我能够创建复杂的NLP流程,实现自动化和智能化的文本处理。
- 自定义语言模型的使用:除了使用开源模型外,我还学习了如何在本机上运行自定义语言模型,并利用LangChain的功能进行集成和调用。这为我提供了更大的灵活性和自定义能力,使得我能够根据特定需求来优化模型。
(六)总结与展望
通过本次学习,我对自然语言处理领域的前沿技术有了更深入的理解。我掌握了如何使用OpenAI API和微调开源模型来开发NLP解决方案,并了解了HuggingFace和LangChain等平台在NLP技术中的应用。未来,我将继续深入学习这些技术,探索它们在更多领域中的应用和可能性。同时,我也将关注NLP领域的最新进展和趋势,不断提升自己的技能和知识水平。