d2l风格迁移--包含tensor与pil图片互换操作

李沐49_样式迁移——自学笔记 由于合成图像是风格迁移所需迭代的模型参数,我们只能在训练过程中通过调用extract_features函数来抽取合成图像的内容特征和风格特征。实验中,我们选择第四卷积块的最后一个卷积层作为内容层,选择每个卷积块的第一个卷积层作为风格层。由于我们还需要中间层的输出,因此这里我们逐层计算,并保留内容层和风格层的输出。使用VGG层抽取特征时,我们只需要用到从输入层到最靠近输出层的内容层或风格层之间的所有层。我们训练模型: 首先将内容图像和风格图像的高和宽分别调整为300和450像素,用内容图像来初始化合成图像。 阅读详情

对13章风格迁移任务进行讲解,并对其中的部分操作如pil与tensor呼唤进行具体介绍,方便后续调用!

目录

1.读取原图片:

2.转换函数

3.抽取图像特征与net构件

4.定义损失

5.训练


1.读取原图片:

d2l.set_figsize()
content_img = d2l.Image.open('img/rainier.jpg')
d2l.plt.imshow(content_img);

style_img = d2l.Image.open('img/autumn-oak.jpg')
d2l.plt.imshow(style_img);

2.转换函数

rgb_mean = torch.tensor([0.485, 0.456, 0.406])
rgb_std = torch.tensor([0.229, 0.224, 0.225])
def preprocess(img, image_shape):
    transforms = torchvision.transforms.Compose([
        torchvision.transforms.Resize(image_shape),
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize(mean=rgb_mean, std=rgb_std)])
    return transforms(img).unsqueeze(0)

def postprocess(img):
    img = img[0].to(rgb_std.device)  # 表示移动到rgb_std的device上
    img = torch.clamp(img.permute(1, 2, 0) * rgb_std + rgb_mean, 0, 1)  # 此时img为hwc
    return torchvision.transforms.ToPILImage()(img.permute(2, 0, 1))  # 此时per后为chw

  PIL图像用可以用img.size返回其(weigh,height),与tensor正好相反!!进行逆std与mean运算时应为(h,w,c),tensor中为(bs,c,h,w),进行ToPILImage操作时应为(c,h,w)

  应用,注:使用d2l.plt.imshow()传入一个pil图像可以直接显示:

# 加载图像并进行预处理
img_tensor = transforms.ToTensor()(Image.open('img/rainier.jpg'))
# 将张量转换为 PIL 图像对象
img_pil = transforms.ToPILImage()(img_tensor)
# 在 Jupyter Notebook 中显示图像
d2l.plt.imshow(img_pil)
img_pil.size

3.抽取图像特征与net构件

pretrained_net = torchvision.models.vgg19(pretrained=True)
style_layers, content_layers = [0, 5, 10, 19, 28], [25]
net = nn.Sequential(*[pretrained_net.features[i] for i in
                    range(max(content_layers + style_layers) + 1)])

  保留了0-28层,后面的不要了,上一节children嵌套list讲过了。

  逐层计算,并保留内容层和风格层的输出fmap:

def extract_features(X, content_layers, style_layers):
    contents = []
    styles = []
    for i in range(len(net)):
        X = net[i](X)
        if i in style_layers:
            styles.append(X)
        if i in content_layers:
            contents.append(X)
    return contents, styles

def get_contents(image_shape, device):
    content_X = preprocess(content_img, image_shape).to(device)
    contents_Y, _ = extract_features(content_X, content_layers, style_layers)
    return content_X, contents_Y
def get_styles(image_shape, device):
    style_X = preprocess(style_img, image_shape).to(device)
    _, styles_Y = extract_features(style_X, content_layers, style_layers)
    return style_X, styles_Y

