最近本菜折腾起了TensorFlow,在折腾到卷积层这个环节的时候有许多的疑惑。
不同的API,傻傻分不清楚
TensorFlow的卷积层API有很多个,tf.nn.conv2d()
, tf.layers.conv2d()
, tf.contrib.layers.conv2d()
, tf.contrib.slim.conv2d()
, tf.keras.layers.Conv2D()
等。还有很多我没有列举出来的。
首先tf.contrib
模块是TensorFlow 1.x才有的,TensorFlow 2.x已经弃用了这个模块,因为“contrib模块的成长,超出了TensorFlow团队 (在一个repo里) 能维护的范围。”量子位:TensorFlow2.0要来了,tf.contrib要砍了
但是TensorFlow 1的其他内容可以在tensorflow.compat.v1
里面找到,并且在2.x的生命周期里,会得到持续的维护。因此,结论是如果安装的是TensorFlow 2.x,而教学书上的、网上的代码是按TensorFlow 1.x写的话,运行的时候大概率会报各种没有这个模块、没有这个方法之类的错误,这个时候换成tensorflow.compat.v1
即可。具体import方法可以是:
1 2 3 |
import tensorflow.compat.v1 as tf tf.disable_v2_behavior() |
但是如果代码里面有tf.contrib
的话,这个方法就行不通了。我就是在寻找替代方案的过程中发现了有那么多conv2d
相关的方法。因此需要记录一下它们的区别。
(1) tf.contrib.layers.conv2d() & tf.contrib.slim.conv2d()
刚刚提到,这个方法只有在1.x里面有。方法的参数定义可以参见 TensorFlow: tf.contrib.layers.conv2d
1 2 3 4 5 6 7 8 |
tf.contrib.layers.conv2d( inputs, num_outputs, kernel_size, stride=1, padding='SAME', data_format=None, rate=1, activation_fn=tf.nn.relu, normalizer_fn=None, normalizer_params=None, weights_initializer=initializers.xavier_initializer(), weights_regularizer=None, biases_initializer=tf.zeros_initializer(), biases_regularizer=None, reuse=None, variables_collections=None, outputs_collections=None, trainable=True, scope=None ) |
inputs
:该卷积层的输入。A Tensor of rank N+2 of shape [batch_size] + input_spatial_shape + [in_channels]
。
num_outputs
:等于卷积核/滤波器的个数,跟其他方法的filters
是一样的。
kernel_size
:卷积核大小。
stride
:步长。
padding
:One of VALID
or SAME
. 默认VALID
。
activation_fn
:激活函数。默认tf.nn.relu
。
weights_initializer
:权重初始化器。默认initializers.xavier_initializer()
biases_initializer
:偏差初始化器。
具体的使用例子:
1 2 3 4 5 6 7 8 9 |
self.conv1 = tf.contrib.layers.convolution2d( \ inputs=self.imageIn,num_outputs=32,kernel_size=[8,8],stride=[4,4],padding='VALID', biases_initializer=None) self.conv2 = tf.contrib.layers.convolution2d( \ inputs=self.conv1,num_outputs=64,kernel_size=[4,4],stride=[2,2],padding='VALID', biases_initializer=None) self.conv3 = tf.contrib.layers.convolution2d( \ inputs=self.conv2,num_outputs=64,kernel_size=[3,3],stride=[1,1],padding='VALID', biases_initializer=None) self.conv4 = tf.contrib.layers.convolution2d( \ inputs=self.conv3,num_outputs=512,kernel_size=[7,7],stride=[1,1],padding='VALID', biases_initializer=None) |
tf.contrib.slim.conv2d()
跟tf.contrib.layers.conv2d()
是一模一样的。另外,tf.contrib.layers.conv2d()
,tf.contrib.layers.Conv2D()
,tf.contrib.layers.convolution2d()
都是一样的,详见上面的官方API说明。
(2) tf.layers.conv2d()
这个方法可以作为tf.contrib.layers.conv2d()
和tf.contrib.slim.conv2d()
在TensorFlow 2.x下的替代(2.x在tensorflow.compat.v1
中)。但是需要小心的是对应参数的Keyword有了变化。 TensorFlow: tf.compat.v1.layers.conv2d
1 2 3 4 5 6 7 8 9 |
tf.compat.v1.layers.conv2d( inputs, filters, kernel_size, strides=(1, 1), padding='valid', data_format='channels_last', dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer=None, bias_initializer=tf.zeros_initializer(), kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, trainable=True, name=None, reuse=None ) |
inputs
:一致。
filters
:即num_outputs
。
kernel_size
:一致。
strides
:即stride
。
padding
:One of VALID
or SAME
. 默认SAME
。
activation
:即activation_fn
。默认None
。
kernel_initializer
:即weights_initializer
。默认None
。
biases_initializer
:即biases_initializer
。
因此除了需要注意参数的Keyword发生了变化,更需要注意的是参数默认值的变化。不注意这个的话会付出惨痛的代价,本人已经亲身经历了。把tf.contrib.layers.convolution2d()
换成tf.layers.conv2d()
之后死活不收敛,最后发现这俩货的激活函数和初始化器的默认值是不一样的,如果没有特别指定,这两个方法得到的效果就会完全不一样。
(3) tf.nn.conv2d()
这是一个底层方法,需要指定卷积核且只完成把图像与卷积核卷积的操作。上面的方法都是tf.nn.conv2d()
的高级封装。
(4) tf.keras.layers.Conv2D()
同样是tf.nn.conv2d()
的高级封装。与(1)(2)方法不同的地方是使用方法不同。但是参数的Keyword和默认值与tf.layers.conv2d()
是类似的(略有不同,具体看文档)。TensorFlow: tf.keras.layers.Conv2D
1 2 3 4 5 6 7 8 |
tf.keras.layers.Conv2D( filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), groups=1, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, **kwargs ) |
使用方法上有较大不同。上一层的输出放的位置不同。
1 2 3 4 5 6 7 8 9 |
# The inputs are 28x28 RGB images with `channels_last` and the batch # size is 4. input_shape = (4, 28, 28, 3) x = tf.random.normal(input_shape) y = tf.keras.layers.Conv2D(2, 3, activation='relu', input_shape=input_shape[1:])(x) print(y.shape) (4, 26, 26, 2) |
债见