In [ ]:
!pip install tensorflow-gpu==2.0.0-rc0
Collecting tensorflow-gpu==2.0.0-rc0
  Downloading tensorflow_gpu-2.0.0rc0-cp37-cp37m-manylinux2010_x86_64.whl (380.5 MB)
     |████████████████████████████████| 380.5 MB 39 kB/s 
Requirement already satisfied: grpcio>=1.8.6 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.39.0)
Requirement already satisfied: wrapt>=1.11.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.12.1)
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.15.0)
Requirement already satisfied: protobuf>=3.6.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (3.17.3)
Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.1.0)
Requirement already satisfied: google-pasta>=0.1.6 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (0.2.0)
Requirement already satisfied: gast>=0.2.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (0.4.0)
Requirement already satisfied: astor>=0.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (0.8.1)
Requirement already satisfied: absl-py>=0.7.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (0.12.0)
Requirement already satisfied: numpy<2.0,>=1.16.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.19.5)
Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (0.37.0)
Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (1.1.2)
Collecting tb-nightly<1.15.0a20190807,>=1.15.0a20190806
  Downloading tb_nightly-1.15.0a20190806-py3-none-any.whl (4.3 MB)
     |████████████████████████████████| 4.3 MB 32.9 MB/s 
Collecting keras-applications>=1.0.8
  Downloading Keras_Applications-1.0.8-py3-none-any.whl (50 kB)
     |████████████████████████████████| 50 kB 6.7 MB/s 
Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.7/dist-packages (from tensorflow-gpu==2.0.0-rc0) (3.3.0)
Collecting tf-estimator-nightly<1.14.0.dev2019080602,>=1.14.0.dev2019080601
  Downloading tf_estimator_nightly-1.14.0.dev2019080601-py2.py3-none-any.whl (501 kB)
     |████████████████████████████████| 501 kB 50.1 MB/s 
