深度学习--DCGAN

代码之后的注释和GAN的一样,大家如果已经掌握GAN,可以忽略掉哦!!!

在学习DCGAN之前,我们要先掌握GAN,深度学习--生成对抗网络GAN-CSDN博客  这篇博客讲的就是GAN的相关知识,还是很详细的。

DCGAN论文:1511.06434 (arxiv.org)

我们先来了解一下DCGAN的原理

DCGAN原理

在学习原理之前,我们要先复习一下GAN的结构,如下图:

DCGAN模型

 它的生成器的结构如下:

生成器的输入是噪声,输出是图片。

在生成器之中,我们就用到了转置卷积的结构,进行了上采样。 

它在不断地提高分辨率,减少通道数。

判别器的结构:

使用的是下采样的卷积 。

它的输入是64*64的图像,输出是真假的判别。

他在不断地提高通道数,减少分辨率。

DCGAN工程技巧

也就是DCGAN与GAN的不同之处:

 简单翻译一下,意思就是:

1.在网络深层去除全连接层,

2.使用带步长的卷积替换池化,

3.在生成器的输出层使用Tanh激活函数,在其他层使用ReLu,

4.在判别器中使用LeakyReLu激活函数,

5.只对生成器模型的输出层和判别器模型的输入层Batch Normalization,BN可以稳定学习,有助于处理初始化不良导致的训练问题。也就是采用了批归一化, 将每一层的输入变换到0均值和单位方差(或者说转变到[0,1]范围内)。

预备知识

torch.nn.BatchNorm1d

nn.BatchNorm1d 是 PyTorch 中的一个用于一维数据(例如序列或时间序列)的批标准化(Batch Normalization)层。

批标准化是一种常用的神经网络正则化技术,旨在加速训练过程并提高模型的收敛性和稳定性。它通过对每个输入小批次的特征进行归一化处理来规范化输入数据的分布。

在一维数据上使用 nn.BatchNorm1d 层时,它会对每个特征维度上的数据进行标准化处理。具体而言,它会计算每个特征维度的均值和方差,并将输入数据进行中心化和缩放,以使其分布接近均值为0、方差为1的标准正态分布。

torch.nn.ConvTranspose2d

这是反卷积,也就是转置卷积的函数.

参数如下:

torch.nn.ConvTranspose2d(

in_channels, out_channels, kernel_size, stride=1, padding=0,

output_padding=0, groups=1,  bias=True, dilation=1, padding_mode='zeros',

device=None, dtype=None)

转置卷积的计算步骤在下面的视频中,简单粗暴

转置卷积这样算就简单多了~_哔哩哔哩_bilibili

torch.nn.Dropout2d

有多个channel的二维输出。赋值对象是彩色的图像数据(batch N,通道 C,高度 H,宽 W)的一个通道里的每一个数据。即输入为 Input: (N, C, H, W) 时,对每一个通道维度 C 按概率赋值为 0

适用性:nn.Dropout2d用于将 dropout 正则化应用于卷积层,要求输入和输出数据为4维(N,C,H,W)。卷积层用于处理空间数据,例如图像,它们具有二维结构。

维度:它在二维张量上运行。如果您有一个 shape 的输入张量(batch_size, channels, height, width),nn.Dropout2d则会独立地将 dropout 应用于每个通道的空间维度,使每个通道独立清零

有利于促进独立性特征图。

torch.nn.functional.leaky_relu

相当于LeakyReLu函数

函数图像如下 

代码

导库

import matplotlib.pyplot as plt
import matplotlib
import torch
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms
import numpy as np
import torch.nn.functional as F

加载处理数据集

# 导入数据集并且进行数据处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(0.5, 0.5)])
traindata = torchvision.datasets.MNIST(root='D:\learn_pytorch\数据集', train=True, download=True,
                                       transform=transform)  # 训练集60,000张用于训练
# 利用DataLoader加载数据集
trainload = DataLoader(dataset=traindata, shuffle=True, batch_size=64)

在加载数据集时,我们要将数据进行归一化,在GAN中,我们就需要将数据归一化到(-1,1)之间,这是为什么呢?原因是我们在下面会用到Tanh激活函数,而Tanh函数的范围是在-1到1之间的,见下图

