CNN提取图片特征,之后用SVM分类

https://blog.csdn.net/qq_27756361/article/details/80479278

先用CNN提取特征,之后用SVM分类,平台是TensorFlow 1.3.0-rc0,python3.6 

这个是我的一个小小的测试,下面这个链接是我主要参考的,在实现过程中,本来想使用vgg16或者VGG19做迁移来提取特征,但是担心自己的算力不够,还有就是UCI手写数据集本来就是一个不大的数据集,使用vgg16或vgg19有点杀鸡用牛刀的感觉。于是放弃做迁移。

我的代码主要是基于下面链接来的。参考链接点击打开链接

这个代码主要是,通过一个CNN网络,在网络的第一个全连接层也就h_fc1得到的一个一维的256的一个特征向量,将这个特征向量作为的svm的输入。主要的操作是在代码行的140-146.    同时代码也实现了CNN的过程(读一下代码就知道)。

如果你要是知道你的CNN的结构,然后就知道在全连接层输出的其实就是一个特征向量。直接用这个特征向量简单处理输入到svm中就可以。

具体的参考论文和代码数据集等,百度网盘

CNN卷积层简介

CNN,有两个卷积(5*5)池化层(2*2的maxPooling),然后两个全连接层h_fc1和h_fc2,我只使用第一个全连接层h_fc1就提取了特征。

然后中间的激活函数使用的是relu函数,同时为了防止过拟合使用了dropout的技巧。然后这个代码中其实是实现了完整的CNN的的预测的,损失使用交叉熵,优化器使用了AdamOptimizer。

图片大小的变化:

最后从全连接层提取的256维的向量。输入svm。

SVM分类

SVM采用的是RBF核(高斯核),C取0.9

也可以尝试线性核,我试了一下效果差不多,但是没有高斯核分类效率好。

流程和实验设计

流程:整理训练网络的数据,对样本进行处理 -> 建立卷积神经网络-> 将数据代入进行训练 -> 保存训练好的模型(从全连接层提取特征) -> 把数据代入模型获得特征向量 -> 用特征向量代替原本的输入送入SVM训练 -> 测试时同样将h_fc1转换为特征向量之后用SVM预测,获得结果。

使用留出法样本处理和评价:

1.将原样本随机地分为两半。一份为训练集,一份为测试集

2.重复1过程十次,得到十个训练集和十个对应的测试集

3.取十份训练集中的一份和其对应的测试集。代入到CNN和SVM中训练。

4.依次取训练集和测试集,则可完成十次第一步。

