Я пытаюсь найти способ выполнить двумерные свертки над тензорами, размерность которых больше 4, что является входным рангом, необходимым для keras.layers.Conv2D и keras.backend.conv2d .Под этим я подразумеваю, что вместо ввода размером [batch, W, H, C]
я хотел бы иметь возможность использовать [batch,<some_other_dimensions>, W, H, C]
, и для этих других измерений обрабатывать, по существу, так же, как «пакет» (например, незатронутыйсвертка).Неудивительно, что это приводит к ошибке, поэтому изменение формы массива кажется наиболее простым решением, однако есть проблемы с этим (как описано ниже).
При изменении формы я возиться с тем, что Керас видит какпакетное измерение, поэтому мне нужно использовать keras.backend.reshape , а не keras.layers.Reshape , который, по-видимому, не обращается к пакетному измерению ваших данных.Используя лямбда-слой и keras.backend.reshape , мы можем создать входные массивы размером [batch*<some_other_dimensions>,W,H,C]
, а затем снова изменить их форму после выполнения нашей свертки. Тем не менее, важно, чтобы этот слой мог образовывать часть полностью сверточной сети, которая может работать с произвольными размерами изображений, которые имеют неопределенные значения W и H (установите значение «Нет» при создании экземпляра формы входного слоя). Следовательно,мы заканчиваем тем, что передаем форму, которая имеет два неопределенных пространственных измерения, в keras.backend.reshape , которую он явно не может использовать: [batch*<some_other_dimensions>,None,None,C]
.
Я могу заставить ее работать, когдаявно объявив ширину и высоту (как вы можете видеть в моем коде).Однако я действительно не хочу жертвовать способностью принимать произвольные размеры пространственных измерений, поскольку для моего проекта важно иметь возможность сделать это.
Единственный другой вариант, который я могу придумать, - это на самом деле определить мойсобственный пользовательский слой, который может обрабатывать> 4-мерные входы для 2D сверток.Я не знаю, с чего начать, но совет был бы весьма желателен, если бы люди думали, что это самый жизнеспособный путь.Или, может быть, есть отличный лямбда-слой, который решает мою проблему?
from keras.layers import Input, Conv2D, Lambda
import keras.backend as K
from keras.models import Model
def reshape_then_conv(data_shape):
input = Input(shape=data_shape)
#should equal (None, *data_shape) because batch is prepended as None
print(' INPUT SHAPE: ', input.shape)
#reshaping input into 4D
reshaped = Lambda(lambda x: K.reshape(x,(-1, *input.shape[3:])))(input)
print(' AFTER RESHAPE: ', reshaped.shape)
#convolve new 4D tensor
convolved = Conv2D(10,(3,3),strides=2)(reshaped)
print('AFTER CONVOLUTION: ', convolved.shape)
#reshaping back but keeping new spatial and channel dimensions from convolution
reshaped_back = Lambda(lambda x: K.reshape(x,(-1,*input.shape[1:3],*convolved.shape[-3:])))(convolved)
return Model(inputs=input,outputs=reshaped_back)
#images of size 100,100,3 in 4-by-4 set
layer = reshape_then_conv([4,4,100,100,3])
print(' OUTPUT SHAPE: ', layer.output_shape,'\n')
#images of undefined size in 4-by-4 set
layer = reshape_then_conv([4,4,None,None,3])
print(' OUTPUT SHAPE: ', layer.output_shape)
Как и ожидалось, первый вызов 'reshape_then_conv' работает, так как мы явно устанавливаем ширину и высоту.Однако во втором примере:
TypeError: Не удалось преобразовать объект типа в Tensor.> Содержание: (-1, Размер (Нет), Размер (Нет), Размер (3)).Рассмотрим> приведение элементов к поддерживаемому типу.
Заранее благодарим за любые идеи, которые у вас могут быть!
ОБНОВЛЕНИЕ
Благодаря @Ответ DMolony, я изменил код следующим образом ...
from keras.layers import Input, Conv2D, Lambda
import keras.backend as K
from keras.models import Model
def reshape_then_conv(data_shape):
input = Input(shape=data_shape)
print(' INPUT SHAPE: ', input.shape)
new_shape = K.concatenate((K.variable([-1],dtype='int32'),K.shape(input)[3:]))
#reshaping input into 4D
reshaped = Lambda(lambda x: K.reshape(x,new_shape))(input)
print(' AFTER RESHAPE: ', reshaped.shape)
#convolve new 4D tensor
convolved = Conv2D(10,(3,3),strides=2)(reshaped)
print('AFTER CONVOLUTION: ', convolved.shape)
returning_shape = K.concatenate((K.variable([-1],dtype='int32'),K.shape(input)[1:3],K.shape(convolved)[-3:]))
#reshaping back but keeping new spatial and channel dimensions from convolution
reshaped_back = Lambda(lambda x: K.reshape(x,returning_shape))(convolved)
return Model(inputs=input,outputs=reshaped_back)
#images of size 100,100,3 in 4-by-4 set
layer = reshape_then_conv([4,4,100,100,3])
print(' OUTPUT SHAPE: ', layer.output_shape,'\n')
#images of undefined size in 4-by-4 set
layer = reshape_then_conv([4,4,None,None,3])
print(' OUTPUT SHAPE: ', layer.output_shape)