在我们既然知道了为什么要这样,下面就要学会如何做到了 

ToTensor中,我们是将数据的范围限制在了(0,1)之间,而后面的Normalize是将数据限制在(-1,1)之间,计算公式为(x-均值)/方差 

生成器

class Generator(torch.nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.linear1 = torch.nn.Linear(100, 7 * 7 * 256)
        self.bn1 = torch.nn.BatchNorm1d(7 * 7 * 256)
        self.uconv1 = torch.nn.ConvTranspose2d(256, 128, kernel_size=(3, 3), padding=1)
        self.bn2 = torch.nn.BatchNorm2d(128)
        self.uconv2 = torch.nn.ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=2, padding=1)
        self.bn3 = torch.nn.BatchNorm2d(64)
        self.uconv3 = torch.nn.ConvTranspose2d(64, 1, kernel_size=(4, 4), stride=2, padding=1)

    def forward(self, x):
        # print('--------------------------------------')
        # print('x.shape:',x.shape)
        x = F.relu(self.linear1(x))  # torchsize([,])    .
        x = F.relu(self.bn1(x))
        # print('x.shape:',x.shape)
        x = self.bn1(x)
        x = x.view(-1, 256, 7, 7)  # 64,256,7,7
        # print('x.shape:',x.shape)
        x = F.relu(self.uconv1(x))
        # print('x.shape:',x.shape)
        x = self.bn2(x)
        # print('x.shape:', x.shape)
        x = F.relu(self.uconv2(x))
        # print('x.shape:', x.shape)
        x = self.bn3(x)
        # print('x.shape:', x.shape)
        x = torch.tanh(self.uconv3(x))
        # print('x.shape:', x.shape)#torch.Size([64, 1, 28, 28])
        return x

判别器

# 判别器,最后判断0,1,这意味着最后可以是一个神经元或者两个神经元
class Discraiminator(torch.nn.Module):
    def __init__(self):
        super(Discraiminator, self).__init__()

        self.conv1 = torch.nn.Conv2d(1, 64, 3, 2)
        self.conv2 = torch.nn.Conv2d(64, 128, 3, 2)
        self.bn = torch.nn.BatchNorm2d(128)
        self.fc = torch.nn.Linear(128 * 6 * 6, 1)

    def forward(self, x):
        # print('--------------------')
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 1, 28, 28])
        x = F.dropout2d(F.leaky_relu(self.conv1(x)), p=0.3)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 128, 6, 6])
        x = F.dropout2d(F.leaky_relu(self.conv2(x)), p=0.3)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 128, 6, 6])
        x = self.bn(x)
        x = x.view(-1, 128 * 6 * 6)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 4608])
        x = torch.sigmoid(self.fc(x))
        # print('x.shape:', x.shape)#torch.size([64,1])
        return x

 定义损失函数,优化函数和优化器

# 定义损失函数和优化函数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
gen = Generator().to(device)
dis = Discraiminator().to(device)
# 定义优化器
gen_opt = torch.optim.Adam(gen.parameters(), lr=0.0001)
dis_opt = torch.optim.Adam(dis.parameters(), lr=0.0001)
loss_fn = torch.nn.BCELoss()  # 损失函数

在这里,我们选择使用BCELoss,交叉熵损失函数,这是因为在GAN中,判别器通常被视为一个二分类器,它试图区分输入是真实样本还是由生成器生成的假样本,而BCELoss就是用来做二分类的损失函数,正好对应。

在优化器部分,它们分别对生成器和判别器的参数进行优化。

图像显示

# 图像显示
def gen_img_plot(model, testdata):
    pre = np.squeeze(model(testdata).detach().cpu().numpy())
    # tensor.detach()
    # 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。
    # 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
    # 这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播
    plt.figure()
    for i in range(16):
        plt.subplot(4, 4, i + 1)
        plt.imshow(pre[i])
    plt.show()

因为我们最终要得到要得到的是处理数据输出的数组,所以我们要用squeeze将额外的单维度删除。

detach是单独开辟空间来保存数据,从而保证数据的稳定性。

