PyTorch深度学习实战(29)——神经风格迁移

PyTorch深度学习实战(29)——神经风格迁移

    • 0. 前言
    • 1. 神经风格迁移原理
      • 1.1 模型介绍
      • 1.2 GramMatrix 的重要性
    • 2. 神经风格迁移模型构建策略
    • 3. 使用 Keras 实现神经风格迁移
    • 小结
    • 系列链接

0. 前言

神经风格迁移 (Neural Style Transfer) 是一种基于深度学习的技术,用于将两个不同图像的风格进行合成,生成新的图像。它通过将一个参考图像的风格应用于另一个内容图像,以创造出独特而富有艺术感的合成图像。神经风格迁移的基本思想是利用预训练的卷积神经网络,将内容图像和风格图像分别输入网络中,并在网络的中间层获取它们的特征表示。通过调整合成图像的像素值,使得合成图像的特征表示既与内容图像的特征表示相似,又与风格图像的特征表示相似。

1. 神经风格迁移原理

1.1 模型介绍

神经风格迁移 (Neural Style Transfer) 是一种基于深度学习的艺术风格转换技术。它的基本思想是利用神经网络将图像 A 的风格与图像 B 的内容进行混合,生成一幅具有 A 风格特征和 B 内容特征的新图像。
神经风格迁移一般通过预训练的卷积神经网络实现。通过将输入图像和风格图像分别输入到这个网络中,提取到它们在神经网络中的特征表示,然后在不同网络层上使用不同权重进行组合,通过优化损失函数,生成一张新图像,使得它同时包含了内容图像的内容特征和风格图像的风格特征。因此,在神经风格迁移中,需要一张内容图像和一张风格图像,将这两个图像组合在一起,使得组合图像同时保留内容图像的内容和风格图像的风格:

风格迁移

在上图中,将右侧左下角子图(风格图像)中的风格迁移到左侧图像(内容图像)中的内容之上,得到融合结果如右侧图像所示。
为了执行神经风格迁移,我们将损失拆分为内容损失 (content loss) 和风格损失 (style loss),内容损失衡量生成的融合图像与内容图像间的差异,风格损失衡量风格图像与生成的融合图像的相似度。
在具体计算时,我们通常并不直接使用原始图像计算内容损失,而是使用图像的特征层激活进行计算,例如,第 2 个网络层的内容损失是内容图像和生成图像通过第 2 个网络层后激活之间的平方差。利用特征层而非原始图像计算内容损失,是由于特征层可以捕获原始图像的某些属性(例如,高层捕获前景轮廓,低层捕获物体细节)。
风格损失是衡量生成图片与风格图像在风格方面相似度的一种评估指标。风格损失通常通过计算生成图片与风格图像在神经网络层的 Gram 矩阵之间的距离来计算。Gram 矩阵是特征矩阵的内积,可以捕捉到图像特征之间的相关性,反映了图像的风格信息:

L G M ( S , G , l ) = 1 4 N l 2 M l 2 ∑ i j ( G M [ l ] ( S ) i j − G M [ l ] ( G ) i j ) 2 L_{GM}(S,G,l)=\frac1 {4N_l^2M_l^2}\sum_{ij}(GM[l](S)_{ij}-GM[l](G)_{ij})^2 LGM(S,G,l)=4Nl2Ml21ij(GM[l](S)ijGM[l](G)ij)2

其中 G M [ l ] GM[l] GM[l] 是风格图像 S S S 和生成图像 G G G 在第 l l l 层的 gram 矩阵值。Gram 矩阵是通过将矩阵与其自身的转置矩阵相乘得到的。
假设网络层的特征图尺寸为 32 x 32 x 256,将特征矩阵重塑为形状为 1024 x 256 的矩阵,其中 256 为矩阵的通道数,32 x 32= 1024 为特征图中的像素点数。然后,比较风格图像和生成图像的 Gram 矩阵的风格损失。
计算得到风格损失和内容损失后,最终生成的修改图像是使总损失最小的图像,即令风格和内容损失的加权平均值最小。

