You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用HuggingFace Transformers构建讽刺检测器时遇RuntimeError求助

问题:PyTorch Lightning训练讽刺检测器时出现梯度相关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),或者加载预训练模型时因配置问题默认冻结参数,会导致模型参数不需要梯度,反向传播时无法计算梯度。

修复步骤

  1. 修正标签维度
    将shared_step中的标签处理代码改为:

    label = batch["label"].squeeze()  # 把二维张量转为一维
    # 若原始标签已是一维,直接使用即可:label = batch["label"]
    

    确保label形状为(batch_size,),与logits的(batch_size, n_classes)形状匹配。

  2. 强制开启BERT参数的可训练状态
    在__init__方法末尾添加代码,确保BERT参数可训练:

    self.bert.train()
    self.bert.requires_grad_(True)
    
  3. 验证优化器覆盖的参数范围
    可在configure_optimizers中添加打印,确认优化器包含所有需要训练的参数:

    print(f"待优化参数总数: {sum(p.numel() for p in self.parameters() if p.requires_grad)}")
    

    若输出远小于BERT+分类器的总参数量,说明有参数被冻结。

内容的提问来源于stack exchange,提问作者lcoandrade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:17:38