4.定义损失

  内容损失直接用生成图片内容与真正图片内容进行均方误差。
  样式一样怎么理解?通过RGB直方图来理解,每个像素值没必要一样,匹配的是通道之间相关性。这里使用格拉姆矩阵,在gram函数中实现。传入X为(b,c,h,w),首先拉成(c,hw)尺寸,其中每一行可看作x1,x2...xc为长度为hw的向量,表示在该通道上的风格特征,进行矩阵相乘格拉姆矩阵中,i行和j列的元素Xij表示上述i行和j行的内积,表示通道i\j之间的风格相关性。
  为了避免风格损失受其中某较大误差值的影响,return的格拉姆矩阵再除矩阵中元素的个数chw(设bs=1)

def content_loss(Y_hat, Y):
    # 我们从动态计算梯度的树中分离⽬标:
    # 这是⼀个规定的值,⽽不是⼀个变量。
    return torch.square(Y_hat - Y.detach()).mean()

def gram(X):
    num_channels, n = X.shape[1], X.numel() // X.shape[1]
    X = X.reshape((num_channels, n))
    return torch.matmul(X, X.T) / (num_channels * n)

def style_loss(Y_hat, gram_Y):
    return torch.square(gram(Y_hat) - gram_Y.detach()).mean()

def tv_loss(Y_hat):
    return 0.5 * (torch.abs(Y_hat[:, :, 1:, :] - Y_hat[:, :, :-1, :]).mean() +
    torch.abs(Y_hat[:, :, :, 1:] - Y_hat[:, :, :, :-1]).mean())

  最后tv_loss是降噪操作,尽可能使临近的像素值相似,避免特别明亮或过暗的像素噪点。

  赋予权重并写总loss计算函数:

content_weight, style_weight, tv_weight = 1, 1e3, 10

def compute_loss(X, contents_Y_hat, styles_Y_hat, contents_Y, styles_Y_gram):
    # 分别计算内容损失、⻛格损失和全变分损失
    contents_l = [content_loss(Y_hat, Y) * content_weight for Y_hat, Y in zip(
        contents_Y_hat, contents_Y)]
    styles_l = [style_loss(Y_hat, Y) * style_weight for Y_hat, Y in zip(
        styles_Y_hat, styles_Y_gram)]
    tv_l = tv_loss(X) * tv_weight
    # 对所有损失求和
    l = sum(10 * styles_l + contents_l + [tv_l])
    return contents_l, styles_l, tv_l, l

  赋予权重,再相加。
  sum中传入3个列表则将列表里面的所有元素都相加起来,返回一个值。

5.训练

  明确一点,训练的使X,使图片,不是参数。
  所以写一个SynthesizedImage的类,将合成图像视为参数,这样就可以利用自动计算梯度更新合成图像,注意这里合成图像一开始用rand随机生成。

class SynthesizedImage(nn.Module):
    def __init__(self, img_shape, **kwargs):
        super(SynthesizedImage, self).__init__(**kwargs)
        self.weight = nn.Parameter(torch.rand(*img_shape))
    
    def forward(self):
        return self.weight

  定义inits函数,创建合成图像,在此可以将内容或风格图像当作初始权重,这样就不用随机rand生成了,使用的使data.copy_(X.data)的命令。
  然后,再将原始风格图像的gram提前计算出。

def get_inits(X, device, lr, styles_Y):
    gen_img = SynthesizedImage(X.shape).to(device)
    gen_img.weight.data.copy_(X.data)
    trainer = torch.optim.Adam(gen_img.parameters(), lr=lr)
    styles_Y_gram = [gram(Y) for Y in styles_Y]
    return gen_img(), styles_Y_gram, trainer

  训练函数,真正backward的只有l,其他的三个分loss画图print用的:

