3D - 变分自动编码器实现错误

3D - Variational Autoencoder implementation Error

我正在尝试按照生成深度学习一书中的说明实现 3D 变分自动编码器,并从这里获取一些东西link,这些示例是二维的,所以我已经对其进行了调整。

这是我正在使用的代码:

import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.layers import Input, BatchNormalization, Conv3D, Dense, Flatten, Lambda, Reshape, UpSampling3D
from tensorflow.keras.regularizers import l2
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K

## Functional API

input_shape = (32, 32, 32, 1)
z_dim = 3000 

###########  Encoder  ############

enc_in = Input(shape = input_shape, name="encoder_input")

enc_conv1 = tf.keras.layers.Conv3D(filters=8, kernel_size=5, strides=(1,1,1), padding='same', activation="ReLU", kernel_initializer="he_uniform", name="conv_1")(enc_in)  
max1 = tf.keras.layers.MaxPool3D(pool_size=(2,2,2), strides=(2,2,2), padding='valid', name="max_pool_1")(enc_conv1) 

enc_conv2 = tf.keras.layers.Conv3D(filters=16, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="conv_2")(max1)
max2 = tf.keras.layers.MaxPool3D(pool_size=2, name="max_pool_2")(enc_conv2)

enc_fc1 = Dense(units = 512, kernel_initializer = 'he_uniform', activation = 'ReLU')(Flatten()(max2))
   
mu = Dense(units = z_dim, kernel_initializer = 'he_uniform', activation = None, name="mu")(enc_fc1)
   
log_variance = Dense(units = z_dim, kernel_initializer = 'he_uniform', activation = None, name="log_variance")(enc_fc1)   

def sampling(args):
    mu, log_variance = args
    epsilon = K.random_normal(shape=K.shape(mu), mean= 0., stddev= 1.)
    return mu + K.exp(0.5 * log_variance) * epsilon

z = Lambda(sampling, output_shape = (z_dim, ), name="z")([mu, log_variance]) 

encoder = Model(enc_in, [mu, log_variance, z], name="encoder")


##########  Decoder  ############

dec_in = Input(shape = (z_dim, ), name="decoder_input")

dec_fc1 = Dense(units = 512, kernel_initializer = 'he_uniform', activation = 'ReLU')(dec_in)
dec_unflatten = Reshape(target_shape = (8,8,8,1))(dec_fc1)

dec_conv1 = tf.keras.layers.Conv3D(filters=32, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="deconv_1")(dec_unflatten)
ups1 = tf.keras.layers.UpSampling3D(size=(2, 2, 2), name="ups_1")(dec_conv1)

dec_conv2 = tf.keras.layers.Conv3D(filters=16, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="deconv_2")(ups1)
ups2 = tf.keras.layers.UpSampling3D(size=(2, 2, 2), name="ups_2")(dec_conv2)

dec_conv4 = Conv3D(filters = 1, kernel_size = (3, 3, 3), padding = 'same', activation="ReLU", kernel_initializer = 'he_uniform', name='decorder_output')(ups2)

decoder = Model(dec_in, dec_conv4, name="decoder")


model_input = enc_in
model_output = decoder(z)
v_autoencoder = Model(model_input, model_output)
######################

def vae_r_loss(T1_input, model_output):
  r_loss = K.mean(K.square(T1_input - model_output), axis = [1,2,3])
  return r_loss_factor * r_loss


def vae_kl_loss(T1_input, model_output):
  kl_loss = -0.5 * K.sum(1 + log_variance - K.square(mu) - K.exp(log_variance), axis = 1)
  return kl_loss


def vae_loss(T1_input, model_output):
  r_loss = vae_r_loss(T1_input, model_output)
  kl_loss = vae_kl_loss(T1_input, model_output)
  return r_loss + kl_loss

learning_rate=0.001
r_loss_factor = 500

optimizer = keras.optimizers.Adam(lr=learning_rate)

v_autoencoder.compile(optimizer=optimizer, loss = vae_loss, metrics = [vae_r_loss, vae_kl_loss])
v_autoencoder.summary()

但是当我尝试训练模型时:

history = v_autoencoder.fit(T1_input, T1_input, epochs=10, validation_split=0.2, shuffle=True)

我收到这个错误:

TypeError: You are passing KerasTensor(type_spec=TensorSpec(shape=(), dtype=tf.float32, name=None), name='Placeholder:0', description="created by layer 'tf.cast_4'"), an intermediate Keras symbolic input/output, to a TF API that does not allow registering custom dispatchers, such as `tf.cond`, `tf.function`, gradient tapes, or `tf.map_fn`. Keras Functional model construction only supports TF API calls that *do* support dispatching, such as `tf.math.add` or `tf.reshape`. Other APIs cannot be called directly on symbolic Kerasinputs/outputs. You can work around this limitation by putting the operation in a custom Keras layer `call` and calling that layer on this symbolic input/output.

encoderdecoder 模型似乎断开连接,KerasTensor 无法正确流动。此外,encoder returns 三个张量 [ mu , variance , z]decoder 只需要 z 作为输入。

替换这些行,

model_input = enc_in
model_output = decoder(z)
v_autoencoder = Model(model_input, model_output)

