Python深度学习之神经风格迁移

本文详细介绍了神经风格迁移,通过深度学习的神经网络实现图像风格转移,保留目标图像内容的同时应用参考图像的风格。内容损失使用VGG19网络高层激活,风格损失依赖于Gram矩阵和多层激活,同时应用总变差损失确保生成图像的连续性。通过Keras实现神经风格迁移,使用L-BFGS算法进行优化。

Deep Learning with Python

这篇文章是我学习《Deep Learning with Python》(第二版,François Chollet 著) 时写的系列笔记之一。文章的内容是从 Jupyter notebooks 转成 Markdown 的,你可以去 GitHubGitee 找到原始的 .ipynb 笔记本。

你可以去这个网站在线阅读这本书的正版原文(英文)。这本书的作者也给出了配套的 Jupyter notebooks

本文为 第8章 生成式深度学习 (Chapter 8. Generative deep learning) 的笔记之一。

8.3 Neural style transfer

神经风格迁移

神经风格迁移(neural style transfer),基于深度学习的神经网络,将参考图像的风格应用于目标图像,同时保留目标图像的内容,创造出新的图像。

一个风格迁移的示例

神经风格迁移的思想很简单:定义一个损失函数来指定要实现的目标,然后将这个损失最小化。这里的目标就是保存原始图像的内容,同时采用参考图像的风格。

假设有函数 content 和 style 分别可以计算出输入图像的内容和风格,以及有范式函数 distance,则神经风格迁移的损失可以表达为:

loss = distance(content(original_image) - content(generated_image)) +
       distance(style(reference_image) - style(generated_image))

事实上,利用深度卷积神经网络,是可以从数学上定义 style 和 content 函数的。

损失定义
  1. 内容损失

卷积神经网络靠底部(前面)的层激活包含关于图像的局部信息,靠近顶部(后面)的层则包含更加全局、抽象的信息。内容就是图像的全局、抽象的信息,所以可以用卷积神经网络靠顶部的层激活来表示图像的内容。

因此,给定一个预训练的卷积神经网络,选定一个靠顶部的层,内容损失可以使用「该层在目标图像上的激活」和「该层在生成图像上的激活」之间的 L2 范数。

  1. 风格损失

不同于内容只用一个层即可表达,风格需要多个层才能定义。风格是多种方面的,比如笔触、线条、纹理、颜色等等,这些内容会出现在不同的抽象程度上。所以风格的表达就需要捕捉所有空间尺度上提取的外观,而不仅仅是在单一尺度上。

在这种思想下,风格损失的表达,可以借助于层激活的 Gram 矩阵。这个 Gram 矩阵就是某一层的各个特征图的内积,表达了层的特征间相互关系(correlation)的映射,它就对应于这个尺度上找到的纹理(texture)的外观。而在不同的层激活内保存相似的内部相互关系,就可以认为是“风格”了。

那么,我们就可以用生成图像和风格参考图像在不同层上保持的纹理,来定义风格损失了。

神经风格迁移的 Keras 实现

神经风格迁移可以用任何预训练卷积神经网络来实现,这里选用 VGG19。

神经风格迁移的步骤如下:

  1. 创建一个网络,同时计算风格参考图像、目标图像和生成图像的 VGG19 层激活;
  2. 使用这三张图像上计算的层激活来定义之前所述的损失函数;
  3. 梯度下降来将这个损失函数最小化。

在开始构建网络前,先定义风格参考图像和目标图像的路径。如果图像尺寸差异很大,风格迁移会比较困难,所以这里我们还统一定义一下尺寸:

# 不使用及时执行模式

import tensorflow as tf

tf.compat.v1.disable_eager_execution()
# 定义初始变量

from tensorflow.keras.preprocessing.image import load_img, img_to_array

target_image_path = 'img/portrait.jpg'
style_referencce_image_path = 'img/transfer_style_reference.jpg'

width, height = load_img(target_image_path).size
img_height = 400
img_width = width * img_height // height

这里图片我选择了:

  • transfer_style_reference: 文森特·梵高《麦田里的丝柏树》(A Wheatfield, with Cypresses),1889年,收藏于纽约大都会博物馆。
  • portrait: 保罗·高更《不列塔尼牧人》(The Swineherd, Brittany),1888年,收藏于美国加州洛杉矶郡立美术馆。

麦田里的丝柏树与不列塔尼牧人

接下来,我们需要一些辅助函数,用于图像的加载、处理。

# 辅助函数

import numpy as np
from tensorflow.keras.applications import vgg19

def preprocess_image(image_path):
    img = load_img(image_path, target_size=(img_height, img_width))
    img = img_to_array(img)
    img = np.expand_dims(img, axis=0)
    img = vgg19.preprocess_input(img)
    return img

def deprocess_image(x):
    # vgg19.preprocess_input 会减去ImageNet的平均像素值,使其中心为0。这里做逆操作:
    x[:, :, 0] += 103.939
    x[:, :, 1] += 116.779
    x[:, 
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值