Keras和Caffe之间的卷积有什么区别?

问题描述 投票:1回答:1

我正在尝试将大型Caffe网络复制到Keras(基于张量流后端)。但即使在单个卷积层,我也很难做到这一点。

简单的卷积一般:

假设我们有一个带有形状(1, 500, 500, 3)的4D输入,我们必须使用96滤波器对此输入执行单个卷积,其内核大小为114x4步幅。

让我们设置我们的权重和输入变量:

w = np.random.rand(11, 11, 3, 96)  # weights 1
b = np.random.rand(96)  # weights 2 (bias)

x = np.random.rand(500, 500, 3)

Keras的简单卷积:

这是如何在Keras中定义的:

from keras.layers import Input
from keras.layers import Conv2D
import numpy as np

inp = Input(shape=(500, 500, 3))
conv1 = Conv2D(filters=96, kernel_size=11, strides=(4, 4), activation=keras.activations.relu, padding='valid')(inp)                                                            


model = keras.Model(inputs=[inp], outputs=conv1)
model.layers[1].set_weights([w, b])  # set weights for convolutional layer


predicted = model.predict([x.reshape(1, 500, 500, 3)])
print(predicted.reshape(1, 96, 123, 123))  # reshape keras output in the form of Caffe

Caffe的简单卷积:

simple.prototxt

name: "simple"
input: "inp"
input_shape {
  dim: 1
  dim: 3
  dim: 500
  dim: 500
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "inp"
  top: "conv1"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 96
    kernel_size: 11
    pad: 0
    stride: 4
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "conv1"
}

Caffe in Python:

import caffe

net = caffe.Net('simple.prototxt', caffe.TEST)
net.params['conv1'][0].data[...] = w.reshape(96, 3, 11, 11)  # set weights 1
net.params['conv1'][1].data[...] = b  # set weights 2 (bias)
net.blobs['inp'].reshape(1, 3, 500, 500) # reshape input layer to fit our input array x
print(net.forward(inp=x.reshape(1, 3, 500, 500)).get('conv1'))

问题:

如果我们执行了两个代码片段,我们会注意到输出彼此不同。我知道很少有差异,比如Caffe的对称填充,但我甚至没有在这里使用填充。然而,Caffe的输出与Keras的输出不同......

为什么会这样?我知道Theano后端不像Caffe那样利用相关性,因此它需要将内核旋转180度,但是它对于tensorflow是否相同?据我所知,Tensorflow和Caffe都使用互相关而不是卷积。

我如何在Keras和Caffe中使用卷积制作两个相同的模型?

任何帮助将不胜感激,谢谢!

python keras conv-neural-network caffe convolution
1个回答
0
投票

我发现了问题,但我不确定如何解决它...

这两个卷积层之间的差异是它们的项目的对齐。这种对齐问题仅在滤波器的数量等于N时发生,使得N > 1 && N > S其中S是滤波器的维数。换句话说,这种问题只发生在我们从卷积获得多维数组时,该数组的行数和列数都大于1。

Evidence:

为了看到这一点,我简化了输入和输出数据,以便我们可以更好地分析两个层的机制。

simple.prototxt

input: "input"
input_shape {
  dim: 1
  dim: 1
  dim: 2
  dim: 2
}
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "input"
  top: "conv1"
  convolution_param {
    num_output: 2
    kernel_size: 1
    pad: 0
    stride: 1
  }
}
layer {
  name: "relu1"
  type: "ReLU"
  bottom: "conv1"
  top: "conv1"
}

simple.py

import keras
import caffe
import numpy as np
from keras.layers import Input, Conv2D
from keras.activations import relu
from keras import Model

filters = 2  # greater than 1 and ker_size
ker_size = 1 

_input = np.arange(2 * 2).reshape(2, 2)
_weights = [np.reshape([[2 for _ in range(filters)] for _ in range(ker_size*ker_size)], (ker_size, ker_size, 1, filters)), np.reshape([0 for _ in range(filters)], (filters,))]  # weights for Keras, main weight is array of 2`s while bias weight is array of 0's
_weights_caffe = [_weights[0].T, _weights[1].T]  # just transpose them for Caffe

# Keras Setup

keras_input = Input(shape=(2, 2, 1), dtype='float32')
keras_conv = Conv2D(filters=filters, kernel_size=ker_size, strides=(1, 1), activation=relu, padding='valid')(keras_input)
model = Model(inputs=[keras_input], outputs=keras_conv)
model.layers[1].set_weights([_weights[0], _weights[1]])

# Caffe Setup

net = caffe.Net("simpler.prototxt", caffe.TEST)
net.params['conv1'][0].data[...] = _weights_caffe[0]
net.params['conv1'][1].data[...] = _weights_caffe[1]
net.blobs['input'].data[...] = _input.reshape(1, 1, 2, 2)


# Predictions


print("Input:\n---")
print(_input)
print(_input.shape)
print("\n")

print("Caffe:\n---")
print(net.forward()['conv1'])
print(net.forward()['conv1'].shape)
print("\n")

print("Keras:\n---")
print(model.predict([_input.reshape(1, 2, 2, 1)]))
print(model.predict([_input.reshape(1, 2, 2, 1)]).shape)
print("\n")

输出:

Input:
---
[[0 1]
 [2 3]]
(2, 2)


Caffe:
---
[[[[0. 2.]
   [4. 6.]]

  [[0. 2.]
   [4. 6.]]]]
(1, 2, 2, 2)


Keras:
---
[[[[0. 0.]
   [2. 2.]]

  [[4. 4.]
   [6. 6.]]]]
(1, 2, 2, 2)

分析:

如果你看一下Caffe模型的输出,你会注意到我们的2x2数组首先加倍(这样我们有一个2个2x2数组的数组),然后用我们的权重矩阵对这两个数组中的每一个进行矩阵乘法。像这样的东西:

原版的:

[[[[0. 2.]
   [4. 6.]]

  [[0. 2.]
   [4. 6.]]]]

转化:

[[[[(0 * 2) (2 * 2)]
   [(4 * 2) (6 * 2)]]

  [[(0 * 2) (2 * 2)]
   [(4 * 2) (6 * 2)]]]]

Tensorflow做了不同的事情,它似乎首先按照Caffe所做的那样,按升序排列输出的2D矢量。这似乎是一种奇怪的行为,我无法理解为什么他们会做这样的事情。

Solution:

我已经回答了我自己关于问题原因的问题,但我还没有意识到任何干净的解决方案。我仍然没有找到满意的答案,因此我将接受有实际解决方案的问题。

我所知道的唯一解决方案是创建自定义图层,这对我来说不是一个非常简洁的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.