昇思25天学习打卡营第38天|生成式-GAN图像生成

昇思25天学习打卡营第38天|生成式-GAN图像生成

GAN简介

生成式对抗网络是一种无监督深度学习模型, 由两个神经网络组成:生成器 (Generator) 和判别器 (Discriminator)。这两个网络通过对抗性训练共同工作,使得生成器能够生成逼真的数据。

生成器 (Generator)

主要任务:生成与真实数据相似的假数据。

输入和输出:生成器接受一个随机噪声向量作为输入,并将其转换为与真实数据分布相似的输出。

损失函数:目标是最大化判别器对生成数据判断为真实数据的概率

在输出生成数据后,会经过标准化处理,使数据限定到特定的范围,后面输出时可以通过reshape进行恢复。

from mindspore import nn
import mindspore.ops as ops

img_size = 28  # 训练图像长(宽)

class Generator(nn.Cell):
    def __init__(self, latent_size, auto_prefix=True):
        super(Generator, self).__init__(auto_prefix=auto_prefix)
        self.model = nn.SequentialCell()
        # [N, 100] -> [N, 128]
        # 输入一个100维的0~1之间的高斯分布,然后通过第一层线性变换将其映射到256维
        self.model.append(nn.Dense(latent_size, 128))
        self.model.append(nn.ReLU())
        # [N, 128] -> [N, 256]
        self.model.append(nn.Dense(128, 256))
        self.model.append(nn.BatchNorm1d(256))
        self.model.append(nn.ReLU())
        # [N, 256] -> [N, 512]
        self.model.append(nn.Dense(256, 512))
        self.model.append(nn.BatchNorm1d(512))
        self.model.append(nn.ReLU())
        # [N, 512] -> [N, 1024]
        self.model.append(nn.Dense(512, 1024))
        self.model.append(nn.BatchNorm1d(1024))
        self.model.append(nn.ReLU())
        # [N, 1024] -> [N, 784]
        # 经过线性变换将其变成784维
        self.model.append(nn.Dense(1024, img_size * img_size))
        # 经过Tanh激活函数是希望生成的假的图片数据分布能够在-1~1之间
        self.model.append(nn.Tanh())

    def construct(self, x):
        img = self.model(x)
        return ops.reshape(img, (-1, 1, 28, 28))

net_g = Generator(latent_size)
net_g.update_parameters_name('generator')

判别器 (Discriminator)

主要任务:通过训练,判别器学会将真实数据和伪造数据区分开来。

输入和输出:判别器可以看作是一个二分类器,其输入是数据样本,输出是一个表示样本为真实数据的概率值。这个值通常在 [0, 1] 之间,其中 1 表示真实数据,0 表示生成数据。

损失函数:最大化真实数据被正确分类为真实的概率,同时最小化生成数据被误分类为真实的概率。

 # 判别器
class Discriminator(nn.Cell):
    def __init__(self, auto_prefix=True):
        super().__init__(auto_prefix=auto_prefix)
        self.model = nn.SequentialCell()
        # [N, 784] -> [N, 512]
        self.model.append(nn.Dense(img_size * img_size, 512))  # 输入特征数为784,输出为512
        self.model.append(nn.LeakyReLU())  # 默认斜率为0.2的非线性映射激活函数
        # [N, 512] -> [N, 256]
        self.model.append(nn.Dense(512, 256))  # 进行一个线性映射
        self.model.append(nn.LeakyReLU())
        # [N, 256] -> [N, 1]
        self.model.append(nn.Dense(256, 1))
        self.model.append(nn.Sigmoid())  # 二分类激活函数,将实数映射到[0,1]

    def construct(self, x):
        x_flat = ops.reshape(x, (-1, img_size * img_size))
        return self.model(x_flat)

net_d = Discriminator()
net_d.update_parameters_name('discriminator')

对抗性训练

在 GAN 的训练过程中,判别器和生成器交替更新。(双方都在不断地进步)

  1. 生成器生成一批伪造数据,这些数据和一批真实数据一起输入到判别器。判别器计算出它对每个样本的分类结果,然后基于真实数据和生成数据的损失来更新判别器的权重。
  2. 接下来,保持判别器的参数不变,使用生成器生成一批假数据。然后通过判别器计算生成器的损失,优化生成器的参数,使得生成器能够更好地欺骗判别器。
  3. 重复步骤1和2,直到生成器生成的假数据与真实数据的分布相似。
