Learning_O说明文档
.jpg)
Learning_O说明文档
Alive~o.0整理自:J
概述
工具函数
功能 | 类/函数 | 描述 |
---|---|---|
计算类别相似度 | get_rehearsal_prototype() | 根据 memory 和 memory_o 数据集预测的特征和标签计算每个类别的余弦相似度 |
预测特征 | get_token_features_and_labels() | 使用上一轮的模型预测特征 |
预测隐藏状态序列 | get_token_encodings_and_labels() | 使用上一轮的模型预测最后一层输出端的隐藏状态序列 |
计算类别的原型 | get_exemplar_means() | 根据支持集的 encoding 计算每个类别的原型,即均值 |
准备数据集
功能 | 类/函数 | 描述 |
---|---|---|
表示训练/测试样本的对象 | InputExample(object) | 包含每个样本的编号,单词序列,标签序列 |
表示样本特征集的对象 | InputFeatures(object) | 包含每个样本特征的 input_ids,input_mask,segment_ids,label_ids |
从文件中读取数据 | read_examples_from_file() | 返回 InputExample 对象的列表 |
提取标签集 | get_labels_dy() | 提取当前任务及之前的所有标签集 |
提取每个样本的 InputFeatures 对象 | convert_examples_to_features | 将输入的文本样本(通过 InputExample 对象表示)转换为模型输入的特征表示(通过 InputFeatures 对象表示) |
加载并处理数据集样本 | load_and_cache_examples() | 调用前两个函数从原始数据集中提取特征 |
训练和评估
功能 | 类/函数 | 描述 |
---|---|---|
老师模型函数 | teacher_evaluate() | 使用老师模型预测 logits 分数和进行重新标记旧实体类 |
评估及重新标记函数 | evaluate() | 评估模型性能以及使用原型对评估集进行重新标记 |
训练函数 | train() | 训练模型,更新参数 |
训练和评估函数 | train_and_eval() | 调用 teacher_evaluate(),evaluate() 和 train() 进行训练和评估 |
损失函数
功能 | 类/函数 | 描述 |
---|---|---|
监督对比损失函数 | SupConLoss() | 实体的监督对比损失函数 |
监督对比损失函数 | SupConLoss_o() | 实体和“O”的联合监督对比损失函数 |
自定义模型
主函数
工具函数
get_rehearsal_prototype()
参数说明:
get_rehearsal_prototype(args, model, tokenizer, labels, pad_token_label_id, mode, data_dir)
- labels:当前任务及之前的所有标签集
- pad_token_label_id:PAD 标记的索引
用法:
- 加载当前任务的 memory 和 memory_o 数据集,并用当前模型预测特征和标签。
- 根据预测特征和标签计算当前任务及之前的所有类别的余弦相似度。
测试:对 task0 的 memory 和 memory_o 数据集进行测试:
get_token_features_and_labels()
参数说明:
get_token_features_and_labels(args, model, batch)
- model:当前加载的上一轮的模型
- btach:要预测的批次
功能:
get_token_encodings_and_labels()
功能:
同 get_token_features_and_labels(),使用上一轮的模型预测最后一层输出端的隐藏状态序列,并提取出原数据集的标签。
get_exemplar_means()
功能:
将每个 label 的所有样本的 encoding 取均值后归一化作为该类别的原型。
准备数据集
InputExample(object)
表示一个训练或测试的样本的对象,该类包含以下属性:
- guid:句子的编号,用作句子的唯一标识符。
- words:句子中的单词序列,以列表形式存储。
- labels:(可选)序列中每个单词的标签,以列表形式存储。对于测试句子,不需要提供标签列表。
InputFeatures(object)
表示一个样本特征集的对象,该类包含以下属性:
- input_ids:表示单词在词汇表中的索引,是模型输入的主要部分。
- input_mask:用于指示哪些部分是真实的输入,哪些部分是填充的。
- segment_ids:在BERT处理句子对中,用于区分不同句子的标识,0表示属于第一个句子,1表示属于第二个句子。
- label_ids:标签的索引。
get_labels_dy()
get_labels_dy(path, per_types, step_id)
参数说明:
- path:标签集的存储路径
- per_types:每个任务要学习的标签数量
- step_id:当前任务的索引
功能:
返回包含当前任务及之前的所有标签的列表。
read_examples_from_file()
参数说明:
read_examples_from_file(data_dir, mode)
- data_dir: 数据文件存储的目录,文件读取的路径格式为"data_dir/{mode}.txt"
- mode:根据不同的模式读取不同的样本
- train:读取 train.txt。
- memory:读取 memory.txt。
- dev:读取 dev.txt。
- rehearsal:同时读取 train.txt 和 memory.txt,并将它们合并成一个列表返回。
用法:
- 使用 os.path.join 构造文件路径,该路径由 data_dir 和 mode 组成。
- 打开文件并逐行读取数据。
- 对于每一行:
- 如果行以 “-DOCSTART-” 开头或为空行,则表示前一个句子的结束。此时,将累积的words和labels作为一个样本添加到 examples 列表中,并清空 words 和 labels 列表。
- 否则,将行按制表符分割,获取单词和标签,并将它们添加到 words 和 labels 列表中。
- 返回 examples 列表,其中每个元素都是一个 InputExample 对象,代表一个句子。
convert_examples_to_features()
参数说明:
1 | convert_examples_to_features(examples, label_list, max_seq_length, tokenizer, cls_token_at_end=False, cls_token="[CLS]", |
- examples:经过 read_example_from_file() 函数处理的 InputExample 对象列表
- label_list:当前增量学习任务的标签
- max_seq_length:tokenization 后的最大序列长度,比这个长的会被截断,比这个短的会被填充。
- cls_token_at_end:是否在序列最后加一个 CLS token:
- False (Default, BERT/XLM pattern): [CLS] + A + [SEP] + B + [SEP]
- True (XLNet/GPT pattern): A + [SEP] + B + [SEP] + [CLS]
- cls_token_segment_id:定义关于 CLS token 的段id (0 for BERT, 2 for XLNet)。
- sep_token_extra:是否在结尾再添加 SEP token( for RoBERTa pattern)。
- pad_on_left:是否在句子左边填充 PAD。
用法
- 将增量学习任务的标签从0编号,构建标签到索引映射 label_map。
- 遍历每个 example:
- 使用分词器 tokenizer 对句子的每个单词进行分词,并在 label_ids 列表中添加它们的标签编号。
- 根据序列的长度和特殊标记的数量,截断序列,使其长度符合 max_seq_length 的要求。
- 添加特殊标记 [CLS] 和 [SEP],以及相应的标签编号。
- 构建 segment_ids (全为0) 表示句子的段落编号。
- 构建 input_ids 列表,将 tokens 序列映射为其对应的 ID。
- 构建输入掩码 input_mask,1 for real tokens and 0 for padding tokens。
- 对不足长度的序列进行填充。
- 将每个 example 的处理结果存储为一个 InputFeatures 对象,并添加到 features 列表中。
- 返回 features 列表。
load_and_cache_examples()
参数说明:
load_and_cache_examples(args, tokenizer, labels, pad_token_label_id, mode, data_dir)
- tokenizer:分词器
- labels: 当前增量学习任务的标签
- pad_token_label_id:PAD 位置的掩码
- mode:指定当前的模式,可能为 train,dev,rehears。
- data_dir: 数据文件存储的目录。
data_dir,mode 传入 read_examples_from_file 函数读取样本。
tokenizer,传入 convert_examples_to_features 函数将样本转换为特征。
功能:
- 调用 read_examples_from_file() 和 convert_examples_to_features() 函数,根据不同的模式从 data_dir 中读取样本并转换为特征,如果是’rehearsal’模式,则读取 train.txt 和 memory.txt,如果是开发,训练,测试模式,则读取相应的dev.txt,train.txt,test.txt。
- 如果是分布式训练的非主进程,直接从缓存文件中加载特征。
- 返回一个 TensorDataset 对象 dataset(all_input_ids, all_input_mask, all_segment_ids, all_label_ids)。
测试
对 task0 的训练集的句子进行测试:
获取标签集
1 | labels = get_labels_dy(path="../data/labels.txt", per_types=6, step_id=0) |
输出
1 | ['O', |
运行 load_and_cache_examples() 函数
1 | train_dataset = load_and_cache_examples(args, tokenizer, labels, pad_token_label_id, mode=mode, data_dir=data_dir) |
输出日志()
1 | 03/28/2024 13:38:28 - INFO - __main__ - Creating features from dataset file at ../data/tasks/task_0 |
训练和评估
teacher_evaluate()
用法:
- 使用老师模型,即上一轮的模型预测训练集的
logits_list
和获取真实标签out_labels
。 - 调用 evaluate(mode=“rehearsal”) 获取训练集的
preds
,emissions
,out_label_ids
, 以及重新标记阈值prototype_dists
。 - 重新标记旧实体类:对于训练集的每个样本,如果它的原型的相似度大于重新标记阈值,则将该样本预测为这个旧实体类,否则保持原来的预测标签不变。
- 返回
logits_list
和重新标记过的标签列表out_label_new_list
。
evaluate()
用法:
- 加载数据集:调用 load_and_cache_examples() 根据不同模式加载评估集,support 集(提取实体样本),support_o 集(提取“O”样本),训练集。
- 计算类别原型:
- 使用上一轮模型预测支持集的 encoding 和label。
- 调用 get_exemplar_means() 根据支持集的 encoding 和label 计算每个类别的原型。
- 调用 get_token_encodings_and_labels() 使用上一轮模型预测评估集的 encoding 和 标签
out_label_ids
。 - 如果是’rehearsal’模式,则剔除掉支持集中当前任务标签的样本,并调用 NNClassification 的 nn_classifier_dot_prototype() 计算:
preds
:评估集每个样本中原型相似度最大值所在的类别索引emissions
:评估集每个样本与每个类别的原型相似度的最大值prototype_dists
:根据支持集计算的每个旧类别的原型重新标记阈值列表
- 如果是’rehearsal’模式,则直接返回
preds
,emissions
,out_label_ids
,prototype_dists
。 - 将
out_label_ids
,preds
的标签从索引形式转换为真实的字符串形式。 - 将评估集的
out_label_list
作为真实标签,将preds_list
作为预测标签,使用 seqeval 库计算 F1 分数macro_results
,
micro_results
。 - 返回
macro_results
,micro_results
,preds_list
。
train()
参数说明:
train(args, train_dataset, train_dataloader, model, tokenizer, labels, pad_token_label_id, data_dir, output_dir, t_logits, out_new_labels):
- train_dataset:训练集
- train_dataloader:训练集加载器
- labels:当前任务及之前的所有真实标签集
- pad_token_label_id:PAD 标记的索引
- data_dir:输入数据集的文件路径
- output_dir:保存模型的检查点的文件路径
- t_logits:老师模型预测的 logits 分数
- out_new_labels:老师模型预测的标签
用法:
参数配置
- 设置训练总步数 t_total(用于传入 warmup 中):
- 通过
args.max_steps
可以指定 t_total,并覆盖arg.num_train_epochs
。 - 否则通过
t_total = len(train_dataloader) // args.gradient_accumulation_steps * args.num_train_epochs
计算 t_total。
- 配置优化器:使用AdamW优化器,使用了权重衰减,学习率调节器。
args.learning_rate
(default=5e-5) 和args.adam_epsilon
(default=1e-8) 可修改AdamW的学习率和模糊因子。args.warmup_steps
(default=0) 可修改 warmup 的初始预热步数。
- 根据
args.fp16
选择是否启用混合精度训练。
训练模型:
迭代每一轮:
- 如果当前轮次 >=
args.start_train_o_epoch
:- 利用 get_rehearsal_prototype() 函数计算类别相似度
- 将
loss_name
设为 实体和“O”联合损失函数。 - 调用 get_token_features_and_labels() 函数使用当前模型预测特征和标签。
- 调用 get_top_emissions_with_th() 选择“O”的正样本。
- 如果是第一个任务,使用原始数据集的标签。
- 如果不是第一个任务,使用老师模型 tearch_evaluate() 预测 logits 分数
t_logits
和标签out_new_labels
。 - 模型前向传播,获取模型输出的损失值。
- 模型反向传播。
- 更新参数
- 调用 evaluate() 的开发模式对开发集进行评估
- 达到
args.save_steps
时保存 checkpoint 文件和模型。 - 返回训练总步数和平均损失值。
train_and_eval()
参数说明:
train_and_eval(args, labels, num_labels, pad_token_label_id, model_name_or_path, output_dir, data_dir, step_id)
- labels:当前任务及之前的所有标签集
- num_labels:labels 的数量
- pad_token_label_id:PAD 标记的索引
- model_name_or_path:加载模型的路径
- output_dir:输出结果的文件路径
- data_dir:读取数据集的文件路径
- step_id:当前任务的 id
用法:
- 加载上一个任务的模型参数,分词器,模型。
- 调用 load_and_cache_examples(mode=“rehearsal”) 加载训练集(由当前任务的 train.txt 和 memory.txt 组成)
- 如果不是第一个任务,则调用 teacher_evaluate(mode=“train”) 使用老师模型预测训练集的 logits 分数
t_logits
和out_new_labels
。 - 调用 train() 进行训练。
- 存储模型的参数,分词器,模型。
- 如果
args.do_eval
为 Ture,对每个 checkpoint 调用 evaluate() 的开发模式对开发集进行评估,并存储进 eval_results.txt 文件。 - 如果
args.do_predict
为 Ture,调用 evaluate() 的测试模式对测试集进行评估和预测,并保存评估和预测结果。
损失函数
SupConLoss()
init():
参数说明:
init(self, temperature=0.07, contrast_mode=‘all’, base_temperature=0.07, topk_th=False)
- temperature:温度参数,用于调整对比损失函数中余弦相似度的尺度。
- contrast_mod:
- base_temperature:基准温度参数,用于调整对比损失函数的基准尺度。
- topk_th:
forward():
参数说明:
forward(self, features, labels=None, mask=None, entity_topk=None, ignore_index=CrossEntropyLoss(), per_types=6, aug_feature=None)
- mask:对比损失的掩码,同一标签的样本设为1,不同为0。
- entity_topk: 实体 Top K,表示每个类别的前 K 个样本在对比中的重要性。
- ignore_index: 忽略索引,默认为 CrossEntropyLoss(),表示在计算损失时需要忽略的标签索引。
用法:
- 根据输入的
labels
和mask
构建mask
:不同标签的设为0,与自身的设为0,ignore_index 所对应的行设为0,“O”样本所在行设为0。 - 选择 Anchor:根据
contrast_mode
选择 anchor 样本,如果contrast_mode
为 ‘one’, 则将第一个样本设为 anchor,如果contrast_mode
为 ‘all’, 则将所有样本设为 anchor。 - 计算对比损失的 Logits:计算 anchor 和其他样本之间的余弦相似度。
entity_topk
非空: 将mask
中所有样本与 entity_topk样本设为1,与当前任务训练集的“O”样本设为 0。- 根据监督对比损失函数公式计算损失值,返回所有 anchor 的平均损失值。
模型
MySftBertModel()
forward():
- 使用 BertModel 模型前向传播
- 提取特征
features
:将ast_hidden_state
通过一个mlp(Linear-ReLU-Linear)
层变换并归一化后赋给features
。 - 提取
logits
:将last_hidden_state
依次通过dropout 层,线性分类器层后赋给logits
。 - 如果是非训练模式,直接返回 loss, features_enc, features, logits,其中
loss = None
,features_enc = last_hidden_state
- 计算损失值
loss
。:- 根据
loss_name
计算损失函数的值。 - 如果不是第一个任务,计算当前任务样本的 logits 与真实标签的交叉熵损失,当前模型与老师模型 logits 的KL散度。将交叉熵损失或KL散度添加到
loss
中。
- 根据
- 返回 loss, features_enc, features, logits。
主函数
main()
功能:
- 创建解释器,添加命令行参数。
- 迭代每个任务,调用 get_labels_dy() 获取当前任务及之前的所有标签集
labels
,然后调用 train_and_eval() 进行训练和评估。