一起学大模型 - 动手写一写langchain调用本地大模型(1)


前言

langchain的手册里只有使用在线openai接口这一个例子,实际运用中我们大部分还是要用本地的大模型的。所以我们一起尝试写一写,练一练


一、如何替代掉openai呢

替掉openai的关键是根据我们所使用的模型的具体调用方式来实现 generate 方法。LangChain 框架为我们提供了一个通用接口,我们需要根据不同模型的特点和 API 来重写这个接口中的方法,以便能够正确调用本地模型并生成所需的输出。

先看具体步骤

  1. 定义模型类:创建一个继承自 LangChainBaseLLM 类,并根据所使用的本地模型重写 generate 方法。
  2. 加载模型和分词器:在模型类的初始化方法中加载你想要使用的本地模型和分词器。
  3. 实现生成方法:在 generate 方法中,处理输入文本并调用模型的生成函数,返回生成的文本。
  4. 构建管道:使用定义好的模型类和生成方法,构建从用户输入到输出的处理管道。

1. 定义模型类

我们以 GPT-2 为例,定义一个调用本地 GPT-2 模型的 LocalGPT2LLM 类:

import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
from langchain.llms import BaseLLM

class LocalGPT2LLM(BaseLLM):
    def __init__(self, model_name='gpt2', device='cpu'):
        self.tokenizer = GPT2Tokenizer.from_pretrained(model_name)
        self.model = GPT2LMHeadModel.from_pretrained(model_name).to(device)
        self.device = device

    def generate(self, prompt, max_length=50, temperature=0.7):
        inputs = self.tokenizer(prompt, return_tensors='pt').to(self.device)
        with torch.no_grad():
            outputs = self.model.generate(
                inputs.input_ids,
                max_length=max_length,
                temperature=temperature,
                pad_token_id=self.tokenizer.eos_token_id
            )
        return self.tokenizer.decode(outputs[0], skip_special_tokens=True)

2. 构建处理管道

创建一个简单的管道类,整合模型的调用过程:

class NLPipeline:
    def __init__(self, llm):
        self.llm = llm

    def process(self, user_input):
        response = self.llm.generate(user_input)
        return response

3. 测试与应用

初始化模型和管道,并进行测试:

# 初始化本地模型
local_gpt2_llm = LocalGPT2LLM(device='cuda' if torch.cuda.is_available() else 'cpu')

# 创建 NLP 管道
pipeline = NLPipeline(local_gpt2_llm)

# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."

# 处理用户输入并生成输出
output = pipeline.process(user_input)
print(f"Output: {output}")

4. 扩展支持其他模型

为了支持其他模型(例如 BERT 进行嵌入和 GPT-3 进行生成),可以类似地定义模型类并重写 generate 方法。这里我们以 BERT 嵌入和 GPT-3 生成的组合为例:

from transformers import BertModel, BertTokenizer
import openai

class BERTEmbedder:
    def __init__(self, model_name='bert-base-uncased'):
        self.tokenizer = BertTokenizer.from_pretrained(model_name)
        self.model = BertModel.from_pretrained(model_name)

    def embed(self, text):
        inputs = self.tokenizer(text, return_tensors='pt')
        with torch.no_grad():
            outputs = self.model(**inputs)
        return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()

class GPT3LLM(BaseLLM):
    def __init__(self, temperature=0.7, max_tokens=150):
        self.temperature = temperature
        self.max_tokens = max_tokens

    def generate(self, prompt):
        response = openai.Completion.create(
            engine="text-davinci-003",
            prompt=prompt,
            temperature=self.temperature,
            max_tokens=self.max_tokens
        )
        return response.choices[0].text.strip()

# 创建和组合模型
bert_embedder = BERTEmbedder()
gpt3_llm = GPT3LLM()