def train(X, contents_Y, styles_Y, device, lr, num_epochs, lr_decay_epoch):
    X, styles_Y_gram, trainer = get_inits(X, device, lr, styles_Y)
    scheduler = torch.optim.lr_scheduler.StepLR(trainer, lr_decay_epoch, 0.8)
    animator = d2l.Animator(xlabel='epoch', ylabel='loss',
                            xlim=[10, num_epochs],
                            legend=['content', 'style', 'TV'],
                            ncols=2, figsize=(7, 2.5))
    for epoch in range(num_epochs):
        trainer.zero_grad()
        contents_Y_hat, styles_Y_hat = extract_features(
            X, content_layers, style_layers)
        contents_l, styles_l, tv_l, l = compute_loss(
            X, contents_Y_hat, styles_Y_hat, contents_Y, styles_Y_gram)
        l.backward()
        trainer.step()
        scheduler.step()
        if (epoch + 1) % 10 == 0:
            animator.axes[1].imshow(postprocess(X))
            animator.add(epoch + 1, [float(sum(contents_l)),
            float(sum(styles_l)), float(tv_l)])
    return X

device, image_shape = d2l.try_gpu(), (300, 450)
net = net.to(device)
content_X, contents_Y = get_contents(image_shape, device)
_, styles_Y = get_styles(image_shape, device)
output = train(content_X, contents_Y, styles_Y, device, 0.3, 500, 50)

torchvision库学习之transforms.ToPILImage(函数) 是库中的一个函数,用于将张量或NumPy数组转换为PIL图像。这个函数在图像处理和深度学习中非常有用,特别是在数据预处理和可视化阶段。 阅读详情

相关推荐

本项目对中文版《动手学深度学习》中的代码进行了PyTorch实现并整理为PDF版本供下载.zip

本项目对中文版《动手学深度学习》中的代码进行了PyTorch实现并整理为PDF版本供下载

遍历文件,进行数据增强,重命名,tensor格式以图像输出

【代码】遍历文件,进行数据增强,重命名,tensor格式以图像输出。

weixin_43587056的博客 296

LAMMPS in文件详解:从零开始手把手教你配置金属分子动力学模拟

本文详细解析了LAMMPS in文件的配置方法,手把手教你完成金属分子动力学模拟的全流程。从软件环境准备、势函数选择,到使用Materials Studio构建模型、编写in文件进行能量最小化与系统弛豫,再到实施单轴拉伸生产模拟并提取应力应变数据,最后通过Python和OVITO进行结果分析与可视化,提供了完整的实战指南和常见问题排查技巧。

weixin_28475533的博客 526

深度学习:图像变换transforms

pytorch,transfrom图像变换

qq_42911863的博客 1827

iOS面试题大全(附带答案)

C语言相关面试题 1.static有什么用途? 答案:在C语言中,static主要定义全局静态变量,定义局部静态变量,定义静态函数。 static 属于静态变量,使用它修饰的变量生命周期是整个源程序。 @1.在函数体内的 static 变量的作用范围为该函数体,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值; @2.在模块内的 static 全局变量可以被模块内所有函数访问,但不能被模块外其它函数访问; @3.在模块内的 static 函数只被这一模块内的其它函数调用,这个函数的使用范围被限

IOSNF的博客 2423

RK3576开发板ROS2部署实战:从Buildroot配置到Hello World Demo

本文详细介绍了在RK3576开发板上部署ROS2的完整实战流程。从Buildroot工程配置、集成ROS2依赖,到搭建Docker交叉编译环境、处理编译难题,最终完成系统镜像打包并在板端成功运行Talker-Listener Demo。该指南旨在帮助开发者深入理解嵌入式机器人系统的构建链,实现从底层到应用的完全掌控。

mac99的博客 1149

【PyTorch】torchvision.transforms.ToPILImage 与图像分辨率

torchvision.transforms.ToPILImage 与图像分辨率

Esperanto.的博客 9462

01. VBA从入门到精通——录制宏、窗口、快捷键

excel表功能区右击→常用→选择显示开发工具选项→确定Visual Basic:打开VBA窗口宏:查看要录制的宏录制宏:准备录制宏使用相对引用:录制宏的时候对单元格的引用做一个设置宏安全性:对宏的使用做安全设置,一般设置为禁用所有宏,并发出通知,此时打开带有宏代码的工作薄时会出现警告标记,如果宏可信就选择启动。

