手把手教你生成对抗网络 GAN,50 行代码玩转 GAN 模型!

简介: 本文为大家介绍了生成对抗网络(Generate Adversarial Network,GAN),以最直白的语言来讲解它,最后实现一个简单的 GAN 程序来帮助大家加深理解。

什么是 GAN?


好了,GAN 如此强大,那它到底是一个什么样的模型结构呢?我们之前学习过的机器学习或者神经网络模型主要能做两件事:预测和分类,这也是我们所熟知的。那么是否可以让机器模型自动来生成一张图片、一段语音?而且可以通过调整不同模型输入向量来获得特定的图片和声音。例如,可以调整输入参数,获得一张红头发、蓝眼睛的人脸,可以调整输入参数,得到女性的声音片段,等等。也就是说,这样的机器模型能够根据需求,自动生成我们想要的东西。因此,GAN 应运而生!

GAN,即生成对抗网络,主要包含两个模块:

生成器(Generative Model)
判别器(Discriminative Model)

生成模型和判别模型之间互相博弈、学习产生相当好的输出。以图片为例,生成器的主要任务是学习真实图片集,从而使得自己生成的图片更接近于真实图片,以“骗过”判别器。而判别器的主要任务是找出出生成器生成的图片,区分其与真实图片的不同,进行真假判别。在整个迭代过程中,生成器不断努力让生成的图片越来越像真的,而判别器不断努力识别出图片的真假。这类似生成器与判别器之间的博弈,随着反复迭代,最终二者达到了平衡:生成器生成的图片非常接近于真实图片,而判别器已经很难识别出真假图片的不同了。其表现是对于真假图片,判别器的概率输出都接近 0.5。

对 GAN 的概念还是有点不清楚?没关系,举个生动的例子来说明。

最近,我想学习绘画,是因为看到梵大师的画作,也想画出类似的作品。梵大师的画作像这样:

image

说画就画,我找来一个研究梵大师作品很多年的王教授来指导我。王教授经验丰富,眼光犀利,市面上模仿梵大师的画作都难逃他的法眼。王教授跟我说了一句话:什么时候你的画这幅画能骗过我,你就算是成功了。

我很激动,立马给王教授画了这幅画:

image

王教授轻轻扫了一眼,满脸黑线,气的直哆嗦,“0 分!这也叫画?差得太多了!” 听了王教授的话,我开始自我反省,确实画的不咋地,连眼睛、鼻子都没有。于是,又 重新画了一幅:

image

王教授一看,不到 2 秒钟,就丢下四个字:1 分!重画!我一想,还是不行,画得太差了,就回去好好研究梵大师的画作风格,不断改进,重新创作,直到有一天,我拿着新的画作给王教授看:

image

王教授看了一看,说有点像了。我得仔细看看。最后,还是跟我说,不行不行,细节太差!继续重新画吧。唉,王教授越来越严格了!我叹了口气回去继续研究,最后将自我很满意的一幅画交给了王教授鉴赏:

image

这下,王教授戴着眼镜,仔细品析,许久之后,王教授拍着我的肩膀说,画得很好,我已经识别不了真假了。哈哈,得到了王教授的夸奖和肯定,心里美滋滋,终于可以创作出梵大师样的绘画作品了。下一步考虑转行去。

好了,例子说完了(接受大家对我绘画天赋的吐槽)。这个例子,其实就是一个 GAN 训练的过程。我就是生成器,目的就是要输出一幅画能够骗过王教授,让王教授真假难辨!王教授就是判别器,目的就是要识别出我的画作,判断其为假的!整个过程就是“生成 — 对抗”的博弈过程,最终,我(生成器)输出一幅“以假乱真”的画作,连王教授(判别器)都难以区分了。

这就是 GAN,懂了吧。

GAN 模型基本结构

在认识 GAN 模型之前,我们先来看一看 Yann LeCun 对未来深度学习重大突破技术点的个人看法:

The most important one, in my opinion, is adversarial training (also called GAN for Generative Adversarial Networks). This is an idea that was originally proposed by Ian Goodfellow when he was a student with Yoshua Bengio at the University of Montreal (he since moved to Google Brain and recently to OpenAI).

This, and the variations that are now being proposed is the most interesting idea in the last 10 years in ML, in my opinion.

Yann LeCun 认为 GAN 很可能会给深度学习模型带来新的重大突破,是20年来机器学习领域最酷的想法。这几年 GAN 发展势头非常强劲。下面这张图是近几年 ICASSP 会议上所有提交的论文中包含关键词 “generative”、“adversarial” 和 “reinforcement” 的论文数量统计。