plt.figure用来生成一个新画布。

 使用subplot函数在一个4x4的网格中定位每个子图。i + 1是因为子图的索引是从1开始的,而不是从0开始。 

imshow是在子图中显示图像。

最后的show来显示整体的图像。

后向传播及可视化

# 后向传播
dis_loss = []  # 判别器损失值记录
gen_loss = []  # 生成器损失值记录
lun = []  # 轮数
for epoch in range(100):
    d_epoch_loss = 0
    g_epoch_loss = 0
    cout = len(trainload)  # 938批次
    for step, (img, _) in enumerate(trainload):
        img = img.to(device)  # 图像数据
        # print('img.size:',img.shape)#img.size: torch.Size([64, 1, 28, 28])
        size = img.size(0)  # 一批次的图片数量64
        # 随机生成一批次的100维向量样本,或者说100个像素点
        random_noise = torch.randn(size, 100, device=device)
        # 先进性判断器的后向传播
        dis_opt.zero_grad()
        real_output = dis(img)
        d_real_loss = loss_fn(real_output, torch.ones_like(real_output))  # 真实数据的损失函数值
        d_real_loss.backward()

        gen_img = gen(random_noise)
        fake_output = dis(gen_img.detach())
        d_fake_loss = loss_fn(fake_output, torch.zeros_like(fake_output))  # 人造的数据的损失函数值
        d_fake_loss.backward()

        d_loss = d_real_loss + d_fake_loss
        dis_opt.step()

        # 生成器的后向传播
        gen_opt.zero_grad()
        fake_output = dis(gen_img)
        g_loss = loss_fn(fake_output, torch.ones_like(fake_output))
        g_loss.backward()
        gen_opt.step()
        d_epoch_loss += d_loss
        g_epoch_loss += g_loss
    dis_loss.append(float(d_epoch_loss))
    gen_loss.append(float(g_epoch_loss))
    print(f'第{epoch + 1}轮的生成器损失值:{g_epoch_loss},判别器损失值{d_epoch_loss}')
    lun.append(epoch + 1)
matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
plt.figure()
plt.plot(lun, dis_loss, 'r', label='判别器损失值')
plt.plot(lun, gen_loss, 'b', label='生成器损失值')
plt.xlabel('训练轮数',  fontsize=12)
plt.ylabel('损失值', fontsize=12)
plt.title('损失值随着训练轮数得变化情况:',fontsize=18)
plt.show()
random_noise = torch.randn(16, 100, device=device)
gen_img_plot(gen, random_noise)

使用enumerate遍历训练数据集trainload,其中img是图像数据,但_表示我们在这里不使用标签(因为GAN是无监督的)。

step()用来更新判别器的模型参数。

在生成器的后向传播部分,

我们先进行梯度清零,然后通过生成器生成假图像,然后进行前向传播。

我们期望判别器对假图像的评分接近1(真实),因此我们将目标标签设置为与fake_output形状相同的全1张量torch.ones_like(fake_output)。

在这里,d_loss和g_loss是一张图像中的损失值,而d_epoch_loss和g_epoch_loss是每一轮损失值的累加,用于最后图像的绘制。

随机生成的噪声有16个样本,100个维度

全部代码

import matplotlib.pyplot as plt
import matplotlib
import torch
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms
import numpy as np
import torch.nn.functional as F

# 导入数据集并且进行数据处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(0.5, 0.5)])
traindata = torchvision.datasets.MNIST(root='D:\learn_pytorch\数据集', train=True, download=True,
                                       transform=transform)  # 训练集60,000张用于训练
# 利用DataLoader加载数据集
trainload = DataLoader(dataset=traindata, shuffle=True, batch_size=64)