# 生成器计算损失过程
def generator_forward(test_noises):
    fake_data = net_g(test_noises)
    fake_out = net_d(fake_data)
    loss_g = adversarial_loss(fake_out, ops.ones_like(fake_out))
    return loss_g


# 判别器计算损失过程
def discriminator_forward(real_data, test_noises):
    fake_data = net_g(test_noises)
    fake_out = net_d(fake_data)
    real_out = net_d(real_data)
    real_loss = adversarial_loss(real_out, ops.ones_like(real_out))
    fake_loss = adversarial_loss(fake_out, ops.zeros_like(fake_out))
    loss_d = real_loss + fake_loss
    return loss_d

# 梯度方法
grad_g = ms.value_and_grad(generator_forward, None, net_g.trainable_params())
grad_d = ms.value_and_grad(discriminator_forward, None, net_d.trainable_params())

def train_step(real_data, latent_code):
    # 计算判别器损失和梯度
    loss_d, grads_d = grad_d(real_data, latent_code)
    optimizer_d(grads_d)
    loss_g, grads_g = grad_g(latent_code)
    optimizer_g(grads_g)

    return loss_d, loss_g

# 保存生成的test图像
def save_imgs(gen_imgs1, idx):
    for i3 in range(gen_imgs1.shape[0]):
        plt.subplot(5, 5, i3 + 1)
        plt.imshow(gen_imgs1[i3, 0, :, :] / 2 + 0.5, cmap="gray")
        plt.axis("off")
    plt.savefig(image_path + "/test_{}.png".format(idx))

# 设置参数保存路径
os.makedirs(checkpoints_path, exist_ok=True)
# 设置中间过程生成图片保存路径
os.makedirs(image_path, exist_ok=True)

net_g.set_train()
net_d.set_train()

# 储存生成器和判别器loss
losses_g, losses_d = [], []

for epoch in range(total_epoch):
    start = time.time()
    for (iter, data) in enumerate(mnist_ds):
        start1 = time.time()
        image, latent_code = data
        image = (image - 127.5) / 127.5  # [0, 255] -> [-1, 1]
        image = image.reshape(image.shape[0], 1, image.shape[1], image.shape[2])
        d_loss, g_loss = train_step(image, latent_code)
        end1 = time.time()
        if iter % 10 == 10:
            print(f"Epoch:[{int(epoch):>3d}/{int(total_epoch):>3d}], "
                  f"step:[{int(iter):>4d}/{int(iter_size):>4d}], "
                  f"loss_d:{d_loss.asnumpy():>4f} , "
                  f"loss_g:{g_loss.asnumpy():>4f} , "
                  f"time:{(end1 - start1):>3f}s, "
                  f"lr:{lr:>6f}")

    end = time.time()
    print("time of epoch {} is {:.2f}s".format(epoch + 1, end - start))

    losses_d.append(d_loss.asnumpy())
    losses_g.append(g_loss.asnumpy())

    # 每个epoch结束后,使用生成器生成一组图片
    gen_imgs = net_g(test_noise)
    save_imgs(gen_imgs.asnumpy(), epoch)

    # 根据epoch保存模型权重文件
    if epoch % 1 == 0:
        save_checkpoint(net_g, checkpoints_path + "/Generator%d.ckpt" % (epoch))
        save_checkpoint(net_d, checkpoints_path + "/Discriminator%d.ckpt" % (epoch))

生成器的损失计算 (generator_forward)
  • 输入test_noises,即随机噪声向量,通常从标准正态分布中采样。
  • 流程
    1. 使用生成器 (net_g) 将噪声向量生成伪造数据 fake_data
    2. 使用判别器 (net_d) 对伪造数据进行判别,输出 fake_out
    3. 使用对抗损失函数 (adversarial_loss) 计算生成器的损失 loss_g,目标是让判别器认为伪造数据是真实的,即 fake_out 趋近于 1。
判别器的损失计算 (discriminator_forward)
  • 输入real_data(真实数据)和 test_noises(随机噪声向量)。
  • 流程
    1. 使用生成器 (net_g) 将噪声向量生成伪造数据 fake_data
    2. 使用判别器 (net_d) 对伪造数据 fake_data 进行判别,输出 fake_out
    3. 使用判别器 (net_d) 对真实数据 real_data 进行判别,输出 real_out
    4. 计算判别器对真实数据的损失 real_loss 和对伪造数据的损失 fake_loss
    5. 判别器的总损失 loss_dreal_lossfake_loss 的和。
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值