Variationale Autoencoder: Trainingsverfahren (Teil 2) | von Krishna Chaitanya | Juni 2023

0
28


Willkommen zum zweiten Teil unserer dreiteiligen Serie über Variational Autoencoder (VAEs). Aufbauend auf unseren Einführungs- und Implementierungsdetails in Teil 1Dieses Phase konzentriert sich auf die Trainingsverfahren, die für die Feinabstimmung dieser Modelle von wesentlicher Bedeutung sind. Wir werden uns eingehend mit der Bedeutung der einzelnen Parameter und ihrem Beitrag zum Trainingsprozess befassen.

In In diesem Artikel beschreiben wir die Schritte zum Einrichten und Verwalten des Trainingsprozesses für einen Variational Autoencoder (VAE), ein hochentwickeltes Deep-Studying-Modell, das besonders effektiv bei Aufgaben im Zusammenhang mit der Bildgenerierung und -änderung ist.

Die Trainingsreise beginnt mit der Akzeptanz einer Reihe von Parametern und Hyperparametern, die bei der Gestaltung verschiedener Aspekte des Modells und des Trainingsprozesses eine entscheidende Rolle spielen. Diese Parameter umfassen unter anderem Aspekte wie den Speicherort der Bilddaten, den Speicherpfad für die Trainingsprotokolle des Modells, die Anzahl der Trainingsepochen, die Stapelgröße und die Lernrate.

Sobald diese Parameter festgelegt sind, legen wir die Pfade zu den Trainings- und Testdaten fest. Die Daten werden in eine Trainingsteilmenge aufgeteilt, aus der das Modell lernen kann, und eine Testteilmenge, um die Leistung des Modells anhand von Daten zu messen, auf die es zuvor noch nicht gestoßen ist.

Als Nächstes richten wir Datengeneratoren ein, eine wichtige Komponente beim Umgang mit großen Datensätzen. Diese Generatoren wenden eine Reihe von Transformationen (bekannt als Datenerweiterung) auf die Trainingsbilder an, wodurch das Modell besser verallgemeinert und Überanpassungen abgemildert werden kann. Für die Testdaten verzichten wir auf die Anwendung dieser Transformationen.

Anschließend übernehmen die Generatoren die Aufgabe, die Bilder entsprechend der Batch-Größe in kleinen Batches zu laden und zu verarbeiten. Dieser Prozess ermöglicht es dem Modell, seine Gewichtungen Schritt für Schritt zu aktualisieren, anstatt zu versuchen, den gesamten Datensatz gleichzeitig zu berechnen.

Nachdem die Daten bereitstehen und die Generatoren vorbereitet sind, kann das VAE-Modell nun mit den angegebenen Parametern und Hyperparametern trainiert werden. Dieser Vorgang wird für zukünftige Analyse-, Verbesserungs- und Debugging-Zwecke protokolliert.

Analysieren der Hyperparameter

Wir beginnen mit der Definition einer Methode parse_arguments() um verschiedene Parameter und Hyperparameter für das Modelltraining zu erhalten.

def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument('--image-dir', kind=str, assist='Path to the picture knowledge', default= r'Information')
parser.add_argument('--logs-dir', kind=str, assist='Path to retailer logs', default=r"logs")
parser.add_argument('--output-image-shape', kind=int, default=56)
parser.add_argument('--filters', kind=int, nargs='+', default=[32, 64])
parser.add_argument('--dense-layer-dim', kind=int, default=16)
parser.add_argument('--latent-dim', kind=int, default=6)
parser.add_argument('--beta', kind=float, default=1.0)
parser.add_argument('--batch-size', kind=int, default=128)
parser.add_argument('--learning-rate', kind=float, default=1e-4)
parser.add_argument('--patience', kind=int, default=10)
parser.add_argument('--epochs', kind=int, default=20)
parser.add_argument('--train-split', kind=float, default=0.8)

args = parser.parse_args()
return args

