人工智能NLP深度学习【免费下载链接】DeepPavlovAn open source library for deep learning end-to-end dialog systems and chatbots.项目地址https://gitcode.com/gh_mirrors/de/DeepPavlov点击查看免费下载导读多任务 BERT 是 DeepPavlov 中基于论文《Knowledge Transfer Between Tasks and Languages in the Multi-task Encoder-agnostic Transformer-based Models》实现的一种训练范式多个任务共享同一个 BERT 主干backbone各自在编码器输出上挂接独立的任务头head从而让一个模型同时承担分类、回归、多选与命名实体识别等异构任务。本文以仓库中的 toy 配置 multitask_example.json 为主线逐段讲解multitask_reader、multitask_iterator、multitask_pipeline_preprocessor与multitask_transformer的配置语义与底层实现并给出多任务指标、自定义早停指标与推理配置的完整写法。读完本文你将能够自行搭建一个共享 BERT 主干的多任务训练管线并读懂 mt_glue.json 这类面向 GLUE 的 8 任务配置。一、设计动机与核心思想在常规流水线中如果模型的不同组件各自使用一份 BERT那么 GPU 显存开销会成倍增长。多任务 BERT 的思路是只保留一份 BERT 编码器作为共享主干为每个任务在编码器输出之上挂接独立的输出头。当模型共有 $T$ 个任务头时一次训练迭代iteration包含为每个任务分别组装一批样本共 $T$ 份样本列表依次执行 $T$ 次梯度更新每个任务对应一次。按原始 MT-DNN 仓库的惯例默认情况下每一步训练中只有一个任务的样本列表非空。训练某个任务头时其余任务头的参数保持不变而每一次梯度步中被训练任务对应的头参数与共享的 BERT 主干参数都会被更新。从源码实现看这一机制由 multitask_transformer.py 中的MultiTaskTransformer.train_on_batch落实它要求一次前向只能接收单个任务的样本并在gradient_accumulation_steps累计后统一执行optimizer.step()与optimizer.zero_grad()见 multitask_transformer.py。模型骨架BertForMultiTask则通过AutoModel.from_pretrained加载一份共享 BERT并按任务索引维护一个final_classifier线性头列表见 multitask_transformer.py。当前实现支持的任务头类型包括分类classification包括单句分类与句对分类回归regression如 STS-B 相似度打分NER / 序列标注sequence_labeling基于 token 级标签多选multiple_choice如 COPA。本文的演示模型以 multitask_example.json 为样本同时训练以下五个任务单句分类CoLA、句对分类RTE、回归STS-B、多选COPA与命名实体识别ConLL-2003。另一个面向 GLUE 的 8 任务配置见 mt_glue.json两者共用同一条架构思路。二、训练配置总览一个配置文件通吃训练与推理使用multitask_transformer组件时训练与推理可以使用同一个配置文件——只需在推理场景去掉训练相关字段详见第七节纯推理配置。完整配置由四大部分组成dataset_reader使用multitask_reader并行读取多个异构数据集dataset_iterator使用multitask_iterator将多任务数据融合为统一 batchchainer数据处理 multitask_transformer 后处理proba2labels、simple_vocab的管道train训练超参数与多任务指标列表metadata.variables路径、backbone 名称、epoch 数等可替换变量。multitask_example.json的完整文件可直接阅读 deeppavlov/configs/multitask/multitask_example.json下文将逐段拆解。三、多任务数据读取MultiTaskReader多任务数据读取由 multitask_reader.py 中的MultiTaskReader完成。其read方法遍历tasks字典为每个任务实例化一个嵌套的 dataset reader并把各任务的原始数据汇总为一个以任务名为键的字典。以 multitask_example.json 中的 reader 配置为例dataset_reader: { class_name: multitask_reader, task_defaults: { class_name: huggingface_dataset_reader, path: glue, train: train, valid: validation, test: test }, tasks: { cola: {name: cola}, copa: { path: super_glue, name: copa }, conll: { class_name: conll2003_reader, use_task_defaults: false, data_path: {DOWNLOADS_PATH}/conll2003/, dataset_name: conll2003, provide_pos: false } } }参数语义如下task_defaults所有任务的默认嵌套 reader 参数当某个任务没有显式给出某参数时从这里取值tasks任务名到该任务嵌套 reader 参数的映射参数合并规则tasks中给出的参数会补充默认值例如cola的name也可以覆盖默认值例如copa用path: super_glue覆盖默认的glueuse_task_defaults: false特殊开关。设置后multitask_reader在创建该嵌套 reader 时完全忽略task_defaults只使用tasks中该任务自己的参数。因此conll任务改用conll2003_reader而非默认的 HuggingFace reader。这一合并逻辑在源码中体现为 multitask_reader.pyif task_params.pop(use_task_defaults, True) is True: task_config copy.deepcopy(task_defaults) task_config.update(task_params) else: task_config task_params reader get_model(task_config.pop(class_name))() data[task_name] reader.read(**task_config)需要注意的是task_defaults与tasks中的class_name 会先被pop取出用于通过注册表get_model实例化嵌套 reader——因此default 用 HuggingFace reader、个别任务换本地 reader的写法是可行的。四、多任务迭代器MultiTaskIterator 与 batch 结构数据迭代由 multitask_iterator.py 中的MultiTaskIterator负责。它与 reader 遵循同样的默认值合并原则task_defaults提供嵌套 iterator 的默认参数tasks中逐任务补充或覆盖同样支持use_task_defaults: false。在示例配置中GLUE 系任务默认使用huggingface_dataset_iteratorlabel字段取label、use_label_name: false而conll任务显式替换为basic_classification_iterator并设置use_task_defaults: falsedataset_iterator: { class_name: multitask_iterator, num_train_epochs: {NUM_TRAIN_EPOCHS}, gradient_accumulation_steps: {GRADIENT_ACC_STEPS}, seed: 42, task_defaults: { class_name: huggingface_dataset_iterator, label: label, use_label_name: false, seed: 42 }, tasks: { cola: {features: [sentence]}, rte: {features: [sentence1, sentence2]}, stsb: {features: [sentence1, sentence2]}, copa: {features: [contexts, choices]}, conll: { class_name: basic_classification_iterator, seed: 42, use_task_defaults: false } } }4.1 Batch 的元组结构multitask_iterator生成的每个 batch 是一个二元组(inputs, labels)其中 inputs 与 labels 都是元组的列表。inputs 的格式为[(first_task_inputs[0], second_task_inputs[0], ...), (first_task_inputs[1], second_task_inputs[1], ...), ...]其中first_task_inputs、second_task_inputs……依次是各任务子迭代器产出的 x 值labels 的第二个元素同理。这一转换由_transform_before_yielding完成见 multitask_iterator.py元组内元素顺序与tasks字典中的任务顺序一一对应。4.2 不等长数据集的 None 填充当各任务数据集大小不一致时较小数据集的位置用None填充。示例配置中给出的例子任务一输入为[0, 1, 2, 3, 4, 5, 6]、任务二输入为[7, 8, 9]、batch_size 为 2则多任务 mini-batch 为[(0, 7), (1, 8)] ← 第一批两个任务都有数据 [(2, 9), (3, None)] ← 任务二耗尽开始填充 None [(4, None), (5, None)] [(6, None)]训练模式下源码还会按gradient_accumulation_steps调整有效 batch sizebatch_size batch_size // gradient_accumulation_steps并通过np.random.choice依据采样概率plain/uniform/anneal三种sampling_mode选中当前步唯一激活的任务见 multitask_iterator.py与每步只训练一个任务头的训练策略保持一致。4.3 chainer 的 in / in_y 命名示例模型共 5 个任务因此chainer的输入命名与 batch 结构对应in: [x_cola, x_rte, x_stsb, x_copa, x_conll], in_y: [y_cola, y_rte, y_stsb, y_copa, y_conll]五、多任务数据预处理multitask_pipeline_preprocessor有时任务迭代器产出的一个输入/标签元素本身包含多个成分例如句对任务的一条样本包含两个字符串。若需要拆分可以使用InputSplitter组件。不过为了精简代码input_splitter与tokenizer可以统一合并为multitask_pipeline_preprocessor其源码位于 multitask_preprocessor.py。该组件有两个关键参数preprocessor单个预处理器类名所有任务共用默认TorchTransformersPreprocessorpreprocessors预处理器类名列表长度须等于任务数逐个任务指定设置后将覆盖preprocessor。possible_keys_to_extract用于指定需要从样本中拆出的位置索引。完成输入拆分后每个预处理器初始化时已传入vocab_file等参数对各自任务的数据做 tokenization。strict参数默认False决定拆分行为当无法确定如何拆分样本时strictFalse会放弃拆分并给出 warningstrictTrue则总是尝试按预定义模式拆分遇到不支持的数据结构会直接抛异常见 multitask_preprocessor.py 的split方法。示例配置中该组件的完整定义class_name: multitask_pipeline_preprocessor, possible_keys_to_extract: [0, 1], preprocessors: [ TorchTransformersPreprocessor, TorchTransformersPreprocessor, TorchTransformersPreprocessor, TorchTransformersMultiplechoicePreprocessor, TorchTransformersNerPreprocessor ], do_lower_case: true, n_task: 5, vocab_file: {BACKBONE}, max_seq_length: 200, max_subword_length: 15, token_masking_prob: 0.0, return_features: true, in: [x_cola, x_rte, x_stsb, x_copa, x_conll], out: [ bert_features_cola, bert_features_rte, bert_features_stsb, bert_features_copa, bert_features_conll ]对照源码前三个任务CoLA、RTE、STS-B使用通用TorchTransformersPreprocessor第四个 COPA 多选任务使用TorchTransformersMultiplechoicePreprocessor第五个 ConLL 序列标注任务使用TorchTransformersNerPreprocessor——三类预处理器均在 torch_transformers_preprocessor.py 中定义分别见第 116、40、478 行附近。其中 NER 预处理器会把词拆成 BERT 子词subtoken并生成子词掩码max_subword_length限制单个词拆分的最大子词数超出则替换为unk见 torch_transformers_preprocessor.py。六、核心模型multitask_transformer 组件6.1 参数结构公共参数与任务参数multitask_transformer的配置分为公共参数与任务专属参数两类。任务专属参数统一放在tasks字典中字典的键是任务名值是任务参数type、options 等公共参数包括backbone_model与 tokenizer 中的 vocab_file 一致以及torch_bert一系参数优化器、学习率调度等。⚠️任务顺序至关重要The order of tasks MATTERStasks字典的顺序必须与in/in_y中变量的顺序、以及 reader / iterator 中任务定义的顺序保持一致因为 batch 元组与in列表是按位置对齐的。multitask_example.json中该组件的完整定义id: multitask_transformer, class_name: multitask_transformer, optimizer_parameters: {lr: 2e-5}, gradient_accumulation_steps: {GRADIENT_ACC_STEPS}, learning_rate_drop_patience: 2, learning_rate_drop_div: 2.0, return_probas: true, backbone_model: {BACKBONE}, save_path: {MODEL_PATH}, load_path: {MODEL_PATH}, tasks: { cola: { type: classification, options: 2 }, rte: { type: classification, options: 2 }, stsb: { type: regression, options: 1 }, copa: { type: multiple_choice, options: 2 }, conll: { type: sequence_labeling, options: #vocab_conll.len } }, in: [ bert_features_cola, bert_features_rte, bert_features_stsb, bert_features_copa, bert_features_conll ], in_y: [y_cola, y_rte, y_stsb, y_copa, y_ids_conll], out: [ y_cola_pred_probas, y_rte_pred_probas, y_stsb_pred, y_copa_pred_probas, y_conll_pred_ids ]参数说明参数含义示例值optimizer_parameters.lr优化器学习率2e-5gradient_accumulation_steps梯度累积步数{GRADIENT_ACC_STEPS}默认 1learning_rate_drop_patience学习率衰减的等待 epoch 数2learning_rate_drop_div学习率衰减的除数2.0return_probas是否返回预测概率回归任务返回连续值序列标注暂不支持 probas仍返回 idtruebackbone_modelHuggingFace backbone 模型名或路径须与预处理器vocab_file一致{BACKBONE}tasks.name.type任务头类型classification/regression/multiple_choice/sequence_labeling源码还支持binary_head见各任务tasks.name.options类别数分类/多选/序列标注的标签种类数回归为 12、3、#vocab_conll.len关于optionsConLL 任务使用#vocab_conll.len即引用管道中simple_vocab组件id 为vocab_conll的len属性——标签种类数由真实标签自动确定。simple_vocab的配置在 pipe 中位于 transformer 之前{ id: vocab_conll, class_name: simple_vocab, unk_token: [O], pad_with_zeros: true, save_path: {MODELS_PATH}/tag.dict, load_path: {MODELS_PATH}/tag.dict, fit_on: [y_conll], in: [y_conll], out: [y_ids_conll] }它把原始 NER 标签序列y_conll映射为 id 序列y_ids_conll后者作为 transformer 的in_y第五个元素。6.2 底层实现要点从 multitask_transformer.py 可以确认以下实现事实MultiTaskTransformer.__init__遍历tasks收集每个任务的options、type、multilabel、weight等参数并据此构造共享 BERT 骨架见 multitask_transformer.pyBertForMultiTask为每个任务在 BERT 输出之上挂一个nn.Linear头分类/回归/多选取[CLS]位置的 pooled 输出序列标注取last_hidden_state全 token 输出见 multitask_transformer.py训练时train_on_batch校验参数数量必须为2 * n_tasks且一次只允许一个任务有样本损失按gradient_accumulation_steps缩放后backward并可选做梯度裁剪clip_norm按累积步数触发optimizer.step()见 multitask_transformer.py推理时__call__对每个任务分别get_logits与predict_on_top序列标注用token_from_subtoken把子词预测还原为词级标签回归/二分类头直接取 logits 首列分类头按return_probas输出 softmax 概率或 argmax id见 multitask_transformer.py。6.3 后处理proba2labels 支持多参数输入multitask_transformer之后分类任务的概率需要转回标签 id。与单任务不同proba2labels现在可以同时接收多个参数见 proba2labels.py 的__call__它逐个处理每个参数并返回列表的列表{ in: [y_cola_pred_probas, y_rte_pred_probas, y_copa_pred_probas], out: [y_cola_pred_ids, y_rte_pred_ids, y_copa_pred_ids], class_name: proba2labels, max_proba: true }proba2labels支持三种标签决策方式max_proba取概率最大的类、confidence_threshold概率高于阈值即判为该类适合多标签、top_n返回概率最高的前 n 个类三者必须且只能指定其一否则抛出ConfigError见 proba2labels.py。在multitask_example.json中该组件按任务拆成了三个实例cola / rte / copa语义等价于上述多参数写法。管道末端还有一个ref: vocab_conll的组件把y_conll_pred_ids反查为标签字符串y_conll_pred_labels供ner_f1等指标使用。七、多任务训练配置指标与早停7.1 内置的多任务指标multitask_example.json 的train段配置了multitask_accuracy一次接收2n个参数前 n 个为 n 个任务的真值后 n 个为预测计算多任务整体准确率实现见 accuracy.py 附近注册表见 metrics_registry.jsonner_f1/ner_token_f1NER 任务的 F1 指标实现见 fmeasure.py各任务独立的accuracy通过alias区分如accuracy_cola、accuracy_rte、accuracy_copaSTS-B 回归任务的pearson_correlation与spearman_correlation。train: { epochs: {NUM_TRAIN_EPOCHS}, batch_size: 32, metrics: [ { name: multitask_accuracy, inputs: [y_rte, y_cola, y_copa, y_rte_pred_ids, y_cola_pred_ids, y_copa_pred_ids] }, {name: ner_f1, inputs: [y_conll, y_conll_pred_labels]}, {name: ner_token_f1, inputs: [y_conll, y_conll_pred_labels]}, {name: accuracy, alias: accuracy_cola, inputs: [y_cola, y_cola_pred_ids]}, {name: accuracy, alias: accuracy_rte, inputs: [y_rte, y_rte_pred_ids]}, {name: accuracy, alias: accuracy_copa, inputs: [y_copa, y_copa_pred_ids]}, {name: pearson_correlation, alias: pearson_stsb, inputs: [y_stsb, y_stsb_pred]}, {name: spearman_correlation, alias: spearman_stsb, inputs: [y_stsb, y_stsb_pred]} ], validation_patience: 3, log_every_n_epochs: 1, show_examples: false, evaluation_targets: [valid], class_name: torch_trainer, pytest_max_batches: 2 }关键训练参数epochs训练轮数来自{NUM_TRAIN_EPOCHS}示例默认为 5batch_size32迭代器内部会按gradient_accumulation_steps折算有效 batchvalidation_patience3验证指标连续多少轮不提升则触发早停evaluation_targets[valid]在验证集上评估class_nametorch_trainer对应 torch_trainer.py 的实现。7.2 自定义早停指标module.submodules:function_name 引用多任务场景常需要自己定义综合早停指标。文档示例定义了一个两个任务的 AUC ROC 均值 NER F1 均值的复合指标from deeppavlov.metrics.roc_auc_score import roc_auc_score def roc_auc__roc_auc__ner_f1(true_onehot1, pred_probas1, true_onehot2, pred_probas2, ner_true3, ner_pred3): roc_auc1 roc_auc_score(true_onehot1, pred_probas1) roc_auc2 roc_auc_score(true_onehot2, pred_probas2) ner_f1_3 ner_f1(ner_true3, ner_pred3) / 100 return (roc_auc1 roc_auc2 ner_f1_3) / 3将上述代码保存为custom_metric.py即可在配置中按module.submodules:function_name格式引用custom_metric:roc_auc__roc_auc__ner_f1即文件名:函数名module.submodules:function_name形式。解析逻辑在 metrics_registry.pyfn_from_str用split(:)拆分出模块名与函数名再通过importlib.import_module动态导入。该复合指标在仓库中已有等价注册版本average__roc_auc__roc_auc__ner_f1见 fmeasure.py可作为参考实现。八、纯推理配置去掉训练字段多任务模型同样可以构建纯推理配置此时不再需要dataset_reader与dataset_iterator移除train字段移除管道中一切用于准备in_y的组件如simple_vocab的 fit 部分、proba2labels等仅训练期需要的后处理可按需保留multitask_transformer中省略所有训练参数学习率、优化器、gradient_accumulation_steps等。由于推理与训练共用同一组件定义load_path会加载训练好的 checkpoint输入侧只需按in顺序提供各任务的特征即可得到out中定义的多任务预测结果。九、进阶参考mt_glue 八任务配置与效果对比仓库还提供面向 GLUE 的 mt_glue.json它把 CoLA、SST-2、QQP、MRPC、RTE、MNLI、QNLI、STS-B 八个任务挂到同一个bert-base-uncased主干上metadata.variables中BACKBONE为bert-base-uncased、MODEL_PATH为~/.deeppavlov/models/glue/8task。与示例配置相比它展示了dataset_reader.tasks.mnli通过覆盖valid: validation_matched自定义验证集拆分全部任务使用统一的preprocessor: TorchTransformersPreprocessormax_seq_length: 128无需按任务拆分预处理器proba2labels用一次多参数调用同时处理 7 个分类任务的概率输出train.metrics中multitask_accuracy一次性接收 14 个输入7 个真值 7 个预测。文档附带了该配置与对应单任务配置在测试服务器上的效果对比数值以测试服务器结果为准任务总体CoLASST-2MRPCSTS-BQQPMNLI(m/mm)QNLIRTEAX指标serverMatthews CorrAccuracyF1/AccPearson/SpearmanF1/AccAccuracyAccuracyAccuracyMatthews Corr多任务配置77.843.693.288.6/84.284.3/84.070.1/87.983.0/82.690.675.435.4单任务配置77.653.692.787.7/83.684.4/83.170.5/88.984.4/83.290.363.436.3总体分数77.8 vs 77.6接近且多任务在部分任务SST-2、MRPC、QNLI、RTE上反超单任务——这正是共享主干带来的任务间知识迁移的直接体现同时单份 BERT 主干显著节省了显存占用。十、常见要点速查任务顺序一致性tasksreader、iterator、transformer 三处与in/in_y/out中的变量顺序必须逐一对应默认值合并reader 与 iterator 均遵循task_defaults提供默认、tasks补充或覆盖的规则use_task_defaults: false可让个别任务完全独立配置None 填充不等长数据集在 batch 元组中用None填充预处理器遇到全None的槽位会返回空列表跳过每步单任务默认每步只训练一个任务头MT-DNN 风格多个任务的梯度通过gradient_accumulation_steps控制更新节奏options 动态引用#vocab_conll.len这类#组件id.属性语法可在配置中引用管道内其他组件的属性例如让 NER 标签类别数由simple_vocab自动确定自定义指标以文件名:函数名module.submodules:function_name格式注册任意多任务复合指标用于早停训练/推理同配置multitask_transformer同时兼容训练与推理推理配置仅需删去数据读取、训练字段与in_y准备组件。延伸阅读多任务 reader 实现multitask_reader.py多任务 iterator 实现multitask_iterator.py多任务预处理器实现multitask_preprocessor.py多任务模型实现multitask_transformer.py示例配置multitask_example.jsonGLUE 多任务配置mt_glue.json指标注册表metrics_registry.json赞分享人工智能NLP深度学习【免费下载链接】DeepPavlovAn open source library for deep learning end-to-end dialog systems and chatbots.项目地址https://gitcode.com/gh_mirrors/de/DeepPavlov点击查看免费下载上一篇UIImageView-Letters入门教程3分钟实现个性化用户头像下一篇OpCore Simplify智能化解构黑苹果配置的技术革命创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考