# 定义组合的管道
class CombinedNLPipeline:
    def __init__(self, embedder, llm):
        self.embedder = embedder
        self.llm = llm

    def process(self, user_input):
        # 生成嵌入向量
        embedding = self.embedder.embed(user_input)
        prompt = f"User input embedding: {embedding}\nGenerate response:"
        # 使用 GPT-3 生成输出
        response = self.llm.generate(prompt)
        return response

# 创建组合管道
combined_pipeline = CombinedNLPipeline(bert_embedder, gpt3_llm)

# 测试输入
user_input = "The quick brown fox jumps over the lazy dog."
output = combined_pipeline.process(user_input)
print(f"Output: {output}")

5. 小结

通过这种方法,可以灵活地集成各种本地模型,并将其与 LangChain 框架结合,构建复杂的自然语言处理管道。根据不同的模型和需求,重写 generate 方法,实现多样化的处理和生成任务。

二、怎么用langchain自带的管道符

LangChain 提供了 LLMChain 类,可以更方便地将不同的模型和步骤组合在一起。下面是如何使用 LLMChain 来替代 CombinedNLPipeline,将 BERT 用于嵌入,GPT-3 用于生成的示例。

1. 安装必要的库

确保你已经安装了所需的库:

pip install transformers openai langchain

2. 定义 BERT 嵌入和 GPT-3 生成模型类

首先,定义用于生成嵌入的 BERT 模型类和用于生成文本的 GPT-3 模型类:

from transformers import BertModel, BertTokenizer
import openai
import torch
from langchain.llms import BaseLLM

# 定义 BERT 嵌入模型类
class BERTEmbedder:
    def __init__(self, model_name='bert-base-uncased'):
        self.tokenizer = BertTokenizer.from_pretrained(model_name)
        self.model = BertModel.from_pretrained(model_name)

    def embed(self, text):
        inputs = self.tokenizer(text, return_tensors='pt')
        with torch.no_grad():
            outputs = self.model(**inputs)
        return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()

# 定义 GPT-3 生成模型类
class GPT3LLM(BaseLLM):
    def __init__(self, temperature=0.7, max_tokens=150):
        self.temperature = temperature
        self.max_tokens = max_tokens

    def generate(self, prompt):
        response = openai.Completion.create(
            engine="text-davinci-003",
            prompt=prompt,
            temperature=self.temperature,
            max_tokens=self.max_tokens
        )
        return response.choices[0].text.strip()

3. 使用 LangChain 的 LLMChain

接下来,使用 LangChain 的 LLMChain 类来替代手动定义的管道类。

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.embeddings import Embeddings

# 定义一个模板,将 BERT 的嵌入作为 GPT-3 的输入
prompt_template = PromptTemplate(
    template="User input embedding: {embedding}\nGenerate response:",
    input_variables=["embedding"]
)

# 实现一个嵌入模型类,用于在 LLMChain 中使用
class EmbeddingsWrapper(Embeddings):
    def __init__(self, embedder):
        self.embedder = embedder

    def embed(self, text):
        return self.embedder.embed(text)

# 初始化 BERT 嵌入模型和 GPT-3 生成模型
bert_embedder = BERTEmbedder()
gpt3_llm = GPT3LLM()

# 包装 BERT 嵌入模型
embedding_wrapper = EmbeddingsWrapper(bert_embedder)

# 创建 LLMChain
llm_chain = LLMChain(
    prompt_template=prompt_template,
    llm=gpt3_llm,
    embeddings=embedding_wrapper
)

# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."

# 处理用户输入并生成输出
embedding = bert_embedder.embed(user_input)
output = llm_chain.run({"embedding": embedding})
print(f"Output: {output}")

4. 解释

  • BERTEmbedder 类:用于生成 BERT 嵌入。
  • GPT3LLM 类:用于调用 GPT-3 生成文本。
  • PromptTemplate:定义了 GPT-3 的提示模板,包含 BERT 生成的嵌入。
  • EmbeddingsWrapper 类:用于将 BERT 嵌入模型包装为 LangChain 的嵌入接口。
  • LLMChain:将 BERT 嵌入模型和 GPT-3 生成模型组合在一起,形成一个完整的处理管道。

