美文网首页
tf2.X-神经风格迁移,人人都是艺术家

tf2.X-神经风格迁移,人人都是艺术家

作者: Python老Q | 来源:发表于2021-11-30 19:05 被阅读0次

点点关注不迷路

什么是神经风格迁移

神经风格迁移是将一幅图片的内容和另一幅艺术图片的风格结合,生成一张艺术化的图片的过程。输入是一张内容图和一张风格图,输出是风格化的结果。例如下面这样:

代码解析

下面我们就用tensorflow2.X来实现最早的神经风格迁移,实现我们自己的艺术创作。

基本设置

首先我们导入需要的库,影像以及设置一些需要的参数。图片来自于http://www.pexels.com/。

importnumpyasnp

importtensorflowastf

fromtensorflowimportkeras

fromtensorflow.keras.applicationsimportvgg19

base_image_path ='building.jpg'

style_reference_image_path ='dids.jpg'

result_prefix ="result"

#损失分量的加权平均所使用的权重

total_variation_weight =1e-6

style_weight =1e-6

content_weight =2.5e-8

# 确保处理后的影像具有相似尺寸

width, height = keras.preprocessing.image.load_img(base_image_path).size

img_nrows =400

img_ncols = int(width * img_nrows / height)

所使用的基础图片与风格图片如下所示。

图像预处理与去处理操作

defpreprocess_image(image_path):

# 处理图像,确保为VGG19接受的输入张量

img = keras.preprocessing.image.load_img(

image_path, target_size=(img_nrows, img_ncols)

)

img = keras.preprocessing.image.img_to_array(img)

img = np.expand_dims(img, axis=0)

img = vgg19.preprocess_input(img)

returntf.convert_to_tensor(img)

defdeprocess_image(x):

# vgg19.preprocess_input的作用是减去ImageNet的平均像素值,使其中心为0。这里相当于vgg19.preprocess_input的逆操作

x = x.reshape((img_nrows, img_ncols,3))

x[:, :,0] +=103.939

x[:, :,1] +=116.779

x[:, :,2] +=123.68

# 'BGR'->'RGB'将图像由BGR格式转换为RGB格式。这也是vgg19.preprocess_input 逆操作的一部分

x = x[:, :, ::-1]

# 裁剪x中元素到指定范围

x = np.clip(x,0,255).astype("uint8")

returnx

定义损失函数

我们需要定义 4 个相关函数:

gram_matrix (用于计算风格损失)

style_loss,使生成的图像风格接近参考图像的局部纹理

content_loss,使生成的图像的基本内容与基础图像的基本内容保持接近

total_variation_loss,也称为总变差正则化,使图像平滑

defgram_matrix(x):

x = tf.transpose(x, (2,0,1))

features = tf.reshape(x, (tf.shape(x)[0],-1))

gram = tf.matmul(features, tf.transpose(features))

returngram

# 定义风格损失,确保生成图像保持参考图像的风格

defstyle_loss(style, combination):

S = gram_matrix(style)

C = gram_matrix(combination)

channels =3

size = img_nrows * img_ncols

returntf.reduce_sum(tf.square(S - C)) / (4.0* (channels **2) * (size **2))

# 内容损失,确保基准影像的内容不丢失

defcontent_loss(base, combination):

returntf.reduce_sum(tf.square(combination - base))

# 定义总变差损失:它对生成的组合图像的像素进行操作。它促使生成图像具有空间连续性,从而避免结果过度像素化。可以将其理解为正则化损失。

deftotal_variation_loss(x):

a = tf.square(

x[:, : img_nrows -1, : img_ncols -1, :] - x[:,1:, : img_ncols -1, :]

)

b = tf.square(

x[:, : img_nrows -1, : img_ncols -1, :] - x[:, : img_nrows -1,1:, :]

)

returntf.reduce_sum(tf.pow(a + b,1.25))

# 这里我们加载在imagenet上预训练好的VGG19

model = vgg19.VGG19(weights="imagenet", include_top=False)

# 获得层的名称与对应输出的字典

outputs_dict = dict([(layer.name, layer.output)forlayerinmodel.layers])

# 创建模型,并返回上述字典内的层的结果

feature_extractor = keras.Model(inputs=model.inputs, outputs=outputs_dict)

# 用于风格损失的层

style_layer_names = [

"block1_conv1",

"block2_conv1",

"block3_conv1",

"block4_conv1",

"block5_conv1",

]