image

数据表明,2018 年,包含关键词 “generative” 和 “adversarial” 的论文数量发生井喷式增长。不难预见, 未来几年关于 GAN 的论文会更多。

下面来介绍一下 GAN 的基本结构,我们已经知道了 GAN 由生成器和判别器组成,各用 G 和 D 表示。以生成图片应用为例,其模型结构如下所示:

image

GAN 基本模型由 输入 Vector、G 网络、D 网络组成。其中,G 和 D 一般都是由神经网络组成。G 的输出是一幅图片,只不过是以全连接形式。G 的输出是 D 的输入,D 的输入还包含真实样本集。这样, D 对真实样本尽量输出 score 高一些,对 G 产生的样本尽量输出 score 低一些。每次循环迭代,G 网络不断优化网络参数,使 D 无法区分真假;而 D 网络也在不断优化网络参数,提高辨识度,让真假样本的 score 有差距。

最终,经过多次训练迭代,GAN 模型建立:

image

最终的 GAN 模型中,G 生成的样本以假乱真,D 输出的 score 接近 0.5,即表示真假样本难以区分,训练成功。

这里,重点要讲解一下输入 vector。输入向量是用来做什么的呢?其实,输入 vector 中的每一维度都可以代表输出图片的某个特征。比如说,输入 vector 的第一个维度数值大小可以调节生成图片的头发颜色,数值大一些是红色,数值小一些是黑色;输入 vector 的第二个维度数值大小可以调节生成图片的肤色;输入 vector 的第三个维度数值大小可以调节生成图片的表情情绪,等等。

image

GAN 的强大之处也正是在于此,通过调节输入 vector,就可以生成具有不同特征的图片。而这些生成的图片不是真实样本集里有的,而是即合理而又没有见过的图片。是不是很有意思呢?下面这张图反映的是不同的 vector 生成不同的图片。

image

说完了 GAN 的模型之后,我们再来简单看一下 GAN 的算法原理。既然有两个模块:G 和 D,每个模块都有相应的网络参数。

先来看 D 模块,它的目标是让真实样本 score 越大越好,让 G 产生的样本 score 越小越好。那么可以得到 D 的损失函数为:

image

其中,x 是真实样本,G(z) 是 G 生成样本。我们希望 D(x) 越大越好,D(G(z)) 越小越好,也就是希望 -D(x) 越小越好,-log(1-D(G(z))) 越小越好。从损失函数的角度来说,能够得到上式。

再来看 G 模块,它的目标就是希望其生成的模型能够在 D 中得到越高的分数越好。那么可以得到 G 的损失函数为:

image

知道了损失函数之后,接下来就可以使用各种优化算法来训练模型了。

动手写个 GAN 模型

接下来,我将使用 PyTorch 实现一个简单的 GAN 模型。仍然以绘画创作为例,假设我们要创造如下“名画”(以正弦图形为例):

image

生成该“艺术画作”的代码如下:

def artist_works():    # painting from the famous artist (real target)
   r = 0.02 * np.random.randn(1, ART_COMPONENTS)
   paintings = np.sin(PAINT_POINTS * np.pi) + r
   paintings = torch.from_numpy(paintings).float()
   return paintings

然后,分别定义 G 网络和 D 网络模型:

G = nn.Sequential(                  # Generator
   nn.Linear(N_IDEAS, 128),        # random ideas (could from normal distribution)
   nn.ReLU(),
   nn.Linear(128, ART_COMPONENTS), # making a painting from these random ideas
)

D = nn.Sequential(                  # Discriminator
   nn.Linear(ART_COMPONENTS, 128), # receive art work either from the famous artist or a newbie like G
   nn.ReLU(),
   nn.Linear(128, 1),
   nn.Sigmoid(),                   # tell the probability that the art work is made by artist
)

我们设置 Adam 算法进行优化:

opt_D = torch.optim.Adam(D.parameters(), lr=LR_D)
opt_G = torch.optim.Adam(G.parameters(), lr=LR_G)

最后,构建 GAN 迭代训练过程:

plt.ion()    # something about continuous plotting

