【本文正在参加金石计划附加挑战赛------第一期命题】
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:
是机器人的回复
小机器人已经能回答出我提的问题, 并带着一丢丢小幽默~
小伙伴们若能成功运行到这步, 会发现上面代码有不足之处, 即无法连续多次提问, 如何解决该问题呢? 我将在下一期继续为大家讲述, 感兴趣的小伙伴们欢迎在评论下方留言、点赞或关注哦~