“Leveraging Pre-trained Checkpoints for Encoder-Decoder Models.ipynb”的副本

正在加载…
“Leveraging Pre-trained Checkpoints for Encoder-Decoder Models.ipynb”的副本
“Leveraging Pre-trained Checkpoints for Encoder-Decoder Models.ipynb”的副本_
目录
利用编码器-解码器模型的预训练语言模型检查点
介绍
BERT
GPT2
编码器-解码器
热启动编码器-解码器模型(理论)
回顾编码器-解码器模型
使用 BERT
的暖启动编码器-解码器 使用 BERT 和 GPT2
编码器-解码器权重共享的暖启动编码器-解码器
热启动编码器-解码器模型(分析)
实验
Sentence Fusion and -Splitting (DiscoFuse, WikiSplit)
机器翻译 (WMT14)
Summarization (CNN/Dailymail, BBC XSum, Gigaword)
结论
使用 🤗Transformers 热启动编码器-解码器模型(练习)
数据预处理
热启动编码器-解码器模型
微调热启动编码器-解码器模型
评估
利用编码器-解码器模型的预训练语言模型检查点
Vaswani 等人提出了基于 Transformer 的编码器-解码器模型。(2017)并且最近经历了兴趣激增,例如 Lewis 等人。(2019),拉菲尔等人。(2019),张等。(2020 年),Zaheer 等人。(2020),严等。(2020 年)。

与 BERT 和 GPT2 类似,大量预训练的编码器-解码器模型已证明可以显着提高各种序列到序列任务的性能Lewis 等人。(2019),拉菲尔等人。(2019)。然而,由于预训练编码器-解码器模型的计算成本巨大,此类模型的开发主要限于大型公司和机构。

在Leveraging Pre-trained Checkpoints for Sequence Generation Tasks (2020)中,Sascha Rothe、Shashi Narayan 和 Aliaksei Severyn 使用预训练的编码器和/或仅解码器检查点(例如BERT、GPT2)初始化编码器-解码器模型,以跳过代价高昂的预训练-训练。作者表明,这种热启动的编码器-解码器模型在多个序列到序列任务上以一小部分训练成本产生与大型预训练编码器-解码器模型(例如T5和Pegasus )具有竞争力的结果。

在本笔记本中,我们将详细解释编码器-解码器模型如何热启动,并根据Rothe 等人提供实用技巧。(2020),最后看一个完整的代码示例,展示如何使用 🤗Transformers 热启动编码器-解码器模型。

本笔记本分为4个部分:

简介- NLP 中预训练语言模型的简短摘要以及对热启动编码器-解码器模型的需求。
热启动编码器-解码器模型(理论) -关于如何热启动编码器-解码器模型的说明性解释?
热启动编码器-解码器模型(分析) -利用预训练检查点进行序列生成任务的总结(2020) - 哪些模型组合对热启动编码器-解码器模型有效;任务与任务有何不同?
使用 🤗Transformers (Practice) 热启动编码器-解码器模型-完整的代码示例,详细展示如何使用EncoderDecoderModel框架来热启动基于转换器的编码器-解码器模型。
强烈建议(甚至可能有必要)阅读这篇关于基于转换器的编码器-解码器模型的博客文章。

让我们首先介绍一些热启动编码器-解码器模型的背景知识。

介绍
最近,预训练的语言模型1彻底改变了自然语言处理(NLP)领域。

正如Dai 等人提出的,第一个预训练语言模型基于循环神经网络 (RNN) 。(2015 年)。戴等。al表明,在未标记的数据上预训练基于 RNN 的模型并随后进行微调2它在特定任务上比直接在此类任务上训练随机初始化模型产生更好的结果。然而,直到 2018 年,预训练的语言模型才被 NLP 广泛接受。Peters 等人的 ELMO。和霍华德等人的 ULMFit。是第一个预训练语言模型,可显着提高一系列自然语言理解 (NLU) 任务的最新技术水平。仅仅几个月后,OpenAI 和谷歌发布了基于转换器的预训练语言模型,被 Radford 等人称为 GPT。和Devlin 等人的 BERT。分别。基于变压器的效率提高基于 RNN 的语言模型允许 GPT2 和 BERT 在大量未标记的文本数据上进行预训练。经过预训练,BERT 和 GPT 被证明只需要很少的微调就可以打破十几个 NLU 任务的最先进结果3.

预训练的语言模型能够有效地将与任务无关的知识转换为特定于任务的知识,结果证明是 NLU 的一个很好的催化剂。工程师和研究人员以前必须从头开始训练语言模型,而现在公开可用的大型预训练语言模型的检查点可以在成本和时间的一小部分进行微调。这可以节省数百万的工业成本,并允许更快的原型设计和更好的研究基准。

预训练的语言模型已经在 NLU 任务上建立了一个新的性能水平,并且越来越多的研究建立在利用这种预训练的语言模型来改进 NLU 系统的基础上。然而,独立的 BERT 和 GPT 模型在序列到序列的任务中不太成功,例如 文本摘要、机器翻译、句子改述等。

序列到序列任务被定义为来自输入序列的映射X1 :n输出序列是1 :米先验未知的输出长度米. 因此,序列到序列模型应该定义输出序列的条件概率分布是1 :米以输入序列为条件X1 :n:

p一世模型(和1 :米| X1 :n).

