mxnet与tensorflow的卷积实现细节比较

mxnet的卷积 kernel = 3 pad=1边界补充0后,不管stride是否1还是2,imgw = 奇数或者偶数, 都是从图像位置(0,0)开始卷积

tensorlfow的卷积 kernel = 3 pad=‘SAME’边界补充0后,

imgw = 偶数

stride=1, 是从图像位置(0,0)开始卷积

stride=2, 是从图像位置(1,1)开始卷积 与mxnet不同

imgw = 奇数

stride=1, 是从图像位置(0,0)开始卷积

stride=2, 是从图像位置(0,0)开始卷积

tensorlfow的卷积 kernel = 3 pad=‘VAILD’ 边界不补充0,

不管stride是否1还是2,imgw = 奇数或者偶数, 都是从图像位置(1,1)开始卷积

#coding=utf-8
import math
import mxnet as mx
import numpy as np
import tensorflow as tf
from mxnet.gluon import nn
from mxnet import ndarray as nd
# import tensorlayer as tl
# from tensorflow.contrib.layers.python.layers import utils
# import collections
# from tensorlayer.layers import Layer, list_remove_repeat

def out_dim(input, kernel, stride, pad, dilate):
    x = input
    p = pad
    s = stride
    d = dilate
    k = kernel
    output = math.floor((x + 2 * p - d * (k - 1) - 1) / s) + 1
    return output


#比较mxnet与tensorflow的conv batchnorm prelu的计算
#mxnet卷积层
# 输入数据格式是:batch * inchannel * height * width
# 输出数据格式是:batch * outchannel * height * width
# 权重格式:      output_channels * in_channels * height * width
#(1)比较卷积
height = 6
width = 6
inchannel = 1
outchannel = 1

# #conv0 (64, 112, 112) kernel (3, 3) stride (1, 1) pad (1, 1)
# wkernel = 3
# stride = 1
# pad = 1
# dilate  = 1
# output_height = out_dim(height, wkernel, stride, pad, dilate)
# if output_height == height:
#     print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "SAME")
# else:
#     print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "VALID")

#stage1_unit1_conv2 (64, 56, 56) kernel (3, 3) stride (2, 2) pad (1, 1)
wkernel = 3
stride = 2
pad = 1
dilate  = 1
output_height = out_dim(height, wkernel, stride, pad, dilate)
if output_height == height:
    print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "SAME")
else:
    print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "VALID")

# #stage1_unit1_conv1sc (64, 56, 56) kernel (1, 1) stride (2, 2) pad (0, 0)
# wkernel = 1
# stride = 2
# pad = 0
# dilate  = 1
# output_height = out_dim(height, wkernel, stride, pad, dilate)
# if output_height == height:
#     print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "SAME")
# else:
#     print("input: ", height, width, " wkernel", wkernel, " stride: ", stride, " pad:", pad, " output_height: ", output_height, output_height, "VALID")

w = nd.arange(wkernel * wkernel * inchannel * outchannel).reshape((outchannel,inchannel,wkernel,wkernel))
b = nd.array([0])
data = nd.arange(height * width * inchannel).reshape((1,inchannel,height,width))
# mxnet直接nd卷积运算nd.Convolution
#out = nd.Convolution(data,w,b,kernel=w.shape[2:],num_filter=outchannel,stride=(1,1), pad=(1, 1))
print('input:',data)
print('weight:',w)
#print('bias:',b)
# print('mxnet ndarray output:',out)
# print('\n')

#mxnet利用symbol计算卷积
ws = mx.sym.Variable('w')
bs = mx.sym.Variable('b')
datas = mx.sym.Variable('data')
# outs = mx.sym.Convolution(data=datas, weight=ws, bias=bs, num_filter=w.shape[1], kernel=w.shape[2:], stride=(1,1), pad=(0, 0),
#                                 no_bias=False, name="conv0")
outs = mx.sym.Convolution(data=datas, weight=ws, num_filter=outchannel, kernel=w.shape[2:], stride=(stride,stride), pad=(pad, pad),
                                no_bias=True, name="conv0")
#outs = mx.sym.Convolution(datas,ws,bs,kernel=w.shape[2:],num_filter=w.shape[1])
ex=outs.bind(mx.cpu(), {'data':data, 'w':w, 'b':b})
ex.forward()
mxnetresult = ex.outputs[0].asnumpy()
print("mxnet symbol:\n", ex.outputs[0].asnumpy())
# output_height = out_dim(height, w.shape[2], stride, pad, dilate)
# output_width = out_dim(width, w.shape[2], stride, pad, dilate)
# print("input_height: ", height, width)
# print("output_height: ", output_height, output_width)



#tensorflow计算卷积
#(W-F + 2 p / S)+ 1
# 输入数据格式是:batch *  height * width * inchannel
# 输出数据格式是:batch  * height * width * outchannel
# 权重格式:      height * width * in_channels * output_channels 
# w = np.arange(4).reshape((2,2,1,1))
# b = np.array([0])
# data = np.arange(9).reshape((1,3,3,1))
# w = w.reshape((wkernel,wkernel,inchannel,outchannel)).asnumpy()
# data = data.reshape((1, height,width,inchannel)).asnumpy()

