这里简要总结一下tensorflow实现卷积操作的几种写法,定义方式有很多。例如使用一个9x9的卷积核将一个三通道图像转换成64通道的feature,遇到过的有以下一些:
直接定义就写
这种写法简单粗暴,一边定义卷积核、偏置和卷及操作一边写,优点是操作灵活,但是代码量太大尤其是重复单元较多的时候,一个例子如下:1
2
3
4
5weight = tf.get_variable('weight',[9,9,3,64], initializer=tf.truncated_normal_initializer(stddev=0.01))#定义权重
biases = tf.get_variable('bias',[64],initializer = tf.constant(0.01))#定义偏置
conv = tf.nn.conv2d(input,weight,stride=[1,1,1,1],padding='SAME')#卷积
bias = tf.nn.bias_add(conv,biases)#加偏置
activate_conv = tf.nn.relu(bias)# 激活
对卷积中的各部分做封装再写
不过上面这样实现卷积仍然过于复杂,如果每层都这么弄那么代码量会非常大,因此可以对权重定义等做封装,如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def weight_variable(shape,name): #定义权重
initial = tf.truncated_normal(shape,stddev=0.01)
return tf.Variable(initial,name=name)
def bias_variable(shape,name): #定义偏置
initial = tf.constant(0.01,shape=shape)
return tf.Variable(initial,name=name)
def conv2d(x,W): #定义卷积
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SMAE')
#这样上述的卷积可以写成
W1 = weight_varialble([9,9,3,64],name='W1')
b1 = bias_variable([64],name='b1')
out = tf.nn.relu(conv2d(input,W1)+b1)
这样每层都可以用三行代码就搞定了,相比于原来的六层代码少写了很多,当然借助tensorflow的slim库,代码量还可以减少的更多。
通过slim库再写
emsp; slim库对卷积的封装程度非常高的,导入slim库,一行就能搞定1
out = slim.conv2d(input,64,kernel_size=[9,9])
这个操作可以说是很简洁了,就连偏置和激活函数都省略了,当然灵活度也降低了很多,slim默认加上bias,激活函数默认使用relu,具体定义接口如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19def convolution(inputs,
num_outputs,
kernel_size,
stride=1,
padding='SAME',
data_format=None,
rate=1,
activation_fn=nn.relu,
normalizer_fn=None,
normalizer_params=None,
weights_initializer=initializers.xavier_initializer(),
weights_regularizer=None,
biases_initializer=init_ops.zeros_initializer(),
biases_regularizer=None,
reuse=None,
variables_collections=None,
outputs_collections=None,
trainable=True,
scope=None):
现在使用多了,还是偏向于使用slim,毕竟方便,当然以后还是要慢慢转pytorch,感觉调试更友好啊。