欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 大模型开发(五):P-Tuning项目——新零售决策评价系统(二)

大模型开发(五):P-Tuning项目——新零售决策评价系统(二)

2025/3/9 8:15:02 来源:https://blog.csdn.net/TANTANWANG/article/details/146021693  浏览:    关键词:大模型开发(五):P-Tuning项目——新零售决策评价系统(二)

P-Tuning项目——新零售决策评价系统(二)

  • 0 前言
  • 1 P-Tuning原理
  • 2 数据处理

0 前言

上篇文章我们介绍了使用PET方式微调BERT模型,PET属于提示词微调的一种,另一种比较常见的提示词微调是P-Tuning,我们今天在相同的项目上面用P-Tuning看看。

1 P-Tuning原理

P-Tuning 的目标是减少对人工设计模板(硬模板)的依赖,并通过引入可学习的参数来自动优化提示(prompt),以达到更好的任务表现。在这种设置下,模板不是固定的文本序列,而是由一组可学习的向量表示,这些向量可以在训练过程中根据任务的具体要求进行调整和优化,因此,P-Tuning的模板被称为软模板。

这种方式的优点包括:

  • 灵活性:软提示允许模型动态地适应不同的任务需求,而不需要手动调整模板。
  • 泛化能力:通过训练,模型可以学到更通用的提示表达,有助于提高在未见过的数据上的表现。
  • 减少工作量:减少了为每个新任务或数据集设计和测试模板的需求。

在实际工作中,纯软模板是比较少见的,模板并不是完全由可学习的参数表示,而是使用特殊字符(特殊字符可以自由学习也可以自己指定),将模版与原始文本拼在一起输入预训练模型,预训练模型会对模板中的mask做预测,得到一个label。
在这里插入图片描述
图中[u1][u2][u3][u4][u5][u6]都是伪标记,它们都是词表中没有使用过的token,所谓没有使用,指的是没有在训练集和验证集中出现过,所以构建软模板时,要找那种肯定不会出现在训练集和验证集的token。也就是说,软模板不再是人能理解的,只有模型能理解。

本项目的结构和PET大致相同,除了数据处理部分,其他代码只需要略微修改即可,因此我们这里只讲数据处理部分。

2 数据处理

数据处理的代码在 data_handle/data_preprocess.py 中,大致过程就是先插入Mask,后插入伪标记,我做了比较详细的注释,代码如下:

