1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > tensorflow多层卷积网络实现CNN文本分类

tensorflow多层卷积网络实现CNN文本分类

时间:2018-10-02 13:10:48

相关推荐

tensorflow多层卷积网络实现CNN文本分类

1.实验数据获取:

这里的实验数据是本人自己提取的,具体方式是:

(大家可以根据自己喜好进行如下步骤)

1.选取3个不同类别的文本,每类500篇,共1500篇。

2.使用TF-IDF或词频等方式,从每个类型的文本中选出100个特征词,3个类别,共300个特征词。将300个特征词存入一个list中。

3.使用300个特征词的列表去遍历每一篇文本,如果第x个特征词在该文本中出现次数为n,则对应该文本的特征list的第x为记为n。1500篇文本,1500个特征list分别对应每个文本。

4.对每个文本设置标签,使用one-hot方式表示即可

5.将其文本顺序打乱即可,但保证其对应关系不变 文本——文本特征list——标签

例如:

这里我使用TF-IDF从3个不同类别的文本中提取到的300个特征词:

我们甚至可以从这些词中看出这三类文本的类别分别为:房产,星座,游戏

当然,有些词的区分性不是太好,我们可以通过增加文本数量,设置更精确的停用词实现更好的效果。

提取一篇文本的特征list:

文本特征list的每一位与特征词list的每一位一一对应,例如文本特征list[1]=11,对应特征词list[1]=“一个”,即表示"一个"这个词在该文本中出现11次。

再对这篇文本设置标签:

[‘0’, ‘1’, ‘0’]

表明该文本属于第二类。

2.代码实现:

关于理论实现这里就不做讲解(如果想要学习,推荐深度学习入门——基于Python的理论与实现-图灵教育-[日]斋藤康毅 著),

直接上代码,具体解释在注释中:

代码参考于:

Tensorflow中文社区

BiliBili视频 深度学习框架Tensorflow学习与应用

