GAN生成手寫數字假圖片

        有一段時間沒有寫博客了,前段時間一直在看一篇關於SSAH算法的行人重識別,也是爭對跨模態的一篇文章,只不過它跨的是圖片和文本的模態,導師想讓我把這篇文章中的想法應用到RGB-IR行人重識別當中來,但是研究了一段時間後發現這篇文章的算法並不適合RGB-IR的SYSU-MM01數據集,因此只能先放一邊,以後能作個參考。之後看了一篇RGB-IR跨模態行人再識別的文章,叫《Cross-ModalityPersonRe-IdentificationwithGenerativeAdversarialTraining_IJCAI2018》是廈門大學的一個團隊做的,裏面用到了GAN,看了之後挺感興趣,就去了解了一下它的原理,並且用GAN拿手寫數字做了一下實驗,做完之後才發現,那篇論文用的GAN跟生成圖像用的GAN完全是兩碼事。       

        那篇論文其實是用了GAN的對坑思想,但是GAN最大的用處其實是生成圖像,行人重識別說到底是一個分類問題,GAN基本上不會用在分類領域,但是對坑思想可以用上,既然做都做了,那還是寫一篇博客記錄一下吧

代碼如下:

import torch
import torch.nn as nn
from torch import optim 
from torch.autograd import variable
from torch.utils.data.dataloader import DataLoader
from torchvision import datasets,transforms
from torchvision.utils import save_image

G_in_dim=100#模型的參數參考別人的網絡設置
D_in_dim=784
hidden1_dim=256
hidden2_dim=256
G_out_dim=784
D_out_dim=1

epoch=50
batch_num=60
lr_rate=0.0003


def to_img(x):#這個函數參考自別人的網絡,是將生成的假圖像經過一系列操作能更清晰的顯示出來,具體爲什麼這樣設置沒研究過
    out = 0.5 * (x + 1)
    out = out.clamp(0, 1)
    out = out.view(-1, 1, 28, 28)
    return out

class G_Net(nn.Module):#生成網絡,或者叫生成器,負責生成假數據
    def __init__(self):
        super().__init__()
        self.layer=nn.Sequential(
          nn.Linear(G_in_dim,hidden1_dim),
          nn.ReLU(),
          nn.Linear(hidden1_dim,hidden2_dim),
          nn.LeakyReLU(),
          nn.Linear(hidden2_dim,G_out_dim),
          nn.Tanh()
          )
    def forward(self,x):
        x=self.layer(x)
        return x
    
class D_Net(nn.Module):#判別網絡,或者叫判別器,用來判別數據真假
    def __init__(self):
        super().__init__()
        self.layer=nn.Sequential(
          nn.Linear(D_in_dim,hidden1_dim),
          nn.LeakyReLU(0.2),
          nn.Linear(hidden1_dim,hidden2_dim),
          nn.LeakyReLU(0.2),
          nn.Linear(hidden2_dim,D_out_dim),
          nn.Sigmoid())
    def forward(self,x):
        x=self.layer(x)
        return x
    
data_tf = transforms.Compose([transforms.ToTensor(),
     transforms.Normalize([0.5], [0.5])])
train_set=datasets.MNIST(root='data',train=True,transform=data_tf,download=True)
train_loader=DataLoader(train_set,batch_size=batch_num,shuffle=True)

g_net=G_Net()
d_net=D_Net()
if torch.cuda.is_available():
   g_net = g_net.cuda()
   d_net = d_net.cuda()
   
criterion = nn.BCELoss()
G_optimizer = optim.Adam(g_net.parameters(), lr=lr_rate)
D_optimizer = optim.Adam(d_net.parameters(), lr=lr_rate)

for e in range(epoch):
    for data in train_loader:
        img,l=data
        img = img.view(img.size(0), -1)
        if torch.cuda.is_available():
           img=variable(img).cuda()
           r_label = variable(torch.ones(batch_num)).cuda()
           f_label = variable(torch.zeros(batch_num)).cuda()
           g_input = variable(torch.randn(batch_num,G_in_dim)).cuda()
        
        r_output=d_net(img)
        r_loss=criterion(r_output,r_label)

        f_output=g_net(g_input)
        d_f_output=d_net(f_output)
        f_loss=criterion(d_f_output,f_label)
        sum_loss=r_loss+f_loss
        D_optimizer.zero_grad()
        sum_loss.backward()
        D_optimizer.step()
        
        if torch.cuda.is_available():
           g_input1 = variable(torch.randn(batch_num,G_in_dim)).cuda()
        g_output=g_net(g_input1)
        d_output=d_net(g_output)
        d_loss=criterion(d_output,r_label)
        G_optimizer.zero_grad()
        d_loss.backward()
        G_optimizer.step()
    g_img=g_net(variable(torch.randn(batch_num,G_in_dim)).cuda())
    images = to_img(g_img)
    save_image(images, './img/fake_images-{}.png'.format(e))

整體的實現思路可以總結如下:首先先訓練判別器,用生成器生成假的圖像和mnist中的真圖像去訓練判別器,因此判別器的輸出就只有兩種情況,真(1)或者假(0),從代碼中可以看到,生成器是一個輸入爲100,輸出爲784的全連接網絡,輸入就用pytorch隨機生成,也可以理解爲輸入一組隨機噪聲吧,在這個過程中,我們只更新判別器的參數,而不更新生成器的參數,損失就爲真圖片和假圖片各自的損失和。之後保持判別器參數不變,我們去訓練生成器,將100維數據輸入到生成器中得到784維的數據,再將得到的這個784維數據輸入到判別器中,將判別器的目標設置爲1,計算損失並更新生成器的參數,這樣生成器就會生成越來越像真圖片的假圖片了

我是看懂了原理順着思路借鑑別人模型的參數實現了一遍,用的只有全連接層的神經網絡,效果沒有那麼好,如果有卷積層應該會更好。訓練了50個epoch,得到了如下一些假圖像:

總的來說還可以,有幾個生成的還是挺像的,這個算法其實很有意思,可惜以後應該不會研究它了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章