卷积神经网络计算
记录m卷积网络计算过程
以tensorflow中的mnist_deep为例
在训练时保存checkpoint
saver = tf.train.Saver()
....
save_path = saver.save(sess,'mnist_deep/model.ckpt')
训练完成后,可以读取checkpoint,保存log可以用tensorboard查看模型结构
reader = tf.train.NewCheckpointReader('mnist_deep/model.ckpt')
all_variables = reader.get_variable_to_shape_map()
mnist = input_data.read_data_sets('../mnist-master/input_data')
saver = tf.train.import_meta_graph('mnist_deep/model.ckpt.meta')
with tf.Session() as sess:
saver.restore(sess,'mnist_deep/model.ckpt')
writer = tf.summary.FileWriter('mnist_deep/log')
writer.add_graph(sess.graph)
writer.flush()
writer.close()
查看模型计算图,在log目录下运行cmd命令如下
tensorboard --logdir=log
按照提示信息打开浏览器,在浏览器中可以看到计算图如下
在tesnorboard中可以查看各个操作的详细情况,可以用以下方式看到任意一步的输出的结果
reader = tf.train.NewCheckpointReader('mnist_deep/model.ckpt')
all_variables = reader.get_variable_to_shape_map()
mnist = input_data.read_data_sets('../mnist-master/input_data')
saver = tf.train.import_meta_graph('mnist_deep/model.ckpt.meta')
with tf.Session() as sess:
saver.restore(sess,'mnist_deep/model.ckpt')
input_x = mnist.test.images
input_x = input_x[0:1,:]
x = tf.get_default_graph().get_operation_by_name('Placeholder').outputs[0]
keep_prob = tf.get_default_graph().get_operation_by_name('dropout/Placeholder').outputs[0]
MatMul_output0 = tf.get_default_graph().get_operation_by_name('conv1/Conv2D').outputs[0]
reshape_output = sess.run(tf.get_default_graph().get_operation_by_name('reshape/Reshape').outputs[0],feed_dict={x:input_x})
result = sess.run(MatMul_output0,feed_dict={x:input_x})
如以上代码得到了’reshape/Reshape’跟’conv1/Conv2D’处的输出
既然可以得到每步输出,那就对照写下各个步骤的计算过程
首先看第一个卷积层
input:[none,28,28,1]
output:[none,28,28,32],
内部长这个样子的
输入28*28的单通道图片,feature map数量为32,边界补零方式为’same’,即输入输出大小相等
卷积函数如下
def Conv2D(x, W, bias,strides=[1, 1, 1, 1], padding='SAME'):
if len(x.shape)!=4:
print("input shape must be [samples,width,height,channel!]")
return -1
#补0后的图片大小
pad_row = W.shape[0]-1
pad_col = W.shape[1]-1
filter_num = W.shape[3]
sample_num = x.shape[0]
width = x.shape[1]
height = x.shape[2]
channel = x.shape[3]
new_width = width+pad_row
new_height = height+pad_col
x_pad = np.zeros((sample_num,new_width,new_height,channel),dtype=float)
x_pad[:,int(pad_row/2):new_width-int(pad_row/2),int(pad_col/2):new_height-int(pad_col/2),:] = x
x_output = np.zeros((sample_num,width,height,filter_num), dtype=float)
#卷积计算
for sample in range(sample_num):
for fi in range(filter_num):
for i in range(width):
for j in range(height):
x_output[sample, i, j, fi] = x_output[sample,i,j,fi] + bias[fi]
for ch in range(channel):
mul = np.multiply(x_pad[sample,i:i+W.shape[0],j:j+W.shape[1],ch],W[:,:,ch,fi])
x_output[sample,i,j,fi] = x_output[sample,i,j,fi]+np.sum(np.sum(mul))
return x_output
这一步完成了权值与输入数据的卷积以及加上偏置
再经过一个Relu激活函数如下
def ReLu(x):
return np.maximum(x,0)
然后再经过一个最大池化层
def max_pool_2x2(x):
width = x.shape[1]
height = x.shape[2]
m=0;
n=0;
x_out = np.zeros((x.shape[0], int(x.shape[1]/2), int(x.shape[2]/2), x.shape[3]), dtype=float)
for filter_index in range(x.shape[3]):
m=0
for i in range(0,width,2):
n=0;
for j in range(0,height,2):
x_out[0,m,n,filter_index] = np.max(x[0,i:i+2,j:j+2,filter_index])
n=n+1
m=m+1
return x_out
然后再经过全连接层
def fc(x,W,bias):
x_reshape = x.reshape(x.shape[0],-1)
return np.dot(x_reshape,W)+bias
mnist例子中的网络结构并不复杂,inference过程很容易写出来,这里仅记录conv层的参数计算问题,
第一个卷积层
输入 [1,28,28,1],输出[1,28,28,32] [ 1 , 28 , 28 , 1 ] , 输 出 [ 1 , 28 , 28 , 32 ] ,权值w大小为 [5,5,1,32],偏置b[1,32] [ 5 , 5 , 1 , 32 ] , 偏 置 b [ 1 , 32 ] ,第二个卷积层
输入 [1,28,28,32],输出[1,28,28,64],权值w[5,5,32,64],偏置b[1,64] [ 1 , 28 , 28 , 32 ] , 输 出 [ 1 , 28 , 28 , 64 ] , 权 值 w [ 5 , 5 , 32 , 64 ] , 偏 置 b [ 1 , 64 ]
第一个通道为1卷积层很容易理解,第二个卷积层中,通道(feature)数为32,可以这样理解,32个通道,每个通道都有64个5X5的卷积核,每个通道都分别与64个卷积核做卷积,得到
[1,28,28,32,64]输出
[
1
,
28
,
28
,
32
,
64
]
输
出
,最后,再将32个通道的各个feature相加得到最终的
[1,28,28,64]输出
[
1
,
28
,
28
,
64
]
输
出
,64个输出feature map,就有64个偏置,偏置相加是
28∗28
28
∗
28
中每个点都要加,也可以直接写成
import numpy as np
具体实现在自己写的Conv2D函数中循环部分
b = np.ones([1,28,28,64])*bias[0]
output = output+b