在自然语言处理(NLP)领域,BERT模型因其卓越的性能而广受欢迎。本文将探讨如何利用Hugging Face提供的Transformers库来简化BERT模型以及其他最先进模型的实现过程。使用TensorFlowHub实现BERT模型虽然可行,但过程繁琐,需要从零开始构建分词器、数据处理函数以及训练模型。而Hugging Face的Transformers库则提供了一种更为简便的方法,使得模型的加载和训练变得轻而易举。
Hugging Face是一个专注于NLP的初创公司,为TensorFlow和PyTorch提供了多种NLP解决方案。Transformers库包含了超过30种预训练模型和100种语言支持,覆盖了8种主要的自然语言理解(NLU)和自然语言生成(NLG)架构,如BERT、GPT-2、Transformer-XL等。使用该库,可以在几行代码内加载模型并进行训练,同时对数据进行预处理。这大大减少了对昂贵计算基础设施的需求,并简化了模型的实现过程。
本文使用的是情感数据集,该数据集包含了文本及其对应的情感标签,分为训练集、测试集和验证集。以下是如何使用Python代码加载和预处理这些数据的示例。
import pandas as pd
df_train = pd.read_csv('train.txt', header=None, sep=';', names=['Input', 'Sentiment'], encoding='utf-8')
df_test = pd.read_csv('test.txt', header=None, sep=';', names=['Input', 'Sentiment'], encoding='utf-8')
print(df_train.head())
print(df_test.head())
接下来,将情感标签映射为数字,并使用to_categorical
函数将整数编码的情感列转换为分类数据。
encoded_dict = {'anger': 0, 'fear': 1, 'joy': 2, 'love': 3, 'sadness': 4, 'surprise': 5}
df_train['Sentiment'] = df_train.Sentiment.map(encoded_dict)
df_test['Sentiment'] = df_train.Sentiment.map(encoded_dict)
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(df_train.Sentiment)
y_test = to_categorical(df_test.Sentiment)
要使用Transformers库,首先需要安装并导入它。然后,可以从库中加载预训练的BERT模型及其分词器。
!pip install transformers
import transformers
from transformers import AutoTokenizer, TFBertModel
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
bert = TFBertModel.from_pretrained('bert-base-cased')
分词器负责将输入文本的单词转换为令牌,而预训练的BERT模型则用于TensorFlow。这里加载的是bert-base-cased
模型。
在训练之前,需要使用分词器将输入文本数据转换为BERT的输入数据格式。由于已经加载了bert-base-cased
,因此分词器也将是Bert-base-cased
。
x_train = tokenizer(
text=df_train.Input.tolist(),
add_special_tokens=True,
max_length=70,
truncation=True,
padding=True,
return_tensors='tf',
return_token_type_ids=False,
return_attention_mask=True,
verbose=True)
x_test = tokenizer(
text=df_test.Input.tolist(),
add_special_tokens=True,
max_length=70,
truncation=True,
padding=True,
return_tensors='tf',
return_token_type_ids=False,
return_attention_mask=True,
verbose=True)
分词器接收所有必要的参数,并以BERT接受的格式返回张量。
接下来,将使用TensorFlow的functional API来设计模型。
import tensorflow as tf
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.initializers import TruncatedNormal
from tensorflow.keras.losses import CategoricalCrossentropy
from tensorflow.keras.metrics import CategoricalAccuracy
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Input, Dense
max_len = 70
input_ids = Input(shape=(max_len,), dtype=tf.int32, name="input_ids")
input_mask = Input(shape=(max_len,), dtype=tf.int32, name="attention_mask")
embeddings = bert(input_ids, attention_mask=input_mask)[0]
out = tf.keras.layers.GlobalMaxPool1D()(embeddings)
out = Dense(128, activation='relu')(out)
out = tf.keras.layers.Dropout(0.1)(out)
out = Dense(32, activation='relu')(out)
y = Dense(6, activation='sigmoid')(out)
model = tf.keras.Model(inputs=[input_ids, input_mask], outputs=y)
model.layers[2].trainable = True
BERT层接受三个输入数组:input_ids, attention_mask, token_type_ids。在本例中,不会传递token_type_ids。对于BERT层,需要两个输入层,即input_ids和attention_mask。Embeddings包含BERT层的隐藏状态。使用GlobalMaxPooling1D然后是密集层来构建CNN层,使用BERT的隐藏状态作为输出。
定义学习参数并编译模型。
optimizer = Adam(
learning_rate=5e-05, # 这个学习率是为BERT模型设置的,取自huggingface网站
epsilon=1e-08,
decay=0.01,
clipnorm=1.0)
# 设置损失和指标
loss = CategoricalCrossentropy(from_logits=True)
metric = CategoricalAccuracy('balanced_accuracy'),
# 编译模型
model.compile(
optimizer=optimizer,
loss=loss,
metrics=metric)
学习率为5e-05,显著低于常规值。损失函数使用CategoricalCrossentropy,因为目标数据是分类数据。平衡准确度将照顾到所有类别的平均准确度。
模型准备好后,可以使用x_train和y_train进行训练。训练和微调BERT模型需要一些时间,因此请耐心等待。
train_history = model.fit(
x={'input_ids': x_train['input_ids'], 'attention_mask': x_train['attention_mask']},
y=y_train,
validation_data=(
{'input_ids': x_test['input_ids'], 'attention_mask': x_test['attention_mask']}, y_test
),
epochs=1,
batch_size=36
)
model.fit返回一个历史对象,保存了所有的训练历史。x_test在预处理后变成了一个包含'input_ids', 'attention_mask'的字典。在训练中传递input_ids和attention_mask。在验证数据中,传递测试数据。
在测试数据上测试模型。
predicted_raw = model.predict({'input_ids': x_test['input_ids'], 'attention_mask': x_test['attention_mask']})
predicted_raw[0]
取最大概率值的索引。
y_predicted = np.argmax(predicted_raw, axis=1)
y_true = df_test.Sentiment
from sklearn.metrics import classification_report
print(classification_report(y_true, y_predicted))
太棒了!输出是准确的。
将索引转换回情感标签:
texts = input(str('输入文本'))
x_val = tokenizer(
text=texts,
add_special_tokens=True,
max_length=70,
truncation=True,
padding='max_length',
return_tensors='tf',
return_token_type_ids=False,
return_attention_mask=True,
verbose=True)
validation = model.predict({'input_ids': x_val['input_ids'], 'attention_mask': x_val['attention_mask']})*100
for key, value in zip(encoded_dict.keys(), validation[0]):
print(key, value)
在推理步骤中,需要将模型数据格式化为训练数据的相同格式,然后调用model.predict,它返回一个概率数组,然后找到最大机会的索引,并将其映射到情感标签,这将是输出。