【问题标题】:Keras CNN Autoencoder input shape is wrongKeras CNN 自动编码器输入形状错误
【发布时间】:2019-10-19 15:48:35
【问题描述】:

我已经使用 keras 构建了一个 CNN 自动编码器,它适用于 MNIST 测试数据集。我现在正在尝试使用从另一个来源收集的不同数据集。有纯图像,我必须使用 cv2 阅读它们,它工作正常。然后,我将这些图像转换为一个 numpy 数组,我认为它也可以正常工作。但是当我尝试执行 .fit 方法时,它给了我这个错误。

Error when checking target: expected conv2d_39 to have shape (100, 100, 1) but got array with shape (100, 100, 3)

我尝试将图像转换为灰度,但它们得到的形状是 (100,100),而不是模型想要的 (100,100,1)。我在这里做错了什么?

这是我正在使用的代码:

def read_in_images(path):
    images = []
    for files in os.listdir(path):
        img = cv2.imread(os.path.join(path, files))
        if img is not None:
            images.append(img)
    return images

train_images = read_in_images(train_path)
test_images = read_in_images(test_path)
x_train = np.array(train_images)
x_test = np.array(test_images) # (36, 100, 100, 3)

input_img = Input(shape=(100,100,3))
x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)


x = Conv2D(16, (3, 3), activation='relu', padding='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Conv2D(168, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), activation='relu')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)


autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')


autoencoder.fit(x_train, x_train,
            epochs=25,
            batch_size=128,
            shuffle=True,
            validation_data=(x_test, x_test),
            callbacks=[TensorBoard(log_dir='/tmp/autoencoder')])

该模型适用于 MNIST 数据集,但不适用于我自己的数据集。任何帮助将不胜感激。

【问题讨论】:

  • 这里input_img = Input(shape=(100,100,3))你已经提到了3通道,如果你得到这个错误,你的错误仍然是矛盾的。并将您的形状 (100,100) 转换为 (100,100,1) 使用numpy.expand_dims
  • 我稍微更改了代码,现在我从 cv2 读取灰度图像。并做了 np.expand(x_train, axis=3) 得到 (36, 100, 100, 1) 但模型什么也没做。它运行但损失是损失:-3104.3462 - val_loss:-2954.8867。我原来的自动编码器给了我这个 - loss: 0.1052 - val_loss: 0.1038 for MNIST
  • 我也尝试过在将数组放入 Input() 之前将其展平
  • 您的输入和输出形状不同,自动编码器不应该是这种情况。

标签: python opencv keras deep-learning conv-neural-network


【解决方案1】:

您的输入和输出形状不同。这会触发错误(我认为)。

decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)

应该是

decoded = Conv2D(num_channels, (3, 3), activation='sigmoid', padding='same')(x)

【讨论】:

  • 实际上在编码器-解码器网络中,您尝试重建输入而不是预测类别。所以输出必须与输入的形状相同,这就是 1x1 Conv2D 所做的
  • 对不起,我的意思是num_channels。输入和输出的通道数不应该相同吗?在发布的代码中,我在输入中看到 3 个通道,在输出中看到 1 个通道,这就是我认为触发错误的原因。最初的问题从不是灰度开始的。
  • 哦,是的,这改变了一切啊啊啊!你是对的,频道必须对应!
  • 另外,你在哪里找到1x1 Convolution?这是一个带有 1 个输出通道的 3x3 卷积。你的答案是正确的,但它并没有解决原来的问题。我会说这只是黑客行为。 :P
  • 我知道什么是 1x1 转换过滤器。我只是在代码中的任何地方都看不到它,而您提到了它。所以想知道。
【解决方案2】:

我进行了一些测试,并以这样的灰度加载数据:

img = cv2.imread(os.path.join(path, files), 0)

然后扩展最终加载的数组的暗淡,如:

x_train = np.expand_dims(x_train, -1)

最后用一个简单的方法标准化你的数据:

x_train = x_train / 255.

(您的模型的输入必须是:input_img = Input(shape=(100, 100, 1)

损失再次恢复正常,模型运行良好!

评论后更新

为了使所有 rgb 通道通过网络,您需要一个与您的输入形状相对应的输出。
在这里,如果您想要形状为 (100, 100, 3) 的图像,您需要从解码器输出 (100, 100, 3)。

decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x) 将缩小输出以具有形状 (100, 100, 1)

所以你只需要改变过滤器的数量,这里我们需要 3 个颜色通道,所以转换必须是这样的:

decoded = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(x)

【讨论】:

  • 成功了,谢谢。有没有办法让它保持颜色呢?
  • 问题是最终的 1x1 conv 层会将你的图像缩小为 (100, 100, 1) 数组,如果要保持 3 种颜色变暗,则需要将最后一层更改为: decoded = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(x) 如果你这样做了,你就不再需要加载到灰度和扩展dims
  • 最后一件事,小心你的第二个 Conv2D 层,你设置了一个过滤器 168 而不是一个过滤器 16
  • @ThibaultBacqueyrisses 请使用输出通道详细信息更新您的答案,因为这是一个可接受的答案。可能会让人们感到困惑。
猜你喜欢
  • 1970-01-01
  • 2021-07-10
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 1970-01-01
  • 2017-10-15
  • 1970-01-01
  • 2018-08-15
相关资源
最近更新 更多