TextCNN文本分类(keras实现)
目录
前言:
一、论文笔记
二、Keras文本预处理
1、读取数据集
2、将文字转换成数字特征
3、将每条文本转换为数字列表
4、将每条文本设置为相同长度
5、将每个词编码转换为词向量
6、Keras文本预处理代码实现
三、基于keras的TextCNN模型的构建、训练与测试
1、基础版CNN(模仿LeNet-5)
2、简单版TextCNN
3、使用Word2Vec词向量的TextCNN
四、绘制TextCNN模型结构图
1、环境配置
2、绘制模型图
五、keras模型的保存与加载
前言:
深度学习模型在计算机视觉和语音识别领域展现出了显著的能力,在自然语言处理领域同样表现出色。将卷积神经网络应用于文本分类任务,通过使用不同尺寸的核来提取句子中的关键信息(类似于n-gram的关键信息),从而更有效地捕捉到局部的相关性。
自然语言处理领域中,文本分类问题因其显著的研究热度而备受关注。工业界对文本分类技术的应用场景极为广泛,在新闻资讯的类型划分、商品评价情感分析以及社交媒体上的内容标签辅助推荐等多个方面均有应用。对于刚开始学习自然语言处理的人员而言,在理论研究与实际应用之间找到平衡点是一项较为理想的学习路径。这项技术不仅操作相对简单而且其应用场景也非常高频。
一、论文笔记
Kim在2014年发表于《Convolutional Neural Networks for Sentence Classification》一文中提出了基于卷积神经网络的文本分类方法(该论文翻译)。


上图生动地展示了模型的整体架构。考虑给定一组待分类的句子,请注意其中每个词都是由n维词向量构成的;因此输入矩阵的规模设定为m*n ,其中m代表句子长度。卷积网络对输入样本执行卷积操作,在文本处理中滤波器并非横向滑动而是垂直向下移动(类似于N-gram提取局部相关性)。该图列出了三种不同的步长策略:2、3、4步长;每种步长配置下均配置两个滤波器(实际训练时滤波器数量会显著增加)。在不同窗口大小下应用不同滤波器后将产生6个卷积后的向量特征;随后对每个特征向量实施最大值池化操作并整合各池化结果最终生成该句的表征向量;将此向量传递至分类器完成识别任务。
(1)嵌入层(Embedding Layer)
通过一个隐藏层, 将 one-hot 编码的词映射到一个低维空间 中。本质上是一个特征提取器,在特定维度中编码语义特征。这样, 语义相似的词, 它们的欧氏距离或余弦相似度也比较接近。(作者所采用的单词向量来源于预训练模型;具体而言, 该方法使用 fasttext 生成了相应的单词向量; 当然在这一技术之外还有其他可供选择的方法如 word2vec 和 GloVe 等)
(2)卷积层(Convolution Laye)
在图像数据处理中使用CNN时,
其滤镜尺寸相同,
但在text-CNN中,
滤镜宽度必须等于词嵌入空间维数!
这是因为输入每一行为单词,
而在特征提取过程中,
每个单词被视为最小单位。
同样支持自己设定参数(通常选择2到5之间),
这种设置方式下,
滤镜的高度相当于n-gram模型的概念。
由于输入是一段连续的文字序列,
其中词语之间关系紧密,
因此利用滤镜操作不仅捕捉到了词语的意义
还考虑了顺序信息及其上下文关系(类似于skip-gram和CBOW的思想)。
(3)池化层(Pooling Layer)
由于在卷积层操作中我们采用了不同高度的小核来处理图像信息 从而使得各特征向量经卷积操作后的维度存在差异 因此 在池化过程中的每个特征向量 我们采用1-max pooling方法将每个特征向量映射为单个数值 这一过程实际上是提取各特征子带中的最大响应作为表征 并认为这个最大响应值能够充分反映该空间位置的重要特性 经过上述处理后 将所有这些最大响应值进行拼接汇总形成最终表征向量 这种全局表征信息能够有效捕捉图像的关键特性 为了防止模型发生过拟合 在此阶段通常会引入Dropout机制进行正则化处理
(4)全连接层(Fully connected layer)
全连接层与其它模型一致,在设定拥有两个全连接层的情况下,在第一层可采用relu作为激活函数,在第二层则选用softmax激活函数以计算出各类别的概率值
(5)TextCNN的小变种
在词向量构建方面存在多种不同的方案:CNN-rand 是指每个单词的词向量均采用随机初始化的方式,并通过后续的训练过程逐步进行优化调整;CNN-static 则基于已有的预训练词向量(如word2vec模型生成的结果),这些固定的词向量仅在主模型中被使用而不参与进一步微调;而CNN-non-static 则是在利用预训练基础之上,在主模型中进一步允许这些初始权重进行更新和优化;此外还有CNN-multichannel 模型,在这种架构下会将static与non-static两类情况分别作为独立的学习通道进行处理。
(6)参数与超参数
在CNN中, 输入和输出具有固定的长度, 但每个句子的长度可能不同。如何处理这种情况?在模型中使用低维嵌入时, 将原始词汇表 |D| 的维度降到 embedding_dim。
考虑词汇量时, 我们将其记为|D|. 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别; 多分类问题可划分为多个类别;
2、2015年《"A Sensitivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classification"》一文对TextCNN模型的调参经验进行了深入分析,并提供了宝贵的实践经验。