不失一般性,输入词序列为n词在此由向量序列表示X1 :n= x1, … , xn和一个输出序列米词作为是1 :米=和1, … ,和米.

让我们看看 BERT 和 GPT2 如何适合对序列到序列的任务进行建模。

↳ 已隐藏 3 个单元格
热启动编码器-解码器模型(理论)
阅读介绍后,我们现在熟悉仅编码器和仅解码器模型。我们注意到编码器-解码器模型架构本质上是一个独立的编码器模型和一个独立的解码器模型的组合,这让我们想到了如何从独立的编码器-解码器模型中热启动的问题模型检查点。

热启动编码器-解码器模型有多种可能性。一罐

从仅编码器模型检查点(例如BERT)初始化编码器和解码器部分,
从仅编码器模型检查点(例如BERT)初始化编码器部分,从仅解码器检查点(例如GPT2)初始化解码器部分,
仅使用仅编码器模型检查点初始化编码器部分,或
仅使用仅解码器模型检查点初始化解码器部分。
在下文中,我们将重点放在可能性 1. 和 2. 上。 可能性 3. 和 4. 在理解了前两个之后是微不足道的。

↳ 已隐藏 4 个单元格
热启动编码器-解码器模型(分析)
在本节中,我们将总结有关热启动编码器-解码器模型的发现,如Sascha Rothe、Shashi Narayan 和 Aliaksei Severyn在利用预训练的检查点进行序列生成任务中提出的。作者比较了热启动编码器-解码器模型与随机初始化的编码器-解码器模型在多个序列到序列任务上的性能,特别是摘要、翻译、句子分割和句子融合。

更准确地说, BERT、RoBERTa和GPT2的公开可用的预训练检查点在不同的变体中被利用来热启动编码器-解码器模型。例如,BERT 初始化的编码器与 BERT 初始化的解码器配对产生 BERT2BERT 模型,或者RoBERTa 初始化的编码器与 GPT2 初始化的解码器配对产生RoBERTa2GPT2模型。此外,还研究了 RoBERTa(即 RoBERTaShare)和 BERT(即 BERTShare )共享编码器和解码器权重的效果(如上一节所述). 随机或部分随机初始化的编码器-解码器模型被用作基线,例如完全随机初始化的编码器-解码器模型,创造了Rnd2Rnd或与随机初始化的编码器配对的 BERT 初始化解码器,定义为Rnd2BERT。

下表显示了所有研究模型变体的完整列表,包括随机初始化权重的数量,即“随机”,以及从各个预训练检查点初始化的权重数量,即“杠杆”。所有模型都基于 12 层架构,具有 768 维隐藏大小的嵌入,对应于 🤗Transformers 模型中心中的bert-base-cased、bert-base-uncased、roberta-base和检查点。gpt2

模型 随机的 杠杆 全部的
Rnd2Rnd 221M 0 221M
Rnd2BERT 112M 109M 221M
BERT2Rnd 112M 109M 221M
Rnd2GPT2 114M 125M 238M
BERT2BERT 26M 195M 221M
BERTShare 26M 109M 135M
RoBERTaShare 26M 126M 152M
BERT2GPT2 26M 234M 260M
罗伯塔2GPT2 26M 250M 276M
基于 BERT2BERT 架构的模型Rnd2Rnd包含 221M 的权重参数——所有这些参数都是随机初始化的。其他两个“基于 BERT”的基线Rnd2BERT和BERT2Rnd大约有一半的权重,即112M 参数,随机初始化。其他 109M 权重参数分别来自bert-base-uncased编码器或解码器部分的预训练检查点。模型BERT2BERT、BERT2GPT2和RoBERTa2GPT2都利用了它们的所有编码器权重参数(分别来自 )和大多数解码器权重参数权重(来自bert-base-uncased、roberta-basegpt2bert-base-uncased分别)。对应于 12 个交叉注意力层的 26M 解码器权重参数因此被随机初始化。RoBERTa2GPT2 和 BERT2GPT2 与Rnd2GPT2基线进行了比较。此外,应该注意共享模型变体BERTShare和RoBERTaShare的参数显着减少,因为所有编码器权重参数都与各自的解码器权重参数共享。

↳ 已隐藏 5 个单元格
使用 🤗Transformers 热启动编码器-解码器模型(练习)
我们解释了热启动编码器-解码器模型的理论,分析了多个数据集的经验结果,并得出了实用的结论。现在让我们看一个完整的代码示例,展示如何热启动BERT2BERT模型,然后在CNN/Dailymail汇总任务上进行微调。我们将利用🤗datasets 和🤗Transformers 库。

此外,以下列表提供了此笔记本和其他笔记本的精简版本,用于热启动其他编码器-解码器模型组合。

对于CNN/Dailymail上的BERT2BERT (此笔记本的精简版),请单击此处。
对于BBC XSum上的RoBERTaShare ,请单击此处。
用于WMT14上的BERT2Rnd→德,点这里。
对于DiscoFuse上的RoBERTa2GPT2,请单击此处。
注意:本笔记本仅使用少量训练、验证和测试数据样本用于演示目的。要在完整的训练数据上微调编码器-解码器模型,用户应该相应地更改训练和数据预处理参数,如注释中突出显示的那样。

