留言送书 | TensorFlow2.0 实战强化专栏(三):新闻文本分类

作者 | 小猴锅
出品 | 磐创AI团队

文本分类是自然语言处理中常见的一类任务,本项目使用的是清华大学提供的数据集“THUCNews”(
http://thuctc.thunlp.org/

),该数据集包含了14个类别的新浪新闻数据,具体类别和对应的样本数如表1所示

表1 THUCNews数据集的数据统计

官网下载的完整数据集大小有1.56G,文件数量较多,处理起来非常不方便,另外考虑到样本数量不平衡,我们在本项目中使用THUCNews的一个子数据集(下载地址:
https://pan.baidu.com/s/1v2r5J3zBVZml7MDch8xEFQ

)。该子数据集包含了表1所示的前10个类别的新闻数据,每个类别10000 条数据。

数据预处理

文本数据相对于图片数据来说,处理会相对繁琐一点,主要是文本数据需要进行Word Embedding,对于不同的数据来说,不同的Word Embedding方式可能对模型最终的效果影响也不同。

我们先定义一些基本的参数:

1  from collections import Counter
2 import tensorflow as tf
3 import os
4
5 DOCUMENTS = list()
6
7 class DataConfig:
8 # 词汇表路径
9 vocab_path = "./vocab.txt"
10 # 词汇表大小
11 vocab_size = 5000
12 # 待分类文本的最大长度
13 max_length = 200

第5行代码中我们定义了一个全局变量“DOCUMENTS”用来保存所有的数据。第7行代码我们定义了一个“DataConfig”类,这里的词汇表是根据我们的数据集来创建的,另外我们对待分类文本的长度也做了限制。创建词汇表的实现如下:

14  def build_vocab():
15 """根据数据集构建词汇表"""
16 all_data = []
17 for content in DOCUMENTS:
18 all_data.extend(content)
19
20 # 选出出现频率最高的前dict_size个字
21 counter = Counter(all_data)
22 count_pairs = counter.most_common(DataConfig.vocab_size - 1)
23 words, _ = list(zip(*count_pairs))
24 # 添加一个 作为填充字符
25 words = [''] + list(words)
26 # 保存词汇表
27 open(DataConfig.vocab_path, mode='w').write('\n'.join(words) + '\n')

为了简便,我们没有对文本进行分词,而是以字符的形式进行分割,词汇表里我们保存了数据集中出现频率最高的5000个字符。25行代码中我们在词汇表里添加了“”作为填充字符,由于我们限定了输入句子的长度,当输入句子的长度不够时使用“”作为填充。
接下来我们定义一个用来读取数据集文件的函数:

28  def read_file(dir_path):
29 global DOCUMENTS
30 # 列出当前目录下的所有子目录
31 dir_list = os.listdir(dir_path)
32 # 遍历所有子目录
33 for sub_dir in dir_list:
34 # 组合得到子目录的路径
35 child_dir = os.path.join('%s/%s' % (dir_path, sub_dir))
36 if os.path.isfile(child_dir):
37 # 获取当前目录下的数据文件
38 with open(child_dir, 'r') as file:
39 document = ''
40 lines = file.readlines()
41 for line in lines:
42 # 将文件内容组成一行,并去掉换行和空格等字符
43 document += line.strip()
44 DOCUMENTS.append(dir_path[dir_path.rfind('/')+1:] + "\t" + document)
45 else:
46 read_file(child_dir)

“read_file”函数用来将所有数据合在一起,并保存的全局变量“DOCUMENTS”中,接下来我们需要对读取的数据进一步处理成可以输入到模型中的数据:

47  def load_data(dir_path):
48 global DOCUMENTS
49 data_x = []
50 data_y = []
51
52 # 读取所有数据文件
53 read_file(dir_path)
54
55 # 读取词汇表,词汇表不存在时重新构建
56 if not os.path.exists(DataConfig.vocab_path):
57 build_vocab()
58
59 with open(DataConfig.vocab_path, 'r') as fp:
60 words = [_.strip() for _ in fp.readlines()]
61 word_to_id = dict(zip(words, range(len(words))))
62
63 # 构建类标
64 categories = ['科技', '股票', '体育', '娱乐', '时政',
65 '社会', '教育', '财经', '家居', '游戏']
66 cat_to_id = dict(zip(categories, range(len(categories))))
67
68 # contents, labels = read_file(data_path)
69 for document in DOCUMENTS:
70 y_, x_ = document.split("\t", 1)
71 data_x.append([word_to_id[x] for x in x_ if x in word_to_id])
72 data_y.append(cat_to_id[y_])
73
74 # 将文本pad为固定长度
75 data_x = tf.keras.preprocessing.sequence.pad_sequences(data_x, DataConfig.max_length)
76 # 将标签转换为one-hot表示
77 data_y = tf.keras.utils.to_categorical(data_y, num_classes=len(cat_to_id))
78
79 return data_x, data_y