(1)TextCNN详细过程:
- Embedding :第一层是图中最左边的7乘5的句子矩阵,每行是词向量,维度=5,这个可以类比为图像中的原始像素点。
- Convolution :然后经过 kernel_sizes=(2,3,4) 的一维卷积层,每个kernel_size 有两个输出 channel。
- MaxPolling :第三层是一个1-max pooling层,这样不同长度句子经过pooling层之后都能变成定长的表示。
- FullConnection and Softmax :最后接一层全连接的 softmax 层,输出每个类别的概率。
(2)论文调参结论:
- 采用预训练的word2vec和GloVe词向量进行初始化效果会更佳,在实际应用中通常不直接采用One-hot编码。
- 卷积核尺寸的影响较为显著,在具体应用中通常取值范围为1至10;当处理较长文本时,则建议选择较大的尺寸。
- 卷积核数量也会对模型性能产生显著影响,在具体实现中通常选取100至600的数量;同时建议配合Dropout机制(范围在[O, 0.5]之间)进行正则化处理。
- 激活函数通常会选择ReLU和tanh两种激活函数。
- 池化操作通常采用1-max pooling的方式。
- 当feature map数量增多导致性能下降时,则尝试适当增加Dropout比例(大于O.5)。
- 在评估模型性能时,请确保采用交叉验证方法进行评估。
二、Keras文本预处理
1、读取数据集
2、将文字转换成数字特征
使用****Tokenizer将文字转换成数字特征
基于Keras的Tokenizer模块完成转换任务。在创建Tokenizer对象之后,在其属性中调用该对象的fit_on_texts()函数,在此过程中能够对输入文本中的每一个词语进行编码处理。通过调用该对象的方法fit_on_texts(), 能够训练模型并生成一个映射表,在此映射表中记录着所有出现过的词语与其对应的索引值之间的对应关系。在此映射表中访问word_index属性, 我们能够获取每个词语对应的编码信息,并以此为基础完成后续的操作流程。
3、将每条文本转换为数字列表
将数据集中的每条文本转换为数字列表,使用每个词的编号进行编号
使用该对象的texts_to_sequences() 函数,将每条文本转变成一个向量。
4、将每条文本设置为相同长度
使用pad_sequences()让每句数字影评长度相同
因为不同句子的长度不一,因此应设定统一的标准长度。对于那些超出标准的部分,则会被截断处理;而对于那些未达到标准的部分,则会在开头补上0来填充。
5、将每个词编码转换为词向量
使用Embedding层将每个词编码转换为词向量
该层基于上下文推导出的词编码,在深度学习模型中对每个词语进行one-hot向量表示后进行处理;随后利用神经网络训练迭代优化得到相应的权重矩阵(具体细节可参阅 skip-gram 模型),其行维度等于 vocabulary_size 空间中每一行代表一个单词对应的低维特征信息;该权重矩阵的作用是将原本以 one-hot 编码表示的单词转换为低维空间中的向量;值得注意的是,在实际应用中我们可以直接使用已经预先训练好的词语嵌入来表征现有语料库中的词语
预处理任务的目标是将每个样本进行数字化表示,并生成相应的词向量矩阵;其中每一行对应一个词向量。

