当前位置: 首页 > news >正文

【第二十周】自然语言处理的学习笔记05

文章目录

  • 摘要
  • Abstract
  • 一、OpenPrompt Demo解读
    • 1. 准备:下载一些基础包
    • 2. 定义一个提示词模板template
    • 3. 对已包裹(wrapped)的样本进行分词处理
    • 4. 对所有数据进行输入处理
    • 5. 构造数据加载器
    • 6. 创建verbalizer表述器
    • 7. 创建分类任务的prompt learning模型
    • 8. 训练模型
      • 8.1 核心组件
      • 8.2 参数更新流程
    • 9. 评估模型
  • 总结


摘要

本周主要完成对OpenPrompt工具包的使用展开,整个流程为基础准备;定义提示词模板并包裹样本;对包裹样本分词;处理所有数据;构造数据加载器;创建表述器与分类任务的 prompt learning 模型,还说明模型训练的损失函数、优化器等,以及模型评估流程。并对代码参数进行说明及常见疑问解答以辅助理解工具包使用。


Abstract

This week I mainly focused on using the OpenPrompt toolkit. The entire process includes: basic preparation; defining the prompt template and wrapping samples; tokenizing the wrapped samples; processing all data; constructing a data loader; creating a verbalizer and a prompt learning model for classification tasks. Additionally, it also illustrates the loss function, optimizer, etc., in model training, as well as the model evaluation process. Furthermore, I explained the code parameters and answered common questions to assist in understanding the usage of the toolkit.


一、OpenPrompt Demo解读

1. 准备:下载一些基础包

!pip install transformers --quiet
!pip install datasets==2.0 --quiet
!pip install openprompt --quiet
!pip install torch --quiet

(1)加载huggingface中的数据
数据格式为:
在这里插入图片描述
(2)加载模型和分词器
(3)搭建和输入
转换输入格式,并且按照训练集、验证集和测试集拆分存储,方便后面使用。
查看转换后的第一条训练集样本,输出的格式如下:
在这里插入图片描述
注:输入数据没有的内容填充null或者直接为空集。

2. 定义一个提示词模板template

将之前转换的 InputExample 样本按照模板格式进行包裹(wrap),生成可供模型输入的提示词结构。
案例使用template:基于文本令牌初始化的软提示
①模板的逻辑:将前提和假设拼接成一个完整的问题(如 “[前提] Deduction: [假设]. Is it correct? [答案]”),引导模型判断假设是否能从前提中推出。
②wrap_one_example()将 dataset[‘train’][0] 这个InputExample 样本按照 template_text 进行填充,生成包含模板 + 数据的结构化对象。
③输出 wrapped_example 可直观查看模板如何与具体数据结合,便于调试模板是否符合预期。
最后输出结果如下:
在这里插入图片描述
对输出结果说明:
(1)文本片段列表
loss_ids 字段:标记该文本片段是否参与损失计算(即是否是模型需要预测的部分):
loss_ids=0:表示该片段是 “输入”,不参与损失计算。
loss_ids=1:表示该片段是 “预测目标”(即位置),参与损失计算。

shortenable_ids 字段:标记该文本片段是否可被截断(用于控制输入长度,避免超出模型上下文窗口):
shortenable_ids=1:表示该片段(如text_a、text_b的长文本)可被截断。
shortenable_ids=0:表示该片段(如固定模板文本、)不可被截断,必须保留。

text 字段:拼接后的完整输入文本,对应模板的每个部分:
第一段 text 是 text_a 字段的内容(原始文本)。
第二段 text 是模板中的固定文本 “Deduction:”。
第三段 text 是 text_b 字段的内容(推导结论)。
第四段 text 是模板中的固定文本 “. Is it correct?”。
第五段 text 是 (模型需要预测的位置)。
第六段 text 是模板中的固定文本 “.”。

(2) 元信息(任务与标签)
{‘guid’: 0, ‘label’: 0}
guid:数据的唯一标识(这里是第 0 条训练数据)。
label:该数据的真实标签(0 表示 “推导不正确”,具体含义需结合任务定义,如0对应 “否”,1对应 “是”)。