data = data.asnumpy().transpose(0,2,3,1)
w = w.asnumpy().transpose(2,3,1,0)
b = b.asnumpy()
# print('input:',data)
# print('inputshape:',data.shape)
# print('weight:',w)
# print('weight:',w.shape)
input = tf.Variable(data, dtype=np.float32)
#input_reshape = tf.reshape(input, [1,inchannel,height,width])
filter = tf.Variable(w, dtype=np.float32)
#filter_reshape = tf.reshape(filter, [outchannel,inchannel,wkernel,wkernel])
if pad == 0:
    conv = tf.nn.conv2d(input, filter, strides=[1, stride, stride, 1], padding='VALID')
else:
    conv = tf.nn.conv2d(input, filter, strides=[1, stride, stride, 1], padding='SAME')

kernel_size = 3
kernel_size_effective = kernel_size
pad_total = kernel_size_effective - 1
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
print(pad_beg, pad_end)
input_PadLayer = tf.pad(input, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]], name='padding')

if stride==2:
    conv_padlayer = tf.nn.conv2d(input_PadLayer, filter, strides=[1, stride, stride, 1], padding='VALID')

# nets = tl.layers.Conv2d(inputs, n_filter=num_outputs, filter_size=(kernel_size, kernel_size), b_init=None,
#                             strides=(strides, strides), W_init=w_init, act=None, padding='VALID', name=scope,
#                             use_cudnn_on_gpu=True)
#nets = BatchNormLayer(nets, act=tf.identity, is_train=True, trainable=trainable, name=scope+'bn3')
#conv_reshape = tf.reshape(conv, [1,outchannel,output_height,output_height])
#conv_reshape = tf.reshape(conv, [1,1,2,2])

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    #print("input: \n", sess.run(input))
    input_reshape = sess.run(input).transpose(0,3,1,2)
    #print("input_reshape: \n", input_reshape)
    #print("filter: \n", sess.run(filter))
    filter_reshape = sess.run(filter).transpose(3,2,0,1)
    #print("filter_reshape: \n", filter_reshape)
    #print("conv ", sess.run(conv))
    conv_reshape = sess.run(conv).transpose(0,3,1,2)
    print("conv_reshape: \n", conv_reshape)
    if stride==2:
        input_PadLayer_reshape = sess.run(input_PadLayer).transpose(0,3,1,2)
        print("input_PadLayer_reshape: \n", input_PadLayer_reshape)

        conv_padlayer_reshape = sess.run(conv_padlayer).transpose(0,3,1,2)
        print("conv_padlayer_reshape: \n", conv_padlayer_reshape)
    
        tensorflowresult = conv_padlayer_reshape
    else:
        tensorflowresult = conv_reshape
    #print("tf_height", op2_reshape.shape.as_list())
    #print("tf_height", op2_reshape.shape.as_list())
    if (tensorflowresult==mxnetresult).all():
        print("success ")
    else:
        print("failed ")

input: 6 6 wkernel 3 stride: 2 pad: 1 output_height: 3 3 VALID

input:

[[[[ 0. 1. 2. 3. 4. 5.]

[ 6. 7. 8. 9. 10. 11.]

[ 12. 13. 14. 15. 16. 17.]

[ 18. 19. 20. 21. 22. 23.]

[ 24. 25. 26. 27. 28. 29.]

[ 30. 31. 32. 33. 34. 35.]]]]

<NDArray 1x1x6x6 @cpu(0)>

weight:

[[[[ 0. 1. 2.]

[ 3. 4. 5.]

[ 6. 7. 8.]]]]

<NDArray 1x1x3x3 @cpu(0)>

mxnet symbol:

[[[[ 103. 196. 262.]

[ 411. 618. 690.]

[ 735. 1050. 1122.]]]]

1 1

conv_reshape:

[[[[ 366. 438. 294.]

[ 798. 870. 546.]

[ 451. 481. 271.]]]]

input_PadLayer_reshape:

[[[[ 0. 0. 0. 0. 0. 0. 0. 0.]

[ 0. 0. 1. 2. 3. 4. 5. 0.]

[ 0. 6. 7. 8. 9. 10. 11. 0.]

[ 0. 12. 13. 14. 15. 16. 17. 0.]

[ 0. 18. 19. 20. 21. 22. 23. 0.]

[ 0. 24. 25. 26. 27. 28. 29. 0.]

[ 0. 30. 31. 32. 33. 34. 35. 0.]

[ 0. 0. 0. 0. 0. 0. 0. 0.]]]]

conv_padlayer_reshape:

[[[[ 103. 196. 262.]

[ 411. 618. 690.]

[ 735. 1050. 1122.]]]]

success