D_loss_history = []
G_loss_history = []
for step in range(10000):
   artist_paintings = artist_works()          # real painting from artist
   G_ideas = torch.randn(BATCH_SIZE, N_IDEAS) # random ideas
   G_paintings = G(G_ideas)                   # fake painting from G (random ideas)
   
   prob_artist0 = D(artist_paintings)         # D try to increase this prob
   prob_artist1 = D(G_paintings)              # D try to reduce this prob
   
   D_loss = - torch.mean(torch.log(prob_artist0) + torch.log(1. - prob_artist1))
   G_loss = torch.mean(torch.log(1. - prob_artist1))
   
   D_loss_history.append(D_loss)
   G_loss_history.append(G_loss)
   
   opt_D.zero_grad()
   D_loss.backward(retain_graph=True)    # reusing computational graph
   opt_D.step()
   
   opt_G.zero_grad()
   G_loss.backward()
   opt_G.step()
   
   if step % 50 == 0:  # plotting
       plt.cla()
       plt.plot(PAINT_POINTS[0], G_paintings.data.numpy()[0], c='#4AD631', lw=3, label='Generated painting',)
       plt.plot(PAINT_POINTS[0], np.sin(PAINT_POINTS[0] * np.pi), c='#74BCFF', lw=3, label='standard curve')
       plt.text(-1, 0.75, 'D accuracy=%.2f (0.5 for D to converge)' % prob_artist0.data.numpy().mean(), fontdict={'size': 8})
       plt.text(-1, 0.5, 'D score= %.2f (-1.38 for G to converge)' % -D_loss.data.numpy(), fontdict={'size': 8})
       plt.ylim((-1, 1));plt.legend(loc='lower right', fontsize=10);plt.draw();plt.pause(0.01)

plt.ioff()
plt.show()

我采用了动态绘图的方式,便于时刻观察 GAN 模型训练情况。

迭代次数为 1 时:

image

迭代次数为 200 时:

image

迭代次数为 1000 时:

image

迭代次数为 10000 时:

image


完美!经过 10000 次迭代训练之后,生成的曲线已经与标准曲线非常接近了。D 的 score 也如预期接近 0.5。

原文发布时间为:2018-07-29
本文作者:红色石头
本文来自云栖社区合作伙伴“数据派THU”,了解相关信息可以关注“数据派THU

相关文章
|
10天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于BP神经网络的苦瓜生长含水量预测模型matlab仿真
本项目展示了基于BP神经网络的苦瓜生长含水量预测模型,通过温度(T)、风速(v)、模型厚度(h)等输入特征,预测苦瓜的含水量。采用Matlab2022a开发,核心代码附带中文注释及操作视频。模型利用BP神经网络的非线性映射能力,对试验数据进行训练,实现对未知样本含水量变化规律的预测,为干燥过程的理论研究提供支持。
|
10天前
|
网络协议 前端开发 Java
网络协议与IO模型
网络协议与IO模型
网络协议与IO模型
|
9天前
|
机器学习/深度学习 网络架构 计算机视觉
目标检测笔记(一):不同模型的网络架构介绍和代码
这篇文章介绍了ShuffleNetV2网络架构及其代码实现,包括模型结构、代码细节和不同版本的模型。ShuffleNetV2是一个高效的卷积神经网络,适用于深度学习中的目标检测任务。
37 1
目标检测笔记(一):不同模型的网络架构介绍和代码
|
16天前
|
安全 NoSQL Java
一文搞懂网络通信的基石✅IO模型与零拷贝
【10月更文挑战第1天】本文深入探讨了网络通信中的IO模型及其优化方法——零拷贝技术。首先介绍了IO模型的概念及五种常见类型:同步阻塞、同步非阻塞、多路复用、信号驱动和异步IO模型。文章详细分析了每种模型的特点和适用场景,特别是多路复用和异步IO在高并发场景中的优势。接着介绍了零拷贝技术,通过DMA直接进行数据传输,避免了多次CPU拷贝,进一步提升了效率。最后总结了各种模型的优缺点,并提供了相关的代码示例和资源链接。
一文搞懂网络通信的基石✅IO模型与零拷贝
|
4天前
|
机器学习/深度学习 算法 数据挖掘
【深度学习】经典的深度学习模型-02 ImageNet夺冠之作: 神经网络AlexNet
【深度学习】经典的深度学习模型-02 ImageNet夺冠之作: 神经网络AlexNet
10 2
|
1月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
86 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
11天前
|
开发者
什么是面向网络的IO模型?
【10月更文挑战第6天】什么是面向网络的IO模型?
16 3
|
11天前
|
数据挖掘 开发者
网络IO模型
【10月更文挑战第6天】网络IO模型
25 3
|
11天前
|
缓存 Java Linux
硬核图解网络IO模型!
硬核图解网络IO模型!
|
12天前
|
数据挖掘 开发者
网络IO模型如何选择?
网络IO模型如何选择?【10月更文挑战第5天】
13 2