6、Keras文本预处理代码实现
from sklearn.model_selection import train_test_split
import pandas as pd
import jieba
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
if __name__=='__main__':
dataset = pd.read_csv('sentiment_analysis/data_train.csv', sep='\t',names=['ID', 'type', 'review', 'label']).astype(str)
cw = lambda x: list(jieba.cut(x))
dataset['words'] = dataset['review'].apply(cw)
tokenizer=Tokenizer() #创建一个Tokenizer对象
#fit_on_texts函数可以将输入的文本中的每个词编号,编号是根据词频的,词频越大,编号越小
tokenizer.fit_on_texts(dataset['words'])
vocab=tokenizer.word_index #得到每个词的编号
x_train, x_test, y_train, y_test = train_test_split(dataset['words'], dataset['label'], test_size=0.1)
# 将每个样本中的每个词转换为数字列表,使用每个词的编号进行编号
x_train_word_ids=tokenizer.texts_to_sequences(x_train)
x_test_word_ids = tokenizer.texts_to_sequences(x_test)
#序列模式
# 每条样本长度不唯一,将每条样本的长度设置一个固定值
x_train_padded_seqs=pad_sequences(x_train_word_ids,maxlen=50) #将超过固定值的部分截掉,不足的在最前面用0填充
x_test_padded_seqs=pad_sequences(x_test_word_ids, maxlen=50)
代码解读
三、基于keras的TextCNN模型的构建、训练与测试
1、基础版CNN(模仿LeNet-5)
由Yann LeCun提出用于MNIST数据集识别任务的LeNet-5模型属于卷积神经网络的一种。该模型结构较为简单,并由一系列卷积和池化层构成。最后,在经过全连接层处理后完成分类任务,并将其成功应用于文本分类这一领域。
#构建CNN分类模型(LeNet-5)
#模型结构:嵌入-卷积池化*2-dropout-BN-全连接-dropout-全连接
def CNN_model(x_train_padded_seqs, y_train, x_test_padded_seqs, y_test):
model = Sequential()
model.add(Embedding(len(vocab) + 1, 300, input_length=50)) #使用Embeeding层将每个词编码转换为词向量
model.add(Conv1D(256, 5, padding='same'))
model.add(MaxPooling1D(3, 3, padding='same'))
model.add(Conv1D(128, 5, padding='same'))
model.add(MaxPooling1D(3, 3, padding='same'))
model.add(Conv1D(64, 3, padding='same'))
model.add(Flatten())
model.add(Dropout(0.1))
model.add(BatchNormalization()) # (批)规范化层
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.1))
model.add(Dense(3, activation='softmax'))
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
one_hot_labels = keras.utils.to_categorical(y_train, num_classes=3) # 将标签转换为one-hot编码
model.fit(x_train_padded_seqs, one_hot_labels,epochs=5, batch_size=800)
y_predict = model.predict_classes(x_test_padded_seqs) # 预测的是类别,结果就是类别号
y_predict = list(map(str, y_predict))
print('准确率', metrics.accuracy_score(y_test, y_predict))
print('平均f1-score:', metrics.f1_score(y_test, y_predict, average='weighted'))
代码解读
2、简单版TextCNN
#构建TextCNN模型
#模型结构:词嵌入-卷积池化*3-拼接-全连接-dropout-全连接
def TextCNN_model_1(x_train_padded_seqs,y_train,x_test_padded_seqs,y_test):
main_input = Input(shape=(50,), dtype='float64')
# 词嵌入(使用预训练的词向量)
embedder = Embedding(len(vocab) + 1, 300, input_length=50, trainable=False)
embed = embedder(main_input)
# 词窗大小分别为3,4,5
cnn1 = Conv1D(256, 3, padding='same', strides=1, activation='relu')(embed)
cnn1 = MaxPooling1D(pool_size=48)(cnn1)
cnn2 = Conv1D(256, 4, padding='same', strides=1, activation='relu')(embed)
cnn2 = MaxPooling1D(pool_size=47)(cnn2)
cnn3 = Conv1D(256, 5, padding='same', strides=1, activation='relu')(embed)
cnn3 = MaxPooling1D(pool_size=46)(cnn3)
# 合并三个模型的输出向量
cnn = concatenate([cnn1, cnn2, cnn3], axis=-1)
flat = Flatten()(cnn)
drop = Dropout(0.2)(flat)
main_output = Dense(3, activation='softmax')(drop)
model = Model(inputs=main_input, outputs=main_output)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
one_hot_labels = keras.utils.to_categorical(y_train, num_classes=3) # 将标签转换为one-hot编码
model.fit(x_train_padded_seqs, one_hot_labels, batch_size=800, epochs=10)
#y_test_onehot = keras.utils.to_categorical(y_test, num_classes=3) # 将标签转换为one-hot编码
result = model.predict(x_test_padded_seqs) # 预测样本属于每个类别的概率
result_labels = np.argmax(result, axis=1) # 获得最大概率对应的标签
y_predict = list(map(str, result_labels))
print('准确率', metrics.accuracy_score(y_test, y_predict))
print('平均f1-score:', metrics.f1_score(y_test, y_predict, average='weighted'))
代码解读
3、使用Word2Vec词向量的TextCNN
w2v_model=Word2Vec.load('sentiment_analysis/w2v_model.pkl')
# 预训练的词向量中没有出现的词用0向量表示
embedding_matrix = np.zeros((len(vocab) + 1, 300))
for word, i in vocab.items():
try:
embedding_vector = w2v_model[str(word)]
embedding_matrix[i] = embedding_vector
except KeyError:
continue
#构建TextCNN模型
def TextCNN_model_2(x_train_padded_seqs,y_train,x_test_padded_seqs,y_test,embedding_matrix):
# 模型结构:词嵌入-卷积池化*3-拼接-全连接-dropout-全连接
main_input = Input(shape=(50,), dtype='float64')
# 词嵌入(使用预训练的词向量)
embedder = Embedding(len(vocab) + 1, 300, input_length=50, weights=[embedding_matrix], trainable=False)
#embedder = Embedding(len(vocab) + 1, 300, input_length=50, trainable=False)
embed = embedder(main_input)
# 词窗大小分别为3,4,5
cnn1 = Conv1D(256, 3, padding='same', strides=1, activation='relu')(embed)
cnn1 = MaxPooling1D(pool_size=38)(cnn1)
cnn2 = Conv1D(256, 4, padding='same', strides=1, activation='relu')(embed)
cnn2 = MaxPooling1D(pool_size=37)(cnn2)
cnn3 = Conv1D(256, 5, padding='same', strides=1, activation='relu')(embed)
cnn3 = MaxPooling1D(pool_size=36)(cnn3)
# 合并三个模型的输出向量
cnn = concatenate([cnn1, cnn2, cnn3], axis=-1)
flat = Flatten()(cnn)
drop = Dropout(0.2)(flat)
main_output = Dense(3, activation='softmax')(drop)
model = Model(inputs=main_input, outputs=main_output)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
one_hot_labels = keras.utils.to_categorical(y_train, num_classes=3) # 将标签转换为one-hot编码
model.fit(x_train_padded_seqs, one_hot_labels, batch_size=800, epochs=20)
#y_test_onehot = keras.utils.to_categorical(y_test, num_classes=3) # 将标签转换为one-hot编码
result = model.predict(x_test_padded_seqs) # 预测样本属于每个类别的概率
result_labels = np.argmax(result, axis=1) # 获得最大概率对应的标签
y_predict = list(map(str, result_labels))
print('准确率', metrics.accuracy_score(y_test, y_predict))
print('平均f1-score:', metrics.f1_score(y_test, y_predict, average='weighted'))
代码解读
四、绘制TextCNN模型结构图
使用keras的plot_model()画出的TextCNN模型结构图
1、环境配置
(1)安装graphviz模块
第一步,在命令行终端中使用 pip 软件包安装 graphviz。接下来,在官网下载 graphviz 软件包:graphviz-2.38.msi。最后一步,请将安装目录中的 graphvim-2.38\release\bin 文件夹添加到系统环境变量的 Path 中。
(2)安装pydot模块
命令行pip install pydot
(3)在运行程序中加入下面两行代码
import os
os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/'
代码解读
2、绘制模型图
使用plot_model()画出模型图
from keras.utils import plot_model
#生成一个模型图,第一个参数为模型,第二个参数为要生成图片的路径及文件名,还可以指定两个参数:
#show_shapes:指定是否显示输出数据的形状,默认为False
#show_layer_names:指定是否显示层名称,默认为True
plot_model(model,to_file='sentiment_analysis/model.png',show_shapes=True,show_layer_names=False)
代码解读
模型图如下:

