vidscbvsdCHEN commited on
Commit
f4a69a4
·
verified ·
1 Parent(s): 35a47bb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -191
app.py CHANGED
@@ -1,90 +1,42 @@
1
  import os
2
  import numpy as np
3
- from tqdm import tqdm
4
  import tensorflow as tf
 
 
5
  import typing
6
- import psutil
7
-
8
 
9
- print("import done")
 
10
 
11
-
12
-
13
- #settings.py迁移
14
- # 内容特征层及loss加权系数
15
  CONTENT_LAYERS = {'block4_conv2': 0.5, 'block5_conv2': 0.5}
16
- # 风格特征层及loss加权系数
17
- STYLE_LAYERS = {'block1_conv1': 0.2, 'block2_conv1': 0.2, 'block3_conv1': 0.2, 'block4_conv1': 0.2,
18
- 'block5_conv1': 0.2}
19
- # 内容图片路径
20
- #CONTENT_IMAGE_PATH = './images/content.jpg'
21
- CONTENT_IMAGE_PATH = input("image path:")
22
- # 风格图片路径
23
- # STYLE_IMAGE_PATH = './images/style.jpg'
24
- STYLE_IMAGE_PATH = input('style image path:')
25
- # 生成图片的保存目录
26
- # OUTPUT_DIR = './output'
27
- OUTPUT_DIR = input('output path:')
28
 
29
- # 内容loss总加权系数
30
  CONTENT_LOSS_FACTOR = 1
31
- # 风格loss总加权系数
32
  STYLE_LOSS_FACTOR = 100
33
 
34
- # 图片宽度
35
  WIDTH = 450
36
- # 图片高度
37
  HEIGHT = 300
38
-
39
- # 训练epoch数
40
  EPOCHS = 20
41
- # 每个epoch训练多少次
42
  STEPS_PER_EPOCH = 100
43
- # 学习率
44
  LEARNING_RATE = 0.03
45
 
46
-
47
-
48
-
49
-
50
-
51
-
52
- #utils.py迁移
53
- # 我们准备使用经典网络在imagenet数据集上的与训练权重,所以归一化时也要使用imagenet的平均值和标准差
54
- print("utils")
55
  image_mean = tf.constant([0.485, 0.456, 0.406])
56
  image_std = tf.constant([0.299, 0.224, 0.225])
57
 
58
-
59
  def normalization(x):
60
- """
61
- 对输入图片x进行归一化,返回归一化的值
62
- """
63
  return (x - image_mean) / image_std
64
 
65
-
66
  def load_images(image_path, width=WIDTH, height=HEIGHT):
67
- """
68
- 加载并处理图片
69
- :param image_path: 图片路径
70
- :param width: 图片宽度
71
- :param height: 图片长度
72
- :return: 一个张量
73
- """
74
- # 加载文件
75
  x = tf.io.read_file(image_path)
76
- # 解码图片
77
  x = tf.image.decode_jpeg(x, channels=3)
78
- # 修改图片大小
79
  x = tf.image.resize(x, [height, width])
80
  x = x / 255.
81
- # 归一化
82
  x = normalization(x)
83
  x = tf.reshape(x, [1, height, width, 3])
84
- # 返回结果
85
  return x
86
 
87
-
88
  def save_image(image, filename):
89
  x = tf.reshape(image, image.shape[1:])
90
  x = x * image_std + image_mean
@@ -95,201 +47,118 @@ def save_image(image, filename):
95
  x = tf.image.encode_jpeg(x)
96
  tf.io.write_file(filename, x)
97
 
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
- #model.py迁移
106
- print("models.py")
107
  def get_vgg19_model(layers):
108
- """
109
- 创建并初始化vgg19模型
110
- :return:
111
- """
112
- # 加载imagenet上预训练的vgg19
113
  vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
114
- # 提取需要被用到的vgg的层的output
115
  outputs = [vgg.get_layer(layer).output for layer in layers]
116
- # 使用outputs创建新的模型
117
  model = tf.keras.Model([vgg.input, ], outputs)
118
- # 锁死参数,不进行训练
119
  model.trainable = False
120
  return model
121
 
122
-
123
  class NeuralStyleTransferModel(tf.keras.Model):
124
-
125
- def __init__(self, content_layers: typing.Dict[str, float] = CONTENT_LAYERS,
126
- style_layers: typing.Dict[str, float] = STYLE_LAYERS):
127
  super(NeuralStyleTransferModel, self).__init__()
128
- # 内容特征层字典 Dict[层名,加权系数]
129
  self.content_layers = content_layers
130
- # 风格特征层
131
  self.style_layers = style_layers
132
- # 提取需要用到的所有vgg层
133
  layers = list(self.content_layers.keys()) + list(self.style_layers.keys())