1.2 GramMatrix 的重要性

在本节中,我们将毕加索的画作风格转移到真实图像上,假设毕加索风格为 S t S_t St (风格图像),真实图像为 S o S_o So (内容图像),生成图像为 T a T_a Ta (目标图像)。在神经风格迁移中,图像 T a T_a Ta 中的局部特征与 S t S_t St 中的局部特征相同。尽管内容可能不同,但是将风格图像中类似的的颜色、形状和纹理应用于目标图像中是风格迁移中的重点。
进一步,如果使用 VGG19 的中间层提取 S o S_o So 图像特征,与提取的 T a T_a Ta 图像特征并不相同。但在每层的特征集中,对应的向量将以相似的方式相对变化。例如,在两个特征集中,第一个通道的平均值与第二个通道的平均值之比是相似的,这就是使用 Gram 进行损失计算的原因。
内容损失是通过比较内容图像与生成图像之间的特征激活差异来计算的;风格损失的计算方法是首先计算预定义层中的 Gram 矩阵,然后比较生成图像和风格图像的 Gram 矩阵;风格迁移模型的总损失是风格损失和内容损失的加权平均值。

2. 神经风格迁移模型构建策略

在了解了神经风格迁移的基本原理之后,我们继续对模型的运行流程进行分析,可以使用以下策略实现神经风格迁移:

  1. 将内容图像传递给预训练模型
  2. 提取内容图像通过预定义层的激活值
  3. 将生成图像输入模型,并在相同的预定义层提取激活值
  4. 计算内容图像和生成图像在每一网络层对应的内容损失
  5. 将风格图像通过模型的多个指定网络层,计算风格图像的 Gram 矩阵值
  6. 将生成图像穿过风格图像通过的相同网络层,并计算对应的 Gram 矩阵值
  7. 计算两幅图像的 Gram 矩阵值的平方差作为风格损失
  8. 总损失是风格损失和内容损失的加权平均值
  9. 最终的生成图像是能够最小化总损失的输入图像

3. 使用 Keras 实现神经风格迁移

了解了模型原理和运算流程后,接下来,使用 PyTorch 实现上述策略。

(1) 导入相关库:

from torchvision import transforms as T
from torch.nn import functional as F
import torch
from PIL import Image
from torch import nn
import numpy as np
from torch import optim
from matplotlib import pyplot as plt
device = 'cuda' if torch.cuda.is_available() else 'cpu'from torchvision.models import vgg19

(2) 定义用于图像预处理和后处理的函数:

preprocess = T.Compose([T.ToTensor(),T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),T.Lambda(lambda x: x.mul_(255))
])
postprocess = T.Compose([T.Lambda(lambda x: x.mul_(1./255)),T.Normalize(mean=[-0.485/0.229, -0.456/0.224, -0.406/0.225], std=[1/0.229, 1/0.224, 1/0.225]),
])

(3) 定义 GramMatrix 类:

class GramMatrix(nn.Module):def forward(self, input):b,c,h,w = input.size()feat = input.view(b, c, h*w)G = feat@feat.transpose(1,2)G.div_(h*w)return G

在以上代码中,计算所有特征与其转置矩阵的内积,用于获取所有向量之间的关系。

(4) 计算 Gram 矩阵对应的 MSE 损失 GramMSELoss

class GramMSELoss(nn.Module):def forward(self, input, target):out = F.mse_loss(GramMatrix()(input), target)return(out)

一旦计算出两个特征集的 Gram 向量,我们需要使用均方误差损失 mse_loss 使它们尽可能匹配。

(5) 定义模型类 vgg19_modified

初始化类:

class vgg19_modified(nn.Module):def __init__(self):super().__init__()

提取特征:

        features = list(vgg19(pretrained = True).features)self.features = nn.ModuleList(features).eval() 

