这个CNN对40x40x2的图像效果很好,但现在我想改为13x78x2,结果出现了以下错误。我应该如何修改我的CNN架构?
Negative dimension size caused by subtracting 3 from 2 for 'conv2d_13/convolution' (op: 'Conv2D') with input shapes: [?,2,35,64], [3,3,64,64].
我的代码如下:
data_w = 40 #CHANGE TO 13 data_h = 40 #CHANGE TO 78 n_classes = 2 n_filters_1 = 32 n_filters_2 = 64 d_filter = 3 p_drop_1 = 0.25 p_drop_2 = 0.50 model = Sequential() model.add(Convolution2D(n_filters_1, d_filter, d_filter, border_mode='valid', input_shape=(data_w, data_h,2))) model.add(Activation('relu')) model.add(Convolution2D(n_filters_1, d_filter, d_filter)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(p_drop_1)) model.add(Convolution2D(n_filters_2, d_filter, d_filter, border_mode='valid')) model.add(Activation('relu')) model.add(Convolution2D(n_filters_2, d_filter, d_filter)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(p_drop_1)) ## Used to flat the input (1, 10, 2, 2) -> (1, 40) model.add(Flatten()) # Full Connected layer model.add(Dense(256)) model.add(Activation('relu')) # Drop layer model.add(Dropout(p_drop_2)) # Output Full Connected layer model.add(Dense(n_classes)) model.add(Activation('softmax'))
回答:
由于你选择了valid
作为卷积的border_mode
,这意味着在每个Convolution2D
层中,使用3×3的滤波器大小会导致边界周围各去掉1个像素。此外,如果省略该参数,也会默认使用valid填充。如果你计算出每一层输出的尺寸减少情况,你会发现输出滤波器尺寸的一个维度(行)将会变为0,从而引发错误。假设d_filter = 3
,我们来逐层查看输入图像尺寸为13×78时的输出滤波器尺寸。请注意,我省略了在Activation
和Dropout
层显示滤波器尺寸输出,因为我们已经知道它们保持输入的输出尺寸一致,以简化说明:
model.add(Convolution2D(n_filters_1, d_filter, d_filter, border_mode='valid', input_shape=(data_w, data_h,2))) # 11 x 76 model.add(Activation('relu')) model.add(Convolution2D(n_filters_1, d_filter, d_filter)) # 9 x 74 model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) # 4 x 37 model.add(Dropout(p_drop_1)) model.add(Convolution2D(n_filters_2, d_filter, d_filter, border_mode='valid')) # 2 x 35 model.add(Activation('relu')) model.add(Convolution2D(n_filters_2, d_filter, d_filter)) # 0 x 33 (!!!!) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(p_drop_1))
我建议你立即更改border_mode
为'same'
。这样,每个Convolution2D
层在到达Pooling层之前可以保持输出滤波器尺寸。我不确定你选择valid卷积的目的,但可以尝试这样做:
model.add(Convolution2D(n_filters_1, d_filter, d_filter, border_mode='same', input_shape=(data_w, data_h,2))) # 13 x 78 model.add(Activation('relu')) model.add(Convolution2D(n_filters_1, d_filter, d_filter), border_mode='same') # 13 x 78 model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) # 6 x 39 model.add(Dropout(p_drop_1)) model.add(Convolution2D(n_filters_2, d_filter, d_filter, border_mode='same')) # 6 x 39 model.add(Activation('relu')) model.add(Convolution2D(n_filters_2, d_filter, d_filter), border_mode='same') # 6 x 39 model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) # 3 x 19 model.add(Dropout(p_drop_1))
如果不这样做,你需要删除一些Convolution2D
和MaxPooling2D
层,以便生成非零的滤波器输出。像我上面一样计算你需要删除多少层。我建议删除第一组使用n_filters_2
滤波器的Convolution2D
和Activation
层之后的所有层:
model.add(Convolution2D(n_filters_1, d_filter, d_filter, border_mode='valid', input_shape=(data_w, data_h,2))) # 11 x 76 model.add(Activation('relu')) model.add(Convolution2D(n_filters_1, d_filter, d_filter)) # 9 x 74 model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) # 4 x 37 model.add(Dropout(p_drop_1)) model.add(Convolution2D(n_filters_2, d_filter, d_filter, border_mode='valid')) # 2 x 35 model.add(Activation('relu'))# model.add(Convolution2D(n_filters_2, d_filter, d_filter)) # 0 x 33 (!!!!)# model.add(Activation('relu'))# model.add(MaxPooling2D(pool_size=(2, 2)))# model.add(Dropout(p_drop_1))