3. 对已包裹(wrapped)的样本进行分词处理

将自然语言提示词转换为模型可识别的 token ID格式,同时适配 T5 等编码器 - 解码器模型的输入要求。
初始化分词器包装器(WrapperClass / T5TokenizerWrapper)
参数说明:
max_seq_length:限制编码器输入的长度(避免模型输入过长)。
decoder_max_length:限制解码器输入的长度(T5 生成任务中,解码器输入通常是标签的 token ID)。
truncate_method=“head”:当文本超长时,从开头(头部)截断(其他方式如 tail 从尾部截断)。
注:
在 Prompt Learning 中,预训练模型的原生分词器(Tokenizer)难以直接适配复杂提示结构,因此需要专门的编码机制(如 OpenPrompt 中的PromptTokenizer)来处理,而编码器的选择需与基础预训练模型(如 BERT、GPT 等)对齐。
疑问:
问题1:代码中哪里使用了预训练tokenizer?
使用了预训练 Tokenizer,并非直接单独使用,而是而是将其作为底层依赖,通过PromptTokenizer对其进行了封装和扩展。
PromptTokenizer(提示分词器)的核心功能依赖预训练模型的原生 Tokenizer(如 BERT 的BertTokenizer、GPT 的GPT2Tokenizer)。
问题2:本段代码中是使用的哪种tokenizer?
T5TokenizerWrapper 是 OpenPrompt 框架提供的封装类,它并非直接使用 OpenPrompt 自研的 Tokenizer,而是对 预训练的tokenizer( T5的原生 Tokenizer)进行了功能扩展

对单个样本进行分词并查看结果
先对wrapped_example进行分词,接着将input_ids、decoder_input_ids转换为对应的token
input_ids、decoder_input_ids的说明:
input_ids 和 decoder_input_ids 是适配 T5 模型 “编码器 - 解码器(Encoder-Decoder)” 结构的关键输入,分别对应模型的编码器输入和解码器输入。
input_ids:包含经过 Prompt 模板处理后的完整文本序列(如任务指令、输入数据、提示词等),用于让编码器理解 “任务目标” 和 “输入信息”。
decoder_input_ids:用于引导解码器生成目标输出(如分类标签、推理结果等)。

teacher_forcing 属性说明:
teacher_forcing=True(训练阶段):在训练阶段强制模型使用 “真实标签(Ground Truth)” 作为下一时间步的输入,而非模型自身生成的预测值。
补充说明:
具体举例说明:训练 “生成句子‘我喜欢机器学习’” 时:
Step 1 输入:< START >,模型预测 “我”;
Step 2 输入:真实标签 “我”(而非模型预测的 “我”),模型预测 “喜欢”;
Step 3 输入:真实标签 “喜欢”,模型预测 “机器”;以此类推
teacher_forcing=False(推理阶段):解码器输入可能是默认的起始符(如< pad > 或 < s >,用于推理时让模型自主生成)。

综合说明:
(1)训练阶段
若 teacher_forcing=True,decoder_input_ids 由 任务的真实标签经过分词得到,在 “自然语言推理” 任务中,若真实标签是 “是”(表示推导正确),则 decoder_input_ids 是 “是” 对应的 Token ID(可能还包含起始 Token < s >)。
在这里插入图片描述
(2)推理阶段
若 teacher_forcing=False,decoder_input_ids来自 “模型自身生成”,仅包含起始 Token,解码器完全依赖自身生成后续内容,模拟真实推理场景。
在这里插入图片描述
最后整段代码输出结果:
在这里插入图片描述
对于decoder_input_ids输出结果的解读:
[< pad >, <extra_id_0>, ]
其中 <extra_id_0> 是模型需要生成的核心标签(如 “是” 或 “否”),前后的< pad > 是为了满足 decoder_max_length=3 的长度要求(代码中设置了 decoder_max_length=3)。
补充:
< pad >:填充 Token,用于补齐序列长度(当实际序列短于 decoder_max_length 时),不携带语义信息。

4. 对所有数据进行输入处理

5. 构造数据加载器

