tf.nn.conv2d和tf.contrib.slim.conv2d的區別
在檢視程式碼的時候,看到有程式碼用到卷積層是tf.nn.conv2d,但是也有的使用的卷積層是tf.contrib.slim.conv2d,這兩個函式呼叫的卷積層是否一致,在查看了API的文件,以及slim.conv2d的原始碼後,做如下總結:
首先是常見使用的tf.nn.conv2d的函式,其定義如下:
conv2d(
input,
filter,
strides,
padding,
use_cudnn_on_gpu=None,
data_format=None,
name=None
)
input指需要做卷積的輸入影象
filter用於指定CNN中的卷積核,它要求是一個Tensor,具有[filter_height, filter_width, in_channels, out_channels]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,影象通道數,卷積核個數],要求型別與引數input相同,有一個地方需要注意,第三維in_channels,就是引數input的第四維,這裡是維度一致,不是數值一致
strides為卷積時在影象每一維的步長,這是一個一維的向量,長度為4,對應的是在input的4個維度上的步長
padding是string型別的變數,只能是"SAME","VALID"其中之一,這個值決定了不同的卷積方式,SAME代表卷積核可以停留影象邊緣,VALID表示不能,更詳細的描述可以參考http://blog.csdn.net/mao_xiao_feng/article/details/53444333
use_cudnn_on_gpu指定是否使用cudnn加速,預設為true
data_format是用於指定輸入的input的格式,預設為NHWC格式
結果返回一個Tensor,這個輸出,就是我們常說的feature map
而對於tf.contrib.slim.conv2d,其函式定義如下:
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):
inputs同樣是指需要做卷積的輸入影象
num_outputs指定卷積核的個數(就是filter的個數)
kernel_size用於指定卷積核的維度(卷積核的寬度,卷積核的高度)
stride為卷積時在影象每一維的步長
padding為padding的方式選擇,VALID或者SAME
data_format是用於指定輸入的input的格式
rate這個引數不是太理解,而且tf.nn.conv2d中也沒有,對於使用atrous convolution的膨脹率(不是太懂這個atrous convolution)
activation_fn用於啟用函式的指定,預設的為ReLU函式
normalizer_fn用於指定正則化函式
normalizer_params用於指定正則化函式的引數
用於指定權重的初始化程式
biases_initializer用於指定biase的初始化程式
biases_regularizer: biases可選的正則化程式
reuse指定是否共享層或者和變數
variable_collections指定所有變數的集合列表或者字典
outputs_collections指定輸出被新增的集合
trainable:卷積層的引數是否可被訓練
scope:共享變數所指的variable_scope
在上述的API中,可以看出去除掉初始化的部分,那麼兩者並沒有什麼不同,只是tf.contrib.slim.conv2d提供了更多可以指定的初始化的部分,而對於tf.nn.conv2d而言,其指定filter的方式相比較tf.contrib.slim.conv2d來說,更加的複雜。去除掉少用的初始化部分,其實兩者的API可以簡化如下:
tf.contrib.slim.conv2d (inputs,
num_outputs,[卷積核個數]
kernel_size,[卷積核的高度,卷積核的寬度]
stride=1,
padding='SAME',
)
tf.nn.conv2d(
input,(與上述一致)
filter,([卷積核的高度,卷積核的寬度,影象通道數,卷積核個數])
strides,
padding,
)
可以說兩者是幾乎相同的,執行下列程式碼也可知這兩者一致
import tensorflow as tf
import tensorflow.contrib.slim as slim
x1 = tf.ones(shape=[1, 64, 64, 3])
w = tf.fill([5, 5, 3, 64], 1)
# print("rank is", tf.rank(x1))
y1 = tf.nn.conv2d(x1, w, strides=[1, 1, 1, 1], padding='SAME')
y2 = slim.conv2d(x1, 64, [5, 5], weights_initializer=tf.ones_initializer, padding='SAME')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
y1_value,y2_value,x1_value=sess.run([y1,y2,x1])
print("shapes are", y1_value.shape, y2_value.shape)
print(y1_value==y2_value)
print(y1_value)
print(y2_value)