“load_data”函数中我们对类标进行了“one-hot”编码,并将文本数据都替换为了id表示,后面我们会利用“tf.keras.layers.Embedding”将id表示的字符编码为向量。

模型搭建

首先导入需要的包:

1  import tensorflow as tf
2 import numpy as np
3 from data_processing import DataConfig
4 import datetime
5 from data_processing import load_data

定义模型:

6  def get_model():
7 model = tf.keras.Sequential()
8 model.add(tf.keras.layers.Embedding(DataConfig.vocab_size, 16))
9 # 使用LSTM的双向循环神经网络
10 model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(16)))
11 # 使用LSTM的单向循环神经网络
12 # model.add(tf.keras.layers.LSTM(16))
13 # 单向循环神经网络
14 # model.add(tf.keras.layers.GRU(16))
15 model.add(tf.keras.layers.Dropout(0.3))
16 model.add(tf.keras.layers.Dense(16, activation='relu'))
17 model.add(tf.keras.layers.Dense(10, activation='softmax'))
18
19 model.summary()
20 model.compile(optimizer='adam',
21 loss='categorical_crossentropy',
22 metrics=['accuracy'])
23 return model

第8行代码中添加了一个“Embedding”层,该层会根据我们输入模型中的数据训练词向量,并将id表示的词替换为词向量。
第9至14行代码中,我们给出了基于LSTM的双向循环神经网络、基于LSTM的单向循环神经网络以及GRU网络的实现,读者可以参照着进行修改,多尝试一些基本的循环神经网络模型。

模型训练

24  if __name__ == '__main__':
25 data_path = "./news_data"
26
27 train_x, train_y = load_data(data_path)
28
29 # 随机打乱数据集顺序
30 np.random.seed(116)
31 np.random.shuffle(train_x)
32 np.random.seed(116)
33 np.random.shuffle(train_y)
34
35 x_val = train_x[:10000]
36 partial_x_train = train_x[10000:]
37 y_val = train_y[:10000]
38 partial_y_train = train_y[10000:]
39
40 # 设置TensorBoard
41 log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
42 tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
43
44 model = get_model()
45 model.fit(partial_x_train, partial_y_train,
46 epochs=40, batch_size=512,
47 validation_data=(x_val, y_val),
48 verbose=1, callbacks=[tensorboard_callback])
训练结果如图7-6所示:

训练结果如图1所示:

图1 训练过程中
Accuracy和Loss的变化
(橙色为训练集,蓝色为验证集)
———— 完 ————
留言送书福利

为了感谢大家长期以来的支持
,磐创AI推出了“留言送书”活动~在本文文末
留言
即可参与活动,留言内容需为主题相关

。欢迎大家在日常推文中留言,以后将不定期推出 “留言送书”活动。

这次磐小仙精心挑选了本《Python自动化测试实战
》送给
2位粉丝

《Python自动化测试实战》
通过经验分享一些在自动化测试领域中的实用技术,能够帮助那些正在从事自动化测试相关工作或者准备转型自动化测试的测试人员。


/  今日留言主题 /

复工后的工作环境如何,心情如何?

本次“留言送书”活动将在2月19号20:00前抽
两位
 

留言粉丝
 

免费赠送
这本书籍。(注:会先对评论做筛选)。届时小仙会公布中奖者评论截图及福利领取方式~

还想看更多TensorFlow2.0
专栏文章?
可在公众号底部菜单栏子菜单“独家原创”中找到TensorFlow2.0
系列文章(如下图


同步更新中,关注公众号了解更多吧~


或点击下方“阅读原文”,进入TensorFlow2.0专栏,即可查看往期文章。