Nlp 精细调整分类:不是学习,为什么损失没有改变?权重没有更新?

Nlp 精细调整分类:不是学习,为什么损失没有改变?权重没有更新?,nlp,pytorch,text-classification,loss-function,huggingface-transformers,Nlp,Pytorch,Text Classification,Loss Function,Huggingface Transformers,我对PyTorch和Huggingface变形金刚比较陌生,并在这方面进行了蒸馏试验 [1608]运行损耗:0.689损耗:0.687 [11248]运行损耗:0.693损耗:0.694 [11988]运行损耗:0.693损耗:0.683 [1528]运行损耗:0.689损耗:0.701 [13168]运行损耗:0.690损耗:0.684 [13808]运行损耗:0.689损耗:0.688 [14448]运行损耗:0.689损耗:0.692等 不管我怎么做,损失从未减少,甚至没有增加,预测也没有

我对PyTorch和Huggingface变形金刚比较陌生,并在这方面进行了蒸馏试验

[1608]运行损耗:0.689损耗:0.687 [11248]运行损耗:0.693损耗:0.694 [11988]运行损耗:0.693损耗:0.683 [1528]运行损耗:0.689损耗:0.701 [13168]运行损耗:0.690损耗:0.684 [13808]运行损耗:0.689损耗:0.688 [14448]运行损耗:0.689损耗:0.692等

不管我怎么做,损失从未减少,甚至没有增加,预测也没有变好。在我看来,我忘记了一些东西,所以权重实际上没有更新。有人有主意吗? O

我尝试的

  • 不同的损失函数
    • BCE
    • 交叉熵
    • 偶均方误差损失
  • 一个热编码与单个神经元输出
  • 不同的学习速率和优化器
  • 我甚至把所有的目标都改成了一个标签,但即使这样,网络也没有融合

我想强调两个可能的原因来说明您的“稳定”结果:

  • 我同意学习率肯定太高了,这会阻止模型进行任何重大更新
  • 但重要的是要知道的是,根据最新的论文微调对变压器的核心NLP能力的影响非常小。例如,报告说,微调只应用非常小的权重变化。引用它:“微调几乎不会影响NEL、COREF和REL的准确性,这表明这些任务已经被预培训充分覆盖”。有几篇论文认为分类任务的微调基本上是浪费时间。因此,考虑到DistilBert实际上是BERT的一个学生模型,也许你不会得到更好的结果先用您的数据进行预训练。一般来说,预培训的影响更大

  • 查看运行损耗和小批量损耗很容易产生误导。你应该看看历元损失,因为每个损失的输入都是相同的

    此外,您的代码中存在一些问题,修复了所有这些问题,其行为如预期的那样:在每个历元之后,损失会慢慢减少,而且它也可能过度适合小批量。请查看代码,更改包括:使用
    model(x)
    而不是
    model.forward(x)
    cuda()
    只调用一次,学习率更低等

    调整和微调ML模型是一项困难的工作

    n_epochs = 5
    batch_size = 1
    
    bert_distil = DistilBertForSequenceClassification.from_pretrained('distilbert-base-uncased')
    tokenizer = DistilBertTokenizer.from_pretrained('distilbert-base-uncased')
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(bert_distil.parameters(), lr=1e-3)
    
    X_train = []
    Y_train = []
    for row in train_df.iterrows():
        seq = tokenizer.encode(row[1]['text'],  add_special_tokens=True, pad_to_max_length=True)[:100]
        X_train.append(torch.tensor(seq).unsqueeze(0))
        Y_train.append(torch.tensor([row[1]['target']]))
    X_train = torch.cat(X_train)
    Y_train = torch.cat(Y_train)
    
    running_loss = 0.0
    bert_distil.cuda()
    bert_distil.train(True)
    for epoch in range(n_epochs):
        permutation = torch.randperm(len(X_train))
        for i in range(0,len(X_train), batch_size):
            optimizer.zero_grad()
            indices = permutation[i:i+batch_size]
            batch_x, batch_y = X_train[indices].cuda(), Y_train[indices].cuda()
            outputs = bert_distil(batch_x)
            loss = criterion(outputs[0], batch_y)
            loss.backward()
            optimizer.step()
       
            running_loss += loss.item()  
    
        print('[%d] epoch loss: %.3f' %
          (epoch + 1, running_loss / len(X_train) * batch_size))
        running_loss = 0.0
    
    输出:

    [1] epoch loss: 0.695
    [2] epoch loss: 0.690
    [3] epoch loss: 0.687
    [4] epoch loss: 0.685
    [5] epoch loss: 0.684
    

    当我尝试使用
    xxxForSequenceClassification
    微调我的下游任务时,我遇到了类似的问题

    最后,我将
    xxxForSequenceClassification
    更改为
    xxxModel
    ,并添加了
    Dropout
    -
    FC
    -
    Softmax
    。奇迹般地解决了,损失如预期的那样减少了

    我还在努力找出原因

    希望它能帮助你


    仅供参考,transformers verion:3.5.0

    您的学习率太高了。试试像1e-4或1e-5这样的小一点的。是的,我试过了。我只是玩了一下学习率,看看有没有什么变化。。。但是,即使数据集中只有一个类,它似乎也没有学到任何东西……试着在单个批次上进行过度拟合。也与您的问题无关,但是:您不需要显式调用model.forward(),只需执行model(X);而且不需要做损耗。requires_grad=True。即使在单个批次上过度装配也不会改变任何东西,损耗保持在0.65左右,但变化与以前相同。。。非常感谢你的回答。这会中断一个错误:RuntimeError:张量的元素0不需要梯度,也没有梯度fn。知道在哪里需要修复吗?如果我不看你的代码,我不知道在哪里修复。你完全复制了上面的代码吗?错误提示某些张量的自动标记已关闭。谢谢您的回答。如上所述,我尝试了不同的学习率,所以这不是问题所在。我还没有尝试过预训练,但我想还有一个更实际的问题:即使数据集中只有一个标签,模型也不会收敛。。。
    [1] epoch loss: 0.695
    [2] epoch loss: 0.690
    [3] epoch loss: 0.687
    [4] epoch loss: 0.685
    [5] epoch loss: 0.684