BERT HuggingFace 给出 NaN 损失

Posted

技术标签:

【中文标题】BERT HuggingFace 给出 NaN 损失【英文标题】:BERT HuggingFace gives NaN Loss 【发布时间】:2020-10-07 16:41:56 【问题描述】:

我正在尝试为文本分类任务微调 BERT,但我得到了 NaN 损失,无法弄清楚原因。

首先我定义一个 BERT 标记器,然后标记我的文本:

from transformers import DistilBertTokenizer, RobertaTokenizer
distil_bert = 'distilbert-base-uncased' 

tokenizer = DistilBertTokenizer.from_pretrained(distil_bert, do_lower_case=True, add_special_tokens=True,
                                                max_length=128, pad_to_max_length=True)

def tokenize(sentences, tokenizer):
    input_ids, input_masks, input_segments = [],[],[]
    for sentence in tqdm(sentences):
        inputs = tokenizer.encode_plus(sentence, add_special_tokens=True, max_length=25, pad_to_max_length=True, 
                                             return_attention_mask=True, return_token_type_ids=True)
        input_ids.append(inputs['input_ids'])
        input_masks.append(inputs['attention_mask'])
        input_segments.append(inputs['token_type_ids'])        

    return np.asarray(input_ids, dtype='int32'), np.asarray(input_masks, dtype='int32'), np.asarray(input_segments, dtype='int32')

train = pd.read_csv('train_dataset.csv')
d = train['text']
input_ids, input_masks, input_segments = tokenize(d, tokenizer)

接下来,我加载整数标签,它们是:0、1、2、3。

d_y = train['label']
0    0
1    1
2    0
3    2
4    0
5    0
6    0
7    0
8    3
9    1
Name: label, dtype: int64

然后我加载预训练的 Transformer 模型并在其上放置层。我在编译模型时使用了 SparseCategoricalCrossEntropy Loss:

from transformers import TFDistilBertForSequenceClassification, DistilBertConfig, AutoTokenizer, TFDistilBertModel

  distil_bert = 'distilbert-base-uncased'
  optimizer = tf.keras.optimizers.RMSprop(learning_rate=0.0000001)

  config = DistilBertConfig(num_labels=4, dropout=0.2, attention_dropout=0.2)
  config.output_hidden_states = False
  transformer_model = TFDistilBertModel.from_pretrained(distil_bert, config = config)

  input_ids_in = tf.keras.layers.Input(shape=(25,), name='input_token', dtype='int32')
  input_masks_in = tf.keras.layers.Input(shape=(25,), name='masked_token', dtype='int32') 

  embedding_layer = transformer_model(input_ids_in, attention_mask=input_masks_in)[0]
  X = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(50, return_sequences=True, dropout=0.1, recurrent_dropout=0.1))(embedding_layer)
  X = tf.keras.layers.GlobalMaxPool1D()(X)
  X = tf.keras.layers.Dense(50, activation='relu')(X)
  X = tf.keras.layers.Dropout(0.2)(X)
  X = tf.keras.layers.Dense(4, activation='softmax')(X)
  model = tf.keras.Model(inputs=[input_ids_in, input_masks_in], outputs = X)

  for layer in model.layers[:3]:
    layer.trainable = False

  model.compile(optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['sparse_categorical_accuracy'],
    )

最后,我使用之前标记化的 input_ids 和 input_masks 作为模型的输入来运行模型,并在第一个 epoch 后获得 NAN Loss:

model.fit(x=[input_ids, input_masks], y = d_y, epochs=3)

    Epoch 1/3
20/20 [==============================] - 4s 182ms/step - loss: 0.9714 - sparse_categorical_accuracy: 0.6153
Epoch 2/3
20/20 [==============================] - 0s 19ms/step - loss: nan - sparse_categorical_accuracy: 0.5714
Epoch 3/3
20/20 [==============================] - 0s 20ms/step - loss: nan - sparse_categorical_accuracy: 0.5714
<tensorflow.python.keras.callbacks.History at 0x7fee0e220f60>

编辑:模型在第一个 epoch 计算损失,但它开始返回 NaN 在第二个纪元。是什么导致了这个问题???

有人对我做错了什么有任何想法吗? 欢迎所有建议!

【问题讨论】:

这个答案可能会有所帮助:=> ***.com/a/40434284/8405902 我看过它并没有真正帮助 @beginner 你解决了吗?我面临同样的问题。 【参考方案1】:

问题出在这里:

X = tf.keras.layers.Dense(1, activation='softmax')(X)

在网络的末端,你只有一个神经元,对应一个类。 0 类的输出概率始终为 100%。如果您有 0、1、2、3 类,则最后需要有 4 个输出

【讨论】:

我已将其更改为 4 个输出,但问题似乎仍然存在。 它计算第一个时期的损失,但从第二个时期开始,以后的损失是 NaN。 现在的代码 sn-p 看起来不错。获得 nans 的最常见原因是除以零。它可能来自数据,例如,您可能将掩码设置为全零。【参考方案2】:

我还建议在使用数据集进行训练和评估之前从 pandas 数据框中删除 NA 值。

train = pd.read_csv('train_dataset.csv')
d = train['text']
d = d.dropna()

【讨论】:

【参考方案3】:

由于未指定num_labels而出现问题

在最终输出层,默认 K = 1(标签数),如前所述 \sigma(\vecz)_i=\frace^z_i\sum_j=1^K e^z_j

因此,在进行多类分类时,我们需要在微调时提供 num_labels。

model = TFBertForSequenceClassification.from_pretrained('bert-base-cased', num_labels=5)

【讨论】:

【参考方案4】:

我有一个类似的问题,我的模型仅在一个时期的最后一批产生 NaN 损失。所有其他批次均产生典型的损失值。就我而言,问题在于批次的大小并不总是相等。因此,该模型产生了 NaN 损失。在我使所有批次的大小相同之后,NaN 就消失了。如果您的情况也是如此,可能也值得调查。

【讨论】:

以上是关于BERT HuggingFace 给出 NaN 损失的主要内容,如果未能解决你的问题,请参考以下文章

通过 Huggingface 转换器更新 BERT 模型

如何微调 HuggingFace BERT 模型以进行文本分类 [关闭]

如何在 HuggingFace Transformers 库中获取中间层的预训练 BERT 模型输出?

Huggingface Bert:输出打印

huggingface-transformers:训练 BERT 并使用不同的注意力对其进行评估

基于 BERT 的 NER 模型在反序列化时给出不一致的预测