Я нашел проблему, но пока не знаю, как ее исправить ...
Разница между этими двумя сверточными слоями заключается в выравнивании их элементов.Эта проблема alignment возникает только тогда, когда количество фильтров равно N
, так что N > 1 && N > S
, где S
- это размер фильтра.Другими словами, такая проблема возникает только тогда, когда мы получаем многомерный массив из свертки, который имеет и число строк и количество столбцов больше, чем 1 .
Доказательства:
Чтобы увидеть это, я упростила свои входные и выходные данные, чтобы мы могли лучше проанализировать механику обоих слоев.
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 делает что-то другое, этоКажется, сначала выравнивает 2D-векторы вывода в порядке возрастания после того же, что и Caffe.Это кажется странным поведением, и я не могу понять, почему они так поступили.
Решение:
Я ответил на свой вопрос о причина проблемы, но я пока не знаю ни одного чистого решения.Я все еще не нахожу свой ответ достаточно удовлетворительным, поэтому я собираюсь принять вопрос, который имеет реальное решение.
Единственное, что я знаю, это создание пользовательского слоя, который не является очень аккуратным решением дляя.