# GAN生成对抗网络,步骤:
# 首先编写生成器和判别器
# 然后固定生成器,用我们的数据优化判别器,试得我们最开始生成器生成的图片判断为0,真实图片判断为1
# 接着固定判别器,利用我们的判别器判断生成器生成的图片,以判断的尽可能接近一为目的优化我们的生成器
# 生成器的代码(针对手写字体识别)
class Generator(torch.nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.linear1 = torch.nn.Linear(100, 7 * 7 * 256)
        self.bn1 = torch.nn.BatchNorm1d(7 * 7 * 256)
        self.uconv1 = torch.nn.ConvTranspose2d(256, 128, kernel_size=(3, 3), padding=1)
        self.bn2 = torch.nn.BatchNorm2d(128)
        self.uconv2 = torch.nn.ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=2, padding=1)
        self.bn3 = torch.nn.BatchNorm2d(64)
        self.uconv3 = torch.nn.ConvTranspose2d(64, 1, kernel_size=(4, 4), stride=2, padding=1)

    def forward(self, x):
        # print('--------------------------------------')
        # print('x.shape:',x.shape)
        x = F.relu(self.linear1(x))  # torchsize([,])    .
        x = F.relu(self.bn1(x))
        # print('x.shape:',x.shape)
        x = self.bn1(x)
        x = x.view(-1, 256, 7, 7)  # 64,256,7,7
        # print('x.shape:',x.shape)
        x = F.relu(self.uconv1(x))
        # print('x.shape:',x.shape)
        x = self.bn2(x)
        # print('x.shape:', x.shape)
        x = F.relu(self.uconv2(x))
        # print('x.shape:', x.shape)
        x = self.bn3(x)
        # print('x.shape:', x.shape)
        x = torch.tanh(self.uconv3(x))
        # print('x.shape:', x.shape)#torch.Size([64, 1, 28, 28])
        return x


# 判别器,最后判断0,1,这意味着最后可以是一个神经元或者两个神经元
class Discraiminator(torch.nn.Module):
    def __init__(self):
        super(Discraiminator, self).__init__()

        self.conv1 = torch.nn.Conv2d(1, 64, 3, 2)
        self.conv2 = torch.nn.Conv2d(64, 128, 3, 2)
        self.bn = torch.nn.BatchNorm2d(128)
        self.fc = torch.nn.Linear(128 * 6 * 6, 1)

    def forward(self, x):
        # print('--------------------')
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 1, 28, 28])
        x = F.dropout2d(F.leaky_relu(self.conv1(x)), p=0.3)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 128, 6, 6])
        x = F.dropout2d(F.leaky_relu(self.conv2(x)), p=0.3)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 128, 6, 6])
        x = self.bn(x)
        x = x.view(-1, 128 * 6 * 6)
        # print('x.shape:', x.shape)#x.shape: torch.Size([64, 4608])
        x = torch.sigmoid(self.fc(x))
        # print('x.shape:', x.shape)#torch.size([64,1])
        return x


# 定义损失函数和优化函数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
gen = Generator().to(device)
dis = Discraiminator().to(device)
# 定义优化器
gen_opt = torch.optim.Adam(gen.parameters(), lr=0.0001)
dis_opt = torch.optim.Adam(dis.parameters(), lr=0.0001)
loss_fn = torch.nn.BCELoss()  # 损失函数


# 图像显示
def gen_img_plot(model, testdata):
    pre = np.squeeze(model(testdata).detach().cpu().numpy())
    # tensor.detach()
    # 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。
    # 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
    # 这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播
    plt.figure()
    for i in range(16):
        plt.subplot(4, 4, i + 1)
        plt.imshow(pre[i])
    plt.show()