vae_input = Input(shape = input_shape, name="encoder_input")
mu_ , variance_ , z_ = encoder( vae_input )
vae_output = decoder( z_ )
v_autoencoder = Model( vae_input , [vae_output , mu_ , variance_] )

所以,基本上,模型现在将输出 mu_variance_,它们是编码器的输出,也是 vae_kl_loss 所必需的。早些时候,您在 vae_kl_loss 中直接使用这些 KerasTensor,因此出现错误。

vae_kl_loss

中删除 axis 参数
def vae_kl_loss( mu , log_variance ):
  kl_loss = -0.5 * K.sum(1 + log_variance - K.square(mu) - K.exp(log_variance))
  return kl_loss

muvariance传递给vae_kl_loss,

def vae_loss(T1_input, model_output):
  mu = model_output[ 1 ]
  variance = model_output[ 2 ]
  vae_output = model_output[ 0 ]
  r_loss = vae_r_loss(T1_input, vae_output )
  kl_loss = vae_kl_loss( mu , variance )
  return r_loss + kl_loss

修改后的代码:

import tensorflow as tf
from tensorflow.keras.layers import Input, BatchNormalization, Conv3D, Dense, Flatten, Lambda, Reshape, UpSampling3D
from tensorflow.keras.regularizers import l2
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K

## Functional API

input_shape = (32, 32, 32, 1)
z_dim = 3000 

###########  Encoder  ############

enc_in = Input(shape = input_shape, name="encoder_input")

enc_conv1 = tf.keras.layers.Conv3D(filters=8, kernel_size=5, strides=(1,1,1), padding='same', activation="ReLU", kernel_initializer="he_uniform", name="conv_1")(enc_in)  
max1 = tf.keras.layers.MaxPool3D(pool_size=(2,2,2), strides=(2,2,2), padding='valid', name="max_pool_1")(enc_conv1) 

enc_conv2 = tf.keras.layers.Conv3D(filters=16, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="conv_2")(max1)
max2 = tf.keras.layers.MaxPool3D(pool_size=2, name="max_pool_2")(enc_conv2)

enc_fc1 = Dense(units = 512, kernel_initializer = 'he_uniform', activation = 'ReLU')(Flatten()(max2))
   
mu = Dense(units = z_dim, kernel_initializer = 'he_uniform', activation = None, name="mu")(enc_fc1)
   
log_variance = Dense(units = z_dim, kernel_initializer = 'he_uniform', activation = None, name="log_variance")(enc_fc1)   

def sampling(args):
    mu, log_variance = args
    epsilon = K.random_normal(shape=K.shape(mu), mean= 0., stddev= 1.)
    return mu + K.exp(0.5 * log_variance) * epsilon

z = Lambda(sampling, output_shape = (z_dim, ), name="z")([mu, log_variance]) 

encoder = Model(enc_in, [mu, log_variance, z], name="encoder")


##########  Decoder  ############

dec_in = Input(shape = (z_dim, ), name="decoder_input")

dec_fc1 = Dense(units = 512, kernel_initializer = 'he_uniform', activation = 'ReLU')(dec_in)
dec_unflatten = Reshape(target_shape = (8,8,8,1))(dec_fc1)

dec_conv1 = tf.keras.layers.Conv3D(filters=32, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="deconv_1")(dec_unflatten)
ups1 = tf.keras.layers.UpSampling3D(size=(2, 2, 2), name="ups_1")(dec_conv1)

dec_conv2 = tf.keras.layers.Conv3D(filters=16, kernel_size=3, padding='same', activation="ReLU", kernel_initializer="he_uniform", name="deconv_2")(ups1)
ups2 = tf.keras.layers.UpSampling3D(size=(2, 2, 2), name="ups_2")(dec_conv2)

dec_conv4 = Conv3D(filters = 1, kernel_size = (3, 3, 3), padding = 'same', activation="ReLU", kernel_initializer = 'he_uniform', name='decorder_output')(ups2)

decoder = Model(dec_in, dec_conv4, name="decoder")

vae_input = Input(shape = input_shape, name="encoder_input")
mu_ , variance_ , z_ = encoder( vae_input )
vae_output = decoder( z_ )
v_autoencoder = Model( vae_input , [vae_output , mu_ , variance_] )
######################

def vae_r_loss(T1_input, model_output):
  r_loss = K.mean(K.square(T1_input - model_output), axis = [1,2,3])
  return r_loss_factor * r_loss


def vae_kl_loss( mu , log_variance ):
  kl_loss = -0.5 * K.sum(1 + log_variance - K.square(mu) - K.exp(log_variance))
  return kl_loss


def vae_loss(T1_input, model_output):
  mu = model_output[ 1 ]
  variance = model_output[ 2 ]
  vae_output = model_output[ 0 ]
  r_loss = vae_r_loss(T1_input, vae_output )
  kl_loss = vae_kl_loss( mu , variance )
  return r_loss + kl_loss

learning_rate=0.001
r_loss_factor = 500

optimizer = tf.keras.optimizers.Adam(lr=learning_rate)

v_autoencoder.compile(optimizer=optimizer, loss = vae_loss, metrics = [vae_r_loss, vae_kl_loss])
v_autoencoder.summary()