预训练BERT转为nn.Sequential后调用forward提示input_ids参数不识别如何解决
报错原因
nn.Sequential的forward方法设计仅支持位置参数传入,不接受关键字参数,你传递input_ids=xxx、attention_mask=xxx这类关键字参数自然会触发参数不匹配的报错。- 你调用
list(model_d.modules())[:-6]的逻辑本身存在严重错误:nn.Module.modules()方法会递归返回所有子模块,第一个返回的元素是model_d本身,后续会依次返回model_d.bert、model_d.bert.embeddings、model_d.bert.encoder等所有嵌套子模块,直接切片拿到的模块序列完全不是你想要的“倒数第6层及之前的BERT结构”,就算解决了参数问题也拿不到正确输出。
解决方法
推荐直接基于HuggingFace BERT原生的隐藏层输出能力自定义封装模型,不要硬拆模块,也不要用不适合多输入场景的nn.Sequential,实现代码如下:
自定义截断BERT类:
import torch import torch.nn as nn class TruncatedBERT(nn.Module): def __init__(self, original_model): super().__init__() # 直接复用原模型的BERT主干和Dropout层 self.bert = original_model.bert self.dropout = original_model.drop def forward(self, input_ids, attention_mask): # 开启所有隐藏层输出 bert_outputs = self.bert( input_ids=input_ids, attention_mask=attention_mask, output_hidden_states=True ) # hidden_states为从embedding到顶层encoder的所有输出,负索引直接取倒数第6层 target_output = bert_outputs.hidden_states[-6] # 可选择保留原有的Dropout逻辑,不需要可删除 target_output = self.dropout(target_output) return target_output
实例化和调用代码:
# 加载原模型 model_d = torch.load(f'{conf.save_path}/DeepPavlov/rubert-base-cased_2.pt', map_location=device) # 实例化截断后的BERT模型 newmodel_bert = TruncatedBERT(model_d) # 调用方式和原模型完全一致 output = newmodel_bert( input_ids = next(iter(train_data_loader))['input_ids'], attention_mask = next(iter(train_data_loader))['attention_mask'] )
如果需要冻结BERT主干参数不参与训练,可以在实例化后添加:
for param in newmodel_bert.bert.parameters(): param.requires_grad = False
内容的提问来源于stack exchange,提问作者BIG_BIT
相关产品推荐
相关产品推荐