weixin_43812198的博客 1696

transforms.ToPILImage

transforms.ToPILImage默认输入tensor取值范围为[0,1],若为[-1,1]则先需要反归一化到[0,1]

Larkii 的博客 4813

我的老款Intel MacBook Pro,如何用OpenVINO把本地大模型推理速度提升10倍?

本文详细介绍了如何在老款Intel MacBook Pro上使用OpenVINO工具包将本地大模型推理速度提升10倍。通过对比Ollama CPU原生、Transformers原生和OpenVINO优化三种方案,展示了OpenVINO在性能优化上的显著优势,并提供了从环境配置到模型转换、性能调优的完整实战指南。

weixin_28694295的博客 299

【DRAM存储器四十六】LPDDR5介绍--基本操作之行操作、读、写

简述LPDDR5的行操作和读写时序

highman110的博客 759

torchvision.transforms.ToTensor()与torchvision.transforms.ToPILImage()详解

torchvision.transforms.ToTensor() pytorch在加载数据集时都需要对数据记性transforms转换,其中最常用的就是torchvision.transforms.ToTensor()函数,但初学者可以认为这个函数只是把输入数据类型转换为pytorch的Tensor(int64)类型,其实不然,该函数内部的具体转换步骤为: 1、将图片转化成内存中的存储格式; 2、将字节以流的形式输入,转化成Tensor类型; 3、对Tensor进行reshape; 4、对Tensor进

weixin_44414948的博客 5690

RandLA-Net Tensorrt 推理 c++

RandLA-Net 实现 Tensorrt 部署.

J。 1108

李沐d2l《动手学深度学习》第二版——风格迁移源码详解

本文是对李沐Dive to DL《动手学深度学习》第二版13.12节风格迁移的源码详解,整体由Jupyter+VSCode完成,几乎所有重要代码均给出了注释,一看就懂。需要的同学可以在文末链接处下载原文件。 话不多说,我们开始。 图1中的内容图像为本书作者在西雅图郊区的雷尼尔山国家公园拍摄的风景照,而风格图像则是一幅主题为秋天橡树的油画。最终输出的合成图像应用了风格图像的油画笔触让整体颜色更加鲜艳,同时保留了内容图像中物体主体的形状。 图1 风格迁移效果示意图 1.一种简单的风格迁移方法 (1) 初始

Polaris的博客 7633

Sigrity Power DC Package Multi-Resistor Compact ET Model Extraction模式提取封装基板电热阻模型