5. 使用注意事项

  • 输入变量:确保 PromptTemplate 中的 input_variables 与实际输入变量匹配。
  • 模型配置:根据需要调整 GPT-3 和 BERT 模型的配置,如 temperaturemax_tokens

通过这种方式,使用 LangChainLLMChain 类,可以更简洁地实现复杂的模型组合,简化代码结构,并提高可读性和维护性。


三、怎么才能用绝对地址引入本地模型呢

transformers 库支持从本地路径加载模型和分词器。只需要将 model_name 替换为模型和分词器所在的本地目录的绝对路径即可。

1. 使用本地模型路径的示例

假设你已经将 BERT 模型和分词器下载到本地目录 /path/to/local/bert-model,你可以这样进行修改:

from transformers import BertModel, BertTokenizer
import openai
import torch
from langchain.llms import BaseLLM

# 定义 BERT 嵌入模型类
class BERTEmbedder:
    def __init__(self, model_path='/path/to/local/bert-model'):
        self.tokenizer = BertTokenizer.from_pretrained(model_path)
        self.model = BertModel.from_pretrained(model_path)

    def embed(self, text):
        inputs = self.tokenizer(text, return_tensors='pt')
        with torch.no_grad():
            outputs = self.model(**inputs)
        return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()

# 定义 GPT-3 生成模型类
class GPT3LLM(BaseLLM):
    def __init__(self, temperature=0.7, max_tokens=150):
        self.temperature = temperature
        self.max_tokens = max_tokens

    def generate(self, prompt):
        response = openai.Completion.create(
            engine="text-davinci-003",
            prompt=prompt,
            temperature=self.temperature,
            max_tokens=self.max_tokens
        )
        return response.choices[0].text.strip()

2. 组合使用 LangChain 的 LLMChain

下面是如何使用 LangChain 的 LLMChain 类,结合本地的 BERT 模型和 GPT-3:

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.embeddings import Embeddings

# 定义一个模板,将 BERT 的嵌入作为 GPT-3 的输入
prompt_template = PromptTemplate(
    template="User input embedding: {embedding}\nGenerate response:",
    input_variables=["embedding"]
)

# 实现一个嵌入模型类,用于在 LLMChain 中使用
class EmbeddingsWrapper(Embeddings):
    def __init__(self, embedder):
        self.embedder = embedder

    def embed(self, text):
        return self.embedder.embed(text)

# 初始化本地 BERT 嵌入模型和 GPT-3 生成模型
bert_embedder = BERTEmbedder(model_path='/path/to/local/bert-model')
gpt3_llm = GPT3LLM()

# 包装 BERT 嵌入模型
embedding_wrapper = EmbeddingsWrapper(bert_embedder)

# 创建 LLMChain
llm_chain = LLMChain(
    prompt_template=prompt_template,
    llm=gpt3_llm,
    embeddings=embedding_wrapper
)

# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."

# 处理用户输入并生成输出
embedding = bert_embedder.embed(user_input)
output = llm_chain.run({"embedding": embedding})
print(f"Output: {output}")

3. 解释

  • model_path:将模型路径从预训练模型名称替换为本地目录的绝对路径。
  • BERTEmbedder 类:加载本地路径中的 BERT 模型和分词器。
  • LLMChain:与之前相同,定义一个 LangChain 的 LLMChain,用于将 BERT 嵌入和 GPT-3 生成结合起来。

通过这种方式,你可以方便地使用本地存储的模型文件,避免了每次使用时都需要从互联网下载模型文件。这样不仅可以节省时间,还可以在没有互联网连接的环境中使用模型。

总结

以上我们用三个章节介绍了如何调用本地模型,如何使用langchain自带的管道方法,以及如何从绝对地址来调用模型。 大家可以清晰的在各段代码里看到改变,可以尝试自己使用自己的方法。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值