使用HuggingFace Transformers构建讽刺检测器时遇RuntimeError求助
在构建基于PyTorch Lightning和HuggingFace Transformers的讽刺检测器时,启动训练遇到如下错误:
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
以下是自定义的LightningModule代码:
class SarcasmTagger(pl.LightningModule): def __init__( self, model_name: str, n_classes: int, n_training_steps=None, n_warmup_steps=None ): super().__init__() self.bert = BertModel.from_pretrained(model_name, return_dict=True) #self.bert = BertForSequenceClassification.from_pretrained(model_name, return_dict=True) self.classifier = nn.Linear(self.bert.config.hidden_size, n_classes) self.n_training_steps = n_training_steps self.n_warmup_steps = n_warmup_steps def forward(self, input_ids, attention_mask): outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask) #print(outputs) logits = self.classifier(outputs.pooler_output) return logits def shared_step(self, batch, batch_idx): input_ids = batch["input_ids"] attention_mask = batch["attention_mask"] label = batch["label"].view(-1, 1) logits = self(input_ids=input_ids, attention_mask=attention_mask) loss = nn.functional.cross_entropy(logits, label) return logits, loss, label def training_step(self, batch, batch_idx): logits, loss, label = self.shared_step(batch, batch_idx) self.log("train_loss", loss, prog_bar=True, logger=True) return {"loss": loss, "predictions": logits, "label": label} def validation_step(self, batch, batch_idx): logits, loss, label = self.shared_step(batch, batch_idx) self.log("val_loss", loss, prog_bar=True, logger=True) return loss def test_step(self, batch, batch_idx): logits, loss, label = self.shared_step(batch, batch_idx) self.log("test_loss", loss, prog_bar=True, logger=True) return loss def configure_optimizers(self): optimizer = AdamW(self.parameters(), lr=2e-5) scheduler = get_linear_schedule_with_warmup( optimizer, num_warmup_steps=self.n_warmup_steps, num_training_steps=self.n_training_steps ) return dict( optimizer=optimizer, lr_scheduler=dict( scheduler=scheduler, interval='step') )
已知错误和反向传播相关,但代码中未手动调用detach,请问可能的原因是什么?
导致该错误的核心是计算传播链路被破坏,具体可能来自以下几点:
标签维度不匹配引发loss计算异常
在shared_step中,你将标签处理为label = batch["label"].view(-1, 1),变成了二维张量,但nn.functional.cross_entropy要求target是一维张量(形状为(batch_size,)),对应每个样本的类别索引。维度不匹配时,PyTorch内部的隐式转换会切断梯度传播链路,导致loss张量丢失grad_fn。BERT模型参数被意外冻结
虽然代码中没有手动冻结self.bert,但如果外部代码(比如数据集加载、训练器初始化环节)不小心设置了self.bert.requires_grad_(False),或者加载预训练模型时因配置问题默认冻结参数,会导致模型参数不需要梯度,反向传播时无法计算梯度。
修复步骤
修正标签维度
将shared_step中的标签处理代码改为:label = batch["label"].squeeze() # 把二维张量转为一维 # 若原始标签已是一维,直接使用即可:label = batch["label"]确保
label形状为(batch_size,),与logits的(batch_size, n_classes)形状匹配。强制开启BERT参数的可训练状态
在__init__方法末尾添加代码,确保BERT参数可训练:self.bert.train() self.bert.requires_grad_(True)验证优化器覆盖的参数范围
可在configure_optimizers中添加打印,确认优化器包含所有需要训练的参数:print(f"待优化参数总数: {sum(p.numel() for p in self.parameters() if p.requires_grad)}")若输出远小于BERT+分类器的总参数量,说明有参数被冻结。
内容的提问来源于stack exchange,提问作者lcoandrade

