【本文正在参加金石计划附加挑战赛------第一期命题】
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_token 和 eos_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}")关键更改:
- 
设置 attention_mask:通过以下代码明确设置 attention_mask,告诉模型哪些标记是有效的(值为 1):pythonattention_mask = torch.ones(bot_input_ids.shape, dtype=torch.long)这确保模型知道哪些位置是有效输入,哪些是填充。 
- 
将 attention_mask传递给model.generate():在生成时将 attention_mask作为参数传递给model.generate(),以确保正确地处理填充标记。
运行代码
点击代码右上方的运行按钮, 执行上述代码, 效果如下图所示
你:是我输入的问题
Chatbot:是机器人的回复
小机器人已经能回答出我提的问题, 并带着一丢丢小幽默~
小伙伴们若能成功运行到这步, 会发现上面代码有不足之处, 即无法连续多次提问, 如何解决该问题呢? 我将在下一期继续为大家讲述, 感兴趣的小伙伴们欢迎在评论下方留言、点赞或关注哦~