五、keras模型的保存与加载
from keras.models import load_model
#模型的保存
model.save('model.h5')
#模型的加载
model=load_model('model.h5')
代码解读
TextCNN文本分类(keras实现)源代码及数据集资源下载:
实践项目 - TextCNN 文本分类任务 (Keras 实现) 源代码和数据集 .zip - 自然语言处理文档资源库 - 下载
参考学习资料:
(1)Keras之文本分类实现
通过Keras实现深度学习,在机器学习领域中是一个非常流行的框架和工具包。它提供了一个功能丰富且易于使用的框架来构建和训练复杂的神经网络模型,并且能够高效地处理各种规模的数据集和复杂度较高的任务。对于希望快速入门并开始实践的开发者来说,Keras凭借其直观的接口和简便的学习曲线而备受推崇;而对于已经在深度学习领域深耕并追求更高效率的工程师来说,则是不可或缺的重要技术支撑点之一。
(3)NLP论文
(4)针对句子建模任务而言,卷积神经网络(CNN)是一种具有显著效果的技术
(5)****用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践
(8)基于 word2vec 和 CNN 的文本分类 :综述 & 实践
本人博文NLP学习内容目录:
一、NLP基础学习
1、NLP的学习路径被概述
第二部分:基于TF-IDF的信息检索模型开发与应用
4、基于英文自然语言处理技术的预处理方法综述及其应用
5、中文自然语言处理技术的总结与实现
第六章 主流NLP语言模型综述
第7章:自然语言处理领域的数据增强技术全面概述及其应用实践
8、TextRank算法的概述及其开发
对NLP领域的关键词提取技术进行归纳和应用
第10章、基于NLP的词向量与句向量方法概述与实现
第十一章 深入探讨了基于深度学习的自然语言处理技术综述及其应用实践
第十二章 NLP 中文 语法结构分析...原样保留
第十二章 NLP 中文 语法结构分析...原样保留
二、NLP项目实战
在本项目中进行的实践环节涉及英文文本分类与电影评论的情感分析
2、项目实战环节中的中文评论分类分析与商品情感判别模型构建
3、实践环节:XGBoost和LightGBM在文本分类任务中的应用
4、实操阶段:基于TextCNN进行文本分类的应用实例训练
5、项目实战-Bert-base中文预训练语言模型的实际应用与分类任务实操
6、实践环节:基于NLP技术实现的中文句式分类识别与分类实践
交流学习资料共享欢迎入群:955817470(群一),801295159(群二)
