IT 领域的三角不可能定律:质量编程、速度编程、廉价编程。
——麦杰克 · 索伊
导读:从本质上讲,我们在做回归或者分类的时候,就是把数据映射到一个或多个离散标签上,或者是映射到连续空间。对于BP前反馈神经网络,我们是构建神经元(非线性映射),通过比较映射结果与标签的误差,用损失函数表示出来。理论上我们能够构建不限数量的神经元来协助我们来无限逼近最合适的映射。
对于复杂多变的数据结构,如图片集合,我们该如何处理?我们已经知道图片可以通过二维矩阵(灰度图片,只有一个channel)来表示,最简单的方法是把矩阵平整化(变换为一维向量),然后应用已有的分类器来训练。这个方法在图片尺寸不大、噪声信息不多的情况下,有一定的效果。需要注意的是,这个方法会丢弃图片的空间特征。对于高像素图片,该如何处理?最容易想到的方法是提取图片中最有效的特征,对图片进行压缩处理。GOOD!卷积神经网络(CNN)正式基于这个思想!
假如说我们已经有了一些合适的过滤器,可以有效地提取特征。我们把图片的像素分别通过这些过滤器进行过滤(相乘),在通过一个阈值,得到提取结果。这个一般过程我们成为卷积。通过卷积,我们可以对图片进行很多操作,比如图片整体模糊,边缘提取。实际上,CNN模型的训练过程,相当多的时间都是在不断求导来逼近最合适的过滤器以及阈值。
压缩图片的过程更加简单,我们选取局部视野内的最大像素(也可以是平均值)来作为我们输出,按照这个算法,我们全局扫描图片,得到压缩后的结果。这个过程我们称之为池化/下采样。池化的唯一目的是减小图片空间大小。
基于此,本文希望通过TensorFlow自带的手写识别图片库,来简单说明CNN的计算过程以及编程的实现。本文分为3个部分:快速了解 TensorFlow,快速了解CNN,以及CNN的TensorFlow实现。
代码如下:
importmatplotlib.pyplotasplt
importtensorflowastf
fromtensorflow.examples.tutorials.mnistimportinput_data
defdraw_fig(mnist,n,m):
fig, axes = plt.subplots(n,m,sharex=True,sharey=True)
foriinrange(n):
forjinrange(m):
temp = mnist.train.images[(i*m+j)]
image = temp.reshape(28,28)
axes[i,j].imshow(image,cmap='binary')# 黑白显示
plt.xticks([])
plt.yticks([])
plt.show()
mnist = input_data.read_data_sets('MNIST_data/',one_hot=True)
draw_fig(mnist,10,10)
defweight_Variable(shape):
weight = tf.truncated_normal(shape=shape,stddev=0.1)
returntf.Variable(weight)
defbias_Variable(shape):
bias = tf.constant(0.1,shape=shape)
returntf.Variable(bias)
defconv2d(input,filter):
returntf.nn.conv2d(input,filter,strides=[1,1,1,1],padding='SAME')
defmax_pool_2_2(input):
returntf.nn.max_pool(input,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
defconv_nn(mnist,channels_1,channels_2,full_connect,prob,n_rounds):
# 分别设置x和y占位符
x_ = tf.placeholder(tf.float32,[None,784])
x_image = tf.reshape(x_,[-1,28,28,1])
y_ = tf.placeholder(tf.float32,[None,10])
# 第一次卷积与池化
filter_1 = weight_Variable([5,5,1,channels_1])
bias_1 = bias_Variable(channels_1)
f_map_1 = tf.nn.relu(conv2d(x_image,filter_1)+bias_1)
max_pool_1 = max_pool_2_2(f_map_1)
# 第二次卷积与池化
filter_2 = weight_Variable([5,5,channels_1,channels_2])
bias_2 = bias_Variable(channels_2)
f_map_2 = tf.nn.relu(conv2d(max_pool_1,filter_2)+bias_2)
max_pool_2 = max_pool_2_2(f_map_2)
# 构建全连接层
filter_full = weight_Variable([7*7*64,full_connect])
bias_full = bias_Variable([full_connect])
filter_full_flat = tf.reshape(max_pool_2,[-1,7*7*64])
connect_flat = tf.nn.relu(tf.matmul(filter_full_flat,filter_full)+bias_full)
# 神经元选择性激活,可以减小过拟合。但是在验证阶段,要打开全部神经元
keep_prob = tf.placeholder(tf.float32)
connect_prob = tf.nn.drop(connect_flat,keep_prob)
# 搭建Softmax作为输出层
filter_out = weight_Variable([full_connect,10])
bias_out = bias_Variable([10])
y_conv = tf.nn.softmax(tf.matmul(connect_prob, filter_out) + bias_out)
# 训练模型
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
optimizer = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prdiction = tf.equal(tf.arg_max(y_conv,1),tf.arg_max(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prdiction,tf.float32))
# 设置参数保存
saver = tf.train.Saver()
withtf.Session()assess:
sess.run(tf.global_bariable_initializer())
saver.save(sess,'saved_model/model.ckpt')# 参数保存路径,如果要读取完成训练的模型参数,改为saver.restore()
foriinrange(n_rounds):
batch = mnist.train.next_batch(50)
sess.run(optimizer,feed_dict=)
ifi%100==:
train_accuracy = accuracy.eval(optimizer,feed_dict=)
print('step %d, training accuracy %g'%(i,train_accuracy))
print('test accuracy %g'%(accuracy.eval(optimizer,feed_dict=)))
if__name__ =='__main__':
mnist = input_data.read_data_sets('MNIST_data/',one_hot=True)
conv_nn(mnist,32,64,1024,0.5,5000)
1、本文代码请在python3.x中调试
2、教程部分参考:
——完——
领取专属 10元无门槛券
私享最新 技术干货