现代黑科技版“指鹿为马:使用CycleGAN实现男女“无痛变性”

本文主要是介绍现代黑科技版“指鹿为马:使用CycleGAN实现男女“无痛变性”,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在秦朝末期,奸臣赵高一手遮天,为了显示自己的权势与力量,他在众人面前指着一头鹿说那是马,大家畏惧赵高的权势,明知那是鹿却不得不配合赵高说那是马,这就是经典成语”指鹿为马“的出处。

在光天化日之下,罔顾事实强行将A说成B,除非你有权有势,别人都依附于你,你才有可能做得到,要不然大家都会认为你傻逼。例如像我这样的平头百姓在大街上指着一个五大三粗,满脸胡渣子的大男人说那是个窈窕大美女,你会不会觉得我傻逼呢?在现代人工智能技术的加持下,我还真有指鹿为马,指男为女的”超能力“。

本节我们介绍一种功能强大的对抗性网络叫CycleGAN,它的特点是能将物体A平和的转变为物体B,例如下图就是CycleGAN的功能实现:

17-14.jpg

从上图可以看到,训练好的网络能将马变成斑马,将苹果与橘子互换,当然我们要实现更强大的功能,那就是男人与女人互换。CycleGAN的实现比前面介绍的对抗性网络在结构和算法上要复杂很多,首先它有两个生成者网络和鉴别者网络,因为我们想把物体A变成B,那么网络必须有识别和生成物体A和B的能力,因此CycleGAN要使用一组生成者和鉴别者网络来识别和生成物体A,使用第二组生成者和鉴别者网络识别和生成物体B,这点跟我们前面描述的对抗性网络一样,因此CycleGAN有如下结构特点:

17-15png.png

不同之处在于两组网络要把自己掌握的信息与对方沟通,这样两组网络能共同掌握物体A和B的特性,这也是Cycle的由来。接下来是CycleGAN的算法关键所在,如下图所示:
17-16.png
从上图可见,两个生成者网络互相交互形成一个循环。由于第一个生成者网络Generator_AB用于接收图片A然后产出图片B,第二个生成者网络Generator_BA接收图片B然后生成图片A,如果第一个网络生成的图片B质量足够好,那么将它伪造的图片B输出给第二个生成者网络,后者生伪造的图片A就应该能获得好质量,因此判断第一个网络生成结果好坏的标准之一就是将它生成的结果用于第二个网络,看看后者能不能得到好结果,因此这就形成一个循环。

同理第二个生成者网络接收图片B后伪造图片A,如果它伪装出A的质量足够好,那么将它伪装的结果输入到第一个生成者网络,后者伪装出的图片B质量就应该足够好,于是这又形成一个循环。

这种循环训练的好处在于两个生成者网络能使用各自对相应图片的识别能力去训练另一个网络。例如一开始算法使用大量真实图片A来训练Generator_AB,于是它就掌握了物体A的内在特征,当Generator_BA将其伪装的图片A输入到Generator_AB,如此就形成了一条输入链,信息由Generator_BA—>Generator_AB,在训练时信息会反向传导变成Generator_AB->Generator_BA,于是前者就把自己对物体A特征的掌握和识别传导给后者,这样后者就能改进自己的构造能力,提升它伪造的图片质量,同理算法也可以形成Generator_AB—>Generator_BA的闭环,让后者伪装的图片A质量越来越好。

网络还有第二个循环,那就是对于接收图片B伪装图片A的生成者网络Generator_BA而言,算法要让它接收图片A,然后伪造的图片A质量也要足够好,其过程如下图所示:

图17-17.png

该循环训练流程本质上是让网络Generator_AB和Generator_BA也学会识别图片A和B的特征,这样才有利于网络去提升他们伪造的图片质量。接下来我们看看算法代码的部分实现,首先是对训练数据的加载:

celeba_train = tfds.load(name="celeb_a", data_dir = '/content/drive/My Drive/tfds_celeba',split="train") #data_dir指向数据存储路径
celeba_test = tfds.load(name="celeb_a", data_dir = '/content/drive/My Drive/tfds_celeba',split="test")
assert isinstance(celeba_train, tf.data.Dataset)
import matplotlib.pyplot as plt
for data in celeba_train.take(1): #利用take接口获取数据print(data) #数据其实是Dict对象,它包含了数据的所有相关属性print(data["attributes"]["Male"])plt.imshow(data['image'])

首先我们使用Tensorflow提供的数据集接口加载Celeba人脸图像数据,然后将图片分为男女两个类别,上面代码运行后所得结果如下:
下载 (1).png

接下来我们看看Generator网络的代码实现:

class Generator(tf.keras.Model):def  __init__(self):super(Generator, self).__init__()self.downsample_layers = []self.upsample_layers = []self.last_layers = []self.resnet_block_layers = []self.channels = 3self.resnet_block_count = 9self.build_self()def  build_self(self):self.down_sample(filters = 64, kernel_size = 7, strides = 1) self.down_sample(filters = 128, kernel_size = 3)self.down_sample(filters = 256, kernel_size = 3)for i in range(self.resnet_block_count):self.resnet_block()self.up_sample(filters = 128, kernel_size = 3) #构造U网络右边网络层self.up_sample(filters = 64, kernel_size = 3)self.last_layers.append(tf.keras.layers.Conv2D(filters = self.channels, kernel_size = 7, strides = 1,padding = 'same', activation = 'tanh'))def  down_sample(self, filters, kernel_size = 4, strides = 2): #构造U型网络的左边down_sample_layers = []down_sample_layers.append(tf.keras.layers.Conv2D(filters = filters, kernel_size = kernel_size,strides = strides, padding = 'same'))down_sample_layers.append(tfa.layers.InstanceNormalization(axis = -1, center = False, scale = False))down_sample_layers.append(tf.keras.layers.ReLU())self.downsample_layers.append(down_sample_layers)def  up_sample(self, filters, kernel_size = 4, strides = 2):up_sample_layers = []up_sample_layers.append(tf.keras.layers.Conv2DTranspose(filters = filters, kernel_size = kernel_size,strides = strides, padding = 'same'))up_sample_layers.append(tfa.layers.InstanceNormalization(axis = -1,center = False,scale = False))up_sample_layers.append(tf.keras.layers.ReLU())self.upsample_layers.append(up_sample_layers)def  resnet_block(self):renset_block_layers = []renset_block_layers.append(tf.keras.layers.Conv2D(filters = 256, kernel_size = 3,strides = 1, padding = 'same'))renset_block_layers.append(tfa.layers.InstanceNormalization(axis = -1,center = False,scale = False))renset_block_layers.append(tf.keras.layers.ReLU())renset_block_layers.append(tf.keras.layers.Conv2D(filters = 256, kernel_size = 3,strides = 1, padding = 'same'))renset_block_layers.append(tfa.layers.InstanceNormalization(axis = -1,center = False,scale = False))self.resnet_block_layers.append(renset_block_layers)def  call(self, x):x = tf.convert_to_tensor(x, dtype = tf.float32)left_layer_results = []for layers in self.downsample_layers:for layer in layers:x = layer(x)last_layer = xfor layers in self.resnet_block_layers:for layer in layers:#实现残余网络层x = layer(x)x = tf.keras.layers.add([last_layer, x])last_layer = xfor layers in self.upsample_layers:for layer in layers:x = layer(x)for layer in self.last_layers:x = layer(x)return xdef  create_variables(self, x): #实例化网络层参数x = np.expand_dims(x, axis = 0)self.call(x)