import tensorflow as tfimport dataN#这里是自己写的获取数据的python文件,可以获取到1200个训练数据,训练标签。300个测试数据,测试标签train_dataN,train_labelN,test_dataN,test_labelN=dataN.dataone()#placeholder为tensor操作创建占位符,可以在TensorFlow运行某一计算时根据该占位符输入具体的值x=tf.placeholder("float",shape=[None,300])#None表示一次传入数据的个数未知,他会根据实际情况自动设置y_=tf.placeholder("float",shape=[None,3])#y_为正确解标签,x为输入的数据#定义两个函数用于初始化W,b:def weight_variable(shape):initial=tf.truncated_normal(shape,stddev=0.1) #正态分布return tf.Variable(initial)def bias_variable(shape):initial=tf.constant(0.1,shape=shape)return tf.Variable(initial)#卷积层:def conv2d(x,W):return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding="SAME")# x input tersor of shape [batch,in_height,in_wight,in_channels]# stride步幅,padd填充,x输入数据,W权重张量|滤波器,0边距(padding size)的模板# strides[0]=strides[3]=1 (默认), strides[1]代表x方向的步长,strides[2]代表y方向的步长# SAME就是一种padding方法,另一个是VALID,在实际中多采用SAME使卷积层不改变数据大小# 如果padding设置为SAME,则输入图片大小和输出图片大小是一致的,如果是VALID则图片经过滤波器后可能会变小# 大家可以去了解下SAME和VALID两种方式(这很重要!!!)#池化层:def max_pool_2x2(x):return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")#ksize窗口大小|过滤器大小,stride步幅,pdd填充,x输入数据#ksize[0]=ksize=[3]=1(默认),ksize[1]代表x方向长,ksize[2]代表y方向长x_text=tf.reshape(x,[-1,10,30,1]) #改变x的形状,[1*300,通道数1]变为[10*30,通道数1],-1表示batch(一个批次)数量未知,1表示通道数为1#第一层:::W_conv1=weight_variable([2,6,1,10])# 卷积的权重张量形状是[2,6,1,10],前两个维度是采样窗口的大小,接着是输入的通道数目,最后是输出的通道数目(表示使用多少卷积核),这里使用10个卷积核从一个平面抽取特征,得到10个通道# 10就是指卷积核的数量,每种卷积只对某些特征敏感,获取的特征有限。# 因此将多种不同的卷积核分别对图像进行处理,就能获得更多的特征。# 每个卷积核按照规则扫描完图像后,就输出一张特征图像(feature map),# 因此10也指输出的特征图b_conv1=bias_variable([10])#对于每一个输出通道都有一个对应的偏置量,前面因为每张图片生成10个特征,这里也要对应10个偏置值h_conv1=tf.nn.relu(conv2d(x_text,W_conv1)+b_conv1)#这里的卷积层不改变大小,即数据仍然为10*30,但因为使用了10个卷积核进行特征抽取,产生了10个通道h_pool1=max_pool_2x2(h_conv1)#池化得到10个5*15的平面#第二层:::W_conv2=weight_variable([2,2,10,20])#2x2的采样窗口,20个卷积核从10个平面抽取特征,输出20个特征平面#输入的是10个2*15的矩阵,这层要输出的矩阵个数为20b_conv2=bias_variable([20])#每一个卷积核对应一个偏置量h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)#这里的卷积层不改变数据大小h_pool2=max_pool_2x2(h_conv2)#池化输出20个3*8的矩阵#连接层:::初始化第一个全连接层W_fc1=weight_variable([3*8*20,500])# 上一层(卷积层)传入3*8*20个神经元,我们设置全连接层有500个神经元b_fc1=bias_variable([500])h_pool2_flat=tf.reshape(h_pool2,[-1,3*8*20])#把池化层2的输出扁平化化为1维,-1表示batch数量未知h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)# 第一个全连接层的输出。得到一个长度为500的向量keep_prob=tf.placeholder("float")h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)#dropout方法能在运行中自动忽略一些神经元,防止过拟合#初始化第二个全连接层:W_fc2=weight_variable([500,3])#500对应上一层的输出,3对应这一场的输出为3类b_fc2=bias_variable([3])prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)#计算概率cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=prediction))#计算 logits 和 labels 之间的 softmax 交叉熵。train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)#学习率为1e-4,使用梯度下降的方式最小化交叉熵correct_prediction = tf.equal(tf.argmax(prediction,1), tf.argmax(y_,1))#求正确率accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))with tf.Session() as sess: #启动图sess.run(tf.initialize_all_variables()) #初始化全部变量for i in range(120): #我们共1200个训练数据,这里我们10个为1批次batch 进行TrainData_batch = train_dataN[i * 10:(i + 1) * 10]label_batch = train_labelN[i * 10:(i + 1) * 10]sess.run(train_step,feed_dict={x:TrainData_batch,y_:label_batch,keep_prob:0.7})#keep_prob:0.7 只有70%的神经元工作"""if i%4==0: #训练每进行4个批次,我们就传入一个批次的测试数据,检测当前的正确率t=int(i/4)TestData_batch=test_dataN[t * 10:(t + 1) * 10]TestLabel_batch=test_labelN[t * 10:(t + 1) * 10]#pre=sess.run([prediction,y_],feed_dict={x:TrainData_batch,y_:TestLabel_batch,keep_prob:1.0})#print(pre) pre为预测结果和真实标签,大家可以打印出来看看acc=sess.run(accuracy,feed_dict={x:TrainData_batch,y_:TestLabel_batch,keep_prob:1.0})print("Iter "+str(t)," accuracy= "+str(acc))"""print(sess.run(accuracy,feed_dict={x:test_dataN,y_:test_labelN,keep_prob:1.0}))#再训练完成后,一次性将所有测试数据传入进行测试,得到总的正确率。#注意!使用该方式,则不能使用使用上方 检测当前的正确率,不然会造成正确率偏大(因为测试数据也经过了训练)

