(一)手把手地教, 带你一步步学会使用 LLM 搭建自己的小机器人

【本文正在参加金石计划附加挑战赛------第一期命题】

python 零基础, 可以学吗?

当然可以, 只要你有其他编程语言经验, 上手python绝非难事.

以下介绍在vscode中, 如何编码python, 以及运行.py文件

环境准备

mac电脑使用Homebrew安装python

bash 复制代码
brew install python

安装好了之后, 在命令行执行which pip, 却没有返回任何路径. 经检查, 是因为我的系统中存在多个python版本, 这种情况下, 需使用如下命令安装其他语言包

bash 复制代码
python3 -m pip install <package_name>

mac 电脑上, vscode 如何运行.py 文件

Command (⌘) + Shift(向上箭头, fn 上方的按键) + P

在命令面板中输入 Python: Select Interpreter,并选择相应的 Python 解释器

OpenAI

  • 若你已经拥有openai_api_key, 且该key有使用额度, 那你可以用LangChain搭建属于自己的小机器人.

若有感兴趣的小伙伴, 欢迎在评论下方留言, 下一期我将会提供基于LangChain的小机器人代码.

  • 若你还没有openai_api_key, 或该key没有使用额度, 那很抱歉, 你无法在中国使用LangChain, 因为当你运行下面代码时, 会抛出You exceeded your current quota, please check your plan and billing details

基于LangChain的部分代码如下所示

python 复制代码
import os

# 设置环境变量
os.environ['OPENAI_API_KEY'] = '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'

# 获取环境变量
api_key = os.getenv('OPENAI_API_KEY')

from langchain.chat_models import ChatOpenAI

# 示例:创建一个 ChatOpenAI 实例
chat_model = ChatOpenAI()

微软的 DialoGPT 模型

在本文中, 我们将使用microsoft/DialoGPT-medium模型, 因为OpenAI目前在中国无法访问, 即使你翻墙准备在其官网充值, 但是人家不接受中国境内的银行卡, 555~~

你可以想其他办法解决该问题, 比如办理国外网上虚拟银行卡, 但我觉得没有这个必要, 主要原因当然是因为我很穷啦, 所以我选择其他开源模型, 比如适合机器人对话的microsoft/DialoGPT-medium模型

模型背景:DialoGPT

DialoGPT 是由微软在 GPT-2 基础上微调出来的模型,专门用于对话生成。它是从大规模对话数据中进行训练的,因此比标准的 GPT-2 更擅长生成具有上下文关联的多轮对话。

  • DialoGPT 分为不同的版本(如 small, medium, large),分别有不同的模型规模(模型参数量)。medium 是其中一个中等规模的版本,适用于大部分任务。

    • small:模型较小,速度较快,但生成的内容可能不如大型模型自然。
    • medium:中等规模的模型,速度和生成质量之间有较好的平衡。
    • large:模型较大,生成效果最好,但需要更多的计算资源

更多开源模型, 可以访问 Hugging Face (需要翻墙, 才能访问哦~)

开始编程啦~

Hugging Face网址中, 该模型有如下的官方代码示例

python 复制代码
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# 加载分词器,设置 padding_side='left' 和 pad_token_id
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium", padding_side='left')
tokenizer.pad_token = tokenizer.eos_token  # 设置 pad_token 为 eos_token

# 加载模型
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")

# 用于生成对话
chat_history_ids = None
while True:
    user_input = input("用户: ")  # 输入用户的消息
    if user_input.lower() == 'exit':  # 如果用户输入 'exit',则退出
        break

    # 编码用户输入,加上结束符
    new_user_input_ids = tokenizer.encode(user_input + tokenizer.eos_token, return_tensors='pt')

    # 将用户输入和之前的对话历史连接起来
    bot_input_ids = new_user_input_ids if chat_history_ids is None else torch.cat([chat_history_ids, new_user_input_ids], dim=-1)

    # 生成响应,确保使用正确的 pad_token_id
    chat_history_ids = model.generate(bot_input_ids, max_length=1000, pad_token_id=tokenizer.pad_token_id)

    # 解码生成的响应并输出
    bot_output = tokenizer.decode(chat_history_ids[:, bot_input_ids.shape[-1]:][0], skip_special_tokens=True)
    print(f"Bot: {bot_output}")

第一个错误:set padding_side='left'

但当它运行时, 一直报错A decoder-only architecture is being used, but right-padding was detected! For correct generation results, please set padding_side='left' when initializing the tokenizer.

经排查, 发现这个错误的意思是,使用的是一个解码器-只架构 (比如 GPT 类的模型),但发现输入的序列使用了右侧填充 (right-padding),而这个架构要求使用左侧填充 (left-padding)。为了确保生成效果正确,需要在初始化 tokenizer 时,设置 padding_side='left'

为了解决该问题, 对上面代码进行修改处理

python 复制代码
from transformers import AutoTokenizer, AutoModelForCausalLM

# 加载预训练模型和分词器
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")

