不说废话先上代码:
#coding:utf-8
#learning how to use tensorboard in cnn
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("data/", one_hot=True)
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
#define fuctions*******************************************************************************************************************
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')
def max_pool_2X2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
def variable_summaries(var,name):
with tf.name_scope('summaries'):
mean = tf.reduce_mean(var)
tf.summary.scalar('mean/'+name,mean)
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var-mean)))
tf.summary.scalar('stddev/'+name,stddev)
tf.summary.histogram(name,var)
def conv_image_visual(conv_image,image_weight,image_height,cy,cx,channels):
#slice off one image ande remove the image dimension
#original image is a 4d tensor[batche_size,weight,height,channels]
conv_image = tf.slice(conv_image,(0,0,0,0),(1,-1,-1,-1))
conv_image = tf.reshape(conv_image,(image_height,image_weight,channels))
#add a couple of pixels of zero padding around the image
image_weight += 4
image_height += 4
conv_image = tf.image.resize_image_with_crop_or_pad(conv_image,image_height,image_weight)
conv_image = tf.reshape(conv_image,(image_height,image_weight,cy,cx))
conv_image = tf.transpose(conv_image,(2,0,3,1))
conv_image = tf.reshape(conv_image,(1,cy*image_height,cx*image_weight,1))
return conv_image
#**********************************************************************************************************************************
with tf.name_scope('intput'):
x = tf.placeholder(tf.float32,shape = [None,784],name = 'x')
y_ = tf.placeholder(tf.float32,shape = [None,10],name = 'labels')
input_image = tf.reshape(x,shape = [-1,28,28,1])
tf.summary.image('input_image',input_image,max_outputs = 1 )
with tf.name_scope('cnn_block'):
w_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])
variable_summaries(w_conv1,'first_cnn_layer_weight')
variable_summaries(b_conv1,'first_cnn_layer_bais')
with tf.name_scope('reshape'):
#将输入数据转换成28×28,channel = 1的图像
x_image = tf.reshape(x,[-1,28,28,1])
with tf.name_scope('first_cnn_layer'):
#进行第一层卷积网络的运算h_conv1=[-1,28,28,32]
h_conv1 = tf.nn.relu(conv2d(x_image,w_conv1)+b_conv1)
with tf.name_scope('conv1_vis'):
conv1_image = conv_image_visual(h_conv1,28,28,4,8,32)
tf.summary.image('h_conv1',conv1_image)
with tf.name_scope('first_pool_layer'):
h_pool1 = max_pool_2X2(h_conv1)
with tf.name_scope('second_cnn_layer'):
#第二层卷积网络
w_conv2 = weight_variable([5,5,32,64])
b_conv2 = bias_variable([64])
#第二层卷积输出[batch_size,14,14,64]
h_conv2 = tf.nn.relu(conv2d(h_pool1,w_conv2)+b_conv2)
with tf.name_scope('conv2_vis'):
conv2_iamge = conv_image_visual(h_conv2,14,14,8,8,64)
tf.summary.image('h_conv2',conv2_iamge)
with tf.name_scope('second_pool_layer'):
h_pool2 = max_pool_2X2(h_conv2)
with tf.name_scope('first_fullconect_layer'):
#经过两个池化操作图片从28*28降维到了7*7,
w_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
#reshape为行向量
with tf.name_scope('h_pool2_reshape'):
h_pool2_reshape = tf.reshape(h_pool2,[-1,7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_reshape,w_fc1)+b_fc1)
#使用dropout防止过拟合
with tf.name_scope('dropout'):
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
with tf.name_scope('out_put_layer'):
#输出层
w_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
with tf.name_scope('softmax'):
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,w_fc2)+b_fc2)
#损失函数
with tf.name_scope('cross_entropy'):
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
tf.summary.scalar('cross_entropy',cross_entropy)
with tf.name_scope('train_step'):
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
with tf.name_scope('accuracy'):
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
tf.summary.scalar('accuracy',accuracy)
init_op = tf.global_variables_initializer()
merged = tf.summary.merge_all()
with tf.Session() as sess:
sess.run(init_op)
train_writer = tf.summary.FileWriter("tensorboard/",sess.graph)
for i in range(1000):
batch = mnist.train.next_batch(50)
summary, _ = sess.run([merged,train_step],feed_dict = {x:batch[0],y_:batch[1],keep_prob:0.5})
train_writer.add_summary(summary,i)
if i%10 == 0:
summary,acc = sess.run([merged,accuracy],feed_dict = {x:batch[0],y_:batch[1],keep_prob:0.5})
train_writer.add_summary(summary,i)
print "step %d,training accuracy %g"%(i,acc)
train_writer.close();
#print "test accuracy %g"%accuracy.eval(feed_dict = {x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}
效果图:
分析一下可视化卷积层最终要的一段代码:
def conv_image_visual(conv_image,image_weight,image_height,cy,cx,channels):
#slice off one image ande remove the image dimension
#original image is a 4d tensor[batche_size,weight,height,channels]
conv_image = tf.slice(conv_image,(0,0,0,0),(1,-1,-1,-1))
conv_image = tf.reshape(conv_image,(image_height,image_weight,channels))
#add a couple of pixels of zero padding around the image
image_weight += 4
image_height += 4
conv_image = tf.image.resize_image_with_crop_or_pad(conv_image,image_height,image_weight)
conv_image = tf.reshape(conv_image,(image_height,image_weight,cy,cx))
conv_image = tf.transpose(conv_image,(2,0,3,1))
conv_image = tf.reshape(conv_image,(1,cy*image_height,cx*image_weight,1))
return conv_image
该函数的参数:conv_image:待可视化的卷积结果;image_w:卷积后图像的宽;iamge_h:卷积后图像的高;cy:图像显示的行数;cx:图像显示的列数;channels:图像的通道数;
比如我要显示第一个卷积层经过激活函数后的图像,经过一次卷积后图像的channels变成了32,如果我要将这32个通道的结果以4行8列显示的话,则cy=4,cx=8;
conv_image = tf.slice(conv_image,(0,0,0,0),(1,-1,-1,-1))
conv_image = tf.reshape(conv_image,(image_height,image_weight,channels))
因为tf.summary.image()函数输入的tensor的格式为:[batch_size,height,width,channels]而channel只能为1,3,4分别表示gray,RGB,RGBA图像,而卷积后的图像格式为[batch_size,height,width,channels],这里的channel=卷积核的个数,因此如果直接将卷积后的图像输入到tf.summary.image()会报错,而且不能显示每一个卷积核作用到图像后的结果,因此我们第一步就是要消减卷积结果的维度tf.slice()操作后,消去了第一个(batch_size)维度,这个操作可以理解为从每一个batch中挑选了第一张图片进行显示,这也就造成了每一步显示的图片是不同的。
经过slice操作以后图像还是四维的因此使用reshape将图像降维成3维彻底剔除batch_size。以下例子说明了此操作的必要性
slice后数据是三维[[[7,8,9]]](三个括号),reshape后为[[7,8,9]]二维。
#add a couple of pixels of zero padding around the image
image_weight += 4
image_height += 4
conv_image = tf.image.resize_image_with_crop_or_pad(conv_image,image_height,image_weight)
使用零填充图像的边界,这里对原图像以外的四个像素进行了扩充
conv_image = tf.reshape(conv_image,(image_height,image_weight,cy,cx))
conv_image = tf.transpose(conv_image,(2,0,3,1))
conv_image = tf.reshape(conv_image,(1,cy*image_height,cx*image_weight,1))
第一个reshape()是为了将n个channel拆分为cy×cx,tf.transpose()将图像由[image_height,image_weight,cy,cx]转换为[cy,image_height,cx,image_width]最后通过reshape()将n个卷积结果在一张图片上显示。