Я пытаюсь обучить вариационный автоэнкодер. Модель существует из двух частей: кодера и декодера. Кодер имеет 2 входа и 3 выхода. Декодер имеет 3 входа (первый - последний выход кодера, второй - потери, третий - маска.) И три выхода. Кодер и декодер объединяются для формирования модели автоматического кодера. Я попытался выполнить настройку, приведенную в примере с автоматическим кодировщиком: https://www.tensorflow.org/guide/keras/functional. Но, похоже, это не работает для меня.
Модель:
from tensorflow import keras
from tensorflow.keras.layers import Dense, Lambda, Reshape, Concatenate, Conv1D
from tensorflow.keras.models import Model
from tensorflow.keras.losses import mse, categorical_crossentropy
from tensorflow.keras import backend as K
import tensorflow.compat.v1 as tf
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
def mse_particles(inputs, outputs, particles):
particles = K.reshape(particles, shape=(K.shape(particles)[0],))
in_slice = K.cast(2 + particles*3, "int32")
mask_fn = lambda n: K.concatenate((K.ones((n,), dtype="float32"), K.zeros((3*16+2-n,), dtype="float32")))
mask = K.map_fn(mask_fn, in_slice, dtype='float32')
se = (inputs - outputs)**2
loss = K.sum(se * mask, axis=None)
loss = loss / K.sum(mask, axis=None)
return loss
def initialize_model(beta, n_particles, n_classes, latent_size, activation_func):
'Network parameters'
input_shape_class = (n_particles, )
input_shape_regress = (3 * n_particles + 2, )
hidden_layer_dim = 512
latent_dim = latent_size * n_particles
'Build encoder'
encoder_inputs_class = keras.Input(shape=input_shape_class, name='inputs_class')
inputs_class_t = Lambda(lambda x: K.one_hot(K.cast(x, 'int32'), n_classes))(encoder_inputs_class)
inputs_class_t2 = Reshape((n_particles*n_classes,))(inputs_class_t)
encoder_inputs_regress = keras.Input(shape=input_shape_regress, name='inputs_regress')
inputs = Concatenate()([inputs_class_t2, encoder_inputs_regress])
x_1 = Dense(hidden_layer_dim, activation=activation_func)(inputs)
x_2 = Dense(int(hidden_layer_dim/2), activation=activation_func)(x_1)
x_3 = Dense(int(hidden_layer_dim/4), activation=activation_func)(x_2)
'Latent space'
z_mean = Dense(latent_dim, activation='linear', name='z_mean')(x_3)
z_log_var = Dense(latent_dim, activation='linear', name='z_log_var')(x_3)
z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])
encoder = Model([encoder_inputs_class, encoder_inputs_regress], [z_mean, z_log_var, z], name='encoder')
encoder.summary()
'Build decoder'
decoder_inputs_latent = keras.Input(shape=(latent_dim,), name='z_sampling')
decoder_inputs_n_particles = keras.Input(shape=(1,), name='input_n_particles')
decoder_inputs_n_particles_mask = keras.Input(shape=(latent_dim, ), name='inputs_n_particles_mask')
# Implement mask
masked_latent = Lambda(lambda x: x[0]*x[1])([decoder_inputs_latent, decoder_inputs_n_particles_mask])
x_4 = Dense(int(hidden_layer_dim/4), activation=activation_func)(masked_latent)
x_5 = Dense(int(hidden_layer_dim/2), activation=activation_func)(x_4)
x_6 = Dense(hidden_layer_dim, activation=activation_func)(x_5)
outputs_class_t = Dense(n_particles*n_classes, activation='elu')(x_6)
outputs_class_t2 = Reshape((n_particles, n_classes))(outputs_class_t)
decoder_outputs_class = Dense(n_classes, activation='softmax')(outputs_class_t2)
decoder_outputs_regress = Dense(n_particles*3+2, activation='linear')(x_6)
decoder_outputs_n_particles = Dense(1, activation='linear')(x_6)
decoder = Model([decoder_inputs_latent, decoder_inputs_n_particles, decoder_inputs_n_particles_mask], [decoder_outputs_class, decoder_outputs_regress, decoder_outputs_n_particles], name='decoder')
decoder.summary()
'Build autoencoder'
vae_input_1 = keras.Input(shape=input_shape_class, name = 'vae_input_1')
vae_input_2 = keras.Input(shape=input_shape_regress, name = 'vae_input_2')
vae_input_3 = keras.Input(shape=(1,), name = 'vae_input_3')
vae_input_4 = keras.Input(shape=(latent_dim, ), name = 'vae_input_4')
outputs = decoder([encoder([vae_input_1, vae_input_2])[2], vae_input_3, vae_input_4])
vae = Model([vae_input_1, vae_input_2, vae_input_3, vae_input_4], outputs, name='bvae')
vae.summary()
'Calculate loss'
n_particles_loss = mse(decoder_inputs_n_particles, outputs[2])
classification_loss = categorical_crossentropy(inputs_class_t, outputs[0])
regression_loss = mse(encoder_inputs_regress, outputs[1])
reconstruction_loss = 100*K.mean(n_particles_loss) + 10*K.mean(classification_loss) + K.mean(regression_loss)
kl_loss = -0.5 * K.sum((1+z_log_var-K.square(z_mean)-K.exp(z_log_var)), axis=-1)
vae_loss = K.mean((1-beta) * reconstruction_loss + beta * kl_loss)
vae.add_loss(vae_loss)
vae.compile(optimizer = keras.optimizers.Adam(lr=1e-4, beta_1=0.9, beta_2=0.999))
return vae, encoder, decoder
И я пытаюсь загрузить его, чтобы обучить, но у меня появляется следующая ошибка:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-7-93e72a9318eb> in <module>
21
22 'Load model'
---> 23 vae = model_v2.initialize_model(beta, max_particles, n_classes, latent_size, activation_function)
24
25
~/Stage/bvae_cut/Functions/model_v2.py in initialize_model(beta, n_particles, n_classes, latent_size, activation_func)
99 kl_loss = -0.5 * K.sum((1+z_log_var-K.square(z_mean)-K.exp(z_log_var)), axis=-1)
100 vae_loss = K.mean((1-beta) * reconstruction_loss + beta * kl_loss)
--> 101 vae.add_loss(vae_loss)
102
103 vae.compile(optimizer = keras.optimizers.Adam(lr=1e-4, beta_1=0.9, beta_2=0.999))
~/Stage/venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/base_layer.py in add_loss(self, losses, inputs)
1130 for symbolic_loss in symbolic_losses:
1131 if getattr(self, '_is_graph_network', False):
-> 1132 self._graph_network_add_loss(symbolic_loss)
1133 else:
1134 # Possible a loss was added in a Layer's `build`.
~/Stage/venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/network.py in _graph_network_add_loss(self, symbolic_loss)
1424
1425 def _graph_network_add_loss(self, symbolic_loss):
-> 1426 new_nodes, new_layers = _map_subgraph_network(self.inputs, [symbolic_loss])
1427 # Losses must be keyed on inputs no matter what in order to be supported in
1428 # DistributionStrategy.
~/Stage/venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/network.py in _map_subgraph_network(inputs, outputs)
1651 base_layer_utils.create_keras_history(outputs)
1652 # Keep only nodes and layers in the topology betweeen inputs and outputs.
-> 1653 _, nodes_by_depth, layers, _ = _map_graph_network(inputs, outputs)
1654 return nest.flatten([nodes for nodes in nodes_by_depth.values()]), layers
1655
~/Stage/venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/network.py in _map_graph_network(inputs, outputs)
1623 'The following previous layers '
1624 'were accessed without issue: ' +
-> 1625 str(layers_with_complete_input))
1626 for x in nest.flatten(node.output_tensors):
1627 computable_tensors.add(x)
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("inputs_class:0", shape=(None, 15), dtype=float32) at layer "inputs_class". The following previous layers were accessed without issue: ['vae_input_1', 'vae_input_2', 'encoder', 'vae_input_3', 'vae_input_4', 'decoder']
Может ли кто-нибудь помочь мне с этой ошибкой?
Редактировать: Я попытался изменить потери, чтобы посмотреть, решит ли это проблему. Кажется, что проблема происходит от classification_loss
. Если я изменяю vae.add_loss(vae_loss)
на vae.add_loss(regression_loss)
или vae.add_loss(n_particle_loss)
, он тренируется, но если я изменяю его на vae.add_loss(classification_loss)
, модель больше не работает. Без учета этой потери на самом деле не вариант исправить модель, так как у нее не будет желаемого результата.