# 初始化对话历史记录
history = []

def chat_with_dialoGPT(user_input):
    # 拼接用户输入和历史对话,作为模型的输入
    new_user_input_ids = tokenizer.encode(user_input + tokenizer.eos_token, return_tensors='pt')
    bot_input_ids = new_user_input_ids

    # 如果有历史对话,将其加入模型的输入
    if history:
        bot_input_ids = torch.cat([history, new_user_input_ids], dim=-1)

    # 生成响应
    bot_output = model.generate(bot_input_ids, max_length=1000, pad_token_id=tokenizer.eos_token_id, do_sample=True, top_k=50)

    # 解码模型生成的响应
    bot_response = tokenizer.decode(bot_output[:, bot_input_ids.shape[-1]:][0], skip_special_tokens=True)
    
    # 更新历史记录
    history.append(new_user_input_ids)
    
    return bot_response

if __name__ == "__main__":
    print("Chatbot: 你好!有什么问题我可以帮你解答吗?")
    while True:
        # 获取用户输入
        user_input = input("你: ")
        if user_input.lower() == "exit":
            print("Chatbot: 再见!期待下次和你聊天!")
            break

        # 获取机器人的回答
        response = chat_with_dialoGPT(user_input)
        print(f"Chatbot: {response}")

再次运行时, 却又抛出第二个错误The attention mask is not set and cannot be inferred from input because pad token is same as eos token. As a consequence, you may observe unexpected behavior. Please pass your input's attention_mask to obtain reliable results.

The attention mask is not set

这个警告提示是由于 pad_tokeneos_token(结束标记)相同,而没有明确设置 attention_mask,导致模型在生成时无法正确区分填充标记和实际输入标记。这可能会影响生成结果,特别是当输入较长时,填充标记可能被误解为有效标记。

为了解决这个问题,你需要明确指定 attention_mask

下面是修改后的代码示例,添加了 attention_mask 来解决这个警告

python 复制代码
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")

# 初始化对话历史记录
history = []

def chat_with_dialoGPT(user_input):
    # 拼接用户输入和历史对话,作为模型的输入
    new_user_input_ids = tokenizer.encode(user_input + tokenizer.eos_token, return_tensors='pt')
    bot_input_ids = new_user_input_ids

    # 如果有历史对话,将其加入模型的输入
    if history:
        bot_input_ids = torch.cat([history, new_user_input_ids], dim=-1)

    # 创建 attention_mask(1表示有效标记,0表示填充标记)
    attention_mask = torch.ones(bot_input_ids.shape, dtype=torch.long)

    # 生成响应
    bot_output = model.generate(
        bot_input_ids,
        attention_mask=attention_mask,  # 明确设置 attention_mask
        max_length=1000,
        pad_token_id=tokenizer.eos_token_id,
        do_sample=True,
        top_k=50
    )

    # 解码模型生成的响应
    bot_response = tokenizer.decode(bot_output[:, bot_input_ids.shape[-1]:][0], skip_special_tokens=True)
    
    # 更新历史记录
    history.append(new_user_input_ids)
    
    return bot_response

if __name__ == "__main__":
    print("Chatbot: 你好!有什么问题我可以帮你解答吗?")
    while True:
        # 获取用户输入
        user_input = input("你: ")
        if user_input.lower() == "exit":
            print("Chatbot: 再见!期待下次和你聊天!")
            break

        # 获取机器人的回答
        response = chat_with_dialoGPT(user_input)
        print(f"Chatbot: {response}")

关键更改:

  1. 设置 attention_mask

    通过以下代码明确设置 attention_mask,告诉模型哪些标记是有效的(值为 1):

    python 复制代码
    attention_mask = torch.ones(bot_input_ids.shape, dtype=torch.long)

    这确保模型知道哪些位置是有效输入,哪些是填充。

  2. attention_mask 传递给 model.generate()

    在生成时将 attention_mask 作为参数传递给 model.generate(),以确保正确地处理填充标记。

运行代码

点击代码右上方的运行按钮, 执行上述代码, 效果如下图所示

你:是我输入的问题

Chatbot:是机器人的回复

小机器人已经能回答出我提的问题, 并带着一丢丢小幽默~

小伙伴们若能成功运行到这步, 会发现上面代码有不足之处, 即无法连续多次提问, 如何解决该问题呢? 我将在下一期继续为大家讲述, 感兴趣的小伙伴们欢迎在评论下方留言、点赞或关注哦~

相关推荐
郭庆汝4 小时前
pytorch、torchvision与python版本对应关系
人工智能·pytorch·python
思则变7 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
漫谈网络8 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find9 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
博观而约取10 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
CoderLiu11 小时前
用这个MCP,只给大模型一个figma链接就能直接导出图片,还能自动压缩上传?
前端·llm·mcp
精灵vector12 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习12 小时前
Python入门Day2
开发语言·python
Vertira12 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉12 小时前
Python之 sorted() 函数的基本语法
python