【问题标题】:Building a VGG Face model in TF: Running into shape mismatch and unsupported shape errors在 TF 中构建 VGG 人脸模型:遇到形状不匹配和不支持的形状错误
【发布时间】:2020-08-09 00:26:49
【问题描述】:

问题:如何设置 CNN 以使形状匹配?这是我第一次与一个人合作,因为我的背景是 NLP,我遇到了形状不匹配的错误。

我尝试过的:

  1. 我已尝试编辑过滤器和 kernel_size 变量。
  2. 我认为 kernel_size 是正确的。我尝试将过滤器变量设置为 tf.constant(kernel).shape[-1] 和 tf.constant(kernel).shape[-2]。在我看来,没有任何其他选择,所以我很困惑,尽管我认为这就是问题所在。

输入权重矩阵:

  1. http://www.robots.ox.ac.uk/~vgg/software/vgg_face/
  2. 下载 vgg_face_matconvnet.tar.gz 并压缩。
  3. vgg_face_matconvnet/Data/vgg_face.mat

代码:

# read layer info
model = tf.keras.Sequential()
model.add(tf.keras.Input([224, 224, 3]))
for layer in layers:
    layer_type = layer[0][0][0][0]
    name = layer[0][0][1][0]
    if layer_type == 'conv':
        print(layer_type)
        print(name)
        weights = layer[0][0][2][0]
        stride = layer[0][0][3][0]
        # pad =  layer[0][0][4][0]
        learningRate = layer[0][0][5][0]
        weightDecay = layer[0][0][6][0]
        momentum = layer[0][0][7][0]
        kernel, bias = weights
        # kernel = np.transpose(kernel, (1, 0, 2, 3))
        bias = np.squeeze(bias).reshape(-1)
        filters = tf.constant(kernel).shape[-1]
        kernel_size = (3,3) #[np.shape(kernel)[-3], np.shape(kernel)[-2]]
        bias_initializer = tf.constant_initializer(bias)
        strides=[1, stride[0]]
        if name[:2] == 'fc':
            padding = 'VALID'
            if name == 'fc6':
                model.add(tf.keras.layers.Flatten())
                dense_layer = tf.keras.layers.Dense(filters, kernel_initializer=tf.constant_initializer(kernel))
            if name == 'fc7':
                dense_layer = tf.keras.layers.Dense(filters, kernel_initializer=tf.constant_initializer(kernel))
            model.add(dense_layer)
        else:
            padding = 'SAME'
            conv2d_layer = tf.keras.layers.Conv2D(filters, kernel_size, strides=strides, kernel_initializer=tf.constant_initializer(kernel))
            model.add(conv2d_layer)
        print(f"{name} stride: {stride} kernel size: {np.shape(kernel)}")        
    elif layer_type == 'relu':
        model.add(tf.keras.layers.ReLU(max_value=None, negative_slope=0, threshold=0))
        print(name)
    elif layer_type == 'pool':
        pool = layer[0][0][3][0]
        stride = layer[0][0][4][0]
        model.add(tf.keras.layers.MaxPool2D(pool_size=pool, strides=(stride[0],stride[0]), padding='SAME', data_format="channels_last"))
        print(f"{name} stride: {stride}")
    elif layer_type == 'softmax':
        model.add(tf.keras.layers.Softmax())
        print(name)

错误信息:

TypeError: Eager execution of tf.constant with unsupported shape (value has 102760448 elements, shape is (2048, 4096) with 8388608 elements).

【问题讨论】:

  • 你在 Google Colab 上运行代码吗?
  • @HaardikDharma 是的
  • @pr338 我的回答解决了你的问题吗?

标签: python tensorflow conv-neural-network


【解决方案1】:

您没有为卷积层使用正确的填充,这会导致层输出形状与预期不符。

最后一个MaxPool2D 的输出具有(None, 2, 2, 512) 的形状,当您将其展平时,您有2048 个输入节点到Densefc6。您创建的 Dense 层具有 4096 个节点,因此预期的权重矩阵具有形状 (2048, 4096) = 8388608 值。但是,您从 .mat 文件中读取的权重矩阵具有更多的值,并且实际上需要 25088 个输入节点,这会导致错误。

像这样修改你的代码:

model = tf.keras.Sequential()
model.add(tf.keras.Input([224, 224, 3]))
for layer in layers:
    layer_type = layer[0][0][0][0]
    name = layer[0][0][1][0]
    if layer_type == 'conv':
        print(layer_type)
        print(name)
        weights = layer[0][0][2][0]
        stride = layer[0][0][3][0]
        # pad =  layer[0][0][4][0]
        learningRate = layer[0][0][5][0]
        weightDecay = layer[0][0][6][0]
        momentum = layer[0][0][7][0]
        kernel, bias = weights
        # kernel = np.transpose(kernel, (1, 0, 2, 3))
        bias = np.squeeze(bias).reshape(-1)
        filters = tf.constant(kernel).shape[-1]
        kernel_size = (3,3) #[np.shape(kernel)[-3], np.shape(kernel)[-2]]
        bias_initializer = tf.constant_initializer(bias)
        strides=[1, stride[0]]
        if name[:2] == 'fc':
            # padding = 'VALID' # <-- not needed, Dense layers do not use padding
            if name == 'fc6':
                model.add(tf.keras.layers.Flatten())
                dense_layer = tf.keras.layers.Dense(filters, kernel_initializer=tf.constant_initializer(kernel))
            if name == 'fc7':
                dense_layer = tf.keras.layers.Dense(filters, kernel_initializer=tf.constant_initializer(kernel))
            model.add(dense_layer)
        else:
            padding = 'SAME'
            conv2d_layer = tf.keras.layers.Conv2D(filters, kernel_size, strides=strides, padding=padding, kernel_initializer=tf.constant_initializer(kernel)) # <--- padding = 'same' so that output shape is the same as input shape!
            model.add(conv2d_layer)
        print(f"{name} stride: {stride} kernel size: {np.shape(kernel)}")        
    elif layer_type == 'relu':
        model.add(tf.keras.layers.ReLU(max_value=None, negative_slope=0, threshold=0))
        print(name)
    elif layer_type == 'pool':
        pool = layer[0][0][3][0]
        stride = layer[0][0][4][0]
        model.add(tf.keras.layers.MaxPool2D(pool_size=pool, strides=(stride[0],stride[0]), padding='SAME', data_format="channels_last"))
        print(f"{name} stride: {stride}")
    elif layer_type == 'softmax':
        model.add(tf.keras.layers.Softmax())
        print(name)

这样可以正确导入权重。

【讨论】:

    猜你喜欢
    • 2016-07-27
    • 2021-12-13
    • 2015-11-06
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多