################################## Save & Test #################################
################################################################################
# Generate Loss Graph
graphics.draw_loss(all_train_loss, all_val_loss, loss_output_path, mode="ae")

# Save Model
torch.save(model.state_dict(), model_output_path)

# Plot Animation Sample
fig, axis = graphics.make_grid(("Sample", sample), 4, 4)
plt.savefig(animation_sample_image_name)

# Create & Save Animation
Writer = animation.writers["ffmpeg"]
writer = Writer()
anim = graphics.make_animation(graphics.make_grid, all_samples)
anim.save(animation_output_path, writer=writer)

model.eval()

# Evaluate on Test Images
# Save Generated Images & Calculate Metrics
# Testing Loop - Standard
all_mse = []
all_ssim = []
with torch.no_grad():
    for iteration, batch in enumerate(tqdm(test_dataloader)):
        # Move batch to device
        filenames, image = batch
        image = image.to(device)
                   all_val_fusion_loss,
                   fusion_loss_output_path,
                   mode="vae")

# Save Model
torch.save(model.state_dict(), model_output_path)

# Plot Animation Sample
fig, axis = graphics.make_grid(("Sample", sample), 4, 4)
plt.savefig(animation_sample_image_name)
fusion_sample = [x for y in fusion_sample for x in y]
fig, axis = graphics.make_grid(("Fusion Sample", fusion_sample), 4, 3)
plt.savefig(fusion_animation_sample_image_name)

# Create & Save Animation
anim = graphics.make_animation(graphics.make_grid, all_samples, width=3)
fusion_anim = graphics.make_animation(graphics.make_grid,
                                      all_fusion_samples,
                                      width=3)
anim.save(animation_output_path)
fusion_anim.save(fusion_animation_output_path)

model.eval()

# Evaluate on Test Images
# Save Generated Images & Calculate Metrics
# Testing Loop - Standard
all_mse = []
all_ssim = []
with torch.no_grad():
    for iteration, batch in enumerate(tqdm(test_dataloader)):