基于CycleGAN的图像季节转换

2023-10-29 11:50
文章标签 图像 转换 cyclegan 季节

本文主要是介绍基于CycleGAN的图像季节转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(1) 季节转换图像数据集简介

下载地址: https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/, 或者 https://www.kaggle.com/datasets/balraj98/summer2winter-yosemite
注意:Kaggle中提供了一些代码案例,keras官网也提供了代码案例,可供参考。
在这里插入图片描述

(2) CycleGAN模型简介

Cycle-GAN是一个2017年推出的直击产业痛点的模型。众所周知,在一系列视觉问题上是很难以找到匹配的高质量图像作为target来供模型学习的,比如在超分辨领域内对于一个低分辨率的物体图像,未必能找到同样场景的高分辨率图像,这使得一系列深度学习模型的适应性有限。上述的困难总结起来就是:由于模型训练时必须依赖匹配的图像,而除非有目的的去产生这样的图像否则无法训练,并且很容易造成数据有偏。
Cycle-GAN训练的目的则避开了上述困难;该模型的思路是旨在形成一个由数据域A到数据域B的普适性映射,学习的目标是数据域A和B的风格之间的变换而非具体的数据a和b之间的一一映射关系。从这样的思路出发Cycle-GAN对于数据一一匹配的依赖性就不存在了,可以解决一系列问题,因此该模型的设计思路与具体做法十分值得学习。
循环生成对抗网络是一种无监督生成对抗网络,它的主要想法是训练两对生成器-判别器模型以将图像从一个领域转换为另一个领域,在这过程中我们要求循环一致性。即在序列地应用生成器后,我们应该得到一个相似于原始 L1 损失的图像。因此我们需要一个循环损失函数(cyclic loss),它能确保生成器不会将一个领域的图像转换到另一个和原始图像完全不相关的领域。
并且,CycleGAN本质上是两个镜像对称的GAN,构成了一个环形网络。
两个GAN共享两个生成器,并各自带一个判别器,即共有两个判别器和两个生成器。一个单向GAN两个loss,两个即共四个loss。
该模型包含两个映射函数 G : X —> Y 和 F : Y —> X,以及相关的对抗式鉴别器 DY 和 DX。DY 鼓励 G 将 X 翻译为 Y 风格的图像,反之亦然。为了进一步规范映射,研究者引入了两个「循环协调损失函数」,确保转换后的风格在反转换后可以回到处理之前的状态,如下图所示:
在这里插入图片描述

总的来说,基于Cycle-GAN的模型具有较强的适应性,能够适应一系列的视觉问题场合,比如超分辨,风格变换,图像增强等等场合。

(1) 季节转换图像数据的读取

import time
from options.train_options import TrainOptions
from data import create_dataset
from models import create_model
from util.visualizer import Visualizerif __name__ == '__main__':opt = TrainOptions().parse()   # get training optionsdataset = create_dataset(opt)  # create a dataset given opt.dataset_mode and other optionsdataset_size = len(dataset)    # get the number of images in the dataset.print('The number of training images = %d' % dataset_size)model = create_model(opt)      # create a model given opt.model and other optionsmodel.setup(opt)               # regular setup: load and print networks; create schedulersvisualizer = Visualizer(opt)   # create a visualizer that displayve images and plotstotal_iters = 0                # the total number of training iterationsfor epoch in range(opt.epoch_count, opt.niter + opt.niter_decay + 1):    # outer loop for different epochs; we save the model by <epoch_count>, <epoch_count>+<save_latest_freq>epoch_start_time = time.time()  # timer for entire epochiter_data_time = time.time()    # timer for data loading per iterationepoch_iter = 0                  # the number of training iterations in current epoch, reset to 0 every epochfor i, data in enumerate(dataset):  # inner loop within one epochiter_start_time = time.time()  # timer for computation per iterationif total_iters % opt.print_freq == 0:t_data = iter_start_time - iter_data_timevisualizer.reset()total_iters += opt.batch_sizeepoch_iter += opt.batch_sizemodel.set_input(data)         # unpack data from dataset and apply preprocessingmodel.optimize_parameters()   # calculate loss functions, get gradients, update network weightsif total_iters % opt.display_freq == 0:   # display images on visdom and save images to a HTML filesave_result = total_iters % opt.update_html_freq == 0model.compute_visuals()visualizer.display_current_results(model.get_current_visuals(), epoch, save_result)if total_iters % opt.print_freq == 0:    # print training losses and save logging information to the disklosses = model.get_current_losses()t_comp = (time.time() - iter_start_time) / opt.batch_sizevisualizer.print_current_losses(epoch, epoch_iter, losses, t_comp, t_data)if opt.display_id > 0:visualizer.plot_current_losses(epoch, float(epoch_iter) / dataset_size, losses)if total_iters % opt.save_latest_freq == 0:   # cache our latest model every <save_latest_freq> iterationsprint('saving the latest model (epoch %d, total_iters %d)' % (epoch, total_iters))save_suffix = 'iter_%d' % total_iters if opt.save_by_iter else 'latest'model.save_networks(save_suffix)iter_data_time = time.time()if epoch % opt.save_epoch_freq == 0:              # cache our model every <save_epoch_freq> epochsprint('saving the model at the end of epoch %d, iters %d' % (epoch, total_iters))model.save_networks('latest')model.save_networks(epoch)print('End of epoch %d / %d \t Time Taken: %d sec' % (epoch, opt.niter + opt.niter_decay, time.time() - epoch_start_time))model.update_learning_rate()

