我们先回忆一下普通的卷积操纵,对于一个输入张量,[N,H,W,C]分别表示图片数目、图片高度、宽度和通道数,如果我们设定卷积核[H_kernal,W_kernal,C_in,C_out]分别表示卷积核的高度、宽度、输入通道数也就是卷积核厚度、输出通道数也就是卷积数目。通常卷积核的厚度是等于图片通道数的,也就是说一个卷积核可以是把一片区域内的所有通道都包住。所以平时卷积函数里面写kernal_size都只有[H_kernal,W_kernal]两个参数,因为厚度默认是图片的通道数了,输出通道数也就是卷积核数量会单独作为一个参数设置。例如函数:
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)
其中的:filter——是输出通道数目,即卷积核的个数。kernel_size: 两个整数的元组或列表,表示卷积核在高、宽尺寸。
而卷积核的厚度是多少呢?函数已经帮你设置好了,就是按照输入张量的通道数来的。
但是,我们的可分卷积就不一样了,它比较复杂,是由一个depthwise卷积再接一个pointwise卷积完成的。
对depthwise卷积,它的卷积核厚度不是输入张量的通道数,而是1,这个也是函数帮你设置好的。通俗地理解就是卷积核厚度只有一层,然后在输入张量上一层一层地滑动,所以一个卷积核就对应了num_channel_in个输出通道,所以总的输出通道数是num_channel_in*depth_multiple。而pointwise卷积其实就是一个1*1卷积,它的卷积核厚度是num_chan