【自然语言处理】情感分析(五):基于 BERT 实现

情感分析(五):基于 BERT 实现

本文是 情感分析 系列的第 5 5 5 篇,也是本系列的收官之作。前四篇分别是:

即使大家没用过 BERT(Bidirectional Encoder Representation from Transformers),相信对它在自然语言处理任务中的优越表现也早已有所耳闻。本篇博客将重点介绍 BERT 是如何助力情感分析的。工欲善其事必先利其器,在正式开始之前,先介绍几个要用到的包。

本文代码已上传至 我的GitHub,需要可自行下载。

1.相关包介绍

1.1 TensorFlow Official Models

TensorFlow Official Models 是使用 TensorFlow 高级 API 的模型集合。比如,它提供了多种 预训练语言模型(Pre-trained Language Model),如下表所示:

模型 参考(论文)
ALBERT ALBERT: A Lite BERT for Self-supervised Learning of Language Representations
BERT BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
ELECTRA ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators

安装时,TensorFlow Official Models 需要与 TensorFlow 的版本匹配。例如,TensorFlow-models v2.8.xTensorFlow v2.8.x 兼容。TensorFlow 的版本不低于 2.2,Python 版本 3.7+。更多安装详情请参阅官方文档。

pip install tf-models-official

1.2 TensorFlow Text

TensorFlow Text 为您提供一系列丰富的操作和库,帮助您处理文本形式的输入,例如原始文本字符串或文档。这些库可以执行基于文本的模型经常需要进行的预处理,并且包含对序列建模非常有用的其他功能。

pip install -U tensorflow-text==<version>

在这里插入图片描述
使用示例

import tensorflow as tf
import tensorflow_text as tf_text

def preprocess(vocab_table, example_text):

	# Normalize text
    tf_text.normalize_utf8(example_text)

    # Tokenize into words
    word_tokenizer = tf_text.WhitespaceTokenizer()
    tokens = word_tokenizer.tokenize(example_text)

    # Tokenize into subwords
    subword_tokenizer = tf_text.WordpieceTokenizer(lookup_table, token_out_type=tf.int64)
    subtokens = subword_tokenizer.tokenize(tokens).merge_dims(1, -1)

    # Apply padding
    padded_inputs = tf_text.pad_model_inputs(subtokens, max_seq_length=16)
    
    return padded_inputs

1.3 TensorFlow Hub

TensorFlow Hub 是一个包含经过训练的机器学习模型的代码库,这些模型稍作调整便可部署到任何设备上。您只需几行代码即可重复使用经过训练的模型,例如 BERT 和 Faster R-CNN。

pip install --upgrade tensorflow_hub

使用示例

nnlm-en-dim128:在英语 Google 新闻 200B 语料库上训练的基于标记的文本嵌入。

import tensorflow_hub as hub

model = hub.KerasLayer("https://tfhub.dev/google/nnlm-en-dim128/2")
embeddings = model(["The rain in Spain.", "falls","mainly", "In the plain!"])

print(embeddings.shape)  # (4,128)

2.基于 BERT 的情感分析实战

import os
import shutil

import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_text as text
from official.nlp import optimization  # to create AdamW optimizer

数据集:Large Movie Review Dataset

扫描二维码关注公众号,回复: 14933952 查看本文章

这是一个用于二元情感分类的数据集,包含比以前的基准数据集多得多的数据。我们提供了一组 25000 25000 25000 条极性电影评论用于训练, 25000 25000 25000 条用于测试,还有其他未标记的数据可供使用。提供了原始文本和已经处理过的词袋格式。

url = 'https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz'

