forked from lazyprogrammer/machine_learning_examples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstyle_transfer2.py
144 lines (108 loc) · 4.02 KB
/
style_transfer2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# https://deeplearningcourses.com/c/advanced-computer-vision
# https://www.udemy.com/advanced-computer-vision
from __future__ import print_function, division
from builtins import range, input
# Note: you may need to update your version of future
# sudo pip install -U future
# In this script, we will focus on generating an image
# with the same style as the input image.
# But NOT the same content.
# It should capture only the essence of the style.
from keras.models import Model, Sequential
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing import image
from keras.applications.vgg16 import VGG16
from style_transfer1 import VGG16_AvgPool, unpreprocess, scale_img
# from skimage.transform import resize
from scipy.optimize import fmin_l_bfgs_b
from datetime import datetime
import numpy as np
import matplotlib.pyplot as plt
import keras.backend as K
def gram_matrix(img):
# input is (H, W, C) (C = # feature maps)
# we first need to convert it to (C, H*W)
X = K.batch_flatten(K.permute_dimensions(img, (2, 0, 1)))
# now, calculate the gram matrix
# gram = XX^T / N
# the constant is not important since we'll be weighting these
G = K.dot(X, K.transpose(X)) / img.get_shape().num_elements()
return G
def style_loss(y, t):
return K.mean(K.square(gram_matrix(y) - gram_matrix(t)))
# let's generalize this and put it into a function
def minimize(fn, epochs, batch_shape):
t0 = datetime.now()
losses = []
x = np.random.randn(np.prod(batch_shape))
for i in range(epochs):
x, l, _ = fmin_l_bfgs_b(
func=fn,
x0=x,
maxfun=20
)
x = np.clip(x, -127, 127)
print("iter=%s, loss=%s" % (i, l))
losses.append(l)
print("duration:", datetime.now() - t0)
plt.plot(losses)
plt.show()
newimg = x.reshape(*batch_shape)
final_img = unpreprocess(newimg)
return final_img[0]
if __name__ == '__main__':
# try these, or pick your own!
path = 'styles/starrynight.jpg'
# path = 'styles/flowercarrier.jpg'
# path = 'styles/monalisa.jpg'
# path = 'styles/lesdemoisellesdavignon.jpg'
# load the data
img = image.load_img(path)
# convert image to array and preprocess for vgg
x = image.img_to_array(img)
# look at the image
# plt.imshow(x)
# plt.show()
# make it (1, H, W, C)
x = np.expand_dims(x, axis=0)
# preprocess into VGG expected format
x = preprocess_input(x)
# we'll use this throughout the rest of the script
batch_shape = x.shape
shape = x.shape[1:]
# let's take the first convolution at each block of convolutions
# to be our target outputs
# remember that you can print out the model summary if you want
vgg = VGG16_AvgPool(shape)
# Note: need to select output at index 1, since outputs at
# index 0 correspond to the original vgg with maxpool
symbolic_conv_outputs = [
layer.get_output_at(1) for layer in vgg.layers \
if layer.name.endswith('conv1')
]
# pick the earlier layers for
# a more "localized" representation
# this is opposed to the content model
# where the later layers represent a more "global" structure
# symbolic_conv_outputs = symbolic_conv_outputs[:2]
# make a big model that outputs multiple layers' outputs
multi_output_model = Model(vgg.input, symbolic_conv_outputs)
# calculate the targets that are output at each layer
style_layers_outputs = [K.variable(y) for y in multi_output_model.predict(x)]
# calculate the total style loss
loss = 0
for symbolic, actual in zip(symbolic_conv_outputs, style_layers_outputs):
# gram_matrix() expects a (H, W, C) as input
loss += style_loss(symbolic[0], actual[0])
grads = K.gradients(loss, multi_output_model.input)
# just like theano.function
get_loss_and_grads = K.function(
inputs=[multi_output_model.input],
outputs=[loss] + grads
)
def get_loss_and_grads_wrapper(x_vec):
l, g = get_loss_and_grads([x_vec.reshape(*batch_shape)])
return l.astype(np.float64), g.flatten().astype(np.float64)
final_img = minimize(get_loss_and_grads_wrapper, 10, batch_shape)
plt.imshow(scale_img(final_img))
plt.show()