-
Notifications
You must be signed in to change notification settings - Fork 6.4k
/
Copy pathstyle_transfer1.py
189 lines (144 loc) · 4.68 KB
/
style_transfer1.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# 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 the content
# E.g. given an image, can we recreate the same image
from keras.layers import Input, Lambda, Dense, Flatten
from keras.layers import AveragePooling2D, MaxPooling2D
from keras.layers.convolutional import Conv2D
from keras.models import Model, Sequential
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing import image
import keras.backend as K
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fmin_l_bfgs_b
import tensorflow as tf
if tf.__version__.startswith('2'):
tf.compat.v1.disable_eager_execution()
def VGG16_AvgPool(shape):
# we want to account for features across the entire image
# so get rid of the maxpool which throws away information
vgg = VGG16(input_shape=shape, weights='imagenet', include_top=False)
# new_model = Sequential()
# for layer in vgg.layers:
# if layer.__class__ == MaxPooling2D:
# # replace it with average pooling
# new_model.add(AveragePooling2D())
# else:
# new_model.add(layer)
i = vgg.input
x = i
for layer in vgg.layers:
if layer.__class__ == MaxPooling2D:
# replace it with average pooling
x = AveragePooling2D()(x)
else:
x = layer(x)
return Model(i, x)
def VGG16_AvgPool_CutOff(shape, num_convs):
# there are 13 convolutions in total
# we can pick any of them as the "output"
# of our content model
if num_convs < 1 or num_convs > 13:
print("num_convs must be in the range [1, 13]")
return None
model = VGG16_AvgPool(shape)
# new_model = Sequential()
# n = 0
# for layer in model.layers:
# if layer.__class__ == Conv2D:
# n += 1
# new_model.add(layer)
# if n >= num_convs:
# break
n = 0
output = None
for layer in model.layers:
if layer.__class__ == Conv2D:
n += 1
if n >= num_convs:
output = layer.output
break
return Model(model.input, output)
def unpreprocess(img):
img[..., 0] += 103.939
img[..., 1] += 116.779
img[..., 2] += 126.68
img = img[..., ::-1]
return img
def scale_img(x):
x = x - x.min()
x = x / x.max()
return x
if __name__ == '__main__':
# open an image
# feel free to try your own
# path = '../large_files/caltech101/101_ObjectCategories/elephant/image_0002.jpg'
path = 'content/elephant.jpg'
img = image.load_img(path)
# convert image to array and preprocess for vgg
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
# we'll use this throughout the rest of the script
batch_shape = x.shape
shape = x.shape[1:]
# see the image
# plt.imshow(img)
# plt.show()
# make a content model
# try different cutoffs to see the images that result
content_model = VGG16_AvgPool_CutOff(shape, 11)
# make the target
target = K.variable(content_model.predict(x))
# try to match the image
# define our loss in keras
loss = K.mean(K.square(target - content_model.output))
# gradients which are needed by the optimizer
grads = K.gradients(loss, content_model.input)
# just like theano.function
get_loss_and_grads = K.function(
inputs=[content_model.input],
outputs=[loss] + grads
)
def get_loss_and_grads_wrapper(x_vec):
# scipy's minimizer allows us to pass back
# function value f(x) and its gradient f'(x)
# simultaneously, rather than using the fprime arg
#
# we cannot use get_loss_and_grads() directly
# input to minimizer func must be a 1-D array
# input to get_loss_and_grads must be [batch_of_images]
#
# gradient must also be a 1-D array
# and both loss and gradient must be np.float64
# will get an error otherwise
l, g = get_loss_and_grads([x_vec.reshape(*batch_shape)])
return l.astype(np.float64), g.flatten().astype(np.float64)
from datetime import datetime
t0 = datetime.now()
losses = []
x = np.random.randn(np.prod(batch_shape))
for i in range(10):
x, l, _ = fmin_l_bfgs_b(
func=get_loss_and_grads_wrapper,
x0=x,
# bounds=[[-127, 127]]*len(x.flatten()),
maxfun=20
)
x = np.clip(x, -127, 127)
# print("min:", x.min(), "max:", x.max())
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)
plt.imshow(scale_img(final_img[0]))
plt.show()