本文目录
这个小项目是关于文本分类的,文本分类作为机器学习、深度学习和自然语言处理(NLP)中的重要课题,也是最基础的应用,但是在这些领域中应用十分广泛,也可以作为许多AI任务的第一个基础步骤。比如目标检测:分类可以通过文本信息进行过滤判断是否为目标(0或1标签),缩小范围,再进一步通过图像等维度的信息确定。
接下来,这篇文章将总结的是文本分类的一个应用,属于二分类问题,检测新报道闻或文本描述是否是关于体育信息的内容。当然,这只是一个使用案例,对于检测其他关于分类的问题都是可以举一反三的。
2 开发环境
IDE: PyCharm Community
Python 3.6
tensorflow 1.14
其他配置如有需要,在下面会指出。
3 模型和算法
这个项目使用深度学习框架,具体是BERT预训练模型、全连接神经网络、Attention注意力机制。
3.1 BERT预训练模型
BERT全称是Bidirectional-Encoder-Representations-from-Transformers。看来这么长一个名字,会有一种复杂的感觉,确实BERT模型不是一下子就能理解的。
早在2019年,BERT就已经由Google AI提出,当时公布出来引起一片狂潮,其中发表的论文也是非常详细的介绍BERT的何去何从,有兴趣可以看看原论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》 。
这里我们也无需深究其实现原理,只需要知道它的应用场景。NLP领域的许多任务,直到现在,一些使用BERT作为预训练模型都达到前所未有的效果,可见BERT的强大。Google BERT预训练模型在深度学习、NLP领域的应用已经十分广泛了,在文本分类任务达到很好的效果。相比传统的词嵌入Word2vec、Golve,使用BERT预训练得到的效果有更好地提升。
3.2 全连接神经网络
各种神经网络都是基于全连接神经网络出发的,比如CNN、RNN、LSTM,最基础的原理都是由反向传播而来。其结构简化如下图。
3.3 注意力机制
注意力模型(Attention Model)已经成为神经网络中的一个重要概念,在人工智能(AI)领域,注意力已成为神经网络结构的重要组成部分,并在自然语言处理、统计学习、语音和计算机等领域有着大量的应用。
对于注意力的理解,可以类比我们通常所说的注意力:听课要集中注意力、注意这个知识点,等等。
所谓注意力模型就是,通过允许模型动态地关注有助于执行手头任务的输入的某些部分,将这种相关性概念结合起来。
4 数据集
数据集如下图,共有2000多条数据,由文本和标签组词,文本是一段描述性信息,标签是0或1,体育信息标记1,非体育信息标记0.
4.1 加载数据集
# 加载数据集合
with open("data/text.txt", "r", encoding="utf-8") as reader:
data = reader.read().splitlines()
4.2 数据预处理
texts = []
labels = []
for line in data:
# line = line.split(" ")
line = re.split("[" "\t]", line)
if len(line) == 2 and int(line[1]) < 2:
texts.append(line[0])
labels.append(line[1])
这里是二分类问题,但训练样本可能包含其他标签,所以进行简单的预处理,去掉label大于1的,并将文本和标签进行分离。
5 搭建模型
5.1 加载BERT配置
首先需要下载BERT预训练的模型,具体可参考这篇文章,里面写的很详细。
import tensorflow as tf
from bert import modeling
import sys
import create_input
import tokenization
import numpy as np
import logging
import re
def main():
bert_config = modeling.BertConfig.from_json_file("chinese_bert_chinese_wwm_L-12_H-768_A-12/bert_config.json")
vocab_file = "chinese_bert_chinese_wwm_L-12_H-768_A-12/vocab.txt"
batch_size = 10
num_labels = 2 # 类别数量,二分类
is_training = True
max_seq_length = 128
max_sentence = 25
iter_num = 10
lr = 0.00005
if max_seq_length > bert_config.max_position_embeddings: # 模型有个最大的输入长度 512
raise ValueError("超出模型最大长度")
5.2 创建BERT模型
tokenizer = tokenization.FullTokenizer(vocab_file=vocab_file) # token 处理器,主要作用就是 分字,将字转换成ID。vocab_file 字典文件路径
input_idsList = []
input_masksList = []
segment_idsList = []
for t in texts:
single_input_id, single_input_mask, single_segment_id = create_input.convert_single_example(max_seq_length,tokenizer, t)
input_idsList.append(single_input_id)
input_masksList.append(single_input_mask)
segment_idsList.append(single_segment_id)
input_idsList = np.asarray(input_idsList, dtype=np.int32)
input_masksList = np.asarray(input_masksList, dtype=np.int32)
segment_idsList = np.asarray(segment_idsList, dtype=np.int32)
labels = np.asarray(labels, dtype=np.int32)
# 创建bert的输入
input_ids = tf.placeholder(shape=[batch_size, max_seq_length], dtype=tf.int32, name="input_ids")
input_mask = tf.placeholder(shape=[batch_size, max_seq_length], dtype=tf.int32, name="input_mask")
segment_ids = tf.placeholder(shape=[batch_size, max_seq_length], dtype=tf.int32, name="segment_ids")
input_labels = tf.placeholder(shape=batch_size, dtype=tf.int32, name="input_ids")
# 创建bert模型
model = modeling.BertModel(
config=bert_config,
is_training=is_training,
input_ids=input_ids,
input_mask=input_mask,
token_type_ids=segment_ids,
use_one_hot_embeddings=False #使用CPU或GPU设置为False
)
output_layer = model.get_pooled_output() # 这个获取句子的output
hidden_size = output_layer.shape[-1].value # 获取输出的维度
创建BERT模型主要是将数据转化为BERT输入的格式,然后配置一下BERT的信息,把搭建BERT搭建起来,就是相当于以前使用Word2vec的词嵌入层一样。
5.3 搭建全连接神经网络
# 一个全连接
output_weights = tf.get_variable(
"output_weights", [num_labels, hidden_size],
initializer=tf.truncated_normal_initializer(stddev=0.02))
output_bias = tf.get_variable(
"output_bias", [num_labels], initializer=tf.zeros_initializer())
with tf.variable_scope("loss"):
if is_training:
output_layer = tf.nn.dropout(output_layer, keep_prob=0.9)
logits = tf.matmul(output_layer, output_weights, transpose_b=True)
logits = tf.nn.bias_add(logits, output_bias)
log_probs = tf.nn.log_softmax(logits, axis=-1)
one_hot_labels = tf.one_hot(input_labels, depth=num_labels, dtype=tf.float32)
per_example_loss = -tf.reduce_sum(one_hot_labels * log_probs, axis=-1)
loss = tf.reduce_mean(per_example_loss)
predict = tf.argmax(tf.nn.softmax(logits), axis=1, name="predictions")
acc = tf.reduce_mean(tf.cast(tf.equal(input_labels, tf.cast(predict, dtype=tf.int32)), "float"),
name="accuracy")
train_op = tf.train.AdamOptimizer(lr).minimize(loss)#优化器
这一层就是搭建神经网络,作用是神经网络对数据进行训练,计算loss、预测结果、计算准确率都在这里完成,然后这里使用Adam优化器,来最小化loss。
5.4 搭建模型
# bert模型参数初始化的地方
init_checkpoint = "chinese_bert_chinese_wwm_L-12_H-768_A-12/bert_model.ckpt"
use_tpu = False
# 获取模型中所有的训练参数。
tvars = tf.trainable_variables()
# 加载BERT模型
(assignment_map, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tvars,
init_checkpoint)
tf.train.init_from_checkpoint(init_checkpoint, assignment_map)
logger.info("**** Trainable Variables ****")
# 打印加载模型的参数
for var in tvars:
init_string = ""
if var.name in initialized_variable_names:
init_string = ", *INIT_FROM_CKPT*"
logger.info(" name = %s, shape = %s%s", var.name, var.shape, init_string)
pred = np.zeros(labels.shape[0])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(iter_num):
shuffIndex = np.random.permutation(np.arange(len(texts)))[:batch_size] # 随机生成np.arange(len(texts))维度
batch_labels = labels[shuffIndex]
batch_input_idsList = input_idsList[shuffIndex]
batch_input_masksList = input_masksList[shuffIndex]
batch_segment_idsList = segment_idsList[shuffIndex]
l, a, y_pre, _ = sess.run([loss, acc, predict, train_op], feed_dict={
input_ids: batch_input_idsList, input_mask: batch_input_masksList,
segment_ids: batch_segment_idsList, input_labels: batch_labels
})
logger.info("Epoch:{}/{},准确率:{},损失函数:{}".format(i + 1, iter_num, a, l))
logger.info(y_pre)
这一步骤就完成了所有网络层的拼接,从数据输入经过BERT预训练,得到转换后的信息,在输入到全连接神经网络,最后输出层得到结果。
这里可以将模型保存下来:
saver = tf.train.Saver()
saver.save(sess, save_path='.\\model\\model.ckpt', global_step=0)
然后就是main函数,开启我们的训练,看看分类结果怎么样。
if __name__ == '__main__':
main()
6 结果
训练的参数可以自行配置。
batch_size = 10
num_labels = 2 # 类别数量,二分类
is_training = True
max_seq_length = 128
max_sentence = 25
iter_num = 10
lr = 0.00005
我使用了batch_size = 10,根据电脑性能可以调整,性能好可以提高每个批次的训练数据。然后训练轮数是iter_num,这里进行10轮训练,结果如下:
可以看到效果真的不错,正确率可以达到90%以上,当然更多实验还需要进行验证。
本文首发古月居博客平台,如果觉得不错欢迎三连,点赞收藏关注,一起加油进步!原创作者:Charzous.
附录 1 部分日志信息
评论(0)
您还未登录,请登录后发表或查看评论