(一)手把手地教, 带你一步步学会使用 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:是机器人的回复

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

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

相关推荐
B站计算机毕业设计超人18 分钟前
计算机毕业设计Python美食推荐系统 美团爬虫 美食可视化 机器学习 深度学习 混合神经网络推荐算法 Hadoop Spark 人工智能 大数据毕业设计
大数据·人工智能·爬虫·python·深度学习·机器学习·课程设计
刀鋒偏冷21 分钟前
python核心语法(二)
python
hummhumm34 分钟前
第 17 章 - Go语言 上下文( Context )
java·服务器·网络·后端·python·sql·golang
不如语冰1 小时前
跟着问题学2——传统神经网络-多层感知机详解
人工智能·python·深度学习·神经网络·机器学习·ai·语言模型
Mopes__1 小时前
Python | Leetcode Python题解之第564题寻找最近的回文数
python·leetcode·题解
Mopes__1 小时前
Python | Leetcode Python题解之第564题数组嵌套
python·leetcode·题解
叫我:松哥1 小时前
基于python Django的boss直聘数据采集与分析预测系统,爬虫可以在线采集,实时动态显示爬取数据,预测基于技能匹配的预测模型
后端·爬虫·python·数据分析·django·bootstrap·薪资预测
H_kiwi2 小时前
APT 参与者将恶意软件嵌入 macOS Flutter 应用程序中
java·python·安全·flutter·macos·安全威胁分析·安全性测试
YiSLWLL2 小时前
在Django中安装、配置、使用CKEditor5,并将CKEditor5录入的文章展现出来,实现一个简单博客网站的功能
服务器·后端·python·django