PromptDataLoader 是为Prompt Learning设计的训练数据加载器,它在传统 PyTorch DataLoader 的基础上,增加了对 Prompt 模板处理、分词适配、特殊格式转换 的支持,最终输出模型可直接训练的批量数据(包含 input_ids、attention_mask、decoder_input_ids 等关键字段)。
Demo中的核心作用是将原始训练数据集(dataset[“train”])按照 Prompt 模板进行格式化处理,转化为可直接输入预训练模型(如 T5)的批量数据,为后续模型训练做准备

训练配置:
shuffle=True:训练时打乱数据集顺序,避免模型学习到数据的排列规律(减少过拟合)。
predict_eos_token=False:是否预测 “结束 Token”(</ s >),此处设为 False 表示无需生成结束 Token(因任务是短序列输出,如分类标签)。
输出结果:
在这里插入图片描述

6. 创建verbalizer表述器

(1)ManualVerbalizer:人工定义标签词与类别的映射。需要给出tokenizer(预训练模型的分词器),num_classes(任务的类别数量),label_words每个列别对应的标签表

在这里插入图片描述
(2)myverbalizer.label_words_ids:标签词的 Token ID 映射。将人类可理解的标签词(如 “yes”)转化为模型可识别的 Token ID。

(3)myverbalizer.process_logits(logits):将 logits 映射到类别概率
在这里插入图片描述

7. 创建分类任务的prompt learning模型

(1)用于分类任务的提示学习模型(PromptForClassification)
核心组件说明:
PromptForClassification 是 OpenPrompt 专为分类任务设计的模型封装类,它将三个核心组件(PLM,template,verbalizer)串联成端到端的分类模型:
预训练语言模型(plm):如 BERT、T5、LLaMA 等,是模型的 “主体”,负责理解输入文本的语义。
Prompt 模板(template):即之前定义的 mytemplate,负责将原始数据转化为带提示的输入格式(如 “文本 + 指令 + 掩码”)。
标签映射器(verbalizer):即之前定义的 myverbalizer,负责将模型输出的词级 logits 映射为分类标签的概率(如将 “yes”“no” 的概率转化为 “类别 0”“类别 1” 的概率)。

参数说明:
freeze_plm=False/True:控制是否冻结预训练模型的参数:
False 表示 “微调预训练模型”(更新 PLM 的参数),适合数据量充足的场景,能让模型更好适配任务。
True表示仅训练模板中的软令牌(Soft Token)和 Verbalizer 的参数,适合小数据场景(减少过拟合风险)。
核心原则:
小数据、低资源、简单任务→冻结;
大数据、高资源、复杂任务→微调。

(2)设备配置
use_cuda = torch.cuda.is_available():检查当前环境是否有可用的 GPU(支持 CUDA)。
if use_cuda: prompt_model = prompt_model.cuda():若有 GPU,则将模型迁移到 GPU 上运行,利用 GPU 的并行计算能力加速训练和推理。

8. 训练模型

8.1 核心组件

1,损失函数:交叉熵损失函数
2,优化器参数分组(optimizer_grouped_parameters)
目的:对模型不同类型的参数应用不同的优化策略(主要是权重衰减,weight_decay),提升训练稳定性和模型性能。

分组逻辑:
第一组:weight_decay=0.01(应用权重衰减)包含所有非偏差、非 LayerNorm 权重的参数(如 Transformer 层的注意力权重、线性层权重)。权重衰减是一种正则化手段,通过惩罚大权重值减少过拟合。
第二组:weight_decay=0.0(不应用权重衰减)包含偏差参数(bias) 和LayerNorm 层的权重。这些参数对模型性能影响较敏感,通常不施加权重衰减,避免破坏模型的稳定性。

实现方式:通过 named_parameters() 遍历模型所有参数,根据参数名称(n)中是否包含 bias 或 LayerNorm.weight 进行分组。

