import tensorflow as tf
import numpy as np
from tensorflow.keras.applications import vgg19
from tensorflow.keras.models import Model
# Load content and style images (preprocessed)
content_image = tf.constant(np.random.rand(1,224,224,3), dtype=tf.float32)
style_image = tf.constant(np.random.rand(1,224,224,3), dtype=tf.float32)
# Define model to extract features
vgg = vgg19.VGG19(include_top=False, weights='imagenet')
vgg.trainable = False
content_layers = ['block5_conv2']
style_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1', 'block5_conv1']
outputs = [vgg.get_layer(name).output for name in (style_layers + content_layers)]
model = Model([vgg.input], outputs)
# Weights for losses
content_weight = 1e3
style_weight = 1e-2
variation_weight = 1e-4
# Initialize generated image
generated_image = tf.Variable(content_image)
# Define loss functions
mse = tf.keras.losses.MeanSquaredError()
def gram_matrix(tensor):
channels = int(tensor.shape[-1])
a = tf.reshape(tensor, [-1, channels])
n = tf.shape(a)[0]
gram = tf.matmul(a, a, transpose_a=True)
return gram / tf.cast(n, tf.float32)
@tf.function
def compute_loss():
outputs = model(generated_image)
style_outputs = outputs[:len(style_layers)]
content_outputs = outputs[len(style_layers):]
style_targets = model(style_image)[:len(style_layers)]
content_targets = model(content_image)[len(style_layers):]
style_loss = 0
for output, target in zip(style_outputs, style_targets):
style_loss += mse(gram_matrix(output), gram_matrix(target))
style_loss *= style_weight / len(style_layers)
content_loss = 0
for output, target in zip(content_outputs, content_targets):
content_loss += mse(output, target)
content_loss *= content_weight / len(content_layers)
# Total variation loss to reduce noise
variation_loss = variation_weight * tf.image.total_variation(generated_image)
total_loss = style_loss + content_loss + variation_loss
return total_loss, style_loss, content_loss, variation_loss
# Optimizer
optimizer = tf.optimizers.Adam(learning_rate=0.02)
# Training loop
@tf.function
def train_step():
with tf.GradientTape() as tape:
total_loss, style_loss, content_loss, variation_loss = compute_loss()
grads = tape.gradient(total_loss, generated_image)
optimizer.apply_gradients([(grads, generated_image)])
generated_image.assign(tf.clip_by_value(generated_image, 0.0, 1.0))
return total_loss, style_loss, content_loss, variation_loss
for i in range(500):
total_loss, style_loss, content_loss, variation_loss = train_step()
# Final losses
final_losses = {
'total_loss': float(total_loss),
'style_loss': float(style_loss),
'content_loss': float(content_loss),
'variation_loss': float(variation_loss)
}
print(final_losses)