# 用于内容损失的层

content_layer_name ="block5_conv2"

defcompute_loss(combination_image, base_image, style_reference_image):

input_tensor = tf.concat(

[base_image, style_reference_image, combination_image], axis=0

)

features = feature_extractor(input_tensor)

# 初始化损失

loss = tf.zeros(shape=())

# 添加内容损失

layer_features = features[content_layer_name]

base_image_features = layer_features[0, :, :, :]

combination_features = layer_features[2, :, :, :]

loss = loss + content_weight * content_loss(

base_image_features, combination_features

)

# 添加风格损失

forlayer_nameinstyle_layer_names:

layer_features = features[layer_name]

style_reference_features = layer_features[1, :, :, :]

combination_features = layer_features[2, :, :, :]

sl = style_loss(style_reference_features, combination_features)

loss += (style_weight / len(style_layer_names)) * sl

# 添加总变差损失

loss += total_variation_weight * total_variation_loss(combination_image)

returnloss

损失与梯度计算

@tf.function

defcompute_loss_and_grads(combination_image, base_image, style_reference_image):

withtf.GradientTape()astape:

loss = compute_loss(combination_image, base_image, style_reference_image)

grads = tape.gradient(loss, combination_image)

returnloss, grads

训练循环

每100次迭代,减小学习率,并保存一次结果图片

# 定义优化器

optimizer = keras.optimizers.SGD(

keras.optimizers.schedules.ExponentialDecay(

initial_learning_rate=100.0, decay_steps=100, decay_rate=0.96

)

)

base_image = preprocess_image(base_image_path)

style_reference_image = preprocess_image(style_reference_image_path)

combination_image = tf.Variable(preprocess_image(base_image_path))

iterations =4000

foriinrange(1, iterations +1):

loss, grads = compute_loss_and_grads(

combination_image, base_image, style_reference_image

)

optimizer.apply_gradients([(grads, combination_image)])

# 每隔100次迭代,打印损失,输出一次结果图片

ifi %100==0:

print("Iteration %d: loss=%.2f"% (i, loss))

img = deprocess_image(combination_image.numpy())

fname = result_prefix +"_at_iteration_%d.png"% i

# 保存结果图片

keras.preprocessing.image.save_img(fname, img)

结果展示

到了这里,我们所有的操作都完成了,下面我们来看一下结果。

emmm,风格有些独特。

总结

今天我们介绍了图像风格迁移的先驱之一Leon A. Gatys在2015年的神经风格迁移网络,感兴趣的同学可以自己试一试,创作自己的艺术图片。

相关文章

  • tf2.X-神经风格迁移,人人都是艺术家

    点点关注不迷路 什么是神经风格迁移 神经风格迁移是将一幅图片的内容和另一幅艺术图片的风格结合,生成一张艺术化的图片...

  • 神经风格迁移

    前言 图像的风格迁移是计算机视觉领域最有趣的应用之一,用深度学习实现图像的风格迁移,可以分为实现神经风格迁移算法和...

  • 神经风格迁移

    准备 一个style image 、一个 content image以及一个训练好的CNN(一般用VGG网络就可以...

  • 人人都是艺术家

    (麦子摇滚) 你是艺术家,我是艺术家,你我都是艺术家 你是艺术家,我是艺术家,人人都是艺术家艺术家,艺术家,艺术家...

  • 人人都是艺术家

    快乐的时光总是短暂的,今天是来南京办正事的一天,也是我们的返程之日。 上午组委会把一行领奖代表车到南京艺术学院实验...

  • 人人都是艺术家

    呆子 人到了50岁以后,你的长相就是你的精神面貌,是你做人这一路的修行和福报。也就是说,是你这几十年的心理活动、三...

  • 人人是艺术家

    (麦子摇滚) 你是艺术家,我是艺术家,你我都是当代艺术家 你是艺术家,我是艺术家,人人都是当代艺术家 艺术家,当代...

  • 人人都是神经病

    有的人重 有的人轻

  • 风格迁移

    风格迁移重要的两步就是风格图像的风格提取和内容图像的内容提取。 纹理合成 纹理能够描述一个图像的风格,所以风格的提...

  • 风格迁移

    A Neural Algorithm of Artistic Style:https://arxiv.org/pd...

网友评论

      本文标题:tf2.X-神经风格迁移,人人都是艺术家

      本文链接:https://www.haomeiwen.com/subject/bigdxrtx.html