该网络使用了一种叫ResNet的结构,其具体原理请参看我的视频讲解,最后我们给出网络的训练流程代码实现:

 def  train_discriminators(self, imgs_A, imgs_B, valid, fake):'''训练discriminator_A识别来自数据集A的图片以及generator_BA伪造的图片,训练discriminoatr_B识别来自数据集B的图片以及generator_AB伪造的图片训练的方法是将图片分成64等分,真实数据每一等分赋值1,伪造数据每一等分赋值0,disriminator接收真实数据后输出每一等分的概率要尽可能接近1,接收伪造数据时输出每一等分的概率要接近0,valid和fake是规格为(64,64)的二维数组,元素分别为1和0'''fake_B = self.generator_AB(imgs_A, training = True)#将来自数据集A的图片伪造成数据集B的图片fake_A = self.generator_BA(imgs_B, training = True)#将来自数据集B的图片伪造成数据集A的图片loss_obj = tf.keras.losses.MSEwith tf.GradientTape(watch_accessed_variables=False) as tape: #训练discriminator_A识别真实图片tape.watch(self.discriminator_A.trainable_variables)d_A = self.discriminator_A(imgs_A, training = True)A_valid_loss = loss_obj(tf.ones_like(d_A), d_A)fake_d_A = self.discriminator_A(fake_A, training = True) A_fake_loss = loss_obj(tf.zeros_like(fake_d_A), fake_d_A)total_loss = (A_fake_loss + A_valid_loss) * 0.5grads = tape.gradient(total_loss, self.discriminator_A.trainable_variables)self.discriminator_A_optimizer.apply_gradients(zip(grads, self.discriminator_A.trainable_variables))with tf.GradientTape(watch_accessed_variables=False) as tape:#训练dicriminator_B识别真实图片tape.watch(self.discriminator_B.trainable_variables)d_B = self.discriminator_B(imgs_B, training = True)B_valid_loss = loss_obj(tf.ones_like(d_B), d_B)fake_d_B = self.discriminator_B(fake_B, training = True)B_fake_loss = loss_obj(tf.zeros_like(fake_d_B), fake_d_B)total_loss = (B_valid_loss + B_fake_loss) * 0.5grads = tape.gradient(total_loss, self.discriminator_B.trainable_variables)self.discriminator_B_optimizer.apply_gradients(zip(grads, self.discriminator_B.trainable_variables))def  train_generators(self, imgs_A, imgs_B, valid):'''generator的训练要满足三个层次,1,generator生成的伪造图片要尽可能通过discrimator的识别;2,先由generator_A将来自数据集A的图片伪造成数据集B的图片,然后再将其输入generator_B,所还原的图片要与来自数据集A的图片尽可能相似;3,将来自数据集B的图片输入generator_AB后所得结果要与数据集B的图片尽可能相同,将来自数据集A的图片输入generator_BA后所得结果要尽可能与来自数据集A的数据相同'''loss_obj = tf.keras.losses.MSEwith tf.GradientTape(watch_accessed_variables=False) as tape_A,tf.GradientTape(watch_accessed_variables=False) as tape_B:tape_A.watch(self.generator_AB.trainable_variables)tape_B.watch(self.generator_BA.trainable_variables)fake_B = self.generator_AB(imgs_A, training = True) d_B = self.discriminator_B(fake_B, training = True)fake_B_loss = loss_obj(tf.ones_like(d_B), d_B)fake_A = self.generator_BA(imgs_B, training = True)d_A = self.discriminator_A(fake_A, training = True)fake_A_loss = loss_obj(tf.ones_like(d_A), d_A)#这段对应图17-15所示的运算流程reconstructB = self.generator_AB(fake_A, training = True)#B->A->Breconstruct_B_loss = tf.reduce_mean(tf.abs(reconstructB - imgs_B))reconstructA = self.generator_BA(fake_B, training = True)#A->B->Areconstruct_A_loss = tf.reduce_mean(tf.abs(reconstructA - imgs_A))cycle_loss_BAB = self.reconstruction_weight * reconstruct_B_loss cycle_loss_ABA = self.reconstruction_weight * reconstruct_A_losstotal_cycle_loss = cycle_loss_BAB + cycle_loss_ABA#这里对应图17-16所示的运算流程img_B_id = self.generator_AB(imgs_B, training = True) #B->Bimg_B_identity_loss = tf.reduce_mean(tf.abs(img_B_id - imgs_B))img_A_id = self.generator_BA(imgs_A, training = True) #A->Aimg_A_identity_loss = tf.reduce_mean(tf.abs(img_A_id - imgs_A))#这段对应图17-17所示运算流程generator_AB_loss = self.validation_weight * fake_B_loss + total_cycle_loss + self.identification_weight * img_B_identity_lossgernator_BA_loss = self.validation_weight * fake_A_loss + total_cycle_loss + self.identification_weight * img_A_identity_lossgrads_AB = tape_A.gradient(generator_AB_loss, self.generator_AB.trainable_variables)grads_BA = tape_B.gradient(gernator_BA_loss, self.generator_BA.trainable_variables)self.generator_AB_optimizer.apply_gradients(zip(grads_AB, self.generator_AB.trainable_variables))self.generator_BA_optimizer.apply_gradients(zip(grads_BA, self.generator_BA.trainable_variables))def train(self, data_loader, run_folder, epochs, test_A_file, test_B_file, batch_size = 1, sample_interval = 100):dummy = np.zeros((batch_size, self.patch, self.patch, 1))valid = tf.ones_like(dummy, dtype = tf.float32)fake = tf.zeros_like(dummy, dtype = tf.float32)for epoch in range(epochs):start = time.time()self.epoch = epochbatch_count = 0for batch_i, (imgs_A, imgs_B) in enumerate(data_loader.load_batch()):self.train_discriminators(imgs_A, imgs_B, valid, fake)self.train_generators(imgs_A, imgs_B, valid)if  batch_i % sample_interval == 0:self.save_model(run_folder) #存储网络内部参数display.clear_output(wait=True)info = "[Epoch {}/{}/ batch {}]".format(self.epoch, epochs, batch_count)batch_count += 1self.sample_images(data_loader, batch_i, run_folder, test_A_file, test_B_file, info) #显示训练效果

由于篇幅原因,笔者没有将所有实现细节的代码都贴出来,感兴趣的读者请参看我的教学课程。

代码运行后会将大量的男女图片输入两个网络,于是能让网络具备将男人转换为女人,女人转换为男人的能力,我们先看网络将男人变成女人的能力:
屏幕快照 2020-05-14 上午11.23.56.png
其中左边是男性图片,右边是”变性“后的女性图片,比较发现女性特征是脸部表情更柔和,更具有女性的柔软,我们再看看将女性变成男性的结果:

屏幕快照 2020-05-14 上午11.25.56.png

上图效果就更加明显,可以看到的是右边男性面孔脸部轮廓曲线与左边女性基本相同,男性脸部特征就在于皮肤比较粗糙,同时线条比较粗狂和硬朗,从显示结果看,网络具备了将男变女,女变男的超能力。

更详细的讲解和完整代码调试演示过程,请点击链接

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
这里写图片描述

这篇关于现代黑科技版“指鹿为马:使用CycleGAN实现男女“无痛变性”的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo