尝试为 NER 微调 ReformerModelWithLMHead (google/reformer-enwik8) 时出错

Posted

技术标签:

【中文标题】尝试为 NER 微调 ReformerModelWithLMHead (google/reformer-enwik8) 时出错【英文标题】:Error while trying to fine-tune the ReformerModelWithLMHead (google/reformer-enwik8) for NER 【发布时间】:2021-10-14 23:10:09 【问题描述】:

我正在尝试为 NER 微调 ReformerModelWithLMHead (google/reformer-enwik8)。我使用了与编码方法相同的填充序列长度(max_length = max([len(string) for string in list_of_strings]))以及 attention_masks。我得到了这个错误:

ValueError:如果是训练,请确保 config.axis_pos_shape 因子:(128, 512) 乘以序列长度。得到 prod((128, 512)) != sequence_length: 2248。您可能需要考虑将序列长度填充为 65536 或更改 config.axis_pos_shape。

当我将序列长度更改为 65536 时,我的 colab 会话因获取长度为 65536 的所有输入而崩溃。 根据第二个选项(更改config.axis_pos_shape),我无法更改。

我想知道,是否有机会在微调模型时更改 config.axis_pos_shape ?或者我在为改革者-enwik8 编码输入字符串时遗漏了什么?

谢谢!

问题更新:我尝试了以下方法:

    通过在模型实例化时提供参数:

model = transformers.ReformerModelWithLMHead.from_pretrained("google/reformer-enwik8", num_labels=9, max_position_embeddings=1024,axial_pos_shape=[16,64],axial_pos_embds_dim=[32,96],hidden_​​size=128)

它给了我以下错误:

RuntimeError:为 ReformerModelWithLMHead 加载 state_dict 时出错: Reformer.embeddings.word_embeddings.weight 的大小不匹配:从检查点复制形状为 torch.Size([258, 1024]) 的参数,当前模型中的形状为 torch.Size([258, 128])。 Reformer.embeddings.position_embeddings.weights.0 的尺寸不匹配:从检查点复制形状为 torch.Size([128, 1, 256]) 的参数,当前模型中的形状为 torch.Size([16, 1, 32] )。

这是一个相当长的错误。

    然后我尝试了这段代码来更新配置:

model1 = transformers.ReformerModelWithLMHead.from_pretrained('google/reformer-enwik8', num_labels = 9)

重塑轴向位置嵌入层以匹配所需的最大序列长度

model1.reformer.embeddings.position_embeddings.weights[1] = torch.nn.Parameter(model1.reformer.embeddings.position_embeddings.weights[1][0][:128])

更新配置文件以匹配自定义最大序列长度

model1.config.axial_pos_shape = 16,128
model1.config.max_position_embeddings = 16*128 #2048
model1.config.axial_pos_embds_dim= 32,96
model1.config.hidden_size = 128
output_model_path = "model"
model1.save_pretrained(output_model_path)

通过这个实现,我收到了这个错误:

RuntimeError:张量 (512) 的扩展大小必须与非单维 2 处的现有大小 (128) 匹配。目标大小:[1, 128, 512, 768]。张量大小:[128, 768]

因为更新后的尺寸/形状与预训练模型的原始配置参数不匹配。原始参数为:axis_pos_shape = 128,512 max_position_embeddings = 128*512 #65536axial_pos_embds_dim= 256,768 hidden_​​size = 1024

这是我更改配置参数的正确方法还是我必须做其他事情?

有没有对 ReformerModelWithLMHead('google/reformer-enwik8') 模型进行微调的示例。

我的主要代码实现如下:

class REFORMER(torch.nn.Module):
def __init__(self):
    super(REFORMER, self).__init__()
    self.l1 = transformers.ReformerModelWithLMHead.from_pretrained("google/reformer-enwik8", num_labels=9)

def forward(self, input_ids, attention_masks, labels):
    output_1= self.l1(input_ids, attention_masks, labels = labels)
    return output_1


model = REFORMER()