数据预处理
在本节中,我们将展示如何对数据进行预处理以进行训练。更重要的是,我们试图让读者对决定如何预处理数据的过程有所了解。

我们需要安装数据集和转换器。

[ ]
1
2
3
%%捕获
!pip install datasets== 1.0.2
!点安装变压器== 4.0.1
让我们从下载CNN/Dailymail数据集开始。

[ ]
1
2
导入 数据集
train_data = datasets.load_dataset( “cnn_dailymail” , “3.0.0” , split= “train” )

好的,让我们对数据集有一个第一印象。或者,也可以使用在线数据集查看器来可视化数据集。

[ ]
1
train_data.info.description

我们的输入称为文章,我们的标签称为亮点。现在让我们打印出训练数据的第一个例子来感受一下数据。

[ ]
1
2
3
4
5
6
7
8
9
10
import pandas as pd
from IPython.display import display, HTML
from datasets import ClassLabel

df = pd.DataFrame(train_data[:1])
del df[“id”]
for column, typ in train_data.features.items():
if isinstance(typ, ClassLabel):
df[column] = df[column].transform(lambda i: typ.names[i])
display(HTML(df.to_html()))

输入数据似乎由简短的新闻文章组成。有趣的是,标签似乎是类似项目符号的摘要。在这一点上,人们可能应该看看其他几个例子,以便更好地了解数据。

还应该注意到这里的文本是区分大小写的。这意味着如果我们想使用不区分大小写的模型,我们必须小心。由于CNN/Dailymail是一个摘要数据集,模型将使用ROUGE指标进行评估。检查🤗数据集中对ROUGE的描述,参见。 在这里,我们可以看到该指标是不区分大小写的,这意味着在评估过程中,大写字母将被标准化为小写字母。因此,我们可以安全地利用未加壳的检查点,例如bert-base-uncased.

凉爽的!接下来,让我们了解一下输入数据和标签的长度。

由于模型在token-length中计算长度,我们将使用bert-base-uncasedtokenizer 来计算文章和摘要长度。

首先,我们加载分词器。

[ ]
1
2
从 变压器 导入 BertTokenizerFast
标记器 = BertTokenizerFast.from_pretrained( “bert-base-uncased” )

接下来,我们利用.map()来计算文章的长度及其摘要。由于我们知道bert-base-uncased可以处理的最大长度为 512,因此我们还对输入样本长于最大长度的百分比感兴趣。同样,我们分别计算超过 64 和 128 的摘要的百分比。

我们可以.map()如下定义函数。

[ ]
1
2
3
4
5
6
7
8

map article and summary len to dict as well as if sample is longer than 512 tokens

def map_to_length(x):
x[“article_len”] = len(tokenizer(x[“article”]).input_ids)
x[“article_longer_512”] = int(x[“article_len”] > tokenizer.max_len)
x[“summary_len”] = len(tokenizer(x[“highlights”]).input_ids)
x[“summary_longer_64”] = int(x[“summary_len”] > 64)
x[“summary_longer_128”] = int(x[“summary_len”] > 128)
return x
查看前 10000 个样本就足够了。我们可以通过使用多个进程来加速映射num_proc=4。

[ ]
1
2
3
sample_size = 10000
data_stats = train_data.select(range(sample_size)).map(map_to_length, num_proc=4)

计算了前 10000 个样本的长度后,我们现在应该将它们平均在一起。为此,我们可以使用该.map()函数batched=True并batch_size=-1访问该.map()函数中的所有 10000 个样本。

[ ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def compute_and_print_stats ( x ): if len (x[ “article_len” ]) == sample_size: print ( “Article Mean: {}, %-Articles > 512:{}, Summary Me an:{}, %-Summary > 64 :{}, %-Summary > 128:{}” .format ( sum ( x [ “article_len” ]) / sample_size, sum (x[ “article_longer_512” ]) / sample_size, sum (x[ “summary_len” ]) /样本大小,总和(x[ “summary_longer_64” ])/样本大小,总和(x[ “summary_longer_128”]) / 样本大小,

    )
)

输出 = data_stats。映射(
compute_and_print_stats, batched
= True ,
batch_size= -1 ,

我们可以看到,一篇文章平均包含 848 个令牌,大约 3/4 的文章比模型的max_length512 长。摘要平均有 57 个标记。在我们的 10000 个样本摘要中,超过 30% 超过 64 个标记,但没有一个超过 128 个标记。

bert-base-cased仅限于 512 个令牌,这意味着我们将不得不从文章中删除可能重要的信息。因为大部分重要信息经常在文章的开头找到,并且因为我们希望计算效率更高,所以我们决定在这个笔记本中坚持bert-base-cased使用max_length512。这种选择不是最优的,但已显示在 CNN/Dailymail 上产生了良好的结果。或者,可以利用远程序列模型,例如Longformer用作编码器。

关于摘要长度,我们可以看到 128 的长度已经包含了所有摘要标签。128 很容易在 的范围内bert-base-cased,因此我们决定将生成限制为 128。

同样,我们将使用该.map()函数——这次将每个训练批次转换为一批模型输入。

“article"并且"highlights"分别被标记并准备为编码器"input_ids"和解码器"decoder_input_ids”。

"labels"自动向左移动以进行语言建模训练。

最后,记住忽略填充标签的丢失非常重要。在 🤗Transformers 中,这可以通过将标签设置为 -100 来完成。好的,那么让我们写下我们的映射函数。

[ ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
编码器最大长度= 512
解码器最大长度= 128

def process_data_to_model_inputs ( batch ): # 对输入和标签进行标记 输入 = tokenizer(batch[ “article” ], padding= “max_length” , truncation= True , max_length=encoder_max_length) outputs = tokenizer(batch[ “highlights” ], padding= “最大长度” ,截断=真,最大长度=解码器最大长度)

批次[ “input_ids” ]=inputs.input_ids
批次[ “attention_mask” ]=inputs.attention_mask
批次[ “decoder_input_ids” ] =outputs.input_ids批次
[ “decoder_attention_mask”] = outputs.attention_mask
批次[ “labels” ]=outputs.input_ids 。复制()

因为 BERT 会自动移动标签,所以标签与 decoder_input_ids 完全对应。 # 我们必须确保忽略 PAD 标记batch [ “labels” ] = [[ -100 if token == tokenizer.pad_token_id else token for token in labels] for labels in batch[ “labels” ]]

退货 批次
在此笔记本中,我们仅在几个训练示例上训练和评估模型以进行演示,并将其设置batch_size为 4 以防止内存不足问题。

以下行将训练数据减少到仅第一个32示例。该单元格可以被注释掉或不运行完整的训练运行。batch_size以 16的成绩获得了良好的结果。

[ ]
1
train_data = train_data.select(范围(32 ))
好的,让我们准备训练数据。

[ ]
1
2
3
4
5
6
7
8
9

batch_size = 16

batch_size= 4

训练数据 = 训练数据。映射(
process_data_to_model_inputs,
batched= True ,
batch_size=batch_size,
remove_columns=[ “article” , “highlights” , “id” ]

查看处理后的训练数据集,我们可以看到列名article、highlights和id已被EncoderDecoderModel.

[ ]
1
火车数据
数据集(特征:{‘attention_mask’:序列(feature=Value(dtype=‘int64’,id=None),长度=-1,id=None),‘decoder_attention_mask’:序列(feature=Value(dtype='int64 ', id=None), length=-1, id=None), ‘decoder_input_ids’: 序列(feature=Value(dtype=‘int64’, id=None), length=-1, id=None), 'input_ids ': 序列(feature=Value(dtype=‘int64’, id=None), length=-1, id=None), ‘labels’: Sequence(feature=Value(dtype=‘int64’, id=None),长度=-1, id=None)}, num_rows: 32)
到目前为止,数据是使用 Python 的List格式处理的。让我们将数据转换为 PyTorch 张量以在 GPU 上进行训练。

[ ]
1
2
3
train_data.set_format( type = “torch” , columns=[ “input_ids” , “attention_mask” , “decoder_input_ids” , “decoder_attention_mask” , “labels” ], )

棒棒哒,训练数据的数据处理就完成了。类似地,我们可以对验证数据做同样的事情。

首先,我们加载 10% 的验证数据集:

[ ]
1
val_data = datasets.load_dataset( “cnn_dailymail” , “3.0.0” , split= “validation[:10%]” )
重用数据集 cnn_dailymail (/root/.cache/huggingface/datasets/cnn_dailymail/3.0.0/3.0.0/0128610a44e10f25b4af6689441c72af86205282d26399642f7db38fa7535602)
出于演示目的,验证数据然后减少到只有 8 个样本,

[ ]
1
val_data = val_data.select(范围(8 ))
应用映射函数,

[ ]
1
2
3
4
5
6
val_data = val_data。映射(
process_data_to_model_inputs,
batched= True ,
batch_size=batch_size,
remove_columns=[ “article” , “highlights” , “id” ]

最后,验证数据也被转换为 PyTorch 张量。

[ ]
1
2
3
val_data.set_format( type = “torch” , columns=[ “input_ids” , “attention_mask” , “decoder_input_ids” , “decoder_attention_mask” , “labels” ], )

伟大的!现在我们可以开始热启动EncoderDecoderModel.

热启动编码器-解码器模型
本节介绍如何使用bert-base-cased检查点热启动编码器-解码器模型。

让我们从导入EncoderDecoderModel. 有关EncoderDecoderModel该类的更多详细信息,建议读者查看文档。

[ ]
1
从 变压器 导入 EncoderDecoderModel
与🤗Transformers 中的其他模型类相比,EncoderDecoderModel该类有两种加载预训练权重的方法,即:

“标准”.from_pretrained(…)方法是从通用PretrainedModel.from_pretrained(…)方法派生的,因此与其他模型类之一完全对应。该函数需要一个模型标识符,例如 .from_pretrained(“google/bert2bert_L-24_wmt_de_en”),并将一个.pt检查点文件加载到EncoderDecoderModel类中。

一种特殊的.from_encoder_decoder_pretrained(…)方法,可用于从两个模型标识符(一个用于编码器,一个用于解码器)热启动编码器-解码器模型。因此,第一个模型标识符用于加载编码器,via AutoModel.from_pretrained(…)(请参阅此处的文档),第二个模型标识符用于加载解码器(请参阅此处AutoModelForCausalLM的文档) 。

好的,让我们热启动我们的BERT2BERT模型。如前所述,我们将使用"bert-base-cased"检查点热启动编码器和解码器。

[ ]
1
bert2bert = EncoderDecoderModel.from_encoder_decoder_pretrained(“bert-base-uncased”, “bert-base-uncased”)

这一次,我们应该好好看看这里的警告。我们可以看到"cls"没有使用对应于一个层的两个权重。这应该不是问题,因为我们不需要 BERT 的 CLS 层来执行序列到序列的任务。此外,我们注意到很多权重是“新”或随机初始化的。当仔细观察时,这些权重都对应于交叉注意力层,这正是我们在阅读了上述理论后所期望的。

让我们仔细看看模型。

[ ]
1
bert2bert
EncoderDecoderModel(
(encoder): BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): Embedding(512, 768)
(token_type_embeddings): Embedding(2, 768)
(LayerNorm ) ): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(encoder): BertEncoder(
(layer): ModuleList(
(0): BertLayer(
(注意):BertAttention(
(自我):BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
)
(中间): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(输出): BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =False)
)
)
(1): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768) , out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =假)


(中间):BertIntermediate(
(密集):线性(in_features = 768,out_features = 3072,偏差= True)

(输出):BertOutput(
(密集):线性(in_features = 3072,out_features = 768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
2): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value ): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768 ,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False
)
)
(中级):BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
( LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(3): BertLayer(
(attention): BertAttention(
(self ) ):BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(4): BertLayer(
(attention): BertAttention(
( self):BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):线性(in_features=768 , out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features) =768, out_features=3072, bias=True)
)
(输出): BertOutput(
(dense): Linear(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e -12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
5): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features= 768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
( LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm(( 768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(6): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):Linear(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=真的)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
7): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias= True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace= False)
)
(输出): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(output): BertOutput(
(dense) : 线性(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(8): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询): Linear(in_features=768, out_features=768, bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
)
(中间): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(输出): BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =False)
)
)
(9): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768) , out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =假)


(中间):BertIntermediate(
(密集):线性(in_features = 768,out_features = 3072,偏差= True)

(输出):BertOutput(
(密集):线性(in_features = 3072,out_features = 768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
10): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value ): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768 ,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False
)
)
(中级):BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
( LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(11): BertLayer(
(attention): BertAttention(
(self ) ):BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
) (pooler
)
: BertPooler(
(dense): Linear (in_features=768, out_features=768, bias=True)
(activation): Tanh()
)
(
decoder): BertLMHeadModel(
(bert): BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): 嵌入(512, 768)
(token_type_embeddings): 嵌入(2, 768)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(encoder): BertEncoder(
(layer): ModuleList(
(0 ): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias= True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =False)
)
)
(crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias =True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =假)


(中间):BertIntermediate(
(密集):线性(in_features = 768,out_features = 3072,偏差= True)

(输出):BertOutput(
(密集):线性(in_features = 3072,out_features = 768,偏差=真)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False
)
)
(1): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features =768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
( value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features= 768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)

(中级):BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(2): BertLayer(
(attention): BertAttention(
(自我):BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
)
(crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
)
(中间): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout (p=0.1, inplace=False)
)
(
3): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key) :线性(in_features=768,out_features=768,bias=True)
(值):Linear(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
)
(crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features= 768,out_features=768,bias=True)
(值):线性(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(辍学): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(output): BertOutput(
(dense): Linear(in_features =3072,out_features=768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
4): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias= True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace= False)
)
(输出): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,偏差=True)
(键):线性(in_features=768,out_features=768,偏差=True)
(值):线性(in_features=768,out_features=768,偏差=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features) =768, out_features=3072, bias=True)
)
(输出): BertOutput(
(dense): Linear(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e -12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
5): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features= 768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
( LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features= 768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
( LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm(( 768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(6): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):Linear(in_features=768,out_features=768,bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =False)
)
)
(7): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768) , out_features=768, bias=True)
(值): 线性(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout (p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768 , out_features=768, bias=True)
(值): 线性(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout (p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(output): BertOutput(
(dense): Linear(in_features= 3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(8): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features= 768,bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear (in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key):线性(in_features=768,out_features=768,bias=True)
(值):线性(in_features=768,out_features=768,bias=True)
(dropout):Dropout(p=0.1,inplace=False)

(输出) : BertSelfOutput(
(dense): 线性(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(output): BertOutput(
(dense) : 线性(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(9): BertLayer(
(注意): BertAttention(
(自我): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):线性(in_features=768,out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm(( 768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):线性(in_features=768,out_features=768,bias=True)
(值):线性(in_features=768,out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm(( 768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm(( 768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(10): BertLayer(
(注意): BertAttention(
(self): BertSelfAttention(
(查询):线性(in_features=768,out_features=768,bias=True)
(键):Linear(in_features=768,out_features=768,bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features =768,bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(密集):线性(in_features=768,out_features=3072,bias=True)

(输出):BertOutput(
(密集):线性(in_features=3072,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout(p=0.1,inplace =False)
)
)
(11): BertLayer(
(attention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768) , out_features=768, bias=True)
(值): 线性(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout (p=0.1, inplace=False)
)
(
crossattention): BertAttention(
(self): BertSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768 , out_features=768, bias=True)
(值): 线性(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(输出):BertSelfOutput(
(密集):线性(in_features=768,out_features=768,bias=True)
(LayerNorm):LayerNorm((768,),eps=1e-12,elementwise_affine=True)
(dropout):Dropout (p=0.1, inplace=False)
)
(
intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
)
(output): BertOutput(
(dense): Linear(in_features= 3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
)
)
(cls): BertOnlyMLMHead(
(预测): BertLMPredictionHead(
(变换): BertPredictionHeadTransform(
(密集): 线性(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768, ), eps=1e-12, elementwise_affine=True)
)
(解码器): 线性(in_features=768, out_features=30522, bias=True
)
)
)
)
我们看到那是 的和的一个bert2bert.encoder实例。但是,这两个实例现在合并为一个,因此可以保存为单个检查点文件。BertModelbert2bert.decoderBertLMHeadModeltorch.nn.Module.pt

.save_pretrained(…)让我们使用标准方法进行尝试。

[ ]
1
bert2bert.save_pretrained(“bert2bert”)
同样,可以使用标准.from_pretrained(…)方法重新加载模型。

[ ]
1
bert2bert = EncoderDecoderModel.from_pretrained(“bert2bert”)
惊人的。让我们也检查一下配置。

[ ]
1
bert2bert.config
EncoderDecoderConfig {
“_name_or_path”:“bert2bert”,
“架构”:[
“EncoderDecoderModel”
],
“解码器”:{
“_name_or_path”:“bert-base-uncased”,
“add_cross_attention”:真,
“架构”:[
“BertForMaskedLM "
],
“attention_probs_dropout_prob”: 0.1,
“bad_words_ids”: null,
“bos_token_id”: null,
“chunk_size_feed_forward”: 0,
“decoder_start_token_id”: null,
“do_sample”: false,
“early_stopping”: false,
“eos_token_id”:null,
“finetuning_task”:null,
“gradient_checkpointing”:false,
“hidden_​​act”:“gelu”,
“hidden_​​dropout_prob”:0.1,
“hidden_​​size”:768,
“id2label”:{
“0”:“LABEL_0”,
“1”:“LABEL_1”
},
“initializer_range”:0.02,
“intermediate_size” “:3072,
“is_decoder”:真,
“is_encoder_decoder”:假,
“label2id”:{
“LABEL_0”:0,
“LABEL_1”:1
},
“layer_norm_eps”:1e-12,
“length_penalty”:1.0,
“max_length ": 20,
“max_position_embeddings”:512,
“min_length”:0,
“model_type”:“bert”,
“no_repeat_ngram_size”:0,
“num_attention_heads”:12,
“num_beams”:1,
“num_hidden_​​layers”:12,
“num_return_sequences”:1,
“output_attentions”:false,
“output_hidden_​​states”:false,
“pad_token_id”:0,
“prefix”:null,
“pruned_heads”:{},
“重复惩罚”:1.0,
“return_dict”:假,
“sep_token_id”:空,
“task_specific_params”:空,
“温度”:1.0,
“tie_encoder_decoder”:假,
“tie_word_embeddings”:真,
“tokenizer_class”:空,
“top_k” : 50,
“top_p”:1.0,
“torchscript”:假,
“type_vocab_size”:2,
“use_bfloat16”:假,
“use_cache”:真,
“vocab_size”:30522,
“xla_device”:空
},
“编码器”:{
“_name_or_path”:“bert-base-uncased”,
“add_cross_attention”:假,
“架构”:[
“BertForMaskedLM”
],
“attention_probs_dropout_prob”:0.1,
“bad_words_ids”:null,
“bos_token_id”:null,
“chunk_size_feed_forward”:0,
“decoder_start_token_id”:null,
“do_sample”:false,
“early_stopping”:false,
“eos_token_id”:null,
“finetuning_task”: null,
“gradient_checkpointing”: false,
“hidden_​​act”: “gelu”,
“hidden_​​dropout_prob”:0.1,
“hidden_​​size”:768,
“id2label”:{
“0”:“LABEL_0”,
“1”:“LABEL_1”
},
“initializer_range”:0.02,
“intermediate_size”:3072,
“is_decoder”:假,
“is_encoder_decoder”:假,
“label2id”:{
“LABEL_0”:0,
“LABEL_1”:1
},
“layer_norm_eps”:1e-12,
“length_penalty”:1.0,
“max_length”:20,
“max_position_embeddings”: 512,
“最小长度”:0,
“model_type”:“bert”,
“no_repeat_ngram_size”:0,
“num_attention_heads”:12,
“num_beams”:1,
“num_hidden_​​layers”:12,
“num_return_sequences”:1,
“output_attentions”:false,
“output_hidden_​​states”:false,
“pad_token_id”:0,
“prefix”:null,
“pruned_heads”:{},
“repetition_penalty”:1.0,
“ return_dict”:假,
“sep_token_id”:空,
“task_specific_params”:空,
“温度”:1.0,
“tie_encoder_decoder”:假,
“tie_word_embeddings”:真,
“tokenizer_class”:空,
“top_k”:50,
“top_p” : 1.0,
"torchscript”:假,
“type_vocab_size”:2,
“use_bfloat16”:假,
“use_cache”:真,
“vocab_size”:30522,
“xla_device”:空
},
“is_encoder_decoder”:真,
“model_type”:“encoder_decoder”
}
配置类似地由编码器配置和解码器配置组成,在我们的例子中,这两者都是实例BertConfig。但是,整体配置是类型EncoderDecoderConfig的,因此保存为单个.json文件。

总之,应该记住,一旦一个EncoderDecoderModel对象被实例化,它提供与🤗Transformers 中的任何其他编码器-解码器模型相同的功能,例如 BART、T5、ProphetNet ……唯一的区别是 anEncoderDecoderModel提供了额外的from_encoder_decoder_pretrained(…)功能,允许要从任何两个编码器和解码器检查点热启动的模型类。

附带说明一下,如果要创建共享的编码器-解码器模型,tie_encoder_decoder=True可以另外传递参数,如下所示:

[ ]
12
shared_bert2bert = EncoderDecoderModel.from_encoder_decoder_pretrained(“bert-base-cased”, “bert-base-cased”, tie_encoder_decoder=True)

作为比较,我们可以看到绑定模型的参数比预期的要少得多。

[ ]
1
print(f"\n\nNum Params. Shared: {shared_bert2bert.num_parameters()}, Non-Shared: {bert2bert.num_parameters()}")

数参数。共享:137298244,非共享:247363386
然而,在这个笔记本中,我们将训练一个非共享的 Bert2Bert模型,所以我们继续使用bert2bertand not shared_bert2bert。

[ ]
1
2

free memory

del shared_bert2bert
我们已经热启动了一个bert2bert模型,但我们还没有定义用于波束搜索解码的所有相关参数。

让我们从设置特殊标记开始。 bert-base-cased没有decoder_start_token_idor eos_token_id,所以我们将分别使用它的cls_token_idand sep_token_id。此外,我们应该pad_token_id在配置上定义 a 并确保设置正确vocab_size。

[ ]
1
2
3
4
bert2bert.config.decoder_start_token_id = tokenize r.cls_token_id
bert2bert.config.eos_token_id = tokenizer.sep_toke n_id
bert2bert.config.pad_token_id = tokenizer.pad_toke n_id

接下来,让我们定义与波束搜索解码相关的所有参数。由于bart-large-cnn在 CNN/Dailymail 上产生了很好的结果,我们将只复制它的波束搜索解码参数。

有关每个参数的作用的更多详细信息,请查看此博客文章或文档。

[ ]
1
2
3
4
5
6
bert2bert.config.max_length = 142
bert2bert.config.min_length = 56
bert2bert.config.no_repeat_ngram_size = 3
bert2bert.config.early_stopping = 真
bert2bert.config.length_penalty = 2.0
bert2bert.config.num_beams = 4
好的,现在让我们开始微调热启动的BERT2BERT模型。

微调热启动编码器-解码器模型
在本节中,我们将展示如何利用示例/seq2seq/seq2seq_trainer.pySeq2SeqTrainer下的文件来微调热启动的编码器-解码器模型。

让我们首先下载Seq2SeqTrainer及其训练参数Seq2SeqTrainingArguments。

[ ]
1
2
3
4
5
%%捕获
!rm seq2seq_trainer.py
!rm seq2seq_training_args.py
!wget https://raw.githubusercontent.com/huggingface/transformers/master/examples/seq2seq/seq2seq_trai ner.py !wget https://raw.githubusercontent.com/huggingface/transformers/master/examples/seq2seq/seq2seq_trai ning_args.py

此外,我们需要几个 python 包来完成这项Seq2SeqTrainer工作。

[ ]
1
2
3
4
%%捕获
!点安装 git-python== 1.0.3
!点安装 rouge_score
!pip install sacrebleu
好的,让我们导入Seq2SeqTrainer和Seq2SeqTrainingArguments。

[ ]
1
2
从 seq2seq_trainer 导入 Seq2SeqTrainer
从 seq2seq_training_args 导入 Seq2SeqTrainingArguments
扩展了Seq2SeqTrainer🤗Transformer’s Trainer 用于编码器-解码器模型。简而言之,它允许generate(…)在评估期间使用该函数,这对于验证编码器-解码器模型在大多数序列到序列任务(例如摘要)上的性能是必要的。

有关 的更多信息Trainer,应该通读这个简短的教程。

让我们从配置Seq2SeqTrainingArguments.

该参数predict_with_generate应设置为True,以便在验证数据上Seq2SeqTrainer运行并将生成的输出传递给我们稍后将定义的函数。额外的论点来自并且可以在这里阅读。对于完整的训练运行,应该根据需要更改这些参数。好的默认值在下面注释掉。generate(…)predictionscompute_metric(…)TrainingArguments

更多信息Seq2SeqTrainer,建议读者看一下代码。

[ ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
training_args = Seq2SeqTrainingArguments(
predict_with_generate= True ,
evaluation_strategy= “steps” ,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
fp16= True ,
output_dir= “./” ,
logging_steps= 2 ,
save_steps= 10 ,
eval_steps= 4 , #logging_steps= 10 # save_steps=500, #eval_steps=7500, #warmup_steps=2000, # save_total_limit=3, )

此外,我们需要定义一个函数来在验证期间正确计算 ROUGE 分数。由于我们激活predict_with_generate了 ,该compute_metrics(…)函数期望predictions使用该generate(…)函数获得。与大多数摘要任务一样,CNN/Dailymail 通常使用 ROUGE 分数进行评估。

让我们首先使用 🤗datasets 库加载 ROUGE 指标。

[ ]
1
胭脂= datasets.load_metric(“胭脂” )

接下来,我们将定义compute_metrics(…)函数。该rouge指标从两个字符串列表中计算得分。因此,我们解码predictions和labels- 确保-100正确替换为pad_token_id并通过设置删除所有特殊字符skip_special_tokens=True。

[ ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def compute_metrics ( pred ):
labels_ids = pred.label_ids
pred_ids = pred.predictions

pred_str = tokenizer.batch_decode(pred_ids, sk ip_special_tokens= True ) 
labels_ids[labels_ids ==  -100 ] = tokenizer.pad_token_id 
label_str = tokenizer.batch_decode(labels_ids,  skip_special_tokens= True )

rouge_output = rouge.compute(predictions=pred_str , references=label_str, rouge_types=[ "rouge2" ])[ "rouge2" ].mid

返回 { “rouge2_precision” : 圆形(rouge_output.precision,  4 ),“rouge2_recall” : 圆形(rouge_output.recall,  4 ),“rouge2_fmeasure” : 圆形(rouge_output.fmeasure,  4 ),    }

太好了,现在我们可以将所有参数传递给Seq2SeqTrainer并开始微调。执行以下单元将需要ca。10 分钟☕。

在完整的CNN/Dailymail训练数据上对BERT2BERT进行微调需要ca. 模型需要大约。在单个TITAN RTX GPU 上运行 8 小时。

[ ]
1
2
3
4
5
6
7
8
9

实例化 trainer

trainer = Seq2SeqTrainer(
model=bert2bert,
args=training_args,
compute_metrics=compute_metrics,
train_dataset=train_data,
eval_dataset=val_data,
)
trainer.train()

太棒了,我们现在应该可以对热启动的编码器-解码器模型进行微调了。为了检查我们微调的结果,让我们看一下保存的检查点。

[ ]
1
!ls
bert2bert checkpoint-20 运行 seq2seq_trainer.py
checkpoint-10 pycache sample_data seq2seq_training_args.py
EncoderDecoderModel.from_pretrained(…)最后,我们可以像往常一样通过该方法加载检查点。

[ ]
1
dummy_bert2bert = EncoderDecoderModel.from_pretrained ( “./checkpoint-20” )
评估
在最后一步,我们可能想要在测试数据上评估BERT2BERT模型。

首先,让我们加载一个在完整训练数据集上微调的BERT2BERT模型,而不是加载虚拟模型。另外,我们加载它的分词器,它只是一个分bert-base-cased词器的副本。

[ ]
1
2
3
4
从 变压器 导入 BertTokenizer

bert2bert = EncoderDecoderModel.from_pretrained( “patrickvonplaten/bert2bert_cnn_daily_mail” ).to( “cuda” )
tokenizer = BertTokenizer.from_pretrained( “patrickvonplaten/bert2bert_cnn_daily_mail” )

接下来,我们只加载CNN/Dailymail 的 2% 的测试数据。对于全面评估,显然应该使用 100% 的数据。

[ ]
1
test_data = datasets.load_dataset( “cnn_dailymail” , “3.0.0” , split= “test[:2%]” )
重用数据集 cnn_dailymail (/root/.cache/huggingface/datasets/cnn_dailymail/3.0.0/3.0.0/0128610a44e10f25b4af6689441c72af86205282d26399642f7db38fa7535602)
现在,我们可以再次利用🤗dataset 的便捷map()功能为每个测试样本生成摘要。

对于每个数据样本,我们:

首先,标记"article",
其次,生成输出令牌 ID,以及
第三,解码输出令牌 id 以获得我们的预测摘要。
[ ]
1
2
3
4
5
6
7
8
9
10
11
12
13
def generate_summary ( batch ): # 在 BERT 最大长度 512 处截断 输入 = tokenizer(batch[ “article” ], padding= “max_length” , truncation= True , max_length= 512 , return_tensors= “pt” ) input_ids = inputs.input_ids .to ( " cuda" ) attention_mask = inputs.attention_mask.to( “cuda” )

输出 = bert2bert.generate(input_ids, 注意ion_mask=attention_mask)

output_str = tokenizer.batch_decode(输出,s kip_special_tokens= True )

批处理[ “pred_summary” ] = output_str

退货 批次

让我们运行 map 函数来获取结果字典,该字典为每个样本存储了模型的预测摘要。执行以下单元可能需要ca。10 分钟☕。

[ ]
1
2
3
batch_size = 16 # change to 64 for full evaluation

results = test_data.map(generate_summary, batched=True, batch_size=batch_size, remove_columns=[“article”])

最后,我们计算 ROUGE 分数。

[ ]
1
rouge.compute(predictions=results[ “pred_summary” ],references=results[ “highlights” ],rouge_types=[ “rouge2” ])[ “rouge2” ] .mid
分数(精度=0.10389454113300968,召回=0.1564771201053348,fmeasure=0.12175271663717585)
而已。我们已经展示了如何热启动BERT2BERT模型并在 CNN/Dailymail 数据集上对其进行微调/评估。

完全训练的BERT2BERT模型上传到patrickvonplaten/bert2bert_cnn_daily_mail下的🤗model hub 。

该模型在完整的评估数据上达到了18.22的 ROUGE-2 分数,甚至比论文中报道的要好一点。

对于一些总结示例,建议读者使用模型的在线推理 API,此处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值