基于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 Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c

在Java中将XLS转换为XLSX的实现方案

《在Java中将XLS转换为XLSX的实现方案》在本文中,我们将探讨传统ExcelXLS格式与现代XLSX格式的结构差异,并为Java开发者提供转换方案,通过了解底层原理、性能优势及实用工具,您将掌握... 目录为什么升级XLS到XLSX值得投入?实际转换过程解析推荐技术方案对比Apache POI实现编程

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y

c/c++的opencv图像金字塔缩放实现

《c/c++的opencv图像金字塔缩放实现》本文主要介绍了c/c++的opencv图像金字塔缩放实现,通过对原始图像进行连续的下采样或上采样操作,生成一系列不同分辨率的图像,具有一定的参考价值,感兴... 目录图像金字塔简介图像下采样 (cv::pyrDown)图像上采样 (cv::pyrUp)C++ O

Python使用FFmpeg实现高效音频格式转换工具

《Python使用FFmpeg实现高效音频格式转换工具》在数字音频处理领域,音频格式转换是一项基础但至关重要的功能,本文主要为大家介绍了Python如何使用FFmpeg实现强大功能的图形化音频转换工具... 目录概述功能详解软件效果展示主界面布局转换过程截图完成提示开发步骤详解1. 环境准备2. 项目功能结

使用Python实现网页表格转换为markdown

《使用Python实现网页表格转换为markdown》在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,本文将使用Python编写一个网页表格转Markdown工具,需... 在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,以便在文档、邮件或

Python将字符串转换为小写字母的几种常用方法

《Python将字符串转换为小写字母的几种常用方法》:本文主要介绍Python中将字符串大写字母转小写的四种方法:lower()方法简洁高效,手动ASCII转换灵活可控,str.translate... 目录一、使用内置方法 lower()(最简单)二、手动遍历 + ASCII 码转换三、使用 str.tr

Java如何将文件内容转换为MD5哈希值

《Java如何将文件内容转换为MD5哈希值》:本文主要介绍Java如何将文件内容转换为MD5哈希值的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java文件内容转换为MD5哈希值一个完整的Java示例代码代码解释注意事项总结Java文件内容转换为MD5

使用Java将实体类转换为JSON并输出到控制台的完整过程

《使用Java将实体类转换为JSON并输出到控制台的完整过程》在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用JSON格式,用Java将实体类转换为J... 在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用j