Zu diesen Argumenten gehören Pfade zum Bilddaten- und Protokollverzeichnis, die Type des Ausgabebilds, die Anzahl der Filter für die Faltungsschichten, die Abmessungen der dichten und latenten Schichten, die Stapelgröße, die Lernrate und die Anzahl der Epochen.

  1. --image-dir: Dies ist das Verzeichnis, in dem sich Ihre Trainingsbilder befinden.
  2. --logs-dir: Hier werden die Trainingsprotokolle gespeichert. Diese Protokolle sind hilfreich für die Fehlerbehebung und die Visualisierung des Trainingsfortschritts.
  3. --output-image-shape: Definiert die Type des Ausgabebildes. Es ist wichtig zu beachten, dass die VAE ein Bild mit derselben Type wie das Eingabebild ausgeben muss.
  4. --filters: Dies ist die Anzahl der Filter für die Faltungsschichten der Encoder- und Decodermodelle.
  5. --dense-layer-dim: Dies ist die Dimensionalität der dichten Schicht im Encodermodell.
  6. --latent-dim: Dies definiert die Dimensionalität des latenten Raums. Es ist von entscheidender Bedeutung, eine geeignete Größe für den latenten Raum zu wählen, da diese die Fähigkeit des VAE zur Darstellung komplexer Daten bestimmt.
  7. --batch-size: Die Anzahl der in einer Iteration verwendeten Trainingsbeispiele. Dies kann die Trainingsleistung Ihres Modells erheblich beeinträchtigen.
  8. --learning-rate: Die Größe der Schritte, die der Optimierer beim Lernen durchführt. Dies muss sorgfältig abgestimmt werden, da ein zu kleiner Wert zu einer langsamen Konvergenz führen kann, während ein zu großer Wert die Konvergenz verhindern kann.
  9. --epochs: Die Anzahl der vollständigen Durchläufe durch den Trainingsdatensatz. Die richtige Anzahl von Epochen hängt normalerweise davon ab, wie schnell das Modell mit der Überanpassung beginnt.

Als nächstes startet das Hauptskript, das diese Argumente analysiert und die Datenpfade wie folgt einrichtet:

args = parse_arguments()
IMAGE_DIR = args.image_dir
LOGS_DIR = args.logs_dir
all_image_paths = get_image_data(IMAGE_DIR)
image_count = len(all_image_paths)
TRAIN_SPLIT = args.train_split
OUTPUT_IMAGE_SHAPE = args.output_image_shape
INPUT_SHAPE = (OUTPUT_IMAGE_SHAPE, OUTPUT_IMAGE_SHAPE, 1)
FILTERS = args.filters
DENSE_LAYER_DIM = args.dense_layer_dim
LATENT_DIM = args.latent_dim
BATCH_SIZE = args.batch_size
EPOCHS = args.epochs
LEARNING_RATE = args.learning_rate

LOGDIR = os.path.be part of(LOGS_DIR, datetime.now().strftime("%Ypercentmpercentd-%HpercentMpercentS"))
os.mkdir(LOGDIR)

Datenextraktion, Vorverarbeitung und Segregation für Schulung und Checks

Wie bereits erwähnt, besteht der nächste Schritt in der Extraktion der Bilddaten und deren Aufteilung in Trainings- und Testsätze.

Wir sammeln zunächst alle Bildpfade mithilfe von in einer Liste get_image_data() Funktion. Anschließend zählen wir die Gesamtzahl der Bilder, um sie später für Coaching und Checks aufzuteilen.

def get_image_data(all_dirs):
# Listing to retailer all picture file paths
all_dirs = [all_dirs]
all_image_paths = []

# Loop by means of all directories and subdirectories within the knowledge listing
for data_dir in all_dirs:
for root, dirs, information in os.stroll(data_dir):
for file in information:
# Test if the file is a picture file (you possibly can add extra extensions as wanted)
if file.endswith('.jpg') or file.endswith('.jpeg') or file.endswith('.png'):
# If the file is a picture file, append its path to the listing
all_image_paths.append(os.path.be part of(root, file))
print(data_dir)
image_count = len(all_image_paths)
print("Complete variety of imges:", image_count)
return all_image_paths

Sobald wir unsere Bilderliste haben, teilen wir sie in zwei Teile auf: den größeren Teil für das Coaching (wie von vorgegeben). TRAIN_SPLIT) und den kleineren Teil zum Testen. Dies wird erreicht, indem die Liste der Bildpfade entsprechend dem Teilungsverhältnis aufgeteilt wird, wodurch zwei separate Hear erstellt werden. Anschließend speichern wir diese Bildpfade in entsprechenden Datenrahmen. df_train Und df_test.

all_image_paths = get_image_data(IMAGE_DIR)
image_count = len(all_image_paths)
df_train = pd.DataFrame({'image_paths': all_image_paths[:int(image_count*TRAIN_SPLIT)]})
df_test = pd.DataFrame({'image_paths': all_image_paths[int(image_count*TRAIN_SPLIT):]})

Der nächste Teil des Prozesses umfasst die Vorbereitung unserer Datengeneratoren. Hierbei handelt es sich im Wesentlichen um Pipelines, die das Laden, Vorverarbeiten und Stapeln von Bildern übernehmen. Wir definieren separate Generatoren für Trainings- und Testdaten. Für die Trainingsdaten verwenden wir Bildvergrößerungstechniken wie Scheren, Zoomen, Spiegeln und Drehen, um die Größe und Variabilität unseres Datensatzes künstlich zu erhöhen, was zu einer besseren Verallgemeinerung während des Trainingsprozesses beiträgt. Für die Testdaten normalisieren wir einfach die Pixelwerte.

Nachdem die Datengeneratoren definiert sind, wenden wir dann die Funktion an flow_from_dataframe() zu unseren Trainings- und Testdatenrahmen. Diese Funktion generiert Stapel von Bildern direkt aus dem angegebenen Datenrahmen, konvertiert die Bilder in Graustufen, ändert ihre Größe auf die gewünschte Type und mischt sie schließlich, um Zufälligkeit im Trainingsprozess sicherzustellen.


train_datagen_args = dict(
rescale=1.0 / 255, # Normalize pixel values between 0 and 1
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
rotation_range=90,
width_shift_range=0.1,
height_shift_range=0.1,
)
test_datagen_args = dict(rescale=1.0 / 255)

train_datagen = ImageDataGenerator(**train_datagen_args)
test_datagen = ImageDataGenerator(**test_datagen_args)
# Use flow_from_dataframe to generate knowledge batches
train_data_generator = train_datagen.flow_from_dataframe(
dataframe=df_train,
color_mode='grayscale',
x_col='image_paths',
y_col=None,
target_size=(OUTPUT_IMAGE_SHAPE, OUTPUT_IMAGE_SHAPE), # Specify the specified measurement of the enter photos
batch_size=BATCH_SIZE,
class_mode=None, # Set to None since there are not any labels
shuffle=True # Set to True for randomizing the order of the photographs
)

test_data_generator = test_datagen.flow_from_dataframe(
dataframe=df_test,
color_mode='grayscale',
x_col='image_paths',
y_col=None,
target_size=(OUTPUT_IMAGE_SHAPE, OUTPUT_IMAGE_SHAPE), # Specify the specified measurement of the enter photos
batch_size=BATCH_SIZE,
class_mode=None, # Set to None since there are not any labels
shuffle=True # Set to True for randomizing the order of the photographs
)

Dieser Prozess führt zu einem Strom verarbeiteter Bildstapel, die für das Coaching und Testen unseres Variational Autoencoder-Modells bereit sind.

Ausbildung

Nach der Einrichtung unserer Datenpipeline fahren wir mit dem entscheidenden Schritt der Erstellung unseres Variational Autoencoder-Modells fort. Dies ist ein zweiteiliger Prozess, der den Zusammenbau eines Encoders und eines Decoders umfasst, die im Abschnitt besprochen wurden erster Teil dieser Serie. Sobald wir diese einzelnen Komponenten zusammengestellt haben, fügen wir sie zum vollständigen VAE-Modell zusammen.

Kurz gesagt ist unser Encodermodul dafür verantwortlich, unsere Eingabebilder in eine Reihe von Parametern zu übersetzen, die eine Verteilung im latenten Raum definieren. Der Decoder entnimmt dann einen Punkt aus dieser Verteilung und transformiert ihn zurück in den ursprünglichen Bildraum. Auf diese Weise lernt die VAE, nützliche Informationen über die Eingabedaten in den latenten Raum zu kodieren, die dann für verschiedene Zwecke verwendet werden können, z. B. zum Generieren neuer Bilder, zum Finden ähnlicher Bilder und mehr.

Zusätzlich zum Aufbau des Modells definieren wir auch eine benutzerdefinierte Metrikklasse TotalLoss um die Leistung unserer VAE während des Trainings zu überwachen.

# customized metrics
class TotalLoss(Metric):
def __init__(self, title="total_loss", **kwargs):
tremendous(TotalLoss, self).__init__(title=title, **kwargs)
self.total_loss = self.add_weight(title="tl", initializer="zeros")

def update_state(self, y_true, y_pred, sample_weight=None):
# Compute the whole loss
z_mean, z_log_var, z, reconstruction = y_pred
reconstruction_loss = reduce_mean(
reduce_sum(
binary_crossentropy(y_true, reconstruction), axis=(1, 2)
)
)
kl_loss = -0.5 * (1 + z_log_var - tf_square(z_mean) - tf_exp(z_log_var))
kl_loss = reduce_mean(reduce_sum(kl_loss, axis=1))
total_loss = reconstruction_loss + kl_loss

self.total_loss.assign(total_loss)

def consequence(self):
return self.total_loss

def reset_states(self):
# The state of the metric shall be reset firstly of every epoch.
self.total_loss.assign(0.)

Diese Metrik berechnet den Gesamtverlust, der sowohl den Rekonstruktionsverlust als auch den KL-Divergenzverlust umfasst, und liefert ein ganzheitliches Maß dafür, wie intestine die VAE lernt, sowohl die Eingabebilder neu zu erstellen als auch eine intestine verhaltene Verteilung im latenten Raum aufrechtzuerhalten.

encoder, encoder_layers_dim = encoder_model(input_shape = INPUT_SHAPE, filters=FILTERS, dense_layer_dim=DENSE_LAYER_DIM, latent_dim=LATENT_DIM)
decoder = decoder_model(encoder_layers_dim)vae = VAE(encoder, decoder)
vae.compile(optimizer=Adam(learning_rate=LEARNING_RATE), metrics=[TotalLoss()])

Um dies weiter aufzuschlüsseln:

  1. Aufbau des Encoders: Wir rufen zuerst unsere an encoder_model Funktion, die das Encodermodell und die Abmessungen seiner Schichten zurückgibt. Das Encodermodell verwendet als Eingabe die Type der Eingabebilder, die Anzahl der in jeder Faltungsschicht zu verwendenden Filter, die Dimension der dichten Schicht und die Dimension des latenten Raums.
  2. Aufbau des Decoders: Als nächstes nennen wir die decoder_model Funktion und liefert ihr die Abmessungen der Encoderschichten. Das Decodermodell verwendet diese Dimensionen, um eine Reihe von Entfaltungsschichten zu konstruieren, die die Struktur des Encoders widerspiegeln und es ihm ermöglichen, die Eingabebilder aus dem latenten Raum genau zu rekonstruieren.
  3. Kombination von Encoder und Decoder: Sobald wir unsere Encoder- und Decodermodelle haben, instanziieren wir unser VAE-Modell, indem wir diese Modelle an die übergeben VAE Klasse. Diese Klasse kombiniert Encoder und Decoder in einem einzigen Finish-to-Finish-Modell, das auf unseren Bilddaten trainiert werden kann.
  4. Definieren der Gesamtverlustmetrik: Zuletzt definieren wir eine benutzerdefinierte Metrik, um den Gesamtverlust unseres Modells während des Trainings zu überwachen. Das TotalLoss Klasse ist eine Unterklasse der Keras Metric Klasse und berechnet den Gesamtverlust durch Summieren des Rekonstruktionsverlusts und des KL-Divergenzverlusts. Dadurch erhalten wir einen einzelnen Wert, der die Gesamtleistung unseres Modells widerspiegelt.

Rückrufe in TensorFlow und Keras bieten eine Möglichkeit, bestimmte Aktionen in verschiedenen Phasen des Trainings auszuführen. Sie sind ein wichtiger Teil des Trainingsprozesses, da sie es uns ermöglichen, während des Trainings benutzerdefinierte Verhaltensweisen hinzuzufügen.

class VAECallback(Callback):
"""
Randomly pattern 5 photos from validation_data set and exhibits the reconstruction after every epoch
"""
def __init__(self, vae, validation_data, log_dir, n=5):
self.vae = vae
self.validation_data = validation_data
self.n = n
self.log_dir = log_dir