(2) 基于CycleGAN模型的图像季节转换

 import os
from options.test_options import TestOptions
from data import create_dataset
from models import create_model
from util.visualizer import save_images
from util import htmlif __name__ == '__main__':opt = TestOptions().parse()  # get test options# hard-code some parameters for testopt.num_threads = 0   # test code only supports num_threads = 1opt.batch_size = 1    # test code only supports batch_size = 1opt.serial_batches = True  # disable data shuffling; comment this line if results on randomly chosen images are needed.opt.no_flip = True    # no flip; comment this line if results on flipped images are needed.opt.display_id = -1   # no visdom display; the test code saves the results to a HTML file.dataset = create_dataset(opt)  # create a dataset given opt.dataset_mode and other optionsmodel = create_model(opt)      # create a model given opt.model and other optionsmodel.setup(opt)               # regular setup: load and print networks; create schedulers
# create a websiteweb_dir = os.path.join(opt.results_dir, opt.name, '%s_%s' % (opt.phase, opt.epoch))  # define the website directorywebpage = html.HTML(web_dir, 'Experiment = %s, Phase = %s, Epoch = %s' % (opt.name, opt.phase, opt.epoch))# test with eval mode. This only affects layers like batchnorm and dropout.# For [pix2pix]: we use batchnorm and dropout in the original pix2pix. You can experiment it with and without eval() mode.# For [CycleGAN]: It should not affect CycleGAN as CycleGAN uses instancenorm without dropoutif opt.eval:model.eval()for i, data in enumerate(dataset):if i >= opt.num_test:  # only apply our model to opt.num_test images.breakmodel.set_input(data)  # unpack data from data loadermodel.test()           # run inferencevisuals = model.get_current_visuals()  # get image resultsimg_path = model.get_image_paths()     # get image pathsif i % 5 == 0:  # save images to an HTML fileprint('processing (%04d)-th image... %s' % (i, img_path))save_images(webpage, visuals, img_path, aspect_ratio=opt.aspect_ratio, width=opt.display_winsize)webpage.save()

结果与对比分析

结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
季节转换指将在某一季节拍摄的照片转换为另一个季节的照片,例如将夏季的照片转换为冬季。在下面的示例中, CycleGAN 实现了冬天和夏天拍摄的风景照之间的相互转换。
对于 Unpaired 问题来说,只是用普通 GAN 的话可以学到的模型有很多种。种类数目为领域 X 和领域 Y 之间的随机映射数目,所以只是用普通 GAN 损失函数无法保证输入 x 能够得到对应领域的 y。而 Cycle 一致性的出现,降低了随机映射的数目,从而保证得到的输出不再是随机的,因此能够实现图片从一个领域到另一个领域的转换。

出现的问题及解决方法

出现的问题:
1.数据集下载慢;
2.代码运行不出来;
3.关于实验结果的分析难以得出;
解决办法:
1.更换网络重新下载;
2.查错,修改代码重新运行;
3.多次对比实验结果进行分析。

结果分析与体会

对于 Unpaired 问题来说,只是用普通 GAN 的话可以学到的模型有很多种。种类数目为领域 X 和领域 Y 之间的随机映射数目,所以只是用普通 GAN 损失函数无法保证输入 x 能够得到对应领域的 y。而 Cycle 一致性的出现,降低了随机映射的数目,从而保证得到的输出不再是随机的,因此能够实现图片从一个领域到另一个领域的转换。
循环生成对抗网络是一种无监督生成对抗网络,它的主要想法是训练两对生成器-判别器模型以将图像从一个领域转换为另一个领域,在这过程中我们要求循环一致性。即在序列地应用生成器后,我们应该得到一个相似于原始 L1 损失的图像。因此我们需要一个循环损失函数(cyclic loss),它能确保生成器不会将一个领域的图像转换到另一个和原始图像完全不相关的领域。
并且,CycleGAN本质上是两个镜像对称的GAN,构成了一个环形网络。
两个GAN共享两个生成器,并各自带一个判别器,即共有两个判别器和两个生成器。一个单向GAN两个loss,两个即共四个loss。
其实在CycleGAN之前,就已经有了Domain Adaptation模型,比如Pix2Pix,不过Pix2Pix要求训练数据必须是成对的,而现实生活中,要找到两个域(画风)中成对出现的图片是相当困难的,因此CycleGAN诞生了,它只需要两种域的数据,而不需要他们有严格对应关系,这使得CycleGAN的应用更为广泛。
Cycle-GAN训练的目的则避开了上述困难;该模型的思路是旨在形成一个由数据域A到数据域B的普适性映射,学习的目标是数据域A和B的风格之间的变换而非具体的数据a和b之间的一一映射关系。从这样的思路出发Cycle-GAN对于数据一一匹配的依赖性就不存在了,可以解决一系列问题,因此该模型的设计思路与具体做法十分值得学习。
cycleGAN是一种由Generative Adversarial Networks发展而来的一种无监督机器学习,是在pix2pix的基础上发展起来的,主要应用于非配对图片的图像生成和转换,可以实现风格的转换,比如把照片转换为油画风格,或者把照片的橘子转换为苹果、马与斑马之间的转换等。因为不需要成对的数据集就能够转换,所以在数据准备上会简单很多,十分具有应用前景。

参考文献:

[1] https://keras.io/examples/generative/cyclegan/
[2] https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/
[3] https://www.kaggle.com/datasets/balraj98/summer2winter-yosemite
[4] https://junyanz.github.io/CycleGAN/
[5] https://zhuanlan.zhihu.com/p/44181821
欢迎大家加我微信交流讨论(请备注csdn上添加)
在这里插入图片描述

这篇关于基于CycleGAN的图像季节转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/300461

相关文章

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

Java实现XML与JSON的互相转换详解

《Java实现XML与JSON的互相转换详解》这篇文章主要为大家详细介绍了如何使用Java实现XML与JSON的互相转换,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. XML转jsON1.1 代码目的1.2 代码实现2. JSON转XML3. JSON转XML并输出成指定的

Java实现将Markdown转换为纯文本

《Java实现将Markdown转换为纯文本》这篇文章主要为大家详细介绍了两种在Java中实现Markdown转纯文本的主流方法,文中的示例代码讲解详细,大家可以根据需求选择适合的方案... 目录方法一:使用正则表达式(轻量级方案)方法二:使用 Flexmark-Java 库(专业方案)1. 添加依赖(Ma

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

Python使用PIL库将PNG图片转换为ICO图标的示例代码

《Python使用PIL库将PNG图片转换为ICO图标的示例代码》在软件开发和网站设计中,ICO图标是一种常用的图像格式,特别适用于应用程序图标、网页收藏夹图标等场景,本文将介绍如何使用Python的... 目录引言准备工作代码解析实践操作结果展示结语引言在软件开发和网站设计中,ICO图标是一种常用的图像