DIE(定义DIE的参数):material设置为silicon(硅),Attach material(贴片的材料,设置为Die Attach),Attach thickness(贴片的材料的厚度,厚度设置为0.001mm,点击ok。Cap为覆盖材料,Material定义材料类型,thickness定义厚度,length和width定义长宽,Adhesive Material为胶的材料,Adhesive Material为胶的厚度,本例不定义,跳过即可。

weixin_54787054的博客 437

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Pytorch之ToPILImage()不输出图片问题

先导torchvision包 from PIL import Image from torchvision.transforms import ToTensor,ToPILImage 定义转换操作 img_to_tensor = ToTensor() # img -> tensor tensor_to_pil = ToPILImage() # tensor -> img 读取图片 img = Image.open('../test.jpg') # ‘’ 引号内为要读取图片的相对路径 把读取

qq_40821163的博客 7859

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

计算机视觉-阅读内容和风格图像

首先,我们读取内容和风格图像。从打印出的图像坐标轴可以看出,它们的尺寸并不一样。

学习笔记,人工智能,教程,技术分享! 748

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

神经网络数据增强transforms的相关操作(持续更新)

transforms的相关操作(Pytorch)一、图像的相关变化1、格式转换(1)transforms.ToTensor()(2)transforms.ToPILImage()1、图像大小(1) 一、图像的相关变化 1、格式转换 (1)transforms.ToTensor() 可将PIL格式、数组格式转换为tensor格式 img_path = "E:\expression_recognition\\2.jpg" img = Image.open(img_path) # #数组类型PIL类型都可 a1

hjkdh的博客 1万+

Pytorch之浅入torchvision.transforms.ToTensor与ToPILImage

torchvision.transforms中定义了一系列数据转换形式,有PILImage,numpy,Tensor间相互转换,还能对数据进行处理。 在torchvision.datasets下载数据的时候,作为一个参数传入,对下载的数据进行处理 (关于数据集下载,具体可参见https://blog.youkuaiyun.com/qq_37385726/article/details/81771943)...

qq_37385726的博客 4万+

Pytorch中使用transforms.ToTensor和transforms.ToPILImage的numpy.ndarray与Tensor和PILImage的转换举例

作为刚接触Pytorch的新人,在刚开始时候处理三种数据tensor,numpy,PIL有点弄晕了,而且中间的转换过程需要注意类型,仅此记录下来,如果能有幸帮到大家那更好了。 进入正题,我们首先看看numpy to tensor的情况: import numpy as np from torchvision import transforms as T x = np.ones((128, 2...

liuestcjun的博客 9993

pytorch:torchvision.transforms实例讲解

crop,filp,resize,totensor,topilimage等常用操作

weixin_41391619的博客 1344

transforms.ToPILImage()

模块的一个常用方法,用于将张量(Tensor)转换为 PIL 图像。以下是具体的使用方法和注意事项。通过以上步骤,可以高效地将张量转换为 PIL 图像,适用于模型输出可视化或后续图像处理任务。可直接用于 PIL 的图像操作(如保存、显示等)。是 PyTorch 中。

m0_69648014的博客 521

动手学深度学习(九、深度学习优化算法)

动手学深度学习(九、深度学习优化算法) 参考链接:优化算法 一、优化与深度学习 由于优化算法的目标函数通常是一个基于训练数据集的损失函数,优化的目标在于降低训练误差。 由于深度学习模型参数通常都是高维的,目标函数的鞍点通常比局部最小值更常见。 优化与深度学习的关系,以及优化在深度学习中的挑战。在一个深度学习问题中,我们通常会预先定义一个损失函数。有了损失函数以后,我们就可以使用优化算法试图将其最小化。在优化中,这样的损失函数通常被称作优化问题的目标函数(objective function)。依据惯

jiangchao98的博客 2095

torchvision.transforms.ToPILImage()使用

第一个空括号 () 用来实例化 ToPILImage 类。实例化后,就可以像函数一样使用这个实例,将 Tensor 或 ndarray 转换为 PIL.Image。

qq_41904729的博客 626

Torch中Tensor与Numpy或各种图像格式的相互转化

在这篇文章中: 前言 格式转换 PIL与Tensor numpy与Tensor 注意 前言 在pytorch中经常会遇到图像格式的转化,例如将PIL库读取出来的图片转化为Tensor,亦或者将Tensor转化为numpy格式的图片。而且使用不同图像处理库读取出来的图片格式也不相同,因此,如何在pytorch中正确转化各种图片格式(PIL、numpy、Tensor)是一个在调试中比较重要的问题。 ...

阿文 8057

使用Python的PIL将数组输出图像

最近拿到一幅txt格式的城市地图,其格式为2400×2400的二维数组,每个数组的值为一个整数,从1到800,将城市划分为800个不同的区,一个区的整数值相同,直接查看txt文档不太容易,因此考虑将该txt利用python转化为图像。 通常的彩色图像可以看作是三维数组,长×宽×通道,其中通道为每个像素点上用于表示颜色的数据,例如RGB三通道就是利用三个0~255的值来描述红、绿、蓝三个颜色。...

theVicTory的博客 9533
上一篇: d2l图像分割数据集制作
下一篇: d2l FCN全连接网络 --children()调用部分原网络操作与分割任务loss计算流程
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值