dataset = tf.keras.utils.get_file('aclImdb_v1.tar.gz', url, untar=True, cache_dir='.', cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')

train_dir = os.path.join(dataset_dir, 'train')

# remove unused folders to make it easier to load the data
remove_dir = os.path.join(train_dir, 'unsup') # 解压缩后,会有一个 unsup 文件夹。因后续未用到,故删除之
shutil.rmtree(remove_dir) # 递归删除文件夹下的所有子文件夹和子文件

在这里插入图片描述
接下来,构造训练、验证、测试数据集。

tf.keras.utils.text_dataset_from_directory:从目录中的文本文件生成 tf.data.Dataset

  • batch_size:数据批次的大小,默认值为 32 32 32。如果为 None,则不会对数据进行批处理(数据集将产生单个样本)。
  • validation_split:介于 0 0 0 1 1 1 之间的可选浮点数,保留用于验证的数据部分。
  • subset:要返回的数据的子集。 “训练”、“验证” 或 “两者” 之一。仅在设置了 validation_split 时使用。当 subset=“both” 时,程序返回两个数据集(分别是训练和验证数据集)的元组。
AUTOTUNE = tf.data.AUTOTUNE # tf.data 运行时动态调整值
batch_size = 32
seed = 42

raw_train_ds = tf.keras.utils.text_dataset_from_directory('aclImdb/train', 
	batch_size=batch_size, validation_split=0.2, subset='training', seed=seed)

class_names = raw_train_ds.class_names

train_ds = raw_train_ds.cache().prefetch(buffer_size=AUTOTUNE)

val_ds = tf.keras.utils.text_dataset_from_directory('aclImdb/train',
    batch_size=batch_size, validation_split=0.2, subset='validation', seed=seed)

val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

test_ds = tf.keras.utils.text_dataset_from_directory('aclImdb/test', batch_size=batch_size)

test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)

在这里插入图片描述

tfhub_handle_preprocess = 'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3'
tfhub_handle_encoder = 'https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-512_A-8/1'

bert_en_uncased_preprocess:Text preprocessing for BERT.

small_bert/bert_en_uncased_L-4_H-512_A-8:Smaller BERT model.

def build_classifier_model():
    text_input = tf.keras.layers.Input(shape=(), dtype=tf.string, name='text')
    preprocessing_layer = hub.KerasLayer(tfhub_handle_preprocess, name='preprocessing')
    encoder_inputs = preprocessing_layer(text_input)
    encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True, name='BERT_encoder')
    outputs = encoder(encoder_inputs)
    net = outputs['pooled_output']
    net = tf.keras.layers.Dropout(0.1)(net)
    net = tf.keras.layers.Dense(1, activation=None, name='classifier')(net)
    return tf.keras.Model(text_input, net)

hub.KerasLayer:该层包装了一个可调用对象以用作 Keras 层。可调用对象可以直接传递,或者由带有传递给 hub.load() 的句柄的 Python 字符串指定。

classifier_model = build_classifier_model()
tf.keras.utils.plot_model(classifier_model)

在这里插入图片描述
tf.keras.losses.BinaryCrossentropy:计算真实标签和预测标签之间的交叉熵损失。

tf.keras.metrics.BinaryAccuracy:计算预测匹配二进制标签的频率。

loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)
metrics = tf.metrics.BinaryAccuracy()

tf.data.experimental.cardinality:返回数据集的基数(如果已知)。

epochs = 5
steps_per_epoch = tf.data.experimental.cardinality(train_ds).numpy()
num_train_steps = steps_per_epoch * epochs
num_warmup_steps = int(0.1*num_train_steps)
init_lr = 3e-5

optimizer = optimization.create_optimizer(init_lr=init_lr,
                                          num_train_steps=num_train_steps,
                                          num_warmup_steps=num_warmup_steps,
                                          optimizer_type='adamw')
classifier_model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
print(f'Training model with {
      
      tfhub_handle_encoder}')
history = classifier_model.fit(x=train_ds, validation_data=val_ds, epochs=epochs)

在这里插入图片描述

loss, accuracy = classifier_model.evaluate(test_ds)

print(f'Loss: {
      
      loss}')
print(f'Accuracy: {
      
      accuracy}')

在这里插入图片描述

def print_my_examples(inputs, results):
    result_for_printing = [f'input: {
      
      inputs[i]:<30} : score: {
      
      results[i][0]:.6f}' for i in range(len(inputs))]
    print(*result_for_printing, sep='\n')


examples = [
    'this is such an amazing movie!',  # this is the same sentence tried earlier
    'The movie was great!',
    'The movie was meh.',
    'The movie was okish.',
    'The movie was terrible...'
]

original_results = tf.sigmoid(classifier_model(tf.constant(examples)))

print('Results from the model in memory:')
print_my_examples(examples, original_results)

在这里插入图片描述


模型的准确度是 85 % 85\% 85% 左右,这是通过一个相对较小的 BERT 模型实现的。

猜你喜欢

转载自blog.csdn.net/be_racle/article/details/128783591