Python 具有非方形图像的CNN自动编码器

Python 具有非方形图像的CNN自动编码器,python,keras,conv-neural-network,keras-layer,autoencoder,Python,Keras,Conv Neural Network,Keras Layer,Autoencoder,我已经为编码器和解码器实现了一个带有CNN层的可变自动编码器。代码如下所示。我的训练数据(train_X)由40000张大小为64 X 78 X 1的图像组成,我的验证数据(valid_X)由4500张大小为64 X 78 X 1的图像组成 当我使用方形图像(例如64 x 64)时,一切正常,但当我使用上述图像(64 x 78)时,我得到以下错误: File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\ke

我已经为编码器和解码器实现了一个带有CNN层的可变自动编码器。代码如下所示。我的训练数据(
train_X
)由40000张大小为64 X 78 X 1的图像组成,我的验证数据(
valid_X
)由4500张大小为64 X 78 X 1的图像组成

当我使用方形图像(例如64 x 64)时,一切正常,但当我使用上述图像(64 x 78)时,我得到以下错误:

File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\keras\engine\training.py", line 1039, in fit
  validation_steps=validation_steps)
File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\keras\engine\training_arrays.py", line 199, in fit_loop
  outs = f(ins_batch)
File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\keras\backend\tensorflow_backend.py", line 2715, in __call__
  return self._call(inputs)
File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\keras\backend\tensorflow_backend.py", line 2675, in _call
  fetched = self._callable_fn(*array_vals)
File "C:\Users\user\AppData\Local\Continuum\anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 1458, in __call__
  run_metadata_ptr)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [655360] vs. [638976]
   [[{{node training/Adam/gradients/loss/decoder_loss/sub_grad/BroadcastGradientArgs}}]]
我必须在我的代码中更改什么,以便它也可以处理非二次图像?我认为问题出在解码器部分

import keras
from keras import backend as K
from keras.layers import (Dense, Input, Flatten)
from keras.layers import Lambda, Conv2D
from keras.models import Model
from keras.layers import Reshape, Conv2DTranspose
from keras.losses import mse

def sampling(args):
    z_mean, z_log_var = args
    batch = K.shape(z_mean)[0]
    dim = K.int_shape(z_mean)[1]
    epsilon = K.random_normal(shape=(batch, dim))
    return z_mean + K.exp(0.5 * z_log_var) * epsilon

inner_dim = 16
latent_dim = 6

image_size = (64,78,1)
inputs = Input(shape=image_size, name='encoder_input')
x = inputs

x = Conv2D(32, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2D(64, 3, strides=2, activation='relu', padding='same')(x)

# shape info needed to build decoder model
shape = K.int_shape(x)

# generate latent vector Q(z|X)
x = Flatten()(x)
x = Dense(inner_dim, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x)

z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])

# instantiate encoder model
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')

# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(inner_dim, activation='relu')(latent_inputs)
x = Dense(shape[1] * shape[2] * shape[3], activation='relu')(x)
x = Reshape((shape[1], shape[2], shape[3]))(x)

x = Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(x)

outputs = Conv2DTranspose(filters=1, kernel_size=3, activation='sigmoid', padding='same', name='decoder_output')(x)

# instantiate decoder model
decoder = Model(latent_inputs, outputs, name='decoder')

# instantiate VAE model
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae')

def vae_loss(x, x_decoded_mean):
    reconstruction_loss = mse(K.flatten(x), K.flatten(x_decoded_mean))
    reconstruction_loss *= image_size[0] * image_size[1]
    kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
    kl_loss = K.sum(kl_loss, axis=-1)
    kl_loss *= -0.5
    vae_loss = K.mean(reconstruction_loss + kl_loss)
    return vae_loss

optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.000)
vae.compile(loss=vae_loss, optimizer=optimizer)
vae.fit(train_X, train_X,
        epochs=500,
        batch_size=128,
        verbose=1,
        shuffle=True,
        validation_data=(valid_X, valid_X))
我必须在我的代码中更改什么,以便它也可以与非 二次图像?我认为问题出在解码器部分

import keras
from keras import backend as K
from keras.layers import (Dense, Input, Flatten)
from keras.layers import Lambda, Conv2D
from keras.models import Model
from keras.layers import Reshape, Conv2DTranspose
from keras.losses import mse

def sampling(args):
    z_mean, z_log_var = args
    batch = K.shape(z_mean)[0]
    dim = K.int_shape(z_mean)[1]
    epsilon = K.random_normal(shape=(batch, dim))
    return z_mean + K.exp(0.5 * z_log_var) * epsilon

inner_dim = 16
latent_dim = 6

image_size = (64,78,1)
inputs = Input(shape=image_size, name='encoder_input')
x = inputs

x = Conv2D(32, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2D(64, 3, strides=2, activation='relu', padding='same')(x)

# shape info needed to build decoder model
shape = K.int_shape(x)

# generate latent vector Q(z|X)
x = Flatten()(x)
x = Dense(inner_dim, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x)

z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])

# instantiate encoder model
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')

# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(inner_dim, activation='relu')(latent_inputs)
x = Dense(shape[1] * shape[2] * shape[3], activation='relu')(x)
x = Reshape((shape[1], shape[2], shape[3]))(x)

x = Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(x)

outputs = Conv2DTranspose(filters=1, kernel_size=3, activation='sigmoid', padding='same', name='decoder_output')(x)

# instantiate decoder model
decoder = Model(latent_inputs, outputs, name='decoder')

# instantiate VAE model
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae')

def vae_loss(x, x_decoded_mean):
    reconstruction_loss = mse(K.flatten(x), K.flatten(x_decoded_mean))
    reconstruction_loss *= image_size[0] * image_size[1]
    kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
    kl_loss = K.sum(kl_loss, axis=-1)
    kl_loss *= -0.5
    vae_loss = K.mean(reconstruction_loss + kl_loss)
    return vae_loss

optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.000)
vae.compile(loss=vae_loss, optimizer=optimizer)
vae.fit(train_X, train_X,
        epochs=500,
        batch_size=128,
        verbose=1,
        shuffle=True,
        validation_data=(valid_X, valid_X))
是的,解码器输出大小与馈送到fit()方法的
y
不匹配。当输入尺寸更改为64 x 78 x 1时,解码器输出尺寸为(64 x 80 x 1),而
y
fed to fit()方法仍为64 x 78 x 1(即忽略批次尺寸的列x形状)。因此,在计算解码器损耗时,y_true为64 x 78 x 1,而y_pred(解码器输出)为64 x 80 x 1,从而导致错误

tensorflow.python.framework.errors\u impl.InvalidArgumentError: 不兼容的形状:[655360]与[638976]

655360/(64*80)=128(批量大小)

638976/128=4992=64*78


解决此问题的一种方法是,如果可以接受的话,将输入_大小馈送为(64 x 80 x 1)

您应该运行
vae.summary()
,它显示
解码器的输出形状是
(64,80,1)
。问题可能出在
conv2dtranpse
layer@Tiendung你是对的,我也假设问题出在解码器中,但我找不到问题。@Tiendung问题也在“是”中描述,使用64 x 80 x 1它工作得很好。在Conv2D函数的参数padding的文档中,它被写为():“padding:valid”或“same”中的一个(不区分大小写)。请注意,“same”在跨距为1的后端之间稍有不一致!=1,如下所述)”当内核大小为奇数而映像大小为偶数时,就会出现不一致的情况:内核3 x 3和映像64 x 80 x 1。这是个问题吗?