Keras Custom Layer 每次接收相同的输入形状
Keras Custom Layer Receives same input shape every time
我在扩展keras层的keras中编写OctConv卷积层,我编写了以下代码。
import keras.backend as K
from keras.layers import Layer, UpSampling2D, Add, Concatenate, Conv2D, Conv2DTranspose
class OCTCONV_LAYER(Layer):
def __init__(self,
filters=16,
kernel_size=(3, 3),
strides=(2, 2),
dilation_rate=(1, 1),
padding='same',
alpha_in=0.6,
alpha_out=0.6,
**kwargs
):
self.filters = filters
self.kernel_size = kernel_size
self.strides = strides
self.padding = padding
self.alpha_in = alpha_in
self.alpha_out = alpha_out
if dilation_rate[0] > 1:
self.strides = (1, 1)
self.dilation_rate = dilation_rate
super(OCTCONV_LAYER, self).__init__(**kwargs)
def build(self, input_shape):
print('INPUT_SHAPE : {}'.format(input_shape))
op_channels = self.filters
low_op_channels = int(op_channels*self.alpha_out)
high_op_channels = op_channels-low_op_channels
inp_channels = input_shape[-1]
low_inp_channels = int(inp_channels*self.alpha_in)
high_inp_channels = inp_channels-low_inp_channels
self.h_2_l = self.add_weight(
name='hl',
shape=self.kernel_size + (high_inp_channels, low_op_channels),
initializer='he_normal'
)
self.h_2_h = self.add_weight(
name='hh',
shape=self.kernel_size + (high_inp_channels, high_op_channels),
initializer='he_normal'
)
self.l_2_h = self.add_weight(
name='lh',
shape=self.kernel_size + (low_inp_channels, high_op_channels),
initializer='he_normal'
)
self.l_2_l = self.add_weight(
name='ll',
shape=self.kernel_size + (low_inp_channels, low_op_channels),
initializer='he_normal'
)
print('High 2 low : {}'.format(self.h_2_l.shape))
print('High 2 high : {}'.format(self.h_2_h.shape))
print('Low 2 high : {}'.format(self.l_2_h.shape))
print('Low 2 low : {}'.format(self.l_2_l.shape))
super(OCTCONV_LAYER, self).build(input_shape)
def call(self, x):
inp_channels = int(x.shape[-1])
low_inp_channels = int(inp_channels*self.alpha_in)
high_inp_channels = inp_channels-low_inp_channels
high_inp = x[:,:,:, :high_inp_channels]
print('High input shape : {}'.format(high_inp.shape))
low_inp = x[:,:,:, high_inp_channels:]
low_inp = K.pool2d(low_inp, (2, 2), strides=(2, 2), pool_mode='avg')
print('Low input shape : {}'.format(low_inp.shape))
out_high_high = K.conv2d(high_inp, self.h_2_h, strides=(2, 2), padding='same')
print('OUT HIGH HIGH shape : {}'.format(out_high_high.shape))
out_low_high = UpSampling2D((2, 2))(K.conv2d(low_inp, self.l_2_h, strides=(2, 2), padding='same'))
print('OUT LOW HIGH shape : {}'.format(out_low_high.shape))
out_low_low = K.conv2d(low_inp, self.l_2_l, strides=(2, 2), padding='same')
print('OUT LOW LOW shape : {}'.format(out_low_low.shape))
out_high_low = K.pool2d(high_inp, (2, 2), strides=(2, 2), pool_mode='avg')
out_high_low = K.conv2d(out_high_low, self.h_2_l, strides=(2, 2), padding='same')
print('OUT HIGH LOW shape : {}'.format(out_high_low.shape))
out_high = Add()([out_high_high, out_low_high])
print('OUT HIGH shape : {}'.format(out_high.shape))
out_low = Add()([out_low_low, out_high_low])
out_low = UpSampling2D((2, 2))(out_low)
print('OUT LOW shape : {}'.format(out_low.shape))
out_final = K.concatenate([out_high, out_low], axis=-1)
print('OUT SHAPE : {}'.format(out_final.shape))
out_final._keras_shape = self.compute_output_shape(out_final.shape)
return out_final
def compute_output_shape(self, inp_shape):
return inp_shape
要创建层,我正在使用以下代码创建模型
from keras.layers import Input
inp = Input(shape=(224, 224, 3))
x = OCTCONV_LAYER(filters=16)(inp)
x = OCTCONV_LAYER()(x)
...
控制台上的输出是,
如您所见,最后一层的输入形状与输入层相同,而第一个octconv层的输出形状不是输入形状。
代码有什么问题?我错过了什么吗?
您的代码可能没问题。 K.conv2d, as observed in 似乎有问题。解决此问题的一种解决方法是从 tensorflow 导入 keras(例如,将所有 keras
导入更改为 tensorflow.keras
)。
然后您需要进行以下更改:
low_inp_channels = int(int(inp_channels) * self.alpha_in)
high_inp_channels = int(inp_channels) - low_inp_channels
在这种情况下,第二个 OCTCONV_LAYER
的输入维度对应于第一个 OCTCONV_LAYER
的输出维度。经过前面的改动,结果是:
第一层
INPUT_SHAPE : (?, 224, 224, 3)
High 2 low : (3, 3, 2, 9)
High 2 high : (3, 3, 2, 7)
Low 2 high : (3, 3, 1, 7)
Low 2 low : (3, 3, 1, 9)
High input shape : (?, 224, 224, 2)
Low input shape : (?, 112, 112, 1)
OUT HIGH HIGH shape : (?, 112, 112, 7)
OUT LOW HIGH shape : (?, 112, 112, 7)
OUT LOW LOW shape : (?, 56, 56, 9)
OUT HIGH LOW shape : (?, 56, 56, 9)
OUT HIGH shape : (?, 112, 112, 7)
OUT LOW shape : (?, 112, 112, 9)
OUT SHAPE : (?, 112, 112, 16)
第二层
INPUT_SHAPE : (?, 112, 112, 16)
High 2 low : (3, 3, 7, 9)
High 2 high : (3, 3, 7, 7)
Low 2 high : (3, 3, 9, 7)
Low 2 low : (3, 3, 9, 9)
High input shape : (?, 112, 112, 7)
Low input shape : (?, 56, 56, 9)
OUT HIGH HIGH shape : (?, 56, 56, 7)
OUT LOW HIGH shape : (?, 56, 56, 7)
OUT LOW LOW shape : (?, 28, 28, 9)
OUT HIGH LOW shape : (?, 28, 28, 9)
OUT HIGH shape : (?, 56, 56, 7)
OUT LOW shape : (?, 56, 56, 9)
OUT SHAPE : (?, 56, 56, 16)
我在扩展keras层的keras中编写OctConv卷积层,我编写了以下代码。
import keras.backend as K
from keras.layers import Layer, UpSampling2D, Add, Concatenate, Conv2D, Conv2DTranspose
class OCTCONV_LAYER(Layer):
def __init__(self,
filters=16,
kernel_size=(3, 3),
strides=(2, 2),
dilation_rate=(1, 1),
padding='same',
alpha_in=0.6,
alpha_out=0.6,
**kwargs
):
self.filters = filters
self.kernel_size = kernel_size
self.strides = strides
self.padding = padding
self.alpha_in = alpha_in
self.alpha_out = alpha_out
if dilation_rate[0] > 1:
self.strides = (1, 1)
self.dilation_rate = dilation_rate
super(OCTCONV_LAYER, self).__init__(**kwargs)
def build(self, input_shape):
print('INPUT_SHAPE : {}'.format(input_shape))
op_channels = self.filters
low_op_channels = int(op_channels*self.alpha_out)
high_op_channels = op_channels-low_op_channels
inp_channels = input_shape[-1]
low_inp_channels = int(inp_channels*self.alpha_in)
high_inp_channels = inp_channels-low_inp_channels
self.h_2_l = self.add_weight(
name='hl',
shape=self.kernel_size + (high_inp_channels, low_op_channels),
initializer='he_normal'
)
self.h_2_h = self.add_weight(
name='hh',
shape=self.kernel_size + (high_inp_channels, high_op_channels),
initializer='he_normal'
)
self.l_2_h = self.add_weight(
name='lh',
shape=self.kernel_size + (low_inp_channels, high_op_channels),
initializer='he_normal'
)
self.l_2_l = self.add_weight(
name='ll',
shape=self.kernel_size + (low_inp_channels, low_op_channels),
initializer='he_normal'
)
print('High 2 low : {}'.format(self.h_2_l.shape))
print('High 2 high : {}'.format(self.h_2_h.shape))
print('Low 2 high : {}'.format(self.l_2_h.shape))
print('Low 2 low : {}'.format(self.l_2_l.shape))
super(OCTCONV_LAYER, self).build(input_shape)
def call(self, x):
inp_channels = int(x.shape[-1])
low_inp_channels = int(inp_channels*self.alpha_in)
high_inp_channels = inp_channels-low_inp_channels
high_inp = x[:,:,:, :high_inp_channels]
print('High input shape : {}'.format(high_inp.shape))
low_inp = x[:,:,:, high_inp_channels:]
low_inp = K.pool2d(low_inp, (2, 2), strides=(2, 2), pool_mode='avg')
print('Low input shape : {}'.format(low_inp.shape))
out_high_high = K.conv2d(high_inp, self.h_2_h, strides=(2, 2), padding='same')
print('OUT HIGH HIGH shape : {}'.format(out_high_high.shape))
out_low_high = UpSampling2D((2, 2))(K.conv2d(low_inp, self.l_2_h, strides=(2, 2), padding='same'))
print('OUT LOW HIGH shape : {}'.format(out_low_high.shape))
out_low_low = K.conv2d(low_inp, self.l_2_l, strides=(2, 2), padding='same')
print('OUT LOW LOW shape : {}'.format(out_low_low.shape))
out_high_low = K.pool2d(high_inp, (2, 2), strides=(2, 2), pool_mode='avg')
out_high_low = K.conv2d(out_high_low, self.h_2_l, strides=(2, 2), padding='same')
print('OUT HIGH LOW shape : {}'.format(out_high_low.shape))
out_high = Add()([out_high_high, out_low_high])
print('OUT HIGH shape : {}'.format(out_high.shape))
out_low = Add()([out_low_low, out_high_low])
out_low = UpSampling2D((2, 2))(out_low)
print('OUT LOW shape : {}'.format(out_low.shape))
out_final = K.concatenate([out_high, out_low], axis=-1)
print('OUT SHAPE : {}'.format(out_final.shape))
out_final._keras_shape = self.compute_output_shape(out_final.shape)
return out_final
def compute_output_shape(self, inp_shape):
return inp_shape
要创建层,我正在使用以下代码创建模型
from keras.layers import Input
inp = Input(shape=(224, 224, 3))
x = OCTCONV_LAYER(filters=16)(inp)
x = OCTCONV_LAYER()(x)
...
控制台上的输出是,
如您所见,最后一层的输入形状与输入层相同,而第一个octconv层的输出形状不是输入形状。 代码有什么问题?我错过了什么吗?
您的代码可能没问题。 K.conv2d, as observed in keras
导入更改为 tensorflow.keras
)。
然后您需要进行以下更改:
low_inp_channels = int(int(inp_channels) * self.alpha_in)
high_inp_channels = int(inp_channels) - low_inp_channels
在这种情况下,第二个 OCTCONV_LAYER
的输入维度对应于第一个 OCTCONV_LAYER
的输出维度。经过前面的改动,结果是:
第一层
INPUT_SHAPE : (?, 224, 224, 3)
High 2 low : (3, 3, 2, 9)
High 2 high : (3, 3, 2, 7)
Low 2 high : (3, 3, 1, 7)
Low 2 low : (3, 3, 1, 9)
High input shape : (?, 224, 224, 2)
Low input shape : (?, 112, 112, 1)
OUT HIGH HIGH shape : (?, 112, 112, 7)
OUT LOW HIGH shape : (?, 112, 112, 7)
OUT LOW LOW shape : (?, 56, 56, 9)
OUT HIGH LOW shape : (?, 56, 56, 9)
OUT HIGH shape : (?, 112, 112, 7)
OUT LOW shape : (?, 112, 112, 9)
OUT SHAPE : (?, 112, 112, 16)
第二层
INPUT_SHAPE : (?, 112, 112, 16)
High 2 low : (3, 3, 7, 9)
High 2 high : (3, 3, 7, 7)
Low 2 high : (3, 3, 9, 7)
Low 2 low : (3, 3, 9, 9)
High input shape : (?, 112, 112, 7)
Low input shape : (?, 56, 56, 9)
OUT HIGH HIGH shape : (?, 56, 56, 7)
OUT LOW HIGH shape : (?, 56, 56, 7)
OUT LOW LOW shape : (?, 28, 28, 9)
OUT HIGH LOW shape : (?, 28, 28, 9)
OUT HIGH shape : (?, 56, 56, 7)
OUT LOW shape : (?, 56, 56, 9)
OUT SHAPE : (?, 56, 56, 16)