def train(epoch):
    model.train()
    for _, data in enumerate(training_loader,0):
        ids = data['input_ids'][0]   # input_ids from encode method of the model https://huggingface.co/google/reformer-enwik8#:~:text=import%20torch%0A%0A%23%20Encoding-,def%20encode,-(list_of_strings%2C%20pad_token_id%3D0
        input_shape = ids.size()
        targets = data['tags']
        print("tags: ", targets, targets.size())
        least_common_mult_chunk_length = 65536 
        padding_length = least_common_mult_chunk_length - input_shape[-1] % least_common_mult_chunk_length
        #pad input 
        input_ids, inputs_embeds, attention_mask, position_ids, input_shape = _pad_to_mult_of_chunk_length(self=model.l1,
                input_ids=ids,
                inputs_embeds=None,
                attention_mask=None,
                position_ids=None,
                input_shape=input_shape,
                padding_length=padding_length,
                padded_seq_length=None,
                device=None,
            )
        outputs = model(input_ids, attention_mask, labels=targets) # sending inputs to the forward method
        print(outputs)
        loss = outputs.loss
        logits = outputs.logits
        if _%500==0:
           print(f'Epoch: epoch, Loss:  loss')

for epoch in range(1):
    train(epoch)

【问题讨论】:

您能否发布代码 sn-p 以获得最小可重现示例? @kkgarg,我已经用代码 sn-p 更新了我的问题。请查看 【参考方案1】:

首先,您应该注意google/reformer-enwik8 不是经过适当训练的语言模型,并且您可能无法通过微调获得良好的结果。 enwik8 是一个压缩挑战,the reformer authors 正是出于这个目的使用了这个数据集:

验证Reformer 确实可以将大型模型安装在单个 核心并在长序列上快速训练,我们训练高达 20 层的大 enwik8 和 imagenet64 上的改革者...

这也是他们没有训练子词分词器并在字符级别进行操作的原因。

您还应该注意,LMHead 通常用于预测序列的下一个标记 (CLM)。您可能想要使用令牌分类头(即使用编码器 ReformerModel 并在顶部添加一个具有 9 个类的线性层+可能是一个 dropout 层)。

不管怎样,如果你还想尝试一下,你可以做下面的事情来减少google/reformer-enwik8reformer的内存占用:

    在训练期间减少哈希数:
from transformers import ReformerConfig, ReformerModel
conf = ReformerConfig.from_pretrained('google/reformer-enwik8')
conf.num_hashes = 2 # or maybe even to 1
model = transformers.ReformerModel.from_pretrained("google/reformer-enwik8", config =conf)

微调模型后,您可以再次增加哈希数以提高性能(比较改革者论文的表 2)。

    替换轴向位置嵌入:
from transformers import ReformerConfig, ReformerModel
conf = ReformerConfig.from_pretrained('google/reformer-enwik8')
conf.axial_pos_embds = False 
model = transformers.ReformerModel.from_pretrained("google/reformer-enwik8", config =conf)

这会将学习到的轴向位置嵌入替换为像 Bert 那样的可学习位置嵌入,并且不需要 65536 的完整序列长度。它们未经训练且随机初始化(即考虑更长的训练时间)。

【讨论】:

【参考方案2】:

Reformer 模型由 Nikita Kitaev、Łukasz Kaiser、Anselm Levskaya 在论文 Reformer:The Efficient Transformer 中提出。 该论文包含一种分解巨大矩阵的方法,该方法是处理非常长的序列的结果!这种分解依赖于 2 个假设

    参数config.axial_pos_embds_dim 设置为元组(d1,d2),其总和必须等于config.hidden_​​size config.axial_pos_shape 设置为元组 (n1s,n2s) 其乘积必须等于 config.max_embedding_size (更多关于这些here!)

最后你的问题;)

我几乎可以肯定您的会话因内存溢出而崩溃 您可以在模型实例化期间更改任何配置参数,例如 official documentation!

【讨论】:

是的,我的 colab 会话由于 RAM 溢出而崩溃。正如建议的那样,我尝试以两种不同的方式更改预训练模型的配置参数,并在此基础上更新了我的问题。请再次查看我的问题。

以上是关于尝试为 NER 微调 ReformerModelWithLMHead (google/reformer-enwik8) 时出错的主要内容,如果未能解决你的问题,请参考以下文章

移除 UIRefreshControl 默认微调器

如何设置微调器下拉列表的最大长度?

为啥我的搜索栏随着微调器移动?

NLP系列1:NER

将 NER 训练数据转换为 Spacy 训练数据格式

为 SpaCy NER 格式化训练数据集