def on_epoch_end(self, epoch, logs=None):
# examine each 10 epochs
if epoch % 10 ==0:
# Generate decoded photos from the validation enter
validation_batch = subsequent(iter(self.validation_data))
_, _, _, reconstructed_images = self.vae.predict(validation_batch)

# Rescale pixel values to [0, 1]
reconstructed_images = np.clip(reconstructed_images, 0.0, 1.0)

# Plot the unique and reconstructed photos aspect by aspect
plt.determine(figsize=(10, 2*self.n)) # Adjusted the determine measurement
for i in vary(self.n):
plt.subplot(self.n, 2, 2*i+1)
plt.imshow(validation_batch[i], cmap='grey')
plt.axis('off')
plt.subplot(self.n, 2, 2*i+2)
plt.imshow(reconstructed_images[i], cmap='grey')
plt.axis('off')
fig_name = os.path.be part of(self.log_dir , 'decoded_images_epoch_{:04d}.png'.format(epoch))
plt.savefig(fig_name)
# plt.present()

vae_callback = VAECallback(vae, test_data_generator, LOGDIR)
tensorboard_cb = TensorBoard(log_dir=LOGDIR, histogram_freq=1)
checkpoint_cb = ModelCheckpoint(filepath=vae_path, save_weights_only=True, verbose=1)
earlystopping_cb = EarlyStopping(monitor="total_loss",min_delta=1e-2,endurance=5,verbose=1,)

In diesem Code werden vier Arten von Rückrufen verwendet:

  1. VAERückruf: Dieser benutzerdefinierte Rückruf erfasst einige Bilder aus dem Validierungsdatensatz und visualisiert die Rekonstruktion dieser Bilder durch die VAE am Ende jeder Trainingsepoche. Durch das Speichern dieser Bilder können wir visuell verfolgen, wie sich die Leistung unseres Modells im Laufe der Zeit verbessert.
  2. TensorBoard: TensorBoard ist ein Visualisierungstool, das mit TensorFlow bereitgestellt wird. Dieser Rückruf protokolliert verschiedene Metriken und Parameter für jede Epoche, sodass Sie sie in TensorBoard visualisieren können. Dies kann zur Überwachung des Trainingsprozesses und zur Diagnose von Problemen nützlich sein.
  3. ModelCheckpoint: Dieser Rückruf speichert die Modellgewichte in bestimmten Abständen, sodass Sie sie verwenden können, um das Coaching später fortzusetzen oder die Leistung Ihres Modells anhand verschiedener Metriken zu bewerten. In diesem Fall werden die Gewichte des bisher besten Modells (gemessen am Validierungsverlust) gespeichert.
  4. Frühes Stoppen: Dieser Rückruf stoppt das Coaching, wenn sich eine überwachte Metrik nicht mehr verbessert, was in diesem Fall der Fall ist total_loss. Dies ist nützlich, um eine Überanpassung zu verhindern und Rechenverschwendung zu reduzieren. Der Parameter „Geduld“ ist die Anzahl der Epochen, die vor dem Stoppen gewartet werden müssen, nachdem sich die Metrik nicht mehr verbessert hat.

Endlich, das match Die Funktion wird im VAE-Modell aufgerufen, um den Trainingsprozess zu starten. An diese Funktion werden die Trainingsdaten, die Anzahl der Epochen, Validierungsdaten und Rückrufe übergeben.

historical past = vae.match(
train_data_generator,
epochs=EPOCHS,
validation_data=test_data_generator,
callbacks=[tensorboard_cb, vae_callback, checkpoint_cb, earlystopping_cb]
)

Am Ende des Trainingsprozesses steht die historical past Das Objekt enthält die Verlust- und Metrikwerte in jeder Epoche, die zum Zeichnen von Lernkurven und zum Auswerten des Modells verwendet werden können.

Abschließend haben wir in diesem Teil der Serie den Prozess des Trainings von Variational Autoencodern besprochen, einschließlich der Einrichtung der Datenpipeline, des Aufbaus des Modells, der Definition benutzerdefinierter Metriken und der Verwendung von Rückrufen. Im nächsten und letzten Teil dieser Serie werden wir uns mit der Optimierung von Hyperparametern befassen, um die Leistung unseres Modells zu optimieren. Bleiben Sie dran!



Source link

HINTERLASSEN SIE EINE ANTWORT

Please enter your comment!
Please enter your name here