【Gans入门】Pytorch实现Gans代码详解【70+代码】

简述

由于科技论文老师要求阅读Gans论文并在网上找到类似的代码来学习。

代码来源

https://github.com/MorvanZhou/PyTorch-Tutorial/blob/master/tutorial-contents/406_GAN.py

代码含义概览

这个大致讲讲这个代码实现了什么。

这个模型的输入为:一些数据夹杂在 x 2 x^2 x2 2 x 2 + 1 2x^2+1 2x2+1这个两个函数之间的一些数据。这个用线性函数的随机生成来生成这个东西
输出: 这是一个生成模型,生成模型的结果就是生成通过上面的输入数据输出这样的数据来画一条曲线

  • 我们每次只取15个在x方向上等距的点。然后画出这条曲线来。
    经过学习之后,我们要求这个模型能自己画出一条在其中的曲线来。

  • 当然,由于我们设置的区间是有弧线的,即区间的概率上是有偏差的。经过足够多的拟合,有较高的概率使得整个模型画出来的曲线也是一个弧线。

代码分段解释

导入包:
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
设置参数:
  • LR_G:生成器的学习率
  • LR_D:判别器的学习率
  • N_IDEAS:生成器的启发因子(就是生成器这个神经网络的初始输入层的节点数)
  • ART_COMPONENTS:观测节点–每次用于画线的那些输出点的数量
  • BATCH_SIZE:其实是输入数据的数量。
  • PAINT_POINTS :就是把重复的那么多数据(将x区间等分为观测节点数量等分的x节点)叠起来而已。这样之后就直接代入就可以知道数据了。
BATCH_SIZE = 64
LR_G = 0.0001  # learning rate for generator
LR_D = 0.0001  # learning rate for discriminator
N_IDEAS = 5  # think of this as number of ideas for generating an art work (Generator)
ART_COMPONENTS = 15  # it could be total point G can draw in the canvas
PAINT_POINTS = np.vstack([np.linspace(-1, 1, ART_COMPONENTS) for _ in range(BATCH_SIZE)])
给出标准数据:

这个函数,会给出特定规模的标准数据

  • 先创建一个(BATCH_SIZE,1)规模的来自于(1,2)均匀分布的随机数。
  • 再用这个数据构建 a ∗ x 2 + ( a − 1 ) a*x ^2 + (a - 1) ax2+(a1) 其中a来自于 ( 1 , 2 ) (1,2) (1,2)的均匀分布。然后有BATCH_SIZE 个结果,所以,我们会在前面说到,这个参数表示输入集合的大小
def artist_works():  # painting from the famous artist (real target)
    a = np.random.uniform(1, 2, size=BATCH_SIZE)[:, np.newaxis]
    paintings = a * np.power(PAINT_POINTS, 2) + (a - 1)
    paintings = torch.from_numpy(paintings).float()
    return paintings
构建模型:

搭建神经网络

  • 这里搭建的神经网络,只需要构建映射层就好了。
  • 生成器模型:先通过一个线性函数构建一个从N_IDEAS到128的映射。再通过激活函数ReLU()函数来做一个映射。最后,再用一个线性函数搭建从128到观测点的映射。(这些映射都是用矩阵乘法来实现的,所以,其实参数空间是三个不同的矩阵)
  • 判别式模型:先通过一个观测点的到128的模型。再通过一个ReLU激活函数。之后,再用一个线性函数使得从128到1维度。一维就是常数,再做一个sigmoid的激活函数映射到 ( 0 , 1 ) (0,1) (0,1)空间。表示概率。
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
)
构建优化器
opt_D = torch.optim.Adam(D.parameters(), lr=LR_D)
opt_G = torch.optim.Adam(G.parameters(), lr=LR_G)

构建了两个优化器。其实就是把对应模型的参数放进来了而已,之后,再设置一下学习率。

这里采用的是Adam模型来做优化。

迭代细节

