Pytorch之经典神经网络Generative Model(四) —— DCGAN (MNIST)

2015年提出

 

DCGAN —— 深度卷积生成对抗网络

深度卷积生成对抗网络特别简单, 就是将生成网络和对抗网络都改成了卷积网络的形式

DCGAN属于比较基本的模型。在一定程度上提高了训练的结果,但是这仅仅是一个治标不治本的架构

 

Discriminator

卷积判别网络Discriminator 就是一个一般的卷积网络,结构如下

  • 32 Filters, 5x5, Stride 1, Leaky ReLU(alpha=0.01)
  • Max Pool 2x2, Stride 2
  • 64 Filters, 5x5, Stride 1, Leaky ReLU(alpha=0.01)
  • Max Pool 2x2, Stride 2
  • Fully Connected size 4 x 4 x 64, Leaky ReLU(alpha=0.01)
  • Fully Connected size 1

 

Generator

卷积生成网络Generator需要将一个低维的噪声向量变成一个图片数据,结构如下

  • Fully connected of size 1024, ReLU
  • BatchNorm
  • Fully connected of size 7 x 7 x 128, ReLU
  • BatchNorm
  • Reshape into Image Tensor
  • 64 conv2d^T filters of 4x4, stride 2, padding 1, ReLU
  • BatchNorm
  • 1 conv2d^T filter of 4x4, stride 2, padding 1, TanH

 

import torch
from torch import nn
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from visdom import Visdom
 
NOISE_DIM = 96
batch_size = 128
 
def show_images(images): # 定义画图工具
    images = np.reshape(images, [images.shape[0], -1])
    sqrtn = int(np.ceil(np.sqrt(images.shape[0])))
    sqrtimg = int(np.ceil(np.sqrt(images.shape[1])))
 
    fig = plt.figure(figsize=(sqrtn, sqrtn))
    gs = gridspec.GridSpec(sqrtn, sqrtn)
    gs.update(wspace=0.05, hspace=0.05)
 
    for i, img in enumerate(images):
        ax = plt.subplot(gs[i])
        plt.axis('off')
        ax.set_xticklabels([])
        ax.set_yticklabels([])
        ax.set_aspect('equal')
        plt.imshow(img.reshape([sqrtimg,sqrtimg]))
    # plt.show()
    return
 
 
class generator(nn.Module): 
    def __init__(self, noise_dim=NOISE_DIM):
        super(generator, self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(noise_dim, 1024),
            nn.ReLU(True),
            nn.BatchNorm1d(1024),
            nn.Linear(1024, 7 * 7 * 128),
            nn.ReLU(True),
            nn.BatchNorm1d(7 * 7 * 128)
        )
        
        self.conv = nn.Sequential(
            nn.ConvTranspose2d(128, 64, 4, 2, padding=1),
            nn.ReLU(True),
            nn.BatchNorm2d(64),
            nn.ConvTranspose2d(64, 1, 4, 2, padding=1),
            nn.Tanh()
        )
        
    def forward(self, x):
        x = self.fc(x)
        x = x.view(x.shape[0], 128, 7, 7) # reshape 通道是 128,大小是 7x7
        x = self.conv(x)
        return x
 
class discriminator(nn.Module):
    def __init__(self):
        super(discriminator, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 32, 5, 1),
            nn.LeakyReLU(0.01),
            nn.MaxPool2d(2, 2),
            nn.Conv2d(32, 64, 5, 1),
            nn.LeakyReLU(0.01),
            nn.MaxPool2d(2, 2)
        )
        self.fc = nn.Sequential(
            nn.Linear(1024, 1024),
            nn.LeakyReLU(0.01),
            nn.Linear(1024, 1)
        )
        
    def forward(self, x):
        x = self.conv(x)
        x = x.view(x.shape[0], -1)
        x = self.fc(x)
        return x
 
 
def discriminator_loss(logits_real, logits_fake): # 判别器的 loss
    size = logits_real.shape[0]
 
    true_labels = torch.tensor(torch.ones(size, 1)).float().cuda() #全1
    false_labels = torch.tensor(torch.zeros(size, 1)).float().cuda() #全0
 
    loss = bce_loss(logits_real, true_labels) + bce_loss(logits_fake, false_labels)
    #表示logits_real和全1还差多少,logits_fake和全0还差多少
    return loss
 
def generator_loss(logits_fake): # 生成器的 loss
    size = logits_fake.shape[0]
    true_labels = torch.tensor(torch.ones(size, 1)).float().cuda()
    #true_label就全是1
 
    loss = bce_loss(logits_fake, true_labels)
    return loss
 
 
def train_gan(D_net, G_net, D_optimizer, G_optimizer, discriminator_loss, generator_loss, show_every=10,
                noise_size=96, num_epochs=10):
    iter_count = 0
    min_D_loss = 1000.0
    min_G_loss = 1000.0
    min_D_iter = 0
    min_G_iter = 0
    for epoch in range(num_epochs):
        for input, _ in train_data:
            batchsz = input.shape[0]
 
            # 判别网络-----------------------------------
            #这里图片不再需要打平了
            real_img = torch.tensor(input).cuda()  # 真实数据
            logits_real = D_net(real_img)  # 判别网络得分
 
            sample_noise = (torch.rand(batchsz, noise_size) - 0.5) / 0.5  # -1 ~ 1 的均匀分布
            g_fake_seed = torch.tensor(sample_noise).cuda()
            fake_images = G_net(g_fake_seed)  # 生成的假的数据
            logits_fake = D_net(fake_images)  # 判别网络得分
 
            # 判别器的 loss
            d_total_loss = discriminator_loss(logits_real, logits_fake)
 
            # 优化判别网络
            D_optimizer.zero_grad()
            d_total_loss.backward()
            D_optimizer.step()
 
 
            # 生成网络----------------------------
            g_fake_seed = torch.tensor(sample_noise).cuda()
            fake_images = G_net(g_fake_seed)  # 生成的假的数据
 
            gen_logits_fake = D_net(fake_images)
            g_loss = generator_loss(gen_logits_fake)  # 生成网络的 loss
            G_optimizer.zero_grad()
            g_loss.backward()
            G_optimizer.step()  # 优化生成网络
 
            if (iter_count % show_every == 0):
                print('Epoch: {}, Iter: {}, D_loss: {:.4}, G_loss:{:.4}'.format(epoch, iter_count, d_total_loss.item(), g_loss.item()))
                imgs_numpy = deprocess_img(fake_images.data.cpu().numpy())
                show_images(imgs_numpy[0:16])
                plt.savefig('plt_img/%d.png'% iter_count)
                plt.close()
                print('       Min_D_loss: %f, iter %d.'%(min_D_loss,min_D_iter))
                print('       Min_G_loss: %f, iter %d.'%(min_G_loss,min_G_iter))
            viz.line([d_total_loss.item()], [iter_count], win='D_loss', update='append')
            viz.line([g_loss.item()], [iter_count], win='G_loss', update='append')
            if d_total_loss.item() < min_D_loss:
                min_D_loss = d_total_loss.item()
                min_D_iter = iter_count
            if g_loss.item() < min_G_loss:
                min_G_loss = g_loss.item()
                min_G_oter = iter_count
            iter_count += 1
        
        checkpoint = {
            "net_D": D.state_dict(),
            "net_G": G.state_dict(),
            'D_optim':D_optim.state_dict(),
            'G_optim':G_optim.state_dict(),
            "epoch": epoch
        }
        torch.save(checkpoint, 'checkpoints/ckpt_%s.pth' %(str(epoch)))
        print('checkpoint of epoch %d has been saved!'%epoch)
 
 
def preprocess_img(x):
    x = transforms.ToTensor()(x)
    return (x - 0.5) / 0.5
 
#把preprocess_img的操作逆回来
def deprocess_img(x):
    return (x + 1.0) / 2.0
 
 
train_set = MNIST(
    root='dataset/',
    train=True,
    download=True,
    transform=preprocess_img
)
 
train_data = DataLoader(
    dataset=train_set,
    batch_size=batch_size,
    # sampler=ChunkSampler(NUM_TRAIN, 0) #从第0个开始,采样NUM_TRAIN个
)
 
val_set = MNIST(
    root='dataset/',
    train=False,
    download=True,
    transform=preprocess_img
)
 
val_data = DataLoader(
    dataset=val_set,
    batch_size=batch_size,
    # sampler=ChunkSampler(NUM_VAL, NUM_TRAIN)
)
 
# print(len(train_set))# 是 391
# print(len(val_set))# 是 40
viz = Visdom()
viz.line([0.], [0.], win='G_loss', opts=dict(title='G_loss'))
viz.line([0.], [0.], win='D_loss', opts=dict(title='D_loss'))
 