5.将十次的表现综合评价,十次验证取平均值,计算正确率、准确率、召回率、F1值。比如 F1 分数 , 用于测量不均衡数据的精度. 

 
  1. # coding=utf8

  2. import random

  3.  
  4. import numpy as np

  5. import tensorflow as tf

  6. from sklearn import svm

  7. from sklearn import preprocessing

  8. import time

  9.  
  10. start = time.clock()

  11.  
  12. right0 = 0.0  # 记录预测为1且实际为1的结果数

  13. error0 = 0  # 记录预测为1但实际为0的结果数

  14. right1 = 0.0  # 记录预测为0且实际为0的结果数

  15. error1 = 0  # 记录预测为0但实际为1的结果数

  16.  
  17. for file_num in range(10):

  18.     # 在十个随机生成的不相干数据集上进行测试,将结果综合

  19.     print('testing NO.%d dataset.......' % file_num)

  20.     ff = open('digit_train_' + file_num.__str__() + '.data')

  21.     rr = ff.readlines()

  22.     x_test2 = []

  23.     y_test2 = []

  24.     

  25.     for i in range(len(rr)):

  26.         x_test2.append(list(map(int, map(float, rr[i].split(' ')[:256]))))

  27.         y_test2.append(list(map(int, rr[i].split(' ')[256:266])))

  28.     ff.close()

  29.     # 以上是读出训练数据

  30.     ff2 = open('digit_test_' + file_num.__str__() + '.data')

  31.     rr2 = ff2.readlines()

  32.     x_test3 = []

  33.     y_test3 = []

  34.     for i in range(len(rr2)):

  35.         x_test3.append(list(map(int, map(float, rr2[i].split(' ')[:256]))))

  36.         y_test3.append(list(map(int, rr2[i].split(' ')[256:266])))

  37.     ff2.close()

  38.     # 以上是读出测试数据

  39.  
  40.     sess = tf.InteractiveSession()

  41.     # 建立一个tensorflow的会话

  42.  
  43.     # 初始化权值向量

  44.     def weight_variable(shape):

  45.         initial = tf.truncated_normal(shape, stddev=0.1)

  46.         return tf.Variable(initial)

  47.  
  48.  
  49.     # 初始化偏置向量

  50.     def bias_variable(shape):

  51.         initial = tf.constant(0.1, shape=shape)

  52.         return tf.Variable(initial)

  53.  
  54.  
  55.     # 二维卷积运算,步长为1,输出大小不变

  56.     def conv2d(x, W):

  57.         return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

  58.  
  59.  
  60.     # 池化运算,将卷积特征缩小为1/2

  61.     def max_pool_2x2(x):

  62.         return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

  63.  
  64.     # 给x,y留出占位符,以便未来填充数据

  65.     x = tf.placeholder("float", [None, 256])

  66.     y_ = tf.placeholder("float", [None, 10])

  67.     # 设置输入层的W和b

  68.     W = tf.Variable(tf.zeros([256, 10]))

  69.     b = tf.Variable(tf.zeros([10]))

  70.     # 计算输出,采用的函数是softmax(输入的时候是one hot编码)

  71.     y = tf.nn.softmax(tf.matmul(x, W) + b)

  72.     # 第一个卷积层,5x5的卷积核,输出向量是32维

  73.     w_conv1 = weight_variable([5, 5, 1, 32])

  74.     b_conv1 = bias_variable([32])

  75.     x_image = tf.reshape(x, [-1, 16, 16, 1])

  76.     # 图片大小是16*16,,-1代表其他维数自适应

  77.     h_conv1 = tf.nn.relu(conv2d(x_image, w_conv1) + b_conv1)

  78.     h_pool1 = max_pool_2x2(h_conv1)

  79.     # 采用的最大池化,因为都是1和0,平均池化没有什么意义

  80.  
  81.     # 第二层卷积层,输入向量是32维,输出64维,还是5x5的卷积核

  82.     w_conv2 = weight_variable([5, 5, 32, 64])

  83.     b_conv2 = bias_variable([64])

  84.  
  85.     h_conv2 = tf.nn.relu(conv2d(h_pool1, w_conv2) + b_conv2)

  86.     h_pool2 = max_pool_2x2(h_conv2)

  87.  
  88.     # 全连接层的w和b

  89.     w_fc1 = weight_variable([4 * 4 * 64, 256])

  90.     b_fc1 = bias_variable([256])

  91.     # 此时输出的维数是256维

  92.     h_pool2_flat = tf.reshape(h_pool2, [-1, 4 * 4 * 64])

  93.     h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, w_fc1) + b_fc1)

  94.     # h_fc1是提取出的256维特征,很关键。后面就是用这个输入到SVM中

  95.  
  96.     # 设置dropout,否则很容易过拟合

  97.     keep_prob = tf.placeholder("float")

  98.     h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

  99.  
  100.     # 输出层,在本实验中只利用它的输出反向训练CNN,至于其具体数值我不关心

  101.     w_fc2 = weight_variable([256, 10])

  102.     b_fc2 = bias_variable([10])

  103.  
  104.     y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, w_fc2) + b_fc2)

  105.     cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv))

  106.     # 设置误差代价以交叉熵的形式

  107.     train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

  108.     # 用adma的优化算法优化目标函数

  109.     correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))

  110.     accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

  111.     sess.run(tf.global_variables_initializer())

  112.     for i in range(3000):

  113.         # 跑3000轮迭代,每次随机从训练样本中抽出50个进行训练

  114.         batch = ([], [])

  115.         p = random.sample(range(795), 50)

  116.         for k in p:

  117.             batch[0].append(x_test2[k])

  118.             batch[1].append(y_test2[k])

  119.         if i % 100 == 0:

  120.             train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})

  121.             # print "step %d, train accuracy %g" % (i, train_accuracy)

  122.         train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.6})

  123.         # 设置dropout的参数为0.6,测试得到,大点收敛的慢,小点立刻出现过拟合

  124.  
  125.     print("test accuracy %g" % accuracy.eval(feed_dict={x: x_test3, y_: y_test3, keep_prob: 1.0}))

  126.     # def my_test(input_x):

  127.     #     y = tf.nn.softmax(tf.matmul(sess.run(x), W) + b)

  128.     

  129.     for h in range(len(y_test2)):

  130.         if np.argmax(y_test2[h]) == 7:

  131.             y_test2[h] = 1

  132.         else:

  133.             y_test2[h] = 0

  134.     for h in range(len(y_test3)):

  135.         if np.argmax(y_test3[h]) == 7:

  136.             y_test3[h] = 1

  137.         else:

  138.             y_test3[h] = 0

  139.     # 以上两步都是为了将源数据的one hot编码改为1和0,我的学号尾数为7

  140.     x_temp = []

  141.     for g in x_test2:

  142.         x_temp.append(sess.run(h_fc1, feed_dict={x: np.array(g).reshape((1, 256))})[0])

  143.     # 将原来的x带入训练好的CNN中计算出来全连接层的特征向量,将结果作为SVM中的特征向量

  144.     x_temp2 = []

  145.     for g in x_test3:

  146.         x_temp2.append(sess.run(h_fc1, feed_dict={x: np.array(g).reshape((1, 256))})[0])

  147.  
  148.     clf = svm.SVC(C=0.9, kernel='linear')  #linear kernel

  149. #    clf = svm.SVC(C=0.9, kernel='rbf')   #RBF kernel

  150.     # SVM选择了RBF核,C选择了0.9

  151. #    x_temp = preprocessing.scale(x_temp)  #normalization

  152.     clf.fit(x_temp, y_test2)

  153.     

  154.     print('svm testing accuracy:')

  155.     print(clf.score(x_temp2,y_test3))

  156.     for j in range(len(x_temp2)):

  157.         # 验证时出现四种情况分别对应四个变量存储

  158.         #这里报错了,需要对其进行reshape(1,-1)

  159.         if clf.predict(x_temp2[j].reshape(1,-1))[0] == y_test3[j] == 1:

  160.             right0 += 1

  161.         elif clf.predict(x_temp2[j].reshape(1,-1))[0] == y_test3[j] == 0:

  162.             right1 += 1

  163.         elif clf.predict(x_temp2[j].reshape(1,-1))[0] == 1 and y_test3[j] == 0:

  164.             error0 += 1

  165.         else:

  166.             error1 += 1

  167.     

  168. accuracy = right0 / (right0 + error0)  # 准确率

  169. recall = right0 / (right0 + error1)  # 召回率

  170. print('svm right ratio ', (right0 + right1) / (right0 + right1 + error0 + error1))

  171. print ('accuracy ', accuracy)

  172. print ('recall ', recall)

  173. print ('F1 score ', 2 * accuracy * recall / (accuracy + recall))  # 计算F1值

  174.  
  175. end = time.clock()

  176. print("time is :")

  177. print(end-start)

使用CNN之后用SVM分类。这个操作有很多。比如RCNN(Regions with CNN features)用于目标检测的网络的一系列的算法【SPP-Net】。基本就是CNN之后svm。

参考文献

[1] Deep Learning using Linear Support Vector Machines, ICML 2013

[2] How transferable are features in deep neural networks?, Jason Yosinski,1 Jeff Clune,2 Yoshua Bengio, NIPS 2014

[3] CNN Features off-the-shelf: an Astounding Baseline for Recognition, Ali Sharif Razavian Hossein Azizpour Josephine Sullivan Stefan Carlsson CVAP, KTH (Royal Institute of Technology). CVPR 2014

主要参考第一篇,具体的论文我把论文放到百度网盘中了:

https://pan.baidu.com/s/1Ghh4nfjfBKDyA47fc6M4JQ

有相同的CNN之后使用SVM的一些GitHub的开源代码:

https://github.com/Fdevmsy/Image_Classification_with_5_methods

https://github.com/efidalgo/AutoBlur_CNN_Features

https://github.com/tomrunia/TF_FeatureExtraction

猜你喜欢

转载自blog.csdn.net/weixin_41036461/article/details/84205924