小白举手03-青训营ai笔记-模型调用篇 | 豆包MarsCode AI 刷题

99 阅读8分钟

一、概念

(一)基础回顾

image.png

(二) 预训练+微调的模式

预训练模型(Pre-trained Model)是深度学习领域的一种重要技术,特别是在自然语言处理(NLP)和计算机视觉等领域。其核心思想是在特定任务之前,先在大规模数据集上训练一个模型,使其能够学习到通用的特征和知识。这一过程通常被称为预训练,而后续在具体任务上的训练则称为微调(fine-tuning)。

(三)一些看不懂的概念梳理

1、接口

接口是一种抽象类型,它定义了一组方法的集合,但不提供具体的实现。在编程中,接口用于规定类必须实现的方法,从而建立不同类之间的一致性和可互操作性。接口通常通过关键字 interface 来声明。

2、pipeline pipeline指的是一系列步骤或阶段,通过这些步骤将一个项目从概念发展到完成。例如,软件开发中的“开发管道”可能包括需求分析、设计、编码、测试和部署等阶段。

3、一些库 transformers库和torch库。transformers库用于处理各种预训练的语言模型,而torch是PyTorch深度学习框架的核心库。

二、代码

(一)通过 HuggingFace 调用 Llama

# 导入HuggingFace API Token,但是有风险
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = '你的HuggingFace API Token'
# 导入必要的库
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调用

1、通过 HuggingFace Hub

第一种集成方式,是通过HuggingFace Hub。HuggingFace Hub 是一个开源模型中心化存储库,主要用于分享、协作和存储预训练模型、数据集以及相关组件。

我们给出一个HuggingFace Hub 和LangChain集成的代码示例。

集成代码的含义:

定义与目的

  • 集成代码:是指在软件开发中,将不同功能模块、服务或系统整合到一起的代码。它负责管理模块间的交互,确保数据流和控制流的正确性。
  • 目的:通过集成代码,开发团队可以实现不同组件之间的协作,从而构建出一个完整、功能丰富的软件系统。

类型:

  • API集成:通过应用程序接口(API)连接不同的软件系统,使它们能够相互通信。例如,使用RESTful API或GraphQL API来获取数据。
  • 中间件集成:使用中间件技术(如消息队列、企业服务总线等)来处理不同系统之间的数据传输和功能调用。
  • 库和框架集成:利用现有的库或框架来简化集成过程,例如使用Spring框架进行Java应用的集成。
# 导入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))

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

初始化LLM,创建提示模板,生成提示的过程,你已经很熟悉了。这段代码中有一个新内容是我通过llm_chain来调用了LLM。这段代码也不难理解,有关Chain的概念我们以后还会详述。

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))

一些参数注释:

image.png

3、用 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模型,并保存在本地。

这个方法优点:

  1. 这可是开源模型,而且是允许商业的免费模型。
  2. 这是在本机 CPU 的环境下运行的,模型的推理速度还是可以接受的。
  3. 这仅仅是Llama的最小版本,也就是7B的量化版,就达到了这么好的效果
# 导入需要的库
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)

一些注释:

  • def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str: :定义一个私有方法_call,用于生成回复。该方法接受一个字符串参数prompt(用户输入)和一个可选的停止符列表。
  • prompt_length = len(prompt) + 5:计算输入提示的长度,并加上5,以便后续处理。
  • llm = Llama(model_path=MODEL_PATH + MODEL_NAME, n_threads=4) :初始化Llama模型,指定模型路径和使用4个线程进行计算。
  • response = llm(f"Q: {prompt} A: ", max_tokens=256) :调用Llama模型生成回复,输入格式为“Q: 用户输入 A:”,并限制生成的最大标记数为256