3.运行结果:

通过测试,我得到的测试数据总的正确率为70%~80%左右。

而每进行4个批次,传入一个批次的测试数据时正确率总时很低,并且没有呈现明显的递增变化,这可能因为测试和训练的数据过少造成:

4.需要注意的点:

以下仅仅是我在学习过程中产生的思考和总结,并不代表正确答案,大家如果有更好解答或其它理解可以在评论区讨论。

1.通过CNN的方式实现文本分类是否具有可靠性?

我认为可靠性并不如CNN对图片的分类,因为文本是1维数据,为了通过卷积神经网络,需要将其变化为多维度,而在变化后(比如1x300变为10x30),这样的变化有很多种。而无论怎么改变,原本是1维的数据,在多维度上究竟有何联系?我认为,这样意义不大的变换并不会带来什么更好的结果。

对此,我设定了一个简单的神经网络,不使用卷积,对上述文本进行了分类实验

其代码如下(讲解就不再给出了):

import dataNimport tensorflow as tftrain_dataN,train_labelN,test_dataN,test_labelN=dataN.dataone()sess = tf.InteractiveSession()x = tf.placeholder("float", shape=[None, 300])y_ = tf.placeholder("float", shape=[None, 3])W = tf.Variable(tf.zeros([300, 3]))b = tf.Variable(tf.zeros([3]))sess.run(tf.global_variables_initializer())y = tf.nn.softmax(tf.matmul(x, W) + b)cross_entropy = -tf.reduce_sum(y_ * tf.log(y))train_step = tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))for i in range(120):TrainData_batch = train_dataN[i * 10:(i + 1) * 10]label_batch = train_labelN[i * 10:(i + 1) * 10]train_step.run(feed_dict={x: TrainData_batch, y_: label_batch})for t in range(30):TestData_batch = test_dataN[t * 10:(t + 1) * 10]TestLabel_batch = test_labelN[t * 10:(t + 1) * 10]result = sess.run(correct_prediction, feed_dict={x: TestData_batch, y_: TestLabel_batch})print(result)

对测试数据的运行结果如下:

我们可以发现,通过简单的神经网络训练,反而得到了更优的效果。但这并不能完全说明上述猜测,或许多层卷积网络有更好的文本分类方式,在之后的学习中或许能解此疑惑。

2.关于卷积层和池化层的输出大小:

这里就不进行讲解了,在了解卷积和池化的原理,和padding方法SAME和VALID后,我们就能自己推导得出

3.卷积层和全连接层的作用:

卷积取的是局部特征,全连接就是把以前的局部特征重新通过权值矩阵组装成完整的图。(来自知乎)

4.全连接层神经元个数对结果的影响:

以下结果仅针对上述代码和数据:

2048个神经元,正确率:75%~85%

1024个神经元,正确率:75%~85%

500个神经元,正确率:70%~80%

100个神经元,正确率:60%~80%

50个神经元,正确率:50%~70%

神经元是否是越多越好呢?

在测试到4096个神经元时,结果出现了不稳定线性,有的很高超过了85%,有的甚至不到50%

在询问了一位大佬后,得到了这样的结果:

神经元数量的设置就是玄学,并不是越高或者越低越好,正确率也不一定与神经元数量呈正比,往往通过多次调试进行选择。

5.关于数据:

在数据传入之前,一定要对数据进行乱序处理!

在未经过乱序处理或者打乱不完全或有规则的打乱,神经网络往往会学习到这些规律性变化,对于满足这些规律的测试文本,往往能获得到惊人的效果。

在之前,我尝试过使用【第一类文本,第二类文本,第三类文本,第一类文本…】的有规律性方式打乱训练文本和测试文本,再经过简单的神经网络(无卷积),这时其正确率就已经达到了98%以上,这样的结果明显是不和常规的,仅仅对有此规律的文本起作用。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。