代码语法分析:
在这里插入图片描述
(1)named_parameters():返回模型中所有可训练参数的迭代器,每个元素是 (参数名称n, 参数值p)
(2)列表推导式语法规则:[表达式 for 变量 in 迭代对象 if 条件],其中 “表达式” 定义了列表中每个元素的形式。
代码中具体使用:[p for …]:列表推导式的最终目的是生成一个参数值的列表。
推导式的作用:筛选出满足条件(名称不含 bias 或 LayerNorm.weight)的参数,并将这些参数的值(p) 收集成一个列表,用于优化器的参数配置。
(3)参数说明
第一组参数(应用权重衰减)
筛选条件:if not any(nd in n for nd in no_decay)
①no_decay = [‘bias’, ‘LayerNorm.weight’]:定义 “不应用权重衰减” 的参数名称关键词。
②any(nd in n for nd in no_decay):判断参数名称 n 中是否包含 no_decay 中的任何关键词(如参数名含 bias 或 LayerNorm.weight)。
③not any(…):筛选出名称中不含 bias 和 LayerNorm.weight 的参数。
第二组参数(不应用权重衰减)
筛选条件:if any(nd in n for nd in no_decay)
筛选出名称中包含 bias 或 LayerNorm.weight 的参数。

3,优化器
选择AdamW,它在 Adam 基础上改进了权重衰减的实现方式(更准确地对参数施加衰减),适合大规模参数的微调。
学习率的设置:
若冻结预训练模型(freeze_plm=True),仅训练软令牌等少量参数,学习率可设为 1e-4 ~ 5e-3(较大,加速收敛)。
若微调预训练模型(freeze_plm=False),学习率需减小(如 1e-5 ~ 5e-5),避免破坏预训练知识。

8.2 参数更新流程

  1. 数据准备(inputs = inputs.cuda())
    将批量数据(inputs,包含 input_ids、labels 等)迁移到 GPU(若可用),与模型设备保持一致,避免计算错误。
  2. 模型前向传播(logits = prompt_model(inputs))
    模型接收批量输入,经过 Prompt 模板处理、预训练模型编码、Verbalizer 映射后,输出类别 logits(形状为 (batch_size, num_classes),如 (4, 3) 表示 4 个样本、3 个类别)。
  3. 计算损失(loss = loss_func(logits, labels))
    用 CrossEntropyLoss 计算 logits 与真实标签 labels 的损失值(标量),损失越大,模型预测与真实结果差异越大。
  4. 反向传播与参数更新
    loss.backward():自动计算损失对所有可训练参数的梯度(链式法则)。
    optimizer.step():根据梯度和优化器配置(如学习率、权重衰减)更新参数。
    optimizer.zero_grad():清空当前梯度(避免与下一批数据的梯度累积,导致更新错误)。
  5. 训练日志(打印平均损失)
    每 100 个 step 打印一次当前 epoch 的平均损失,用于监控训练过程:
    若损失持续下降,说明模型在有效学习;
    若损失趋于稳定或上升,可能出现过拟合或收敛问题,需调整学习率、批量大小等。
    补充:
    疑问一:为什么要使用item方法?
    loss.item() 是 torch.Tensor(张量)对象的一个方法,用于将单元素张量转换为 Python 标量(如 float 或 int)。
    如果直接写 tot_loss += loss,会导致 tot_loss 变成一个张量(而非 Python 标量),后续计算(如求平均 tot_loss/(step+1))会产生不必要的计算图跟踪(影响性能),甚至可能导致内存泄漏。
    而 loss.item() 会剥离张量的计算图信息,做纯数值计算,也仅返回数值,既节省内存,又保证后续计算符合 Python 原生逻辑。
    疑问二:什么是张量?什么是标量?
    张量(Tensor) 和标量(Scalar) 是两种基础的数据形式,核心区别在于维度和存储的信息,具体如下:
    一,标量(Scalar)
    存储内容:0 维的单一数值
    用途:损失值、准确率等单一指标
    二,张量(Tensor)
    存储内容:多维数组(>=1)
    用途:输入数据、模型参数、中间特征等
    核心特点:
    1,张量不仅包含数值,还携带维度信息(shape)和设备信息(如 CPU/GPU)。
    2,张量支持并行计算和自动求导(PyTorch 的核心功能).

9. 评估模型

流程:
(1)加载验证集数据,进行格式化处理
(2)验证流程:预测与指标计算
逐行解读代码:
迭代验证集,收集预测与标签:

for step, inputs in enumerate(validation_dataloader):
if use_cuda:
inputs = inputs.cuda() # 迁移数据到 GPU(若可用)# 模型前向传播,输出预测值:类别 logits(形状:[batch_size, num_classes])
logits = prompt_model(inputs)  
# 获取当前批次的真实标签(形状:[batch_size]) 
labels = inputs['label'] 
# 收集真实标签:将 GPU 张量转为 CPU 列表,存入 alllabels 
alllabels.extend(labels.cpu().tolist()) # 收集预测结果: 
# 1. torch.argmax(logits, dim=-1):对 logits 按最后一维取最大值索引(即预测的类别) 
# 2. 转为 CPU 列表,存入 allpreds 
allpreds.extend(torch.argmax(logits, dim=-1).cpu().tolist())

疑问1:为什么要把GPU张量转为CPU列表?
模型在 GPU 上完成计算后,得到的预测结果(logits)和标签(labels)仍是 GPU 上的张量(torch.Tensor),而后续的结果存储、指标计算(如准确率)、可视化等操作通常依赖 Python 原生数据结构(如列表),且这些操作更适合在 CPU 上进行。核心目的:适配后处理需求。

疑问2:为什么一开始又要迁移到GPU?
为了让数据与模型在同一设备,利用 GPU 并行计算加速模型的前向 / 反向传播(核心目的:提升计算效率)。

(3)计算准确率(Accuracy)
zip(allpreds, alllabels)
zip() 是 Python内置函数 ,用于将两个列表(allpreds 和 alllabels)按位置一一配对,生成一个包含元组的迭代器。
具体举例说明:

  • allpreds = [0, 1, 0, 2](模型对 4 个样本的预测类别)
  • alllabels = [0, 1, 1, 2](4 个样本的真实类别)

zip(allpreds, alllabels) 生成的迭代器包含以下元组:
结果:(0, 0), (1, 1), (0, 1), (2, 2)


总结

本周主要围绕OpenPrompt工具包展开,在对工具包的使用过程中产生的疑问也通过大模型工具进行解决。本周停留在工具包的时间太长,因此下周将尽量加快速度,开启其他方面知识的学习。

http://www.dtcms.com/a/561356.html

相关文章:

  • 集成测试的分类
  • 上海网站建设百度推广公司wordpress 暂停前台访问
  • 微信网站建设哪家好企业网站分类举例
  • PyTorch 中 model.eval() 的使用与作用详解
  • Linux文件搜索:grep、find命令实战应用(附案例)
  • 搞一个卖东西的网站怎么做企业形象设计英文
  • WebStorm Deployment 实战:一键实时同步到腾讯云 ECS
  • 《深入理解 Python asyncio 事件循环:原理剖析、实战案例与最佳实践》
  • 网络安全事故响应全流程详解
  • 深圳 微网站建设ydgcm网络推广竞价
  • 中文网站 可以做谷歌推广吗制作一个网站数据库怎么做的
  • 【技术指南】打造个人Z-Library镜像:从架构解析到可持续运维
  • 广州最大网站建设做数字艺术设计的网站
  • StarRocks 4.0:基于 Apache Iceberg 的 Catalog 中心化访问控制
  • MySQL下载安装配置(超级超级入门级)
  • 如何制作一个简单的网站在线制作图片书
  • 十三、JS进阶(二)
  • bfs/dfs-最大连通问题
  • 找考卷做要去哪个网站百度推广app怎么收费
  • Matlab自学笔记六十七:(编程实例)非线性方程组求解fsolve
  • 【第1章·第2节】MEX文件的用途详解,在MATLAB中执行“Hello world”
  • 如何做网站的充值功能网站广告源码
  • OpenCV(十七):绘制多边形
  • 数据结构:双向链表-从原理到实战完整指南
  • 网站 栏目管理wordpress瘦身
  • 4D毫米波雷达理解
  • 了解AI 用好AI 拥抱AI哪个公司好
  • 用python streamlit sqlite3 写一个聊天室
  • 【Swift】LeetCode 76. 最小覆盖子串
  • 网站优化哪家专业工厂关键词网络推广