学机器学习或者CNN的大神们入门都必研究的就是MNIST手写数字识别,而MNIST数据集通常在各种平台上(Tensorflow,caffee,theao…)都是做分类的,而本人研究的是基于CNN的图像检索问题,怎么办呢?先从MNIST手写数字开始吧!
一开始我用的Tensorlayer去做检索(不了解tl的可以进入tl中文文档),用tl实现MNIST也是及其简单的,相比于用tf实现来讲代码上简单了些许,源代码戳这里。然而改代码的时候就发现了问题,因为在tl上一切变量都是以Tensor的形式运行的,用eval()转换也试过,总是提示错误。所以提取特征的时候没办法转换成数组,也就没办法计算距离。
本人使用的平台是Tensorflow,语言python,网络是最简单的LENET,源代码在github上能搜到,我是基于LENET把源代码改成图像检索的,检索的思路有两种方式,第一种是基于分类的检索,简单的来讲就是先做分类,然后输入一张测试图像,判别属于某一类,在把测试集中所有属于这一类的保存即可,这个比较简单,会分类的应该都会,本文不做介绍。第二种是基于特征的检索,简单的讲就是全连接层会输出维度为1024的特征(LENET),输入一张测试图片提取其特征,再将库里所有图像的特征都提取出来,进行特征距离的计算,然后根据实际情况设定一个阈值,低于这个阈值的图像保存即可。下面为大家讲解具体如何实现的。
我的运行环境是linux,python2.7,在win10下我也安装了Anaconda,python3.5,运行会提示出错,所以建议大家在python2.7下运行。
源代码的地址我找不到了,因此贴出:
import tensorflow as tf
import numpy as np
#导入input_data用于自动下载和安装MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
#创建一个交互式Session
sess = tf.InteractiveSession()
#创建两个占位符,x为输入网络的图像,y_为输入网络的图像类别
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
#权重初始化函数
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)
#创建卷积op
#x 是一个4维张量,shape为[batch,height,width,channels]
#卷积核移动步长为1。填充类型为SAME,可以不丢弃任何像素点
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding="SAME")
#创建池化op
#采用最大池化,也就是取窗口中的最大值作为结果
#x 是一个4维张量,shape为[batch,height,width,channels]
#ksize表示pool窗口大小为2x2,也就是高2,宽2
#strides,表示在height和width维度上的步长都为2
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1,2,2,1],
strides=[1,2,2,1], padding="SAME")
#第1层,卷积层
#初始化W为[5,5,1,32]的张量,表示卷积核大小为5*5,第一层网络的输入和输出神经元个数分别为1和32
W_conv1 = weight_variable([5,5,1,