# 后向传播
dis_loss = []  # 判别器损失值记录
gen_loss = []  # 生成器损失值记录
lun = []  # 轮数
for epoch in range(100):
    d_epoch_loss = 0
    g_epoch_loss = 0
    cout = len(trainload)  # 938批次
    for step, (img, _) in enumerate(trainload):
        img = img.to(device)  # 图像数据
        # print('img.size:',img.shape)#img.size: torch.Size([64, 1, 28, 28])
        size = img.size(0)  # 一批次的图片数量64
        # 随机生成一批次的100维向量样本,或者说100个像素点
        random_noise = torch.randn(size, 100, device=device)
        # 先进性判断器的后向传播
        dis_opt.zero_grad()
        real_output = dis(img)
        d_real_loss = loss_fn(real_output, torch.ones_like(real_output))  # 真实数据的损失函数值
        d_real_loss.backward()

        gen_img = gen(random_noise)
        fake_output = dis(gen_img.detach())
        d_fake_loss = loss_fn(fake_output, torch.zeros_like(fake_output))  # 人造的数据的损失函数值
        d_fake_loss.backward()

        d_loss = d_real_loss + d_fake_loss
        dis_opt.step()

        # 生成器的后向传播
        gen_opt.zero_grad()
        fake_output = dis(gen_img)
        g_loss = loss_fn(fake_output, torch.ones_like(fake_output))
        g_loss.backward()
        gen_opt.step()
        d_epoch_loss += d_loss
        g_epoch_loss += g_loss
    dis_loss.append(float(d_epoch_loss))
    gen_loss.append(float(g_epoch_loss))
    print(f'第{epoch + 1}轮的生成器损失值:{g_epoch_loss},判别器损失值{d_epoch_loss}')
    lun.append(epoch + 1)
matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
plt.figure()
plt.plot(lun, dis_loss, 'r', label='判别器损失值')
plt.plot(lun, gen_loss, 'b', label='生成器损失值')
plt.xlabel('训练轮数',  fontsize=12)
plt.ylabel('损失值', fontsize=12)
plt.title('损失值随着训练轮数得变化情况:',fontsize=18)
plt.show()
random_noise = torch.randn(16, 100, device=device)
gen_img_plot(gen, random_noise)

运行结果

