Skip to content

Instantly share code, notes, and snippets.

@standarderror
Created November 12, 2016 04:26
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save standarderror/855adcadce2e627a7b9a25d6261e03a6 to your computer and use it in GitHub Desktop.
Save standarderror/855adcadce2e627a7b9a25d6261e03a6 to your computer and use it in GitHub Desktop.
20161112_Neural_Style_TensorFlow
import os
import numpy as np
import scipy.misc
import scipy.io
import math
import tensorflow as tf
from sys import stderr
from functools import reduce
import time
## Inputs
file_content_image = 'starry_night_mini.jpg'
file_style_image = 'klimt_2.jpg'
## Parameters
input_noise = 0.1 # proportion noise to apply to content image
weight_style = 2e2
## Layers
layer_content = 'conv4_2'
layers_style = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1']
layers_style_weights = [0.2,0.2,0.2,0.2,0.2]
## VGG19 model
path_VGG19 = 'imagenet-vgg-verydeep-19.mat'
# VGG19 mean for standardisation (RGB)
VGG19_mean = np.array([123.68, 116.779, 103.939]).reshape((1,1,1,3))
## Reporting & writing checkpoint images
# NB. the total # of iterations run will be n_checkpoints * n_iterations_checkpoint
n_checkpoints = 10 # number of checkpoints
n_iterations_checkpoint = 10 # learning iterations per checkpoint
path_output = 'output' # directory to write checkpoint images into
### Helper functions
def imread(path):
return scipy.misc.imread(path).astype(np.float) # returns RGB format
def imsave(path, img):
img = np.clip(img, 0, 255).astype(np.uint8)
scipy.misc.imsave(path, img)
def imgpreprocess(image):
image = image[np.newaxis,:,:,:]
return image - VGG19_mean
def imgunprocess(image):
temp = image + VGG19_mean
return temp[0]
# function to convert 2D greyscale to 3D RGB
def to_rgb(im):
w, h = im.shape
ret = np.empty((w, h, 3), dtype=np.uint8)
ret[:, :, 0] = im
ret[:, :, 1] = im
ret[:, :, 2] = im
return ret
### Preprocessing
# create output directory
if not os.path.exists(path_output):
os.mkdir(path_output)
# read in images
img_content = imread(file_content_image)
img_style = imread(file_style_image)
# convert if greyscale
if len(img_content.shape)==2:
img_content = to_rgb(img_content)
if len(img_style.shape)==2:
img_style = to_rgb(img_style)
# resize style image to match content
img_style = scipy.misc.imresize(img_style, img_content.shape)
# apply noise to create initial "canvas"
noise = np.random.uniform(
img_content.mean()-img_content.std(), img_content.mean()+img_content.std(),
(img_content.shape)).astype('float32')
img_initial = noise * input_noise + img_content * (1 - input_noise)
# preprocess each
img_content = imgpreprocess(img_content)
img_style = imgpreprocess(img_style)
img_initial = imgpreprocess(img_initial)
#### BUILD VGG19 MODEL
## with thanks to http://www.chioka.in/tensorflow-implementation-neural-algorithm-of-artistic-style
VGG19 = scipy.io.loadmat(path_VGG19)
VGG19_layers = VGG19['layers'][0]
# help functions
def _conv2d_relu(prev_layer, n_layer, layer_name):
# get weights for this layer:
weights = VGG19_layers[n_layer][0][0][2][0][0]
W = tf.constant(weights)
bias = VGG19_layers[n_layer][0][0][2][0][1]
b = tf.constant(np.reshape(bias, (bias.size)))
# create a conv2d layer
conv2d = tf.nn.conv2d(prev_layer, filter=W, strides=[1, 1, 1, 1], padding='SAME') + b
# add a ReLU function and return
return tf.nn.relu(conv2d)
def _avgpool(prev_layer):
return tf.nn.avg_pool(prev_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# Setup network
with tf.Session() as sess:
a, h, w, d = img_content.shape
net = {}
net['input'] = tf.Variable(np.zeros((a, h, w, d), dtype=np.float32))
net['conv1_1'] = _conv2d_relu(net['input'], 0, 'conv1_1')
net['conv1_2'] = _conv2d_relu(net['conv1_1'], 2, 'conv1_2')
net['avgpool1'] = _avgpool(net['conv1_2'])
net['conv2_1'] = _conv2d_relu(net['avgpool1'], 5, 'conv2_1')
net['conv2_2'] = _conv2d_relu(net['conv2_1'], 7, 'conv2_2')
net['avgpool2'] = _avgpool(net['conv2_2'])
net['conv3_1'] = _conv2d_relu(net['avgpool2'], 10, 'conv3_1')
net['conv3_2'] = _conv2d_relu(net['conv3_1'], 12, 'conv3_2')
net['conv3_3'] = _conv2d_relu(net['conv3_2'], 14, 'conv3_3')
net['conv3_4'] = _conv2d_relu(net['conv3_3'], 16, 'conv3_4')
net['avgpool3'] = _avgpool(net['conv3_4'])
net['conv4_1'] = _conv2d_relu(net['avgpool3'], 19, 'conv4_1')
net['conv4_2'] = _conv2d_relu(net['conv4_1'], 21, 'conv4_2')
net['conv4_3'] = _conv2d_relu(net['conv4_2'], 23, 'conv4_3')
net['conv4_4'] = _conv2d_relu(net['conv4_3'], 25, 'conv4_4')
net['avgpool4'] = _avgpool(net['conv4_4'])
net['conv5_1'] = _conv2d_relu(net['avgpool4'], 28, 'conv5_1')
net['conv5_2'] = _conv2d_relu(net['conv5_1'], 30, 'conv5_2')
net['conv5_3'] = _conv2d_relu(net['conv5_2'], 32, 'conv5_3')
net['conv5_4'] = _conv2d_relu(net['conv5_3'], 34, 'conv5_4')
net['avgpool5'] = _avgpool(net['conv5_4'])
### CONTENT LOSS: FUNCTION TO CALCULATE AND INSTANTIATION
# with thanks to https://github.com/cysmith/neural-style-tf
# Recode to be simpler: http://www.chioka.in/tensorflow-implementation-neural-algorithm-of-artistic-style
def content_layer_loss(p, x):
_, h, w, d = [i.value for i in p.get_shape()] # d: number of filters; h,w : height, width
M = h * w
N = d
K = 1. / (2. * N**0.5 * M**0.5)
loss = K * tf.reduce_sum(tf.pow((x - p), 2))
return loss
with tf.Session() as sess:
sess.run(net['input'].assign(img_content))
p = sess.run(net[layer_content]) # Get activation output for content layer
x = net[layer_content]
p = tf.convert_to_tensor(p)
content_loss = content_layer_loss(p, x)
### STYLE LOSS: FUNCTION TO CALCULATE AND INSTANTIATION
def style_layer_loss(a, x):
_, h, w, d = [i.value for i in a.get_shape()]
M = h * w
N = d
A = gram_matrix(a, M, N)
G = gram_matrix(x, M, N)
loss = (1./(4 * N**2 * M**2)) * tf.reduce_sum(tf.pow((G - A), 2))
return loss
def gram_matrix(x, M, N):
F = tf.reshape(x, (M, N))
G = tf.matmul(tf.transpose(F), F)
return G
with tf.Session() as sess:
sess.run(net['input'].assign(img_style))
style_loss = 0.
# style loss is calculated for each style layer and summed
for layer, weight in zip(layers_style, layers_style_weights):
a = sess.run(net[layer])
x = net[layer]
a = tf.convert_to_tensor(a)
style_loss += style_layer_loss(a, x)
### Define loss function and minimise
with tf.Session() as sess:
# loss function
L_total = content_loss + weight_style * style_loss
# instantiate optimiser
optimizer = tf.contrib.opt.ScipyOptimizerInterface(
L_total, method='L-BFGS-B',
options={'maxiter': n_iterations_checkpoint})
init_op = tf.initialize_all_variables()
sess.run(init_op)
sess.run(net['input'].assign(img_initial))
for i in range(1,n_checkpoints+1):
# run optimisation
optimizer.minimize(sess)
## print costs
stderr.write('Iteration %d/%d\n' % (i*n_iterations_checkpoint, n_checkpoints*n_iterations_checkpoint))
stderr.write(' content loss: %g\n' % sess.run(content_loss))
stderr.write(' style loss: %g\n' % sess.run(weight_style * style_loss))
stderr.write(' total loss: %g\n' % sess.run(L_total))
## write image
img_output = sess.run(net['input'])
img_output = imgunprocess(img_output)
timestr = time.strftime("%Y%m%d_%H%M%S")
output_file = path_output+'/'+timestr+'_'+'%s.jpg' % (i*n_iterations_checkpoint)
imsave(output_file, img_output)
@Fred159
Copy link

Fred159 commented Nov 16, 2017

cool . awesome code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment