下面来介绍tf.nn.separable_conv2d 的用法。
可以参考官方文档:官方文档
大家只要知道函数的参数,以及参数的设定方式:
input: 一个Tensor。数据维度是四维 [batch, in_height, in_width, in_channels]。
depthwise_filter: 一个Tensor。数据维度是四维 [filter_height, filter_width, in_channels, channel_multiplier]。其中,in_channels 的卷积深度是 1。
pointwise_filter: 一个Tensor。数据维度是四维 [1, 1, channel_multiplier * in_channels, out_channels]。其中,pointwise_filter 是在 depthwise_filter 卷积之后的混合卷积。
strides: 一个长度是4的一维整数类型数组,每一维度对应的是 input 中每一维的对应移动步数,比如,strides[1] 对应 input[1] 的移动步数。
padding: 一个字符串,取值为 SAME 或者 VALID 。
name: (可选)为这个操作取一个名字。
输出参数:
一个四维的Tensor,数据维度为 [batch, out_height, out_width, out_channels]。
异常:
数值异常: 如果 channel_multiplier * in_channels > out_channels ,那么将报错。
接下来是具体的做法,先附上代码:
import numpy as np
import tensorflow as tf
input_data = tf.Variable(np.random.randint(1,5,size=(1, 4, 4,3)), dtype = np.float32 )
depthwise_filter = tf.Variable(np.random.randint(1,5,size=(3, 3, 3, 3)), dtype = np.float32)
pointwise_filter = tf.Variable(np.random.randint(1,5,size=(1, 1, 9, 1)), dtype = np.float32)
y = tf.nn.separable_conv2d(input_data, depthwise_filter, pointwise_filter, strides = [1, 1, 1, 1], padding = 'VALID')
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print("out1=",sess.run(input_data))
print("out2=",sess.run(depthwise_filter))
print("out3=",sess.run(pointwise_filter))
print ("out4=",sess.run(y))
print ("out5=",sess.run(tf.shape(y)))
因为是随机产生的数,我的程序产生如下:
out1= [[[[ 1. 4. 4.]
[ 3. 4. 2.]
[ 3. 1. 3.]
[ 2. 1. 3.]]
[[ 3. 1. 4.]
[ 2. 2. 1.]
[ 3. 2. 2.]
[ 4. 1. 1.]]
[[ 3. 4. 1.]
[ 1. 4. 2.]
[ 1. 3. 1.]
[ 2. 2. 2.]]
[[ 4. 2. 4.]
[ 1. 1. 1.]
[ 1. 4. 3.]
[ 3. 1. 2.]]]]
out2= [[[[ 4. 1. 3.]
[ 4. 2. 1.]
[ 4. 4. 4.]]
[[ 3. 3. 3.]
[ 4. 2. 1.]
[ 1. 2. 3.]]
[[ 4. 3. 4.]
[ 3. 3. 2.]
[ 2. 3. 4.]]]
[[[ 2. 1. 2.]
[ 1. 1. 4.]
[ 4. 3. 3.]]
[[ 3. 1. 2.]
[ 2. 3. 1.]
[ 4. 4. 1.]]
[[ 3. 4. 3.]
[ 3. 2. 1.]
[ 4. 3. 3.]]]
[[[ 2. 3. 1.]
[ 1. 2. 4.]
[ 1. 1. 2.]]
[[ 2. 3. 2.]
[ 3. 1. 3.]
[ 3. 4. 2.]]
[[ 3. 1. 2.]
[ 2. 2. 3.]
[ 1. 4. 3.]]]]
out3= [[[[ 4.]
[ 4.]
[ 4.]
[ 1.]
[ 2.]
[ 3.]
[ 4.]
[ 4.]
[ 4.]]]]
out4= [[[[ 1697.]
[ 1496.]]
[[ 1513.]
[ 1372.]]]]
out5= [1 2 2 1]
具体请看下图
:
具体做法就是每个filter 的第 i个通道和input的第 i个channel进行卷积,举个例子就是本文中的三个滤波器的第一个通道和输入的第一个通道做卷积,得到三张特征图,依次计算,便得到9个特征图,这些特征图再和pointwise_filter作卷积,最终求和。
我用matlab测试了一下,的确是这样。这个应该就是Mobilenet中的depthwise separable convolution,具体原理参考我的上一篇博文:深度神经网络模型压缩
clc,clear all
channel1_1=[1 3 3;3 2 3;3 1 1];
channel1_2=[3 3 2;2 3 4;1 1 2];
channel1_3=[3 2 3;3 1 1;4 1 1];
channel1_4=[2 3 4;1 1 2;1 1 3];
channel2_1=[4 4 1;1 2 2;4 4 3];
channel2_2=[4 1 1;2 2 1;4 3 2];
channel2_3=[1 2 2;4 4 3;2 1 4];
channel2_4=[2 2 1;4 3 2;1 4 1];
channel3_1=[4 2 3;4 1 2;1 2 1];
channel3_2=[2 3 3;1 2 1;2 1 2];
channel3_3=[4 1 2;1 2 1;4 1 3];
channel3_4=[1 2 1;2 1 2;1 3 2];
%滤波器
filter1_1=[4 3 4;2 3 3;2 2 3];
filter1_2=[4 4 3;1 2 3;1 3 2];
filter1_3=[4 1 2;4 4 4;1 3 1];
filter2_1=[1 3 3;1 1 4;3 3 1];
filter2_2=[2 2 3;1 3 2;2 1 2];
filter2_3=[4 2 3;3 4 3;1 4 4];
filter3_1=[3 3 4;2 2 3;1 2 2];
filter3_2=[1 1 2;4 1 1;4 3 3];
filter3_3=[4 3 4;3 1 3;2 2 3];
%卷积结果
O1_1=sum(sum(channel1_1.*filter1_1));
O1_2=sum(sum(channel1_2.*filter1_1));
O1_3=sum(sum(channel1_3.*filter1_1));
O1_4=sum(sum(channel1_4.*filter1_1));
O2_1=sum(sum(channel1_1.*filter2_1));
O2_2=sum(sum(channel1_2.*filter2_1));
O2_3=sum(sum(channel1_3.*filter2_1));
O2_4=sum(sum(channel1_4.*filter2_1));
O3_1=sum(sum(channel1_1.*filter3_1));
O3_2=sum(sum(channel1_2.*filter3_1));
O3_3=sum(sum(channel1_3.*filter3_1));
O3_4=sum(sum(channel1_4.*filter3_1));
OO_1=[O1_1 O1_2;O1_3 O1_4]
OO_2=[O2_1 O2_2;O2_3 O2_4]
OO_3=[O3_1 O3_2;O3_3 O3_4]
O4_1=sum(sum(channel2_1.*filter1_2));
O4_2=sum(sum(channel2_2.*filter1_2));
O4_3=sum(sum(channel2_3.*filter1_2));
O4_4=sum(sum(channel2_4.*filter1_2));
O5_1=sum(sum(channel2_1.*filter2_2));
O5_2=sum(sum(channel2_2.*filter2_2));
O5_3=sum(sum(channel2_3.*filter2_2));
O5_4=sum(sum(channel2_4.*filter2_2));
O6_1=sum(sum(channel2_1.*filter3_2));
O6_2=sum(sum(channel2_2.*filter3_2));
O6_3=sum(sum(channel2_3.*filter3_2));
O6_4=sum(sum(channel2_4.*filter3_2));
OO_4=[O4_1 O4_2;O4_3 O4_4]
OO_5=[O5_1 O5_2;O5_3 O5_4]
OO_6=[O6_1 O6_2;O6_3 O6_4]
O7_1=sum(sum(channel3_1.*filter1_3));
O7_2=sum(sum(channel3_2.*filter1_3));
O7_3=sum(sum(channel3_3.*filter1_3));
O7_4=sum(sum(channel3_4.*filter1_3));
O8_1=sum(sum(channel3_1.*filter2_3));
O8_2=sum(sum(channel3_2.*filter2_3));
O8_3=sum(sum(channel3_3.*filter2_3));
O8_4=sum(sum(channel3_4.*filter2_3));
O9_1=sum(sum(channel3_1.*filter3_3));
O9_2=sum(sum(channel3_2.*filter3_3));
O9_3=sum(sum(channel3_3.*filter3_3));
O9_4=sum(sum(channel3_4.*filter3_3));
OO_7=[O7_1 O7_2;O7_3 O7_4]
OO_8=[O8_1 O8_2;O8_3 O8_4]
OO_9=[O9_1 O9_2;O9_3 O9_4]
X_3=4*OO_1+4*OO_2+4*OO_3+1*OO_4+2*OO_5+3*OO_6+4*OO_7+4*OO_8+4*OO_9
最后,请大家看一下这篇博文,有类似的卷积操作:tf.nn.depthwiseconv2d
如有错误,欢迎指出