import torch
import numpy as np
from rich import print
from functools import partial
from datasets import load_dataset
from transformers import AutoTokenizerdef convert_example(examples: dict,tokenizer,max_seq_len: int,max_label_len: int,p_embedding_num=6,train_mode=True,return_tensor=False
) -> dict:"""将样本数据转换为模型接收的输入数据。Args:examples (dict): 训练数据样本, e.g. -> {"text": ['娱乐	嗨放派怎么停播了','体育	世界杯为何迟迟不见宣传',...]}max_label_len (int): 最大label长度,若没有达到最大长度,则padding为最大长度p_embedding_num (int): p-tuning token(伪标记) 的个数train_mode (bool): 训练阶段 or 推理阶段。return_tensor (bool): 是否返回tensor类型,如不是,则返回numpy类型。Returns:dict (str: np.array) -> tokenized_output = {'input_ids': [[101, 3928, ...], [101, 4395, ...]],'token_type_ids': [[0, 0, ...], [0, 0, ...]],'mask_positions': [[5, 6, ...], [3, 4, ...]],'mask_labels': [[183, 234], [298, 322], ...]}"""# 定义输出格式(Bert模型的接收格式)tokenized_output = {'input_ids': [],'attention_mask': [],'mask_positions': [],  # 记录label的位置(即MASK Token的位置)'mask_labels': []  # 记录MASK Token的原始值(即Label值)}# 遍历样本数据,将样本填充到模板中,并转化为Bert模型的输入格式for i, example in enumerate(examples['text']):try:# 将[MASK]插在[CLS]之后,[MASK]的位置可以在任何位置,但提示词的开头和结尾必须为[CLS]和[SEP]start_mask_position = 1if train_mode:# 如果是训练模式,则既有样本的label,也有样本的文本内容label, content = example.strip().split('\t', 1) # 第二个参数为1表示最多分割1次,结果列表中最多包含2个元素else:# 如果是评估(推理)模式,则只有样本的文本内容content = example.strip()# 将文本转换为Bert模型的输入格式encoded_inputs = tokenizer(text=content,truncation=True,max_length=max_seq_len,padding='max_length')# encoded_inputs包含三个键:'input_ids', 'token_type_ids', 'attention_mask'except:continue# 生成 MASK Tokens, 和label长度一致mask_tokens = ['[MASK]'] * max_label_len# 将 MASK Tokens 转为 idmask_ids = tokenizer.convert_tokens_to_ids(mask_tokens)# 构建 prompt token(s),即构建伪标记,[[unused1] [unused2] ... [unused6]]p_tokens = ["[unused{}]".format(i + 1) for i in range(p_embedding_num)]# 伪标记 转 idp_tokens_ids = tokenizer.convert_tokens_to_ids(p_tokens)# 获取input_idsinput_ids = encoded_inputs['input_ids']# 去掉最后的[SEP]tmp_input_ids = input_ids[:-1]# 裁剪content的长度tmp_input_ids = tmp_input_ids[:max_seq_len - len(mask_ids) - len(p_tokens_ids) - 1]# 因为要插入 p_embedding_num 个伪标记,并且标签长度为 max_label_len,并且最后要加上[SEP]# 所以原来的 input_ids 只能保存 max_seq_len - len(mask_ids) - len(p_tokens_ids) - 1 个token# 插入[MASK]对应的idtmp_input_ids = tmp_input_ids[:start_mask_position] + mask_ids + tmp_input_ids[start_mask_position:]# 插入后,tmp_input_ids 变为 [CLS][MASK][MASK]世界杯...# 补上[SEP]input_ids = tmp_input_ids + [input_ids[-1]]# 插入伪标记input_ids = p_tokens_ids + input_ids  # [unused1][unused2]...[CLS][MASK][MASK]世界杯...[SEP]# 将 Mask Tokens 的位置记录下来mask_positions = [len(p_tokens_ids) + start_mask_position + i for i in range(max_label_len)]# 将填充后的提示词加入到输出字典中tokenized_output['input_ids'].append(input_ids)# 如果输入需要token_type_ids,可以进行添加,if 'token_type_ids' in encoded_inputs:  # 兼容不需要 token_type_id 的模型, e.g. Roberta-Basetmp = encoded_inputs['token_type_ids']if 'token_type_ids' not in tokenized_output:# 循环第一轮时,'token_type_ids'不在字典tokenized_output中,所以需要增加键值对tokenized_output['token_type_ids'] = [tmp]else:# 从第二轮循环开始,直接在列表里添加tokenized_output['token_type_ids'].append(tmp)# 收集Bert模型需要的其他信息tokenized_output['attention_mask'].append(encoded_inputs['attention_mask'])tokenized_output['mask_positions'].append(mask_positions)# 对于训练模式,则需要将label转化为Bert模型的输入格式if train_mode:mask_labels = tokenizer(text=label)  # label token 转 idmask_labels = mask_labels['input_ids'][1:-1]  # 丢掉[CLS]和[SEP]mask_labels = mask_labels[:max_label_len]   # 如果标签的长度大于max_label_len,则截断mask_labels += [tokenizer.pad_token_id] * (max_label_len - len(mask_labels))  # 将 label 补到最长tokenized_output['mask_labels'].append(mask_labels)     # 收集处理后的标签# 将数据转化为torch.tensor或者numpy.array格式,方便后续处理for k, v in tokenized_output.items():if return_tensor:tokenized_output[k] = torch.LongTensor(v)else:tokenized_output[k] = np.array(v)return tokenized_outputif __name__ == '__main__':# 导入数据train_dataset = load_dataset('text', data_files={'train': '../data/train.txt'})print(f'train_dataset==>{train_dataset}')print(train_dataset['train']['text'][0])print('-'*80)# 创建分词器tokenizer = AutoTokenizer.from_pretrained('../../预训练模型/bert-base-chinese')# 函数式编程new_func = partial(convert_example,tokenizer=tokenizer,max_seq_len=20,max_label_len=2,p_embedding_num=6)# 数据批处理new_dataset = train_dataset.map(new_func, batched=True)# 打印print(f'dataset---》{new_dataset}')for value in new_dataset['train']:# value将是一个字典,包含输入的text、input_ids、token_type_id、attention_mask、mask_position和mask_labelprint(type(value))for k, v in value.items():print(k, v)print(len(value['input_ids']))break

输出

train_dataset==>DatasetDict({train: Dataset({features: ['text'],num_rows: 63})
})
电脑	(1)这款笔记本外观感觉挺漂亮的,分量吗,对我来说不算沉。 (2)安装了WindowsXP系统后,运行的速度挺快。发热量没有想象中那么大。可能尚未运行很耗资源的程序,没有感到内存的弊病。不过,1G的内存确实有点小。 (3)附赠的包很不错,挺有手感的。但是附赠的鼠标实在是太小了,幸好同时订了一个双飞燕的鼠标哟。
--------------------------------------------------------------------------------
dataset---》DatasetDict({train: Dataset({features: ['text', 'input_ids', 'attention_mask', 'mask_positions', 'mask_labels', 'token_type_ids'],num_rows: 63})
})
<class 'dict'>
text 电脑	(1)这款笔记本外观感觉挺漂亮的,分量吗,对我来说不算沉。 (2)安装了WindowsXP系统后,运行的速度挺快。发热量没有想象中那么大。可能尚未运行很耗资源的程序,没有感到内存的弊病。不过,1G的内存确实有点小。 (3)附赠的包很不错,挺有手感的。但是附赠的鼠标实在是太小了,幸好同时订了一个双飞燕的鼠标哟。
input_ids [1, 2, 3, 4, 5, 6, 101, 103, 103, 113, 122, 114, 6821, 3621, 5011, 6381, 3315, 1912, 6225, 102]
attention_mask [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
mask_positions [7, 8]
mask_labels [4510, 5554]
token_type_ids [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
20

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词