Requirement already satisfied: h5py in /usr/local/lib/python3.7/dist-packages (from keras-applications>=1.0.8->tensorflow-gpu==2.0.0-rc0) (3.1.0)
Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.7/dist-packages (from tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (57.4.0)
Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.7/dist-packages (from tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (3.3.4)
Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.7/dist-packages (from tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (1.0.1)
Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.7/dist-packages (from markdown>=2.6.8->tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (4.6.4)
Requirement already satisfied: cached-property in /usr/local/lib/python3.7/dist-packages (from h5py->keras-applications>=1.0.8->tensorflow-gpu==2.0.0-rc0) (1.5.2)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata->markdown>=2.6.8->tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (3.5.0)
Requirement already satisfied: typing-extensions>=3.6.4 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata->markdown>=2.6.8->tb-nightly<1.15.0a20190807,>=1.15.0a20190806->tensorflow-gpu==2.0.0-rc0) (3.7.4.3)
Installing collected packages: tf-estimator-nightly, tb-nightly, keras-applications, tensorflow-gpu
Successfully installed keras-applications-1.0.8 tb-nightly-1.15.0a20190806 tensorflow-gpu-2.0.0rc0 tf-estimator-nightly-1.14.0.dev2019080601
In [ ]:
import tensorflow as tf
In [ ]:
import IPython.display as display

import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['figure.figsize'] = (12,12)
mpl.rcParams['axes.grid'] = False

import numpy as np
import time
import functools
In [ ]:
!rm -rf nst_colab_assets
!git clone https://github.com/jinh0park/nst_colab_assets.git
Cloning into 'nst_colab_assets'...
remote: Enumerating objects: 48, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 48 (delta 0), reused 0 (delta 0), pack-reused 44
Unpacking objects: 100% (48/48), done.

Define some useful functions.

In [ ]:
def load_img(path_to_img):
  max_dim = 512
  img = tf.io.read_file(path_to_img)
  img = tf.image.decode_image(img, channels=3)
  img = tf.image.convert_image_dtype(img, tf.float32)

  shape = tf.cast(tf.shape(img)[:-1], tf.float32)
  long_dim = max(shape)
  scale = max_dim / long_dim

  new_shape = tf.cast(shape * scale, tf.int32)

  img = tf.image.resize(img, new_shape)
  img = img[tf.newaxis, :]
  return img
In [ ]:
def imshow(image, title=None):
  if len(image.shape) > 3:
    image = tf.squeeze(image, axis=0)

  plt.imshow(image)
  if title:
    plt.title(title)
In [ ]:
content_path = 'nst_colab_assets/images/bg-index.png'
style_path = 'nst_colab_assets/images/starry_night.png'

content_image = load_img(content_path)
style_image = load_img(style_path)

plt.subplot(1, 2, 1)
imshow(content_image, 'Content Image')

plt.subplot(1, 2, 2)
imshow(style_image, 'Style Image')

print("Check the type of the variable 'content_image': {}".format(type(content_image)))
Check the type of the variable 'content_image': <class 'tensorflow.python.framework.ops.EagerTensor'>
In [ ]:
vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
print()
for layer in vgg.layers:
  print(layer.name)
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5
80142336/80134624 [==============================] - 2s 0us/step

input_1
block1_conv1
block1_conv2
block1_pool
block2_conv1
block2_conv2
block2_pool
block3_conv1
block3_conv2
block3_conv3
block3_conv4
block3_pool
block4_conv1
block4_conv2
block4_conv3
block4_conv4
block4_pool
block5_conv1
block5_conv2
block5_conv3
block5_conv4
block5_pool
In [ ]:
# Content layer where will pull our feature maps
content_layers = ['block5_conv2'] 

# Style layer of interest
style_layers = ['block1_conv1',
                'block2_conv1',
                'block3_conv1', 
                'block4_conv1', 
                'block5_conv1']
In [ ]:
def vgg_layers(layer_names):
  """ Creates a vgg model that returns a list of intermediate output values."""
  # Load our model. Load pretrained VGG, trained on imagenet data
  vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
  vgg.trainable = False
  
  outputs = [vgg.get_layer(name).output for name in layer_names]
  
  model = tf.keras.Model([vgg.input], outputs)
  return model

# style_outputs = vgg_layers(style_layers)(style_image * 255)
# print("Ckeck the type of outputs and inspect them.", type(style_outputs))
# for name, output in zip(style_layers, style_outputs):
#   print(name)
#   print("  shape: ", output.numpy().shape)
#   print("  min: ", output.numpy().min())
#   print("  max: ", output.numpy().max())
#   print("  mean: ", output.numpy().mean())
#   print()
In [ ]:
def gram_matrix(input_tensor):
  result = tf.linalg.einsum('bijc,bijd->bcd', input_tensor, input_tensor)
  input_shape = tf.shape(input_tensor)
  num_locations = tf.cast(input_shape[1]*input_shape[2], tf.float32)
  return result/(num_locations)


class StyleContentModel(tf.keras.models.Model):
  def __init__(self, style_layers, content_layers):
    super(StyleContentModel, self).__init__()
    self.vgg =  vgg_layers(style_layers + content_layers)
    self.style_layers = style_layers
    self.content_layers = content_layers
    self.num_style_layers = len(style_layers)
    self.vgg.trainable = False

  def call(self, inputs, gram=True):
    "Expects float input in [0,1]"
    inputs = inputs*255.0
    preprocessed_input = tf.keras.applications.vgg19.preprocess_input(inputs)
    outputs = self.vgg(preprocessed_input)
    style_outputs, content_outputs = (outputs[:self.num_style_layers], 
                                      outputs[self.num_style_layers:])
    

    style_outputs = [gram_matrix(style_output)
                    for style_output in style_outputs]
    
    content_dict = {content_name:value 
                    for content_name, value 
                    in zip(self.content_layers, content_outputs)}

    style_dict = {style_name:value
                  for style_name, value
                  in zip(self.style_layers, style_outputs)}
    
    return {'content':content_dict, 'style':style_dict}
In [ ]:
extractor = StyleContentModel(style_layers, content_layers)

results = extractor(tf.constant(content_image), gram=True)

style_results = results['style']

print('Styles:')
for name, output in sorted(results['style'].items()):
  print("  ", name)
  print("    shape: ", output.numpy().shape)
  print("    min: ", output.numpy().min())
  print("    max: ", output.numpy().max())
  print("    mean: ", output.numpy().mean())
  print()

print("Contents:")
for name, output in sorted(results['content'].items()):
  print("  ", name)
  print("    shape: ", output.numpy().shape)
  print("    min: ", output.numpy().min())
  print("    max: ", output.numpy().max())
  print("    mean: ", output.numpy().mean())
Styles:
   block1_conv1
    shape:  (1, 64, 64)
    min:  0.029165905
    max:  55334.93
    mean:  395.3797

   block2_conv1
    shape:  (1, 128, 128)
    min:  0.0
    max:  82591.12
    mean:  12998.954

   block3_conv1
    shape:  (1, 256, 256)
    min:  0.0
    max:  227377.62
    mean:  10687.842

   block4_conv1
    shape:  (1, 512, 512)
    min:  0.0
    max:  3184842.8
    mean:  165103.7

   block5_conv1
    shape:  (1, 512, 512)
    min:  0.0
    max:  77444.836
    mean:  1202.8584

Contents:
   block5_conv2
    shape:  (1, 23, 31, 512)
    min:  0.0
    max:  857.687
    mean:  12.097354
In [ ]:
def style_content_loss(outputs, style_targets, content_targets, style_weight, content_weight):
  style_outputs = outputs['style']
  content_outputs = outputs['content']

  style_loss = tf.add_n([tf.reduce_mean((style_outputs[name]-style_targets[name])**2)
                          for name in style_outputs.keys()])

  
  style_loss *= style_weight / len(style_outputs)

  content_loss = tf.add_n([tf.reduce_mean((content_outputs[name]-content_targets[name])**2) 
                            for name in content_outputs.keys()])
  content_loss *= content_weight / len(content_outputs)
  loss = style_loss + content_loss
  return loss
In [ ]:
def total_variation_loss(image):
  x_deltas = image[:,:,1:,:] - image[:,:,:-1,:]
  y_deltas = image[:,1:,:,:] - image[:,:-1,:,:]
  return tf.reduce_mean(x_deltas**2) + tf.reduce_mean(y_deltas**2)
In [ ]:
def clip_0_1(image):
  return tf.clip_by_value(image, clip_value_min=0.0, clip_value_max=1.0)
In [ ]:
def run_style_transfer(style_image, content_image, params):

  content_layers = params['content_layers']
  style_layers = params['style_layers']
  lr = params['lr']
  style_weight=params['style_weight']
  content_weight=params['content_weight']
  total_variation_weight=params['total_variation_weight'] 
  noise = params['noise']

  if noise:
    image = tf.Variable(tf.random.uniform(content_image.shape, 0, 1))
  else:
    image = tf.Variable(content_image)
  extractor = StyleContentModel(style_layers, content_layers)
  
  style_targets = extractor(style_image)['style']
  content_targets = extractor(content_image)['content']

  opt = tf.optimizers.Adam(learning_rate=lr, beta_1=0.99, epsilon=1e-1)

  @tf.function()
  def train_step(image):
    with tf.GradientTape() as tape:
      outputs = extractor(image)
      loss = style_content_loss(outputs, style_targets, content_targets, style_weight, content_weight)
      loss += total_variation_weight * total_variation_loss(image)
    grad = tape.gradient(loss, image)
    opt.apply_gradients([(grad, image)])
    image.assign(clip_0_1(image))
  

  epochs = 10
  steps_per_epoch = 100
  step = 0
  for n in range(epochs):
    for m in range(steps_per_epoch):
      step += 1
      train_step(image)
      print(".", end='')
    display.clear_output(wait=True)
    imshow(image.read_value())
    plt.title("Train step: {}".format(step))
    plt.show()
  return image
In [ ]:
%%time
params = {
    'content_layers': ['block5_conv2'],
    'style_layers': ['block1_conv1',
                    'block2_conv1',
                    'block3_conv1', 
                    'block4_conv1', 
                    'block5_conv1'],
    'style_weight': 1e-2,
    'content_weight': 1e4,
    'total_variation_weight': 1e8,
    'lr': 0.02,
    'noise': False  
}
run_style_transfer(style_image, content_image, params)
CPU times: user 30.1 s, sys: 4.15 s, total: 34.3 s
Wall time: 3min 14s
In [ ]:
%%time
params = {
    'content_layers': ['block5_conv2'],
    'style_layers': ['block1_conv1',
                    'block2_conv1',
                    'block3_conv1', 
                    'block4_conv1', 
                    'block5_conv1'],
    'style_weight': 1e-3,
    'content_weight': 1e4,
    'total_variation_weight': 1e8,
    'lr': 0.02,
    'noise': False  
}
run_style_transfer(style_image, content_image, params)
CPU times: user 28.2 s, sys: 3.87 s, total: 32.1 s
Wall time: 3min 13s
In [ ]:
%%time
params = {
    'content_layers': ['block5_conv2'],
    'style_layers': ['block1_conv1',
                    'block2_conv1',
                    'block3_conv1', 
                    'block4_conv1', 
                    'block5_conv1'],
    'style_weight': 1e-1,
    'content_weight': 1e4,
    'total_variation_weight': 1e8,
    'lr': 0.02,
    'noise': False  
}
run_style_transfer(style_image, content_image, params)
CPU times: user 29.5 s, sys: 5.11 s, total: 34.6 s
Wall time: 3min 13s
In [ ]: