这是 Data Mining 这门课的期末项目,主要记录一下中文文本的处理方式与 CNN 作用于文本特征的原理,网络训练调参和与其他模型的对比就不详细记录了。
数据集准备
使用的是中文对话情感分析的一个数据集。下载地址:z17176
这个是数据集是来自这篇 paper :Sentiment Classification with Convolutional Neural Networks: an Experimental Study on a Large-scale Chinese Conversation Corpus
- sentiment_XS_30k.txt:作为训练集
- sentiment_XS_test.txt:作为测试集
中文文本的预处理
分词处理
中文文本与英文文本不同,不像英文文本一样,单词与单词之间是有空隙的,所以拿到中文文本(已经去除掉标点符号及其他符号的纯文本)之后,需要进行分词处理。常用的分词工具有 jieba 分词。该数据集已经用 jieba
工具处理过分词了,所以就不需要额外处理了。
停用词处理
中文的停用词资源有挺多的,停用词处理主要依据不同的文本或者不同的目的来处理。我的项目中,没有进行停用词处理。
Tokenization
将输入文本拆分为有意义的块 (chunks) 的过程称为 Tokenization,并且这个被拆分出来的块实际上被称为令牌 (Token)。
- 可以认为在语义处理过程中一个 Token 就是一个有用的单元
- 可以划分为一个单词 (word),一个句子 (sentence),一个段落 (paragraph) 等等。
Tokenization 的过程就是建立一个词典或者词汇表的过程。将一个个单词转换成由整数组成的序列,每个整数都对应于词汇表中的一个索引值。Tokenization 之后,将序列处理成等长,这样后续就容易处理。
from keras.preprocessing.text import Tokenizer
from keras.preprocessing import sequence
# 建立一个 4000 个单词的词典
tokenizer = Tokenizer(num_words=4000)
tokenizer.fit_on_texts(X)
# 将每个文本转换成序列列表, 使用每个词的编号进行编码
x_train_seq = tokenizer.texts_to_sequences(X)
x_test_seq = tokenizer.texts_to_sequences(X_test)
# 将每个序列变成相同的长度,多的截断,不足补 0
seq = x_train_seq + x_test_seq
maxlen= np.max([len(i) for i in seq])
X_train = sequence.pad_sequences(x_train_seq, maxlen=maxlen)
X_test = sequence.pad_sequences(x_test_seq, maxlen=mexlen)
Word Embedding
后面将输入的 Token 序列转换成词嵌入矩阵,通常这个可以在搭建模型的时候处理,作为模型隐藏层的第一层,这时候就相当于自己训练一个词嵌入矩阵,也可以直接使用 Word2Vec 或者 GloVe 提供的词嵌入矩阵,相当于迁移学习了。但现在做的是中文文本的分类问题,所以迁移学习这个不合适。
# num_words 为前面设置的字典的长度,embed_size为词向量的长度
embed = Embedding(num_words, embed_size)
CNN 处理文本的过程
这时候就要贡献出经典的一张图了。如下图所示,CNN 处理文本的时候,输入就是一个为矩阵的句子,就像原先图像像素的输入一样,不过是单通道的。矩阵的每一行对应一个单词的 Token,通常是一个单词,但它可以是一个字符。也就是说,每行是表示单词的向量表示。通常,这些向量是词嵌入向量(低维表示),如 word2vec 或 GloVe,但它们也可以是将单词索引为词汇表的 one-hot 向量。
在计算机视觉中,滤波器会滑过图像的局部色块,但在 NLP 中,我们通常使用在矩阵的整行上滑动的滤波器。因此,滤波器的 “宽度” 通常与输入矩阵的宽度相同。高度或区域大小可以变化,通常可以一次滑动超过 2-5 个单词。
CNN 处理文本过程在这幅图中,使用了 3 种尺寸的滤波器([2, 3, 4]),每种尺寸包含两个滤波器,所以一共有 6 个滤波器,然后在输入矩阵上进行卷积操作,再使用非线性的激活函数,得到 6 个feature maps
,再进行最大池化操作,最后送入 softmax
层进行分类。
搭建 CNN 模型
def text_cnn(maxlen, max_features=4000, embed_size=100):
# Inputs
comment_seq = Input(shape=[maxlen])
# Embedding layer
emb_comment = Embedding(max_features, embed_size)(comment_seq)
# SpatialDropout1D layer for reduce overfitting
emb_comment = SpatialDropout1D(0.4)(emb_comment)
# Conv layers
convs = []
filter_sizes = [2, 3, 4, 5]
for fsz in filter_sizes:
l_conv = Conv1D(filters=100, kernel_size=fsz, activation='relu')(emb_comment)
l_pool = MaxPooling1D(maxlen - fsz + 1)(l_conv)
l_pool = Flatten()(l_pool)
convs.append(l_pool)
merge = concatenate(convs, axis=1)
out = Dropout(0.5)(merge)
output = Dense(32, activation='relu')(out)
output = Dense(units=1, activation='sigmoid')(output)
model = Model([comment_seq], output)
#adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
return model
测试模型
t = time.time()
model = text_cnn(maxlen=23)
batch_size = 64
epochs = 30
history = model.fit(X_train, y_train,
validation_split=0.1,
batch_size=batch_size,
epochs=epochs,
shuffle=True,
callbacks=[PlotLossesKeras()],verbose=1)
# Testing for test set
scores = model.evaluate(X_test, y_test)
print('Test set accuracy: ', str(round(scores[1],3)* 100) + '%')
print("It took", time.time() - t, "seconds to run the model.")
这里只给出了简单的初始模型,最后的训练的结果没有完全收敛。可以试试把学习率调小,这篇文章主要是学习中文文本的处理方法及 CNN 是如何作用于文本特征的。
参考
[1]. 使用Keras进行深度学习:(三)使用text-CNN处理自然语言(上)
[2]. How to Use Word Embedding Layers for Deep Learning with Keras
[3]. DNN/LSTM/Text-CNN情感分类实战与分析
[4]. Understanding how Convolutional Neural Network (CNN) perform text classification with word embeddings
网友评论