定义 forward 方法,接受预定义网络层列表并返回每个网络层对应的特征:

    def forward(self, x, layers=[]):order = np.argsort(layers)_results, results = [], []for ix,model in enumerate(self.features):x = model(x)if ix in layers: _results.append(x)for o in order: results.append(_results[o])return results if layers is not [] else x

定义模型对象:

vgg = vgg19_modified().to(device)

(6) 导入内容和风格图片:

# 根据计算性能调整图像尺寸
imgs = [Image.open(path).resize((1200,675)).convert('RGB') for path in ['Vincent_van_Gogh_779.jpg', '3.jpeg']]
style_image, content_image = [preprocess(img).to(device)[None] for img in imgs]

(7) 使用 requires_grad = True 指定要修改的内容图像:

opt_img = content_image.data.clone()
opt_img.requires_grad = True

(8) 定义内容损失和风格损失的层,即我们使用哪些中间 VGG 层,来比较风格的 Gram 矩阵和内容的原始特征向量:

style_layers = [0, 5, 10, 19, 28] 
content_layers = [21]
loss_layers = style_layers + content_layers

(10) 定义内容和风格损失的损失函数:

loss_fns = [GramMSELoss()] * len(style_layers) + [nn.MSELoss()] * len(content_layers)
loss_fns = [loss_fn.to(device) for loss_fn in loss_fns]

(11) 定义用于平衡内容和风格损失的权重:

style_weights = [1000/n**2 for n in [64,128,256,512,512]] 
content_weights = [1]
weights = style_weights + content_weights

(12) 对图像进行操作,使其风格尽可能与 style_image 相似。因此,我们通过计算从几个选定的 VGG 层获得的特征的 GramMatrix 来计算 style_imagestyle_targets 值。由于应该保留整体内容,我们使用 content_layer 变量来计算 VGG 的原始特征:

style_targets = [GramMatrix()(A).detach() for A in vgg(style_image, style_layers)]
content_targets = [A.detach() for A in vgg(content_image, content_layers)]
targets = style_targets + content_targets

(13) 定义优化器和迭代次数 max_iters。尽管我们可以使用 Adam 或其他优化器,但 LBFGS 是在神经风格迁移模型中表现最佳的优化器。实验表明 LBFGS 收敛速度更快,并且损失值更小:

max_iters = 500
optimizer = optim.LBFGS([opt_img])

(14) 执行优化过程。优化过程中,我们需要迭代相同张量,因此可以将优化过程封装为函数并重复调用:

iters = 0
trn_loss = []
while iters < max_iters:def closure():global itersiters += 1optimizer.zero_grad()out = vgg(opt_img, loss_layers)layer_losses = [weights[a] * loss_fns[a](A, targets[a]) for a,A in enumerate(out)]loss = sum(layer_losses)loss.backward()trn_loss.append(loss.item())# log.record(pos=iters, loss=loss, end='\r')return lossoptimizer.step(closure)

(15) 绘制损失的变化情况:

epochs = np.arange(len(trn_loss)) + 1
plt.plot(epochs, trn_loss, 'bo', label='loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid('off')
plt.show()

损失变化情况
(16) 绘制神经风格迁移结果图像:

with torch.no_grad():out_img = postprocess(opt_img[0]).permute(1,2,0)
plt.imshow(out_img.detach().cpu())
plt.show()

神经风格迁移结果图像

从上图中可以看出,生成图像是内容图像和风格图像的组合。

小结

神经风格迁移是一种利用深度学习技术合成两个图像风格的方法,通过卷积神经网络提取图像的特征表示,并通过优化损失函数的方式合成新的图像,从而创造出独特而富有艺术感的合成图像。在本节中,首先介绍了神经风格迁移的核心思想与风格迁移图像的生成流程,然后利用 PyTorch 从零开始实现了神经风格迁移算法,可以通过修改模型中的超参数来生成不同观感的图像。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化
PyTorch深度学习实战(9)——学习率优化
PyTorch深度学习实战(10)——过拟合及其解决方法
PyTorch深度学习实战(11)——卷积神经网络
PyTorch深度学习实战(12)——数据增强
PyTorch深度学习实战(13)——可视化神经网络中间层输出
PyTorch深度学习实战(14)——类激活图
PyTorch深度学习实战(15)——迁移学习
PyTorch深度学习实战(16)——面部关键点检测
PyTorch深度学习实战(17)——多任务学习
PyTorch深度学习实战(18)——目标检测基础
PyTorch深度学习实战(19)——从零开始实现R-CNN目标检测
PyTorch深度学习实战(20)——从零开始实现Fast R-CNN目标检测
PyTorch深度学习实战(21)——从零开始实现Faster R-CNN目标检测
PyTorch深度学习实战(22)——从零开始实现YOLO目标检测
PyTorch深度学习实战(23)——使用U-Net架构进行图像分割
PyTorch深度学习实战(24)——从零开始实现Mask R-CNN实例分割
PyTorch深度学习实战(25)——自编码器(Autoencoder)
PyTorch深度学习实战(26)——卷积自编码器(Convolutional Autoencoder)
PyTorch深度学习实战(27)——变分自编码器(Variational Autoencoder, VAE)
PyTorch深度学习实战(28)——对抗攻击(Adversarial Attack)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2661005.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

C语言中的联合体的由来和存储

一、联合体的由来 1.1. 数据类型的不足 C语言中&#xff0c;基本数据类型只有整型、字符型、浮点型等少数几种&#xff0c;无法满足复杂数据类型的需要。 1.2. 数组的限制 虽然数组可以存储多个同类型的数据&#xff0c;但是数组中的元素个数是固定的&#xff0c;无法动态地…

【51单片机系列】DS18B20温度传感器扩展实验之设计一个智能温控系统

本文是关于DS18B20温度传感器的一个扩展实验。 文章目录 一、相关元件介绍二、实验分析三、proteus原理图设计四、软件设计 本扩展实验实现的功能&#xff1a;利用DS18B20设计一个智能温度控制系统&#xff0c;具有温度上下限值设定。当温度高于上限值时&#xff0c;电机开启&a…

[react]脚手架create-react-app/vite与reac项目

[react]脚手架create-react-app/vite与reac项目 环境问题描述create-react-app 脚手架根据脚手架修改项目结构安装脚手架注入配置文件-config文件夹package.json文件变更删除 serviceWorker.js新增reportWebVitals.js文件更新index.js文件 脚手架creat-react-app 缺点 vite 脚手…

Java技术栈 —— Nginx的使用

Java技术栈 —— Nginx的使用 一、认识Nginx二、搭建Nginx环境2.1 在Ubuntu上安装Nginx 三、使用Nginx3.1 配置负载均衡(HTTP) 一、认识Nginx 企业需要运行多个相同的副本&#xff0c;并将负载分散在整个系统集群上&#xff0c;为了高性能的负载均衡&#xff0c;引入了Nginx代…

阿里云30个公共云地域、89个可用区、5个金融云和政务云地域

阿里云基础设施目前已面向全球四大洲&#xff0c;公共云地域开服运营30个公共云地域、89个可用区&#xff0c;此外还拥有5个金融云、政务云地域&#xff0c;并且致力于持续的新地域规划和建设&#xff0c;从而更好的满足用户多样化的业务和场景需求。伴随着基础设施的加速投入和…

[RoarCTF2019] TankGame

不多说&#xff0c;用dnspy反编译data文件夹中的Assembly-CSharp文件 使用分析器分析一下可疑的FlagText 发现其在WinGame中被调用&#xff0c;跟进WinGame函数 public static void WinGame(){if (!MapManager.winGame && (MapManager.nDestroyNum 4 || MapManager.n…

【C语言】数据结构——排序(一)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;数组打印与交换1. 插入排序1.1 直接插入排序1.1.1 基本思想1.1.2 实现代码1.1.3 图解 1.2 希尔排序1.2.1…

机器人中的数值优化之无约束优化

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 本文ppt来自深蓝学院《机器人中的数值优化》

人工智能的新篇章:深入了解大型语言模型(LLM)的应用与前景

LLM&#xff08;Large Language Model&#xff09;技术是一种基于深度学习的自然语言处理技术&#xff0c;旨在训练能够处理和生成自然语言文本的大型模型。 LLM 技术的核心思想是使用深度神经网络&#xff0c;通过大规模的文本数据预训练模型&#xff0c;并利用这些预训练模型…

伪装目标检测的算术不确定性建模

Modeling Aleatoric Uncertainty for Camouflaged Object Detection 伪装目标检测的算术不确定性建模背景贡献实验方法Camouflaged Object Detection Network&#xff08;伪装目标检测框架&#xff09;Online Confidence Estimation Network&#xff08;在线置信度估计网络&…

【Week-P3】CNN天气识别

文章目录 一、环境配置二、准备数据三、搭建网络结构四、开始训练五、查看训练结果六、总结6.1 不改变学习率的前提下&#xff0c;将训练epoch分别增加到60、70、80、90&#xff08;1&#xff09;epoch 50 的训练情况如下&#xff1a;&#xff08;2&#xff09;epoch 60 的训…

Redis哨兵sentinel

是什么&#xff1f; 哨兵巡查监控后台master主机是否故障&#xff0c;如果故障根据投票数自动将某一个slave库变为master&#xff0c;就行对外服务&#xff0c;称为无人值守运维 能干嘛&#xff1f; 主从监控&#xff1a;监控主从redis库是否正常工作 消息通知&#xff1a;…

C++面向对象(OOP)编程-C++11新特性详解

C11作为一个重要的版本&#xff0c;引入了很多新的特性&#xff0c;解决了C语言本身很多遗留的内存泄露问题&#xff0c;并且提供了很多比较灵活的用法。引入的auto&#xff0c;智能指针、线程机制都使得C语言的灵活性、安全性、并发性有了很大的提升。 本文会比较详细的介绍C1…

YOLOv5改进 | 2023注意力篇 | FocusedLinearAttention聚焦线性注意力

一、本文介绍 本文给大家带来的改进机制是FLAttention&#xff08;聚焦线性注意力&#xff09;是一种用于视觉Transformer模型的注意力机制(但是其也可以用在我们的YOLO系列当中从而提高检测精度)&#xff0c;旨在提高效率和表现力。其解决了两个在传统线性注意力方法中存在的…

MySQL 数据库归档工具pt-archive 与归档数据的安全存储 与 为什么每次归档都少数...

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;共1780人左右 1 2 3 4 5&#xff0…

java球队信息管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web球队信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5…

开源预约挂号平台 - 从0到上线

文章目录 开源预约挂号平台 - 从0到上线演示地址源码地址可以学到的技术前端技术后端技术部署上线开发工具其他技术业务功能 项目讲解前端创建项目 - 安装PNPM - 使用VSCODE - 安装插件首页顶部与底部 - 封装组建 - 使用scss左右布局中间内容部分路由 - vue-routerBANNER- 走马…

HCIA-Datacom题库(自己整理分类的)——OSPF协议判断

1.路由表中某条路由信息的Proto为OSPF则此路由的优先级一定为10。√ 2.如果网络管理员没有配置骨干区域,则路由器会自动创建骨干区域&#xff1f; 路由表中某条路由信息的Proto为OSPF&#xff0c;则此路由的优先级一定为10。 当两台OSPF路由器形成2-WAY邻居关系时&#xff0…

小梅哥Xilinx FPGA学习笔记18——专用时钟电路 PLL与时钟向导 IP

目录 一&#xff1a;IP核简介&#xff08;具体可参考野火FPGA文档&#xff09; 二&#xff1a; 章节导读 三&#xff1a;PLL电路原理 3.1 PLL基本实现框图 3.2 PLL倍频实现 3.3 PLL分频实现 四: 基于 PLL 的多时钟 LED 驱动设计 4.1 配置 Clocking Wizard 核 4.2 led …

useReducer 的奇妙世界:探索 React 状态管理的新境界(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…