其实这上面应该还有一些画图而加上的函数,但是对于模型不是很重要,这里就不看了。最后会有一个整体的模型。

for step in range(10000):

明显看出,使用了10000次的迭代。

  • 先调用标准数据生成函数,生成标准数据。
  • 再用pytorch的随机数来生特定大小的生成器启发因子。
  • 之后,再把这个随机数丢给生成器。
  • 明显,通过这样的训练,其实逐渐的训练这个生成器模型,在随机给输入的情况下,渐渐掌握输出正确的结果(个人感觉这里有提高的可能
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)

再把假画和真画都丢给判别式模型。给出一个概率来。

之后构建两个模型的交叉熵,需要降低的损失函数

D_loss = - torch.mean(torch.log(prob_artist0) + torch.log(1. - prob_artist1))
G_loss = torch.mean(torch.log(1. - prob_artist1))

这个其实是根据论文中的公式给出的。

  • 注意到,这里跟下面算法中给出的梯度是相同的。就是前面少了个系数,但是有没系数,对于这个不影响的。

在这里插入图片描述

其实上面只是把整个模型搭建起来,其实都还没有运行的。
真正运行的部分是下面这里

opt_D.zero_grad()
D_loss.backward(retain_graph=True)  # reusing computational graph
opt_D.step()

opt_G.zero_grad()
G_loss.backward(retain_graph=True)
opt_G.step()

注意到,其实非常重复的。

  • 第一步的zero_grad()函数:

原因:
In PyTorch, we need to set the gradients to zero before starting to do backpropragation because PyTorch accumulates the gradients on subsequent backward passes. This is convenient while training RNNs. So, the default action is to accumulate the gradients on every loss.backward() call.
在PyTorch中,我们需要设置这个梯度到0,在开始反向传播的训练之前,因为Pytorch会累积这个梯度在之后的反向传播过程中。这是非常方便的当训练RNNs的时候,所以默认就这么设置了。
Because of this, when you start your training loop, ideally you should zero out the gradients so that you do the parameter update correctly. Else the gradient would point in some other directions than the intended direction towards the minimum (or maximum, in case of maximization objectives).
由于这个,当你开始你的训练循环的时候,比较聪明的一点就是先把这个梯度设置为0,以确保你的训练的参数会是正确的。否则的话,这个梯度会指向一些其他地方(乱跑)

上面的解释来自于stackoverflow
https://stackoverflow.com/questions/48001598/why-is-zero-grad-needed-for-optimization

  • 第二步:反向传播,这里设置保留整个图的情况下。
  • 第三步:.step() 其实这个函数才真正表示这个模型被训练了。
画图

由于我们每次生成时候后,其实都是生成了一个BATCH_SIZE个。但是我们一次画太多的图的话,会显得很丑,所以就只画第一个图就好了。

这里取模的原因就在于避免画太多的图,导致耗费太多资源。

    if step % 500 == 0:  # plotting
        plt.cla()
        plt.plot(PAINT_POINTS[0], G_paintings.data.numpy()[0], c='#4AD631', lw=3, label='Generated painting', )
        # 2x^2 + 1
        plt.plot(PAINT_POINTS[0], 2 * np.power(PAINT_POINTS[0], 2) + 1, c='#74BCFF', lw=3, label='upper bound')
        # x^2
        plt.plot(PAINT_POINTS[0], 1 * np.power(PAINT_POINTS[0], 2) + 0, c='#FF9359', lw=3, label='lower bound')
        plt.text(-.5, 2.3, 'D accuracy=%.2f (0.5 for D to converge)' % prob_artist0.data.numpy().mean(),
                 fontdict={'size': 13})
        plt.text(-.5, 2, 'D score= %.2f (-1.38 for G to converge)' % -D_loss.data.numpy(), fontdict={'size': 13})
        plt.ylim((0, 3))
        plt.legend(loc='upper right', fontsize=10)
        plt.draw()
        plt.pause(0.01)