134
- # 创建layer_name到output索引的映射
135
  self.outputs_index_map = dict(zip(layers, range(len(layers))))
136
- # 创建并初始化vgg网络
137
  self.vgg = get_vgg19_model(layers)
138
 
139
  def call(self, inputs, training=None, mask=None):
140
- """
141
- 前向传播
142
- :return
143
- typing.Dict[str,typing.List[outputs,加权系数]]
144
- """
145
  outputs = self.vgg(inputs)
146
- # 分离内容特征层和风格特征层的输出,方便后续计算 typing.List[outputs,加权系数]
147
  content_outputs = []
148
  for layer, factor in self.content_layers.items():
149
  content_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
150
  style_outputs = []
151
  for layer, factor in self.style_layers.items():
152
  style_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
153
- # 以字典的形式返回输出
154
  return {'content': content_outputs, 'style': style_outputs}
155
 
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
- # 创建模型
164
- model = NeuralStyleTransferModel()
165
-
166
- print("进入主程序")
167
-
168
- # 加载内容图片
169
- content_image = load_images(CONTENT_IMAGE_PATH)
170
- # 风格图片
171
- style_image = load_images(STYLE_IMAGE_PATH)
172
-
173
- # 计算出目标内容图片���内容特征备用
174
- target_content_features = model([content_image, ])['content']
175
- # 计算目标风格图片的风格特征
176
- target_style_features = model([style_image, ])['style']
177
-
178
- M = WIDTH * HEIGHT
179
- N = 3
180
-
181
-
182
  def _compute_content_loss(noise_features, target_features):
183
- """
184
- 计算指定层上两个特征之间的内容loss
185
- :param noise_features: 噪声图片在指定层的特征
186
- :param target_features: 内容图片在指定层的特征
187
- """
188
  content_loss = tf.reduce_sum(tf.square(noise_features - target_features))
189
- # 计算系数
190
- x = 2. * M * N
191
  content_loss = content_loss / x
192
  return content_loss
193
 
194
-
195
- def compute_content_loss(noise_content_features):
196
- """
197
- 计算并当前图片的内容loss
198
- :param noise_content_features: 噪声图片的内容特征
199
- """
200
- # 初始化内容损失
201
  content_losses = []
202
- # 加权计算内容损失
203
  for (noise_feature, factor), (target_feature, _) in zip(noise_content_features, target_content_features):
204
  layer_content_loss = _compute_content_loss(noise_feature, target_feature)
205
  content_losses.append(layer_content_loss * factor)
206
  return tf.reduce_sum(content_losses)
207
 
208
-
209
  def gram_matrix(feature):
210
- """
211
- 计算给定特征的格拉姆矩阵
212
- """
213
- # 先交换维度,把channel维度提到最前面
214
  x = tf.transpose(feature, perm=[2, 0, 1])
215
- # reshape,压缩成2d
216
  x = tf.reshape(x, (x.shape[0], -1))
217
- # 计算x和x的逆的乘积
218
  return x @ tf.transpose(x)
219
 
220
-
221
  def _compute_style_loss(noise_feature, target_feature):
222
- """
223
- 计算指定层上两个特征之间的风格loss
224
- :param noise_feature: 噪声图片在指定层的特征
225
- :param target_feature: 风格图片在指定层的特征
226
- """
227
  noise_gram_matrix = gram_matrix(noise_feature)
228
  style_gram_matrix = gram_matrix(target_feature)
229
  style_loss = tf.reduce_sum(tf.square(noise_gram_matrix - style_gram_matrix))
230
- # 计算系数
231
- x = 4. * (M ** 2) * (N ** 2)
232
  return style_loss / x
233
 
234
-
235
- def compute_style_loss(noise_style_features):
236
- """
237
- 计算并返回图片的风格loss
238
- :param noise_style_features: 噪声图片的风格特征
239
- """
240
  style_losses = []
241
  for (noise_feature, factor), (target_feature, _) in zip(noise_style_features, target_style_features):
242
  layer_style_loss = _compute_style_loss(noise_feature, target_feature)
243
  style_losses.append(layer_style_loss * factor)
244
  return tf.reduce_sum(style_losses)
245
 
246
-
247
- def total_loss(noise_features):
248
- """
249
- 计算总损失
250
- :param noise_features: 噪声图片特征数据
251
- """
252
- content_loss = compute_content_loss(noise_features['content'])
253
- style_loss = compute_style_loss(noise_features['style'])
254
  return content_loss * CONTENT_LOSS_FACTOR + style_loss * STYLE_LOSS_FACTOR
255
 
256
-
257
- # 使用Adma优化器
258
  optimizer = tf.keras.optimizers.Adam(LEARNING_RATE)
 
259
 
260
- # 基于内容图片随机生成一张噪声图片
261
- noise_image = tf.Variable((content_image + np.random.uniform(-0.2, 0.2, (1, HEIGHT, WIDTH, 3))) / 2)
262
-
263
-
264
- # 使用tf.function加速训练
265
- @tf.function
266
- def train_one_step():
267
- """
268
- 一次迭代过程
269
- """
270
- # 求loss
271
- with tf.GradientTape() as tape:
272
- noise_outputs = model(noise_image)
273
- loss = total_loss(noise_outputs)
274
- # 求梯度
275
- grad = tape.gradient(loss, noise_image)
276
- # 梯度下降,更新噪声图片
277
- optimizer.apply_gradients([(grad, noise_image)])
278
- return loss
279
 
 
280
 
281
- # 创建保存生成图片的文件夹
282
- if not os.path.exists(OUTPUT_DIR):
283
- os.mkdir(OUTPUT_DIR)
 
 
 
 
 
284
 
285
- # 共训练EPOCHS个epochs
286
- for epoch in range(EPOCHS):
287
- # 使用tqdm提示训练进度
288
- with tqdm(total=STEPS_PER_EPOCH, desc='Epoch {}/{}'.format(epoch + 1, EPOCHS)) as pbar:
289
- # 每个epoch训练STEPS_PER_EPOCH次
290
  for step in range(STEPS_PER_EPOCH):
291
  _loss = train_one_step()
292
- pbar.set_postfix({'loss': '%.4f' % float(_loss)})
293
- pbar.update(1)
294
- # 每个epoch保存一次图片
295
- save_image(noise_image, '{}/{}.jpg'.format(OUTPUT_DIR, epoch + 1))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import numpy as np
 
3
  import tensorflow as tf
4
+ from tqdm import tqdm
5
+ import gradio as gr
6
  import typing
7
+ from huggingface_hub import HfApi, Repository
8
+ import tempfile
9
 
10
+ # 定义模型和辅助函数
11
+ print("Importing necessary libraries and defining functions...")
12
 
 
 
 
 
13
  CONTENT_LAYERS = {'block4_conv2': 0.5, 'block5_conv2': 0.5}
14
+ STYLE_LAYERS = {'block1_conv1': 0.2, 'block2_conv1': 0.2, 'block3_conv1': 0.2, 'block4_conv1': 0.2, 'block5_conv1': 0.2}
 
 
 
 
 
 
 
 
 
 
 
15
 
 
16
  CONTENT_LOSS_FACTOR = 1
 
17
  STYLE_LOSS_FACTOR = 100
18
 
 
19
  WIDTH = 450
 
20
  HEIGHT = 300
 
 
21
  EPOCHS = 20
 
22
  STEPS_PER_EPOCH = 100
 
23
  LEARNING_RATE = 0.03
24
 
 
 
 
 
 
 
 
 
 
25
  image_mean = tf.constant([0.485, 0.456, 0.406])
26
  image_std = tf.constant([0.299, 0.224, 0.225])
27
 
 
28
  def normalization(x):
 
 
 
29
  return (x - image_mean) / image_std
30
 
 
31
  def load_images(image_path, width=WIDTH, height=HEIGHT):
 
 
 
 
 
 
 
 
32
  x = tf.io.read_file(image_path)
 
33
  x = tf.image.decode_jpeg(x, channels=3)
 
34
  x = tf.image.resize(x, [height, width])
35
  x = x / 255.
 
36
  x = normalization(x)
37
  x = tf.reshape(x, [1, height, width, 3])
 
38
  return x
39
 
 
40
  def save_image(image, filename):
41
  x = tf.reshape(image, image.shape[1:])
42
  x = x * image_std + image_mean
 
47
  x = tf.image.encode_jpeg(x)
48
  tf.io.write_file(filename, x)
49
 
 
 
 
 
 
 
 
 
 
50
  def get_vgg19_model(layers):
 
 
 
 
 
51
  vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
 
52
  outputs = [vgg.get_layer(layer).output for layer in layers]
 
53
  model = tf.keras.Model([vgg.input, ], outputs)
 
54
  model.trainable = False
55
  return model
56
 
 
57
  class NeuralStyleTransferModel(tf.keras.Model):
58
+ def __init__(self, content_layers=CONTENT_LAYERS, style_layers=STYLE_LAYERS):
 
 
59
  super(NeuralStyleTransferModel, self).__init__()
 
60
  self.content_layers = content_layers
 
61
  self.style_layers = style_layers
 
62
  layers = list(self.content_layers.keys()) + list(self.style_layers.keys())
 
63
  self.outputs_index_map = dict(zip(layers, range(len(layers))))
 
64
  self.vgg = get_vgg19_model(layers)
65
 
66
  def call(self, inputs, training=None, mask=None):
 
 
 
 
 
67
  outputs = self.vgg(inputs)
 
68
  content_outputs = []
69
  for layer, factor in self.content_layers.items():
70
  content_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
71
  style_outputs = []
72
  for layer, factor in self.style_layers.items():
73
  style_outputs.append((outputs[self.outputs_index_map[layer]][0], factor))
 
74
  return {'content': content_outputs, 'style': style_outputs}
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  def _compute_content_loss(noise_features, target_features):
 
 
 
 
 
77
  content_loss = tf.reduce_sum(tf.square(noise_features - target_features))
78
+ x = 2. * WIDTH * HEIGHT * 3
 
79
  content_loss = content_loss / x
80
  return content_loss
81
 
82
+ def compute_content_loss(noise_content_features, target_content_features):
 
 
 
 
 
 
83
  content_losses = []
 
84
  for (noise_feature, factor), (target_feature, _) in zip(noise_content_features, target_content_features):
85
  layer_content_loss = _compute_content_loss(noise_feature, target_feature)
86
  content_losses.append(layer_content_loss * factor)
87
  return tf.reduce_sum(content_losses)
88
 
 
89
  def gram_matrix(feature):
 
 
 
 
90
  x = tf.transpose(feature, perm=[2, 0, 1])
 
91
  x = tf.reshape(x, (x.shape[0], -1))
 
92
  return x @ tf.transpose(x)
93
 
 
94
  def _compute_style_loss(noise_feature, target_feature):
 
 
 
 
 
95
  noise_gram_matrix = gram_matrix(noise_feature)
96
  style_gram_matrix = gram_matrix(target_feature)
97
  style_loss = tf.reduce_sum(tf.square(noise_gram_matrix - style_gram_matrix))
98
+ x = 4. * (WIDTH * HEIGHT) ** 2 * 3 ** 2
 
99
  return style_loss / x
100
 
101
+ def compute_style_loss(noise_style_features, target_style_features):
 
 
 
 
 
102
  style_losses = []
103
  for (noise_feature, factor), (target_feature, _) in zip(noise_style_features, target_style_features):
104
  layer_style_loss = _compute_style_loss(noise_feature, target_feature)
105
  style_losses.append(layer_style_loss * factor)
106
  return tf.reduce_sum(style_losses)
107
 
108
+ def total_loss(noise_features, target_content_features, target_style_features):
109
+ content_loss = compute_content_loss(noise_features['content'], target_content_features)
110
+ style_loss = compute_style_loss(noise_features['style'], target_style_features)
 
 
 
 
 
111
  return content_loss * CONTENT_LOSS_FACTOR + style_loss * STYLE_LOSS_FACTOR
112
 
 
 
113
  optimizer = tf.keras.optimizers.Adam(LEARNING_RATE)
114
+ model = NeuralStyleTransferModel()
115
 
116
+ def neural_style_transfer(content_image_path, style_image_path):
117
+ content_image = load_images(content_image_path)
118
+ style_image = load_images(style_image_path)
119
+ target_content_features = model([content_image, ])['content']
120
+ target_style_features = model([style_image, ])['style']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
+ noise_image = tf.Variable((content_image + np.random.uniform(-0.2, 0.2, (1, HEIGHT, WIDTH, 3))) / 2)
123
 
124
+ @tf.function
125
+ def train_one_step():
126
+ with tf.GradientTape() as tape:
127
+ noise_outputs = model(noise_image)
128
+ loss = total_loss(noise_outputs, target_content_features, target_style_features)
129
+ grad = tape.gradient(loss, noise_image)
130
+ optimizer.apply_gradients([(grad, noise_image)])
131
+ return loss
132
 
133
+ for epoch in range(EPOCHS):
 
 
 
 
134
  for step in range(STEPS_PER_EPOCH):
135
  _loss = train_one_step()
136
+
137
+ output_image_path = tempfile.mktemp(suffix='.jpg')
138
+ save_image(noise_image, output_image_path)
139
+ return output_image_path
140
+
141
+ def transfer_style(content_image, style_image):
142
+ content_image_path = tempfile.mktemp(suffix='.jpg')
143
+ style_image_path = tempfile.mktemp(suffix='.jpg')
144
+
145
+ content_image.save(content_image_path)
146
+ style_image.save(style_image_path)
147
+
148
+ output_image_path = neural_style_transfer(content_image_path, style_image_path)
149
+ return output_image_path
150
+
151
+ # 创建Gradio界面
152
+ iface = gr.Interface(
153
+ fn=transfer_style,
154
+ inputs=[
155
+ gr.inputs.Image(type="pil", label="Content Image"),
156
+ gr.inputs.Image(type="pil", label="Style Image")
157
+ ],
158
+ outputs=gr.outputs.Image(type="file", label="Styled Image"),
159
+ title="Neural Style Transfer",
160
+ description="Upload a content image and a style image to perform neural style transfer."
161
+ )
162
+
163
+ # 运行Gradio应用
164
+ iface.launch()