感謝伯禹學習平臺惹恃,本次學習將記錄記錄如何使用Pytorch高效實現(xiàn)網(wǎng)絡庇茫,熟練掌握Pytorch的基礎知識。記錄不包含理論知識的細節(jié)展開搀菩。
DCGAN
DCGAN呕臂,實在GAN的基礎上,使用卷積網(wǎng)絡替換了原有的G和D中的全連接層肪跋,在圖像生成上具有較好的表現(xiàn)歧蒋。
初始準備
使用的輸入圖像的大小為(64,64州既,3)彩色的RGB圖像谜洽。在DCGAN中比較重要的一點是,G生成的圖像大小需要和真實圖片大小保持一致性吴叶,確定G的輸入大小后阐虚,可以設計G的基本結構。
Generator
G的作用是將一個噪聲使用反卷積的操作蚌卤,將其拉伸到真實數(shù)據(jù)大小实束,反卷積的參數(shù)是可以學習,所以與D的學習參數(shù)迭代造寝,有了對抗磕洪。
import torch
import torchvision
import torch.nn as nn
# G_block,G與之前的網(wǎng)絡設計思想一致诫龙,將復用的模塊封裝為塊
class G_block(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size=4,strides=2, padding=1):
super(G_block,self).__init__()
self.conv2d_trans=nn.ConvTranspose2d(in_channels, out_channels, kernel_size=kernel_size,
stride=strides, padding=padding, bias=False)
# 前幾層都是 trans_conv+bn+relu
self.batch_norm=nn.BatchNorm2d(out_channels,0.8)
self.activation=nn.ReLU()
def forward(self,x):
return self.activation(self.batch_norm(self.conv2d_trans(x)))
如上block中的反卷積輸入大小可以參考如下計算公式析显,在輸入的情況下輸出大小為(32签赃,32)谷异,也就增大一倍
在G的網(wǎng)絡結構中分尸,它每層的輸出通道數(shù)時遞減的,這點與D剛好有點對稱的意思歹嘹。
class net_G(nn.Module):
def __init__(self,in_channels):
super(net_G,self).__init__()
n_G=64
self.model=nn.Sequential(
G_block(in_channels,n_G*8,strides=1,padding=0),
G_block(n_G*8,n_G*4),
G_block(n_G*4,n_G*2),
G_block(n_G*2,n_G),
# 最后的輸出卷積層使用的激活函數(shù)為Tanh箩绍,具有較好的泛化能力
nn.ConvTranspose2d(
n_G,3,kernel_size=4,stride=2,padding=1,bias=False
),
nn.Tanh()
)
def forward(self,x):
x=self.model(x)
return x
在給定輸入為(1,1)的噪聲情況下尺上,不難驗證輸出為(64材蛛,64)
Discriminator
D的作用是區(qū)分真假,生成對抗網(wǎng)絡是一個無監(jiān)督學習怎抛,其標簽區(qū)分只有0卑吭,1,分別對應生成數(shù)據(jù)和真實數(shù)據(jù)马绝。D的結構豆赏,類似于G的反過來的意思。
# 定義D的復用塊富稻,使用正常的卷積網(wǎng)絡
class D_block(nn.Module):
def __init__(self,in_channels,out_channels,kernel_size=4,strides=2,
padding=1,alpha=0.2):
super(D_block,self).__init__()
self.conv2d=nn.Conv2d(in_channels,out_channels,kernel_size,strides,padding,bias=False)
# 這里用的時conv+bn+leakyrelu掷邦,論文中給出這樣有利于收斂。
self.batch_norm=nn.BatchNorm2d(out_channels,0.8)
self.activation=nn.LeakyReLU(alpha)
def forward(self,X):
return self.activation(self.batch_norm(self.conv2d(X)))
對應的D
class net_D(nn.Module):
def __init__(self,in_channels):
super(net_D,self).__init__()
n_D=64
self.model=nn.Sequential(
D_block(in_channels,n_D),
D_block(n_D,n_D*2),
D_block(n_D*2,n_D*4),
D_block(n_D*4,n_D*8)
)
self.conv=nn.Conv2d(n_D*8,1,kernel_size=4,bias=False)
# 最后使用的sigmoid激活椭赋,常的分類激活函數(shù)
self.activation=nn.Sigmoid()
def forward(self,x):
x=self.model(x)
x=self.conv(x)
x=self.activation(x)
return x
這里由于D輸入尺寸為為(64抚岗,64)所以其最后的輸出為(1,1)
如何訓練這樣的網(wǎng)絡
在DCGAN中纹份,網(wǎng)絡通常是迭代訓練的苟跪,固定G訓練D,固定D訓練G蔓涧。件已。。
訓練過程中的損失計算參考如下代碼
def update_D(X,Z,net_D,net_G,loss,trainer_D):
batch_size=X.shape[0]
Tensor=torch.cuda.FloatTensor
ones=Variable(Tensor(np.ones(batch_size,)),requires_grad=False).view(batch_size,1)
zeros = Variable(Tensor(np.zeros(batch_size,)),requires_grad=False).view(batch_size,1)
#訓練D的時候元暴,給原始圖1標簽篷扩,生成圖0標簽
real_Y=net_D(X).view(batch_size,-1)
fake_X=net_G(Z)
fake_Y=net_D(fake_X).view(batch_size,-1)
loss_D=(loss(real_Y,ones)+loss(fake_Y,zeros))/2
loss_D.backward()
trainer_D.step()
return float(loss_D.sum())
def update_G(Z,net_D,net_G,loss,trainer_G):
batch_size=Z.shape[0]
Tensor=torch.cuda.FloatTensor
ones=Variable(Tensor(np.ones((batch_size,))),requires_grad=False).view(batch_size,1)
# 在訓練G的時候我們需要給定生成圖1標簽
fake_X=net_G(Z)
fake_Y=net_D(fake_X).view(batch_size,-1)
loss_G=loss(fake_Y,ones)
loss_G.backward()
trainer_G.step()
return float(loss_G.sum())
讀取數(shù)據(jù)訓練參考如下
for epo in range(epochs):
for data in dataiter:
z = ..
d.zero_grad()
update_D(...)
g.zero_grad()
update_G
總結
DCGAN 可以說是入門GAN的開始,后面有很多基于GAN思路的改進茉盏,本質上來說鉴未,GAN的思路使得神經(jīng)網(wǎng)絡具有了可控的創(chuàng)造性,但距離人的差距還是很大鸠姨。