第1轮的生成器损失值:1637.9466552734375,判别器损失值464.1025695800781
第2轮的生成器损失值:2530.494384765625,判别器损失值305.1524353027344
第3轮的生成器损失值:2997.694580078125,判别器损失值222.53155517578125
第4轮的生成器损失值:3006.974365234375,判别器损失值275.3566589355469
第5轮的生成器损失值:3013.507080078125,判别器损失值306.8394775390625
第6轮的生成器损失值:3041.133056640625,判别器损失值317.3689270019531
第7轮的生成器损失值:3017.63427734375,判别器损失值323.7129821777344
第8轮的生成器损失值:3007.423828125,判别器损失值324.5998840332031
第9轮的生成器损失值:3128.52783203125,判别器损失值313.85247802734375
第10轮的生成器损失值:3165.2890625,判别器损失值310.9962158203125
第11轮的生成器损失值:3216.90673828125,判别器损失值292.4429931640625
第12轮的生成器损失值:3296.56396484375,判别器损失值286.9037780761719
第13轮的生成器损失值:3320.12255859375,判别器损失值291.0125732421875
第14轮的生成器损失值:3348.47802734375,判别器损失值278.4036560058594
第15轮的生成器损失值:3400.251708984375,判别器损失值286.7728576660156
第16轮的生成器损失值:3417.241943359375,判别器损失值287.98321533203125
第17轮的生成器损失值:3390.15380859375,判别器损失值282.5353088378906
第18轮的生成器损失值:3410.00732421875,判别器损失值281.8512878417969
第19轮的生成器损失值:3500.480224609375,判别器损失值294.86407470703125
第20轮的生成器损失值:3470.27392578125,判别器损失值292.0498046875
第21轮的生成器损失值:3449.343505859375,判别器损失值283.53033447265625
第22轮的生成器损失值:3558.106689453125,判别器损失值301.805908203125
第23轮的生成器损失值:3544.840087890625,判别器损失值284.54559326171875
第24轮的生成器损失值:3507.136474609375,判别器损失值296.3019104003906
第25轮的生成器损失值:3535.285888671875,判别器损失值292.21417236328125
第26轮的生成器损失值:3483.247802734375,判别器损失值319.2896728515625
第27轮的生成器损失值:3452.71533203125,判别器损失值300.94207763671875
第28轮的生成器损失值:3441.982177734375,判别器损失值305.394287109375
第29轮的生成器损失值:3545.740234375,判别器损失值292.4477233886719
第30轮的生成器损失值:3500.8740234375,判别器损失值299.3537902832031
第31轮的生成器损失值:3530.58837890625,判别器损失值290.83367919921875
第32轮的生成器损失值:3547.6357421875,判别器损失值303.5927734375
第33轮的生成器损失值:3536.327392578125,判别器损失值299.1307373046875
第34轮的生成器损失值:3599.991943359375,判别器损失值293.924560546875
第35轮的生成器损失值:3553.3603515625,判别器损失值307.1707763671875
第36轮的生成器损失值:3607.927734375,判别器损失值301.6771240234375
第37轮的生成器损失值:3578.015380859375,判别器损失值307.1168212890625
第38轮的生成器损失值:3564.02197265625,判别器损失值304.1378479003906
第39轮的生成器损失值:3477.672119140625,判别器损失值307.8915100097656
第40轮的生成器损失值:3523.138427734375,判别器损失值300.7839660644531
第41轮的生成器损失值:3580.55615234375,判别器损失值296.95367431640625
第42轮的生成器损失值:3537.208984375,判别器损失值317.746826171875
第43轮的生成器损失值:3497.8994140625,判别器损失值333.478759765625
第44轮的生成器损失值:3499.179443359375,判别器损失值309.1123352050781
第45轮的生成器损失值:3470.083984375,判别器损失值319.6141052246094
第46轮的生成器损失值:3515.869873046875,判别器损失值321.9976806640625
第47轮的生成器损失值:3509.823486328125,判别器损失值310.7447814941406
第48轮的生成器损失值:3486.165283203125,判别器损失值330.5418395996094
第49轮的生成器损失值:3492.86083984375,判别器损失值324.3530578613281
第50轮的生成器损失值:3480.895263671875,判别器损失值343.64190673828125
第51轮的生成器损失值:3458.932373046875,判别器损失值335.3240661621094
第52轮的生成器损失值:3449.647216796875,判别器损失值320.6033630371094
第53轮的生成器损失值:3507.733154296875,判别器损失值340.7387390136719
第54轮的生成器损失值:3528.40185546875,判别器损失值352.86712646484375
第55轮的生成器损失值:3414.6552734375,判别器损失值343.109130859375
第56轮的生成器损失值:3427.310546875,判别器损失值352.00225830078125
第57轮的生成器损失值:3446.245849609375,判别器损失值371.7415771484375
第58轮的生成器损失值:3488.618896484375,判别器损失值343.9029846191406
第59轮的生成器损失值:3388.469482421875,判别器损失值351.0376281738281
第60轮的生成器损失值:3410.164794921875,判别器损失值354.8907165527344
第61轮的生成器损失值:3424.15625,判别器损失值354.5815124511719
第62轮的生成器损失值:3369.984130859375,判别器损失值371.8444519042969
第63轮的生成器损失值:3419.359619140625,判别器损失值375.1051025390625
第64轮的生成器损失值:3432.91796875,判别器损失值344.61578369140625
第65轮的生成器损失值:3324.12109375,判别器损失值364.02874755859375
第66轮的生成器损失值:3386.9599609375,判别器损失值387.5386962890625
第67轮的生成器损失值:3340.77392578125,判别器损失值369.8281555175781
第68轮的生成器损失值:3354.0810546875,判别器损失值367.2720642089844
第69轮的生成器损失值:3291.53662109375,判别器损失值378.1933898925781
第70轮的生成器损失值:3375.2119140625,判别器损失值350.12457275390625
第71轮的生成器损失值:3324.4580078125,判别器损失值357.1696472167969
第72轮的生成器损失值:3334.96875,判别器损失值363.599365234375
第73轮的生成器损失值:3353.963623046875,判别器损失值372.2528381347656
第74轮的生成器损失值:3279.52001953125,判别器损失值381.4432678222656
第75轮的生成器损失值:3248.873291015625,判别器损失值359.6973876953125
第76轮的生成器损失值:3334.107177734375,判别器损失值385.186279296875
第77轮的生成器损失值:3272.5595703125,判别器损失值373.97161865234375
第78轮的生成器损失值:3282.48388671875,判别器损失值374.6603698730469
第79轮的生成器损失值:3315.8173828125,判别器损失值400.2161865234375
第80轮的生成器损失值:3250.458984375,判别器损失值406.6080627441406
第81轮的生成器损失值:3347.8037109375,判别器损失值359.7836608886719
第82轮的生成器损失值:3269.06982421875,判别器损失值390.88812255859375
第83轮的生成器损失值:3244.718994140625,判别器损失值386.9516906738281
第84轮的生成器损失值:3229.3994140625,判别器损失值402.3242492675781
第85轮的生成器损失值:3282.469482421875,判别器损失值392.0705871582031
第86轮的生成器损失值:3261.463134765625,判别器损失值367.95782470703125
第87轮的生成器损失值:3246.7060546875,判别器损失值398.2889099121094
第88轮的生成器损失值:3325.021240234375,判别器损失值391.1697692871094
第89轮的生成器损失值:3181.181396484375,判别器损失值400.4288024902344
第90轮的生成器损失值:3212.197998046875,判别器损失值384.01031494140625
第91轮的生成器损失值:3181.767578125,判别器损失值386.2222595214844
第92轮的生成器损失值:3253.033447265625,判别器损失值381.6040344238281
第93轮的生成器损失值:3239.474853515625,判别器损失值393.23797607421875
第94轮的生成器损失值:3275.764404296875,判别器损失值387.4879150390625
第95轮的生成器损失值:3249.69482421875,判别器损失值353.1047668457031
第96轮的生成器损失值:3305.953857421875,判别器损失值386.5541687011719
第97轮的生成器损失值:3298.284423828125,判别器损失值380.4208068847656
第98轮的生成器损失值:3199.724609375,判别器损失值389.3112487792969
第99轮的生成器损失值:3217.61962890625,判别器损失值392.8823547363281
第100轮的生成器损失值:3273.804443359375,判别器损失值378.09771728515625

