博主最近在跑一个 github 上面的基于 Keras 的深度学习模型的时候发现如下的报错:
ValueError: Negative dimension size caused by subtracting 2 from 1 for 'MaxPool_21' (op: 'MaxPool') with input shapes: [?,1,128,128].
初步判断是 tensor 的 shape 有问题 ,其中使用了简化版本的 vgg16 模块,使用的模型部分结构如下:
def create_vgg16_dense_kpf( input_shape, model_name = 'vgg16_dense_kpf', is_simplified = True ) :
'''Create a CNN feature extractor that is identical to the well known VGG16 architecture
INPUT:
input_shape = tuple of ( nb_chs, nb_rows, nb_cols ), input image shape
model_name = string, name of the output model
is_simplified = bool, whether or not use all 5 CNN blocks of VGG16
OUTPUT:
vgg16_cnn_featex = keras.model, output model
'''
img_input = Input( shape = input_shape )
print(1, img_input.shape)
# Block 1
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name= model_name + '-block1_conv1')(img_input)
print(2, x.shape)
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name= model_name + '-block1_conv2')(x)
print(3, x.shape)
x = MaxPooling2D((2, 2), strides=(2, 2), name= model_name + '-block1_pool')(x)
print(4, x.shape)
# Block 2
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name= model_name + '-block2_conv1')(x)
print(5, x.shape)
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name= model_name + '-block2_conv2')(x)
print(6, x.shape)
x = MaxPooling2D((2, 2), strides=(2, 2), name= model_name + '-block2_pool')(x)
print(7, x.shape)
# Block 3
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name= model_name + '-block3_conv1')(x)
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name= model_name + '-block3_conv2')(x)
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name= model_name + '-block3_conv3')(x)
x = MaxPooling2D((2, 2), strides=(2, 2), name= model_name + '-block3_pool')(x)
print(x.shape)
# Block 4
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name= model_name + '-block4_conv1')(x)
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name= model_name + '-block4_conv2')(x)
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name= model_name + '-block4_conv3')(x)
x = MaxPooling2D((2, 2), strides=(2, 2), name= model_name + '-block4_pool')(x)
print(x.shape)
查看每层的 x 的 shape 后,发现如下结果:
模型的输入是 (3, 256, 256)
讲道理,经过第一层卷积输出后的 shape 应该是(?,64, 256, 256),而非(?, 3, 256, 64),可见我的初步判断并没有错。最后的通道发生了改变。
查阅 Keras 的手册,发现:
Keras 是一个模型级的库,提供了快速构建深度学习网络的模块。Keras 并不处理如张量乘法、卷积等底层操作。这些操作依赖于某种特定的、优化良好的张量操作库。Keras 依赖于处理张量的库就称为“后端引擎”。Keras 提供了两种后端引擎Theano/Tensorflow,并将其函数统一封装,使得用户可以以同一个接口调用不同后端引擎的函数。
‘th’模式下,输入形如(samples,channels,rows,cols)的4D张量
‘tf’模式下,输入形如(samples,rows,cols,channels)的4D张量
‘th’模式下,为形如(samples,nb_filter, new_rows, new_cols)的4D张量
‘tf’模式下,为形如(samples,new_rows, new_cols,nb_filter)的4D张量
th:Theano
tf:Tensorflow
可见我的模型是在 'tf' 模式下运行的。
如果你至少运行过一次Keras,你将在下面的目录下找到Keras的配置文件:
~/.keras/keras.json
如果该目录下没有该文件,你可以手动创建一个
文件的默认配置如下:
{
"image_dim_ordering":"tf",
"epsilon":1e-07,
"floatx":"float32",
"backend":"tensorflow"
}
将 backend
字段的值改写为你需要使用的后端:theano
或 tensorflow
,即可完成后端的切换
可以通过定义环境变量 KERAS_BACKEND
来覆盖上面配置文件中定义的后端:
KERAS_BACKEND=tensorflow python -c "from keras import backend;"
Using TensorFlow backend.
{
"image_dim_ordering": "tf",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"
}
你可以更改以上 ~/.keras/keras.json
中的配置
其中:
image_dim_ordering
:字符串,"tf" 或 "th",该选项指定了 Keras 将要使用的维度顺序
epsilon
:浮点数,防止除0错误的小数字
floatx
:字符串,"float16", "float32", "float64" 之一,为浮点数精度
backend
:字符串,所使用的后端,为 "tensorflow " 或 "theano"
参考资料:
https://keras-cn-docs.readthedocs.io/zh_CN/latest/backend/