从零开始学 LangChain(7) | 豆包MarsCode AI刷题

67 阅读7分钟

调用模型

预训练模型的微调(Fine-tuning):经过预训练的大模型中所习得的语义信息和所蕴含的语言知识,能够非常容易地向下游任务迁移。NLP应用人员可以对模型的头部或者部分参数根据自己的需要进行适应性的调整,这通常涉及在相对较小的有标注数据集上进行有监督学习,让模型适应特定任务的需求。

  • 预训练:在大规模无标注文本数据上进行模型的训练,目标是让模型学习自然语言的基础表达、上下文信息和语义知识,为后续任务提供一个通用的、丰富的语言表示基础。
  • 微调:在预训练模型的基础上,可以根据特定的下游任务对模型进行微调。现在你经常会听到各行各业的人说:我们的优势就是领域知识嘛!我们比不过国内外大模型,我们可以拿开源模型做垂直领域嘛!做垂类模型! —— 啥叫垂类?指的其实就是根据领域数据微调开源模型这件事儿。

这种预训练+微调的大模型应用模式优势明显。首先,预训练模型能够将大量的通用语言知识迁移到各种下游任务上,作为应用人员,我们不需要自己寻找语料库,从头开始训练大模型,这减少了训练时间和数据需求;其次,微调过程可以快速地根据特定任务进行优化,简化了模型部署的难度;最后,预训练+微调的架构具有很强的可扩展性,可以方便地应用于各种自然语言处理任务,大大提高了NLP技术在实际应用中的可用性和普及程度,给我们带来了巨大的便利。

使用HuggingFace的Transformers库来调用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() 方法将输出的数字转化回文本,并且跳过任何特殊的标记。

如何把HuggingFace里面的模型接入LangChain

1.通过 HuggingFace Hub:只需要在HuggingFaceHub类的repo_id中指定模型名称,就可以直接下载并使用模型,模型会自动下载到HuggingFace的Cache目录,并不需要手工下载。

2.通过 HuggingFace Pipeline

# 指定预训练模型的名称
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))

代码中使用到的transformers pipeline的配置参数。

https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/a6adfe568ef5497e898513af001a2691~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCP5p2o5ZCM5a2mNzY2:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjEzNzU0MDc2NzM4MDMwIn0%3D&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1731551778&x-orig-sign=aPdyOHCb56DoLS%2F%2BPI8G%2B3L78Hs%3D

用 LangChain 调用自定义语言模型

创建一个LLM的衍生类,自己定义模型。而LLM这个基类,则位于langchain.llms.base中,通过from langchain.llms.base import LLM语句导入。

这个自定义的LLM类只需要实现一个方法:

  • _call方法:用于接收输入字符串并返回响应字符串。

    以及一个可选方法:

  • _identifying*params方法:用于帮助打印此类的属性。

注意:量化是AI模型大小和性能优化的常用技术,它将模型的权重简化到较少的位数,以减少模型的大小和计算需求,让大模型甚至能够在CPU上面运行。当你看到模型的后缀有GGML或者GPTQ,就说明模型已经被量化过,其中GPTQ 是一种仅适用于 GPU 的特定格式。GGML 专为 CPU 和 Apple M 系列设计,但也可以加速 GPU 上的某些层。llama-cpp-python这个包就是为了实现GGML而制作的。

# 导入需要的库
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)