Python Huggingface TFBertForSequenceClassification总是预测相同的标签

Python Huggingface TFBertForSequenceClassification总是预测相同的标签,python,tensorflow,bert-language-model,huggingface-transformers,Python,Tensorflow,Bert Language Model,Huggingface Transformers,TL;博士: 我的模型总是预测相同的标签,我不知道为什么。下面是我进行微调的全部代码,希望有人能向我指出哪里出了问题 我正在使用Huggingface的TFBertForSequenceClassification进行序列分类任务,以预测德语文本中的4个句子标签 我使用基于bert的德语大小写模式,因为我不使用小写文本(因为德语比英语更区分大小写) 我从一个csv文件中获取输入,该文件是我从收到的带注释的语料库中构建的。下面是一个例子: 0 Hier kommen wir ins S

TL;博士: 我的模型总是预测相同的标签,我不知道为什么。下面是我进行微调的全部代码,希望有人能向我指出哪里出了问题

我正在使用Huggingface的TFBertForSequenceClassification进行序列分类任务,以预测德语文本中的4个句子标签

我使用基于bert的德语大小写模式,因为我不使用小写文本(因为德语比英语更区分大小写)

我从一个csv文件中获取输入,该文件是我从收到的带注释的语料库中构建的。下面是一个例子:

0       Hier kommen wir ins Spiel Die App Cognitive At...
1       Doch wenn Athlet Lebron James jede einzelne Mu...
2       Wie kann ein Gehirn auf Hochleistung getrimmt ...
3       Wie schafft es Warren Buffett knapp 1000 Wörte...
4       Entfalte dein mentales Potenzial und werde ein...
Name: sentence_clean, Length: 3094, dtype: object
这些是我的标签,来自同一个csv文件:

0       e_1
1       e_4
2       e_4
3       e_4
4       e_4
不同的标签是:e_1、e_2、e_3和e_4

这是我用来微调模型的代码:

import pandas as pd
import numpy as np
import os
    
# read in data
# sentences_df = pd.read_csv('path/file.csv')


X = sentences_df.sentence_clean
Y = sentences_df.classId

# =============================================================================
# One hot encode labels
# =============================================================================

# integer encode labels
from numpy import array
from numpy import argmax
from sklearn.preprocessing import LabelEncoder


label_encoder = LabelEncoder()
Y_integer_encoded = label_encoder.fit_transform(list(Y))


# one hot encode labels
from sklearn.preprocessing import OneHotEncoder

onehot_encoder = OneHotEncoder(sparse=False)
Y_integer_encoded_reshaped = Y_integer_encoded.reshape(len(Y_integer_encoded), 1)
Y_one_hot_encoded = onehot_encoder.fit_transform(Y_integer_encoded_reshaped)

# train test split
from sklearn.model_selection import train_test_split


X_train_raw, X_test_raw, y_train, y_test = train_test_split(X, Y_one_hot_encoded, test_size=0.20, random_state=42)


# =============================================================================
# Perpare datasets for finetuning
# =============================================================================
import tensorflow as tf
physical_devices = tf.config.list_physical_devices('GPU') 
tf.config.experimental.set_memory_growth(physical_devices[0], True)

from transformers import BertTokenizer, TFBertForSequenceClassification


tokenizer = BertTokenizer.from_pretrained('bert-base-german-cased') # initialize tokenizer


# tokenize trai and test sets
max_seq_length = 128

X_train_tokens = tokenizer(list(X_train_raw),
                            truncation=True,
                            padding=True)

X_test_tokens = tokenizer(list(X_test_raw),
                            truncation=True,
                            padding=True)


# create TF datasets as input for BERT model
bert_train_ds = tf.data.Dataset.from_tensor_slices((
    dict(X_train_tokens),
    y_train
))

bert_test_ds = tf.data.Dataset.from_tensor_slices((
    dict(X_test_tokens),
    y_test
))

# =============================================================================
# setup model and finetune
# =============================================================================

# define hyperparams
num_labels = 4
learninge_rate = 2e-5
epochs = 3
batch_size = 16

# create BERT model
bert_categorical_partial = TFBertForSequenceClassification.from_pretrained('bert-base-german-cased', num_labels=num_labels)

optimizer = tf.keras.optimizers.Adam(learning_rate=learninge_rate)
bert_categorical_partial.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])

history = bert_categorical_partial.fit(bert_train_ds.shuffle(100).batch(batch_size),
          epochs=epochs,
          # batch_size=batch_size,
          validation_data=bert_test_ds.shuffle(100).batch(batch_size))