bce_loss = nn.BCEWithLogitsLoss()
 

 
D = discriminator().cuda()
G = generator().cuda()

 
D_optim = torch.optim.Adam(D.parameters(), lr=3e-4, betas=(0.5, 0.999))
G_optim = torch.optim.Adam(G.parameters(), lr=3e-4, betas=(0.5, 0.999))


train_gan(D, G, D_optim, G_optim, discriminator_loss, generator_loss, num_epochs=100)

最终能train的差不多这样子

 

 

DCGAN的效果

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PyTorch中的卷积神经网络(Convolutional Neural Network,CNN)可以用于MNIST手写数字识别问题。MNIST数据集包含60,000个训练图像和10,000个测试图像,每个图像都是28x28像素的手写数字。使用CNN可以在训练数据上学习图像特征,并在测试数据上评估模型的准确性。 ### 回答2: Pytorch是一个具有强大深度学习功能的开源机器学习框架,它支持卷积神经网络(CNN)的构建,同时也支持很多常用的数据集,例如MNIST数据集。下面是一个用Pytorch实现的卷积神经网络(CNN)模型来处理MNIST数据集。 MNIST数据集包含60,000个训练图像和10,000个测试图像,每张图像都是28像素x28像素的灰度图像。这个模型的目标就是通过训练这些图像,可以识别手写数字,从而在测试集上得到足够准确的结果。 首先,我们需要导入所需的Pytorch库,包括torchvision、torch以及其他用于数据集操作和可视化的库。 ```python import torch import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.nn.functional as F # Define transforms transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]) # Load Data trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True) testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=True) ``` 然后,我们将设计一个包含两个卷积层、两个池化层和三个全连接层的CNN模型。 ```python class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, 1) self.conv2 = nn.Conv2d(32, 64, 3, 1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(9216, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 9216) x = F.relu(self.fc1(x)) x = self.fc2(x) return x ``` 在这个模型中,我们首先使用了一个32通道,大小为3的卷积核对图像进行卷积,并添加relu激活函数。接着,我们再添加一个64通道,大小也为3的卷积核对图像进行卷积,并再次添加relu激活函数。这两个卷积层的目的是从图像中提取特征,同时保留空间信息。 之后,我们使用了一个最大池化层来缩减图像的大小。 在这之后,我们将一个全连接层添加到网络中,里面有128个神经元,接着再通过一次ReLU激活函数。最后,我们添加了第二个全连接层,里面有10个神经元,以产生0到9的10个类别的预测。 最后,我们使用交叉熵损失函数和反向传播算法来训练模型。我们将执行50个训练时期并设定学习率为0.001。 ```python # Define the network net = Net() # Loss and optimizer criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(net.parameters(), lr=0.001) # Train the network for epoch in range(50): running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data optimizer.zero_grad() # Forward + backward + optimize outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 600 == 599: # Print every 600 minibatches print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 600)) running_loss = 0.0 print('Finished Training') ``` 在训练完成后,我们需要使用测试数据进行验证,并计算出预测的准确率。 ```python # Test the network on the test data correct = 0 total = 0 with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total)) ``` 最后,我们根据测试集来评估模型的性能,可以得到约98%的准确率,这个结果相比手工设计的模型高得多。这就展示了使用Pytorch编写卷积神经网络的过程,并训练MNIST数据集的过程。 ### 回答3: PyTorch 是一种流行的深度学习框架,包含丰富的神经网络层和在计算图中自动求导等特性。本文将介绍如何使用 PyTorch 实现卷积神经网络 (Convolutional Neural Networks, CNNs) 来识别手写数字 MNIST 数据集。 MNIST 数据集是一个经典的手写数字数据集,包括60000张训练图像和10000张测试图像。每张图片是 $28\times28$ 的灰度图像,对应一个0到9的数字。本次实现的卷积神经网络将采用一个经典的架构,包括卷积层、池化层和全连接层。下面我们将介绍具体的实现细节。 首先,我们需要导入必要的 Python 包。除了 PyTorch 之外,我们还需要用到 torchvision 库来处理 MNIST 数据集。 ```python import torch import torchvision from torch import nn, optim from torchvision import transforms, datasets ``` 接下来,我们加载 MNIST 数据集,并对图像进行大小归一化和数据增强处理。 ```python train_data = datasets.MNIST(root='data', train=True, download=True, transform=transforms.Compose([ transforms.Resize((32, 32)), transforms.RandomCrop(28), transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ])) test_data = datasets.MNIST(root='data', train=False, download=True, transform=transforms.Compose([ transforms.Resize((32, 32)), transforms.RandomCrop(28), transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ])) ``` 由于卷积神经网络将处理图像数据,因此需要对图像进行处理和归一化。在这里,我们对 MNIST 数据集进行了如下处理: - 将图像大小重新调整为 $32\times 32$。 - 随机裁剪图像到 $28 \times 28$ 的大小,以增强数据集。 - 将图像转换为张量,并将像素值归一化到 $[-1, 1]$ 之间。 接下来,我们定义卷积神经网络的架构。我们将使用两个卷积层和两个全连接层,包括 ReLU 激活函数和 dropout 层,用于增强模型的鲁棒性和泛化能力。 ```python class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, padding=1) self.conv2 = nn.Conv2d(32, 64, 3, padding=1) self.fc1 = nn.Linear(64 * 7 * 7, 128) self.fc2 = nn.Linear(128, 10) self.dropout = nn.Dropout(0.25) def forward(self, x): x = nn.functional.relu(self.conv1(x)) x = nn.functional.relu(self.conv2(x)) x = nn.functional.max_pool2d(x, 2) x = self.dropout(x) x = torch.flatten(x, 1) x = nn.functional.relu(self.fc1(x)) x = self.dropout(x) x = self.fc2(x) return x ``` 首先定义了两个卷积层和两个全连接层,其中第一个卷积层具有1个输入通道和32个输出通道,第二个卷积层具有32个输入通道和64个输出通道。我们使用 3x3 的卷积核,调整填充以保持输入和输出的大小一致。卷积层后面跟着一个 ReLU 激活函数,用于增强模型的非线性拟合能力。然后进行最大池化操作,将图像尺寸降低一半。最后,通过全连接层将得到的特征向量映射到输出类别空间。我们使用 dropout 层随机丢弃一定比例的神经元,以减少过拟合风险。 定义完卷积神经网络的架构后,我们将使用 Adam 优化器和交叉熵损失函数来训练网络。 ```python batch_size = 128 epochs = 10 train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=True) test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=False) model = Net() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters()) ``` 我们将训练集分为128大小的小批量,每个小批量进行简单的随机移动,然后使用 Adam 优化器优化模型。我们使用交叉熵损失函数度量模型训练效果。接下来,我们使用以下代码循环训练模型: ```python for epoch in range(epochs): train_loss = 0.0 train_corrects = 0.0 test_loss = 0.0 test_corrects = 0.0 model.train() for images, labels in train_loader: optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() train_loss += loss.item() * images.size(0) _, preds = torch.max(outputs.data, 1) train_corrects += torch.sum(preds == labels.data) train_loss = train_loss / len(train_loader.dataset) train_acc = train_corrects.double() / len(train_loader.dataset) model.eval() with torch.no_grad(): for images, labels in test_loader: outputs = model(images) loss = criterion(outputs, labels) test_loss += loss.item() * images.size(0) _, preds = torch.max(outputs.data, 1) test_corrects += torch.sum(preds == labels.data) test_loss = test_loss / len(test_loader.dataset) test_acc = test_corrects.double() / len(test_loader.dataset) print('Epoch: {} Train Loss: {:.4f} Train Acc: {:.4f} ' 'Test Loss: {:.4f} Test Acc: {:.4f}'.format(epoch + 1, train_loss, train_acc, test_loss, test_acc)) ``` 对于每个训练时期,我们会迭代每个小批量,计算预测输出和损失,并使用反向传播更新模型参数。此外,我们还将评估模型在测试集上的表现。我们迭代测试集中的每个小批量,并计算预测输出和损失,以及计算模型的分类准确率。在训练过程结束后,我们可以根据测试集的表现来评估模型的性能。 最后,我们将加载训练好的模型,并在测试集上进行预测。 ```python model.load_state_dict(torch.load('model.pt')) model.eval() with torch.no_grad(): for images, labels in test_loader: outputs = model(images) _, preds = torch.max(outputs.data, 1) print(preds) ``` 总之,本文展示了如何使用 PyTorch 实现卷积神经网络来识别手写数字 MNIST 数据集。我们训练了一个包含两个卷积层和两个全连接层的模型,并通过使用 Adam 优化器和交叉熵损失函数进行优化,并在测试集上评价了模型的性能。我们的模型在测试集上取得了不错的分类准确率,证明了卷积神经网络在图像分类任务中的强大表现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值