进程已结束,退出代码为 0

生成图片 

这里训练了100轮,其实30轮就差不多,这里可以清楚的看出来,我们生成器生成的图片(我们是以手写字体数据集为例子),很接近真实图片了。 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/617856.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

吃掉 N 个橘子的最少天数

代码实现: 方法一:递归——超时 #define min(a, b) ((a) > (b) ? (b) : (a))int minDays(int n) {if (n 1 || n 2) {return n;}if (n % 3 0) {if (n % 2 0) {return min(min(minDays(n - 1), minDays(n / 2)), minDays(n - 2 * (n / 3))) 1;} e…

引擎:主程渲染

一、引擎发展 二、引擎使用 1.游戏渲染流程 2.3D场景编辑器操作与快捷键 3.节点的脚本组件 脚本介绍 引擎执行流程 物体节点、声音组件\物理组件\UI组件、脚本组件 暴露变量到面板 4.节点的查找 基本查找 this.node:挂载当前脚本的节点A; this.nod…

echarts环形图 legend文字过长显示...鼠标移动上展示全称

legend: {type: scroll,orient: vertical,x: left,y: bottom,top: "42%",left: 13%,data: this.dutyNames,textStyle: { color: #fff },triggerEvent: true,tooltip: {show: true,trigger: item,//鼠标移动上去展示全称},formatter: function (params) {var val &qu…

【每日刷题】Day38

【每日刷题】Day38 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 2696. 删除子串后的字符串最小长度 - 力扣(LeetCode) 2. LCR 123. 图书整理…

使用 Spring Boot 配合策略模式增强系统接口扩展能力

使用 Spring Boot 配合策略模式增强系统接口扩展能力 在软件开发中,系统的可扩展性是一个至关重要的方面。而策略模式是一种常见的设计模式,它可以帮助我们实现灵活的算法选择和系统功能扩展。结合 Spring Boot 框架,我们可以更加方便地利用策…

域控操作十四:统一修改域控内计算机用户头像

1,Windows默认头像存储路径,所以我们把这里面的图片都改成自己想要的头像,然后写策略强制使用默认头像就行了 此设置是替换默认头像使用 此设置是为设置默认头像

039——解决室内不能使用GPS问题

目录 引入 GUI整改 client添加GPS分析 完善服务器网络通讯部分代码 添加GPS的BSW层 GPS操作部分代码(相当于驱动) 效果展示 项目管理操作 引入 最近在写论文加上出去玩了一圈所以停更了一段时间。上次咱们GPS有个室内用不了的问题,咱…

本地vite启动的vue项目使用nginx代理

前提: 必须在同一网段或者相同的局域网!!! nginx下载通道: https://nginx.org/en/download.html 步骤: 1、最好下载稳定版本: 2、下载后直接解压(注意:解压后不要放…

C++入门系列-拷贝构造函数

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 拷贝构造函数 概念 在创建对象的时候,能不能创建一个和已知已存在的对象一模一样的对象呢? 拷贝构造函数:只有单个形参,该形参…

【JavaWeb】Day74.Spring——AOP进阶(连接点)

连接点 连接点可以简单理解为可以被AOP控制的方法。我们目标对象当中所有的方法不是都是可以被AOP控制的方法。而在SpringAOP当中,连接点又特指方法的执行。 在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名…

Mybatis操作数据库的两种方式:原生API

mybatis操作数据的两种方式:原生api和mapper代理对象 1.mybatis的api提供的方法 insert() 增加 delete() 删除 update() 更新 selectOne() 返回一个数据 selectList() 返回多个数据,结果类型为List selectMap() 返回多个数据&…

算法学习系列(六十):区间DP

目录 引言区间合并模板一、石子合并二、环形石子合并三、能量项链 引言 关于这个区间 D P DP DP ,其实是有套路和模板的,题型的话也是变化不多,感觉就那几种,只不过有些题会用到高精度或者是要记录方案,所以整体来说…

为什么你总是买不到心仪的房?可能是因为你忽略了这些!

​在人生的旅途中,过多的选择有时并无益处。当选择变得繁多,我们往往容易迷失方向,渴望拥有所有,但最终可能一无所获。 对于迫切需要购房的人来说,他们常常面临这样的困境:被各种声音和推荐所包围&#xf…

STM32窗口看门狗的操作

STM32的窗口看门狗的主要功能是,程序过早的喂狗还有太晚喂狗,都会触发单片机重启,就是有一个时间段,在这个时间段内喂狗才不会触发单片机重启。 下面我就总结一下窗口看门狗的设置过程: 第一步:开启窗口看…

搭建本地yum仓库

步骤 找个地方存你的rpm包 #我创建了一个rpm文件夹存放我的rpm包 makdir -p /opt/repo/rpmcreaterepo 这个很重要,一定要安装 # 我的能连外网,所以直接yum安装,你的自己想办法 yum install createrepo -y创建repodata 安装了createrepo后…

day001 ~如何修改主机名

命令行方式设置主机名 # 这个很重要!用命令改方便些 hostnamectl set-hostname ocloud-252 #查询,exit或logout重新登录后发现主机名换掉 hostname nmtui方式修改 nmtui 在工作中,如果机器很多,最好修改主机名做好标识不至于弄混,方便管理.

WEB后端复习——监听器、过滤器

Listener监听器 是Servlet规范中定义的一种特殊类,它用于监听web应用程序中的ServletContext, HttpSession和ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。 注解WebListener 1.ServletContextListener 监听Serv…

Windows使用cowaxess(goaccess)分析Nginx日志

原文网址:Windows使用cowaxess(goaccess)分析Nginx日志_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Windows安装cowaxess来分析Nginx的access.log日志的方法。 cowaxess是goaccess的Windows版本,cowaxess底层会调用goaccess。 GoAccess 是一个专门用来…

uniapp获取当前位置及检测授权状态——支持App、微信小程序

uniapp获取当前位置检测及定位权限——支持App、微信小程序 首先,祝天下母亲,节日快乐~ 文章目录 uniapp获取当前位置检测及定位权限——支持App、微信小程序效果图新增 兼容小程序方法manifest Tips: 上一篇介绍 App端 uniapp获取当前位置及…

# 电脑突然连接不上网络了,怎么办?

电脑突然连接不上网络了,怎么办? 一、原因分析: 1、IP 地址冲突 2、DNS 解析出现问题。 3、电脑网络设置是否打开了【移动热点】或【飞行模式】。 4、【WLAN AutoConfig】服务是否打开。 5、无线网卡驱动损坏。 6、检查 WIFI 开关是否…