全部代码:

import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt

# Hyper Parameters
BATCH_SIZE = 64
LR_G = 0.0001  # learning rate for generator
LR_D = 0.0001  # learning rate for discriminator
N_IDEAS = 5  # think of this as number of ideas for generating an art work (Generator)
ART_COMPONENTS = 15  # it could be total point G can draw in the canvas
PAINT_POINTS = np.vstack([np.linspace(-1, 1, ART_COMPONENTS) for _ in range(BATCH_SIZE)])


def artist_works():  # painting from the famous artist (real target)
    a = np.random.uniform(1, 2, size=BATCH_SIZE)[:, np.newaxis]
    paintings = a * np.power(PAINT_POINTS, 2) + (a - 1)
    paintings = torch.from_numpy(paintings).float()
    return paintings


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
)

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

plt.ion()  # something about continuous plotting

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))

    opt_D.zero_grad()
    D_loss.backward(retain_graph=True)  # reusing computational graph
    opt_D.step()

    opt_G.zero_grad()
    G_loss.backward(retain_graph=True)
    opt_G.step()

    if step % 500 == 0:  # plotting
        plt.cla()
        plt.plot(PAINT_POINTS[0], G_paintings.data.numpy()[0], c='#4AD631', lw=3, label='Generated painting', )
        # 2x^2 + 1
        plt.plot(PAINT_POINTS[0], 2 * np.power(PAINT_POINTS[0], 2) + 1, c='#74BCFF', lw=3, label='upper bound')
        # x^2
        plt.plot(PAINT_POINTS[0], 1 * np.power(PAINT_POINTS[0], 2) + 0, c='#FF9359', lw=3, label='lower bound')
        plt.text(-.5, 2.3, 'D accuracy=%.2f (0.5 for D to converge)' % prob_artist0.data.numpy().mean(),
                 fontdict={'size': 13})
        plt.text(-.5, 2, 'D score= %.2f (-1.38 for G to converge)' % -D_loss.data.numpy(), fontdict={'size': 13})
        plt.ylim((0, 3))
        plt.legend(loc='upper right', fontsize=10)
        plt.draw()
        plt.pause(0.01)

plt.ioff()
plt.show()

参考并学习的链接

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
条件GAN(Conditional GANs)是一种生成对抗网络(GAN)的变体,它通过给生成器和鉴别器提供额外的条件信息来改进生成过程。在PyTorch实现条件GANs时,需要对生成器和判别器的结构进行修改。 引用中给出了生成器的具体实现。生成器接收两个输入:一个是噪声向量x,一个是条件向量c。首先,将x通过线性层进行处理,得到一个大小为128x7x7的张量。然后,将x和c通过cat操作在channels方向上进行合并,形成一个大小为256x7x7的张量。最后,通过三次转置卷积操作将张量的尺寸逐渐放大,最终生成一个大小为1x28x28的图像。 引用中给出了判别器的具体实现。判别器接收两个输入:一个是真实图像x,一个是条件向量c。首先,将c通过线性层进行处理,得到一个大小为1x28x28的张量。然后,将x和c通过cat操作在channels方向上进行合并,形成一个大小为2x28x28的张量。接下来,通过卷积层、LeakyReLU激活函数和Dropout层对张量进行处理。最后,将张量展平后通过全连接层得到一个概率值,表示输入图像为真实图像的概率。 通过以上改进,条件GANs可以在生成过程中根据给定的条件生成特定的图像。这种结构可以应用于各种任务,如图像生成、图像修复和图像转换等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Conditional GAN代码实现Pytorch)](https://blog.csdn.net/weixin_40330033/article/details/127212518)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [pytorch-GANs:我对各种GAN(生成对抗网络)架构的实现,例如香草GAN(Goodfellow等),cGAN(Mirza等),...](https://download.csdn.net/download/weixin_42116701/15910571)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥宅_Sean

公众号“肥宅Sean”欢迎关注

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值