以下是微调的输出:

Epoch 1/3
155/155 [==============================] - 31s 198ms/step - loss: 8.3038 - accuracy: 0.2990 - val_loss: 8.7751 - val_accuracy: 0.2811
Epoch 2/3
155/155 [==============================] - 30s 196ms/step - loss: 8.2451 - accuracy: 0.2913 - val_loss: 8.9314 - val_accuracy: 0.2779
Epoch 3/3
155/155 [==============================] - 30s 196ms/step - loss: 8.3101 - accuracy: 0.2913 - val_loss: 9.0355 - val_accuracy: 0.2746
最后,我尝试预测测试集的标签,并使用混淆矩阵验证结果:

X_test_tokens_new = {'input_ids': np.asarray(X_test_tokens['input_ids']),
                     'token_type_ids': np.asarray(X_test_tokens['token_type_ids']),
                     'attention_mask': np.asarray(X_test_tokens['attention_mask']),
                     }

pred_raw = bert_categorical_partial.predict(X_test_tokens_new)
pred_proba = tf.nn.softmax(pred_raw).numpy()
pred = pred_proba[0].argmax(axis = 1)
y_true = y_test.argmax(axis = 1)

cm = confusion_matrix(y_true, pred)
打印输出(厘米):

正如你所看到的,我的准确性非常差,当我看cm时,我可以看到我的模型几乎只预测一个标签。 我已经尝试了所有的方法,并多次运行模型,但我总是得到相同的结果。 我知道我处理的数据不是很好,我只训练了大约2k个带标签的句子。但我有一种感觉,准确度应该更高,更重要的是,模型不应该只预测一个标签98%的时间,对吗

我发布了所有我用来运行模型的东西,希望有人能告诉我哪里出了问题。
非常感谢您的帮助

你训练了几分钟。这甚至对训练前的伯特来说都是不够的


试着降低学习速度,使你的准确度在每一个历元(前10个历元)后都有所提高。并训练更多的时间段(直到你看到10个时间段的验证准确度下降)。

为什么你在
Y
数据上执行
LabelEncoding
然后执行
onehotcoding
?标签是如何分布的(数据中有多少e1、e2、e3、e4)?你只训练了2000个句子中的465个步骤。我认为e4的数量是30%,所以模型更容易预测这个标签。尝试训练50个时代。@yudhiesh我需要将标签转换成数字格式,以便OneHotEncoder在这种情况下工作,因此我做了临时步骤。不过,一个热向量应该是正确的,我仔细检查了输出,它们与标签对齐(因此e_1位于位置0,e_2位于位置1,等等)@alxgal您每个历元都会训练所有数据。但你要循序渐进,每一步训练一批。历元的数量取决于可训练变量的数量和训练数据的数量。如果你的数据很小,你需要训练更多的时代。您的模型中有多少可训练变量?关于迁移学习的目的,你是对的。如果你从一开始就训练你的rmodel,那需要几个月的时间。使用迁移学习可能需要几个小时。但即使是在100万个样本上,也绝对不会在几分钟内完成TPU。@alxgal我建议降低学习速度,以便在每个历元(前10个历元)后提高精度,因此我完全按照您的评论这样做。我接受了50个时代的培训,学习率为1e-6。在第25纪元,我得到了41.2%的val精度,然后在第50纪元,它开始下降到5.01%。这是否意味着我应该只使用25个纪元来训练模型?@alxgal是的,您的数据太小,25个纪元后的模型拟合过度。但你可以进一步利用学习率。这是有道理的,但我还有一个问题要问你:当你说我的模型与数据拟合过度时,这难道不意味着我的训练准确率会很高(比如99%)吗?它也会降低到5%左右,所以训练和val的准确度总是在2%左右。@是的,通常你的训练准确度应该会提高。不到99%,但不应减少(在若干个时期后应保持稳定)。但神经网络优化了训练损失,而不是精度。理论上它可以减少,但训练损失不一定会减少。培训损失是如何表现的?损失通常相当高,鉴于数据集中的数据量很小,而且性能很差,我认为这是有道理的。损失从~5开始,然后在6和7.5之间徘徊,直到最后一个历元中达到7.34。是的,那是7.34,不是0.734。
array([[  0,   0,   0,  41],
       [  2,   0,   0, 253],
       [  2,   0,   0, 219],
       [  6,   0,   0,  96]], dtype=int64)