接續本文上集,我們複習一下GAN的兩個角色:生成器(G)和判別器(D)。
準備訓練數據:使用ShapeNet數據集
GAN(生成對抗網)是由蒙特利爾大學的Ian Goodfellow在2014年提出來的神經網路模型。GAN通常包含兩個角色,兩者互相較量(對抗),但又展現出教學相長,共同成長的美好機制和效果。這兩個角色就是:判別者(Discriminator)與生成者(Generator)。
其中的判別者(D)是老師角色,而生成者(G)則是學生角色。老師引導學生創作,兩者互相較量(對抗),但又展現出教學相長的效果。例如,在圖像渲染的應用上,它們的功能分別是:
- G(學生)負責生成圖片。它接收一個隨機噪音(z),或者其他條件(如黑白底圖或邊框),然後基于這個噪音或條件來生成新圖片。
- D(老師)負責辨別一張圖片的真或假。它的輸入是一張圖片,進行辨別之後,輸出其判斷爲真品或假品的概率。如果輸出值愈接近于1,代表其爲真品的概率愈大;而當輸出值愈接0,代表其爲假品的概率愈大。
在GAN模型的訓練過程中,我們會拿真品來輸入給D,也會拿由G生成的假品來輸入給D。其目的是要訓練D,以便提升它判斷圖片真或假的能力。
如果D判斷正確,表示G(學生)生成的新作品(假品),被D識破了,這意味著G的作品不够逼真,此時G就會依據D的反饋而調整其參數,因而G就成長了。反之,如果D判斷錯誤,表示D的辨別能力不足,例如被G騙了(將假品誤判爲真品),于是D就會調整其參數,因而D也成長了。
這樣的訓練過程,持續重複下去,GAN裏的兩個角色,互相較量(對抗),展現出了教學相長的美好效果。最後,G大幅成長了,繪製出來非常逼真的作品(假品)了。
程式4:定義GAN的生成器,並進行訓練
定義並單獨訓練生成器(G);暫時不訓練判別器(D)。
由生成器(Generator)自己學習重建點雲3D圖像,訓練300回合。並且,把訓練過程的圖像(儲存)顯示出來。在訓練過程中,每60回合儲存一次。程式碼如下:
# paa_GAN_005.py
import numpy as np
import os
import torch
import paddle
import paddle.nn as nn
import paddle.optimizer as optim
from paddle.io import Dataset, DataLoader
import scipy.ndimage as nd
import scipy.io as sio
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
data_dir = 'c:/oopc/ShapeNet_data/chair/train/'
file_list = [os.path.join(data_dir, name)
for name in os.listdir(data_dir)
if name.endswith('.mat')]
print(len(file_list))
#-----------------------------------------------------
nchw =
# 讀取一個3D的*.mat檔案
def getVoxelFromMat(file_path):
voxels = sio.loadmat(file_path)
voxels = np.pad(voxels, (1, 1), 'constant', constant_values=(0, 0))
if nchw != 32:
ratio = nchw / 32.
voxels = nd.zoom(voxels, (ratio, ratio, ratio),
mode='constant', order=0)
return voxels
def SavePloat_Voxels(voxels, path, iteration):
voxels = voxels.__ge__(0.5)
fig = plt.figure(figsize=(32, 16))
gs = gridspec.GridSpec(2, 4)
gs.update(wspace=0.05, hspace=0.05)
for i, sample in enumerate(voxels):
x, y, z = sample.nonzero()
ax = plt.subplot(gs, projection='3d')
ax.scatter(x, y, z, zdir='z', c='red')
ax.set_xticklabels()
ax.set_yticklabels()
plt.savefig(path + '/{}.png'.format(str(iteration).zfill(3)), bbox_inches='tight')
plt.close()
#---------------------------------
class ShapeNetDataset(Dataset):
def __init__(self):
self.filenames = file_list
def __getitem__(self, index):
fna = self.filenames
volume = np.asarray(getVoxelFromMat(fna), dtype=np.float32)
return paddle.to_tensor(volume)
def __len__(self):
return len( self.filenames)
#---------------------------------------
batch_size = 1
d_thresh = 0.8
z_dim = 100
f_dim = 32
g_lr = 0.0025
d_lr = 0.0005
beta = (0.5, 0.999)
cube_len = 32
leak_value = 0.2
bias = False
def get_noise():
z = paddle.normal(shape=)
z = paddle.to_tensor(z)
return z
class Generator(nn.Layer):
def __init__(self):
super().__init__()
self.cube_len = cube_len
padd = (0, 0, 0)
if self.cube_len == 32:
padd = (1,1,1)
self.layer1 = nn.Sequential(
nn.Conv3DTranspose(z_dim, f_dim * 8,
kernel_size=4, stride=2,
padding=(1,1,1), bias_attr=False),
nn.BatchNorm3D(f_dim*8),
nn.ReLU()
)
self.layer2 = nn.Sequential(
nn.Conv3DTranspose(f_dim * 8, f_dim * 4,
kernel_size=4, stride=2,
padding=(1,1,1), bias_attr=False),
nn.BatchNorm3D(f_dim*4),
nn.ReLU()
)
self.layer3 = nn.Sequential(
nn.Conv3DTranspose(f_dim * 4, f_dim * 2,
kernel_size=4, stride=2,
padding=(1,1,1), bias_attr=False),
nn.BatchNorm3D(f_dim*2),
nn.ReLU()
)
self.layer4 = nn.Sequential(
nn.Conv3DTranspose(f_dim * 2, f_dim,
kernel_size=4, stride=2,
padding=(1,1,1), bias_attr=False),
nn.BatchNorm3D(f_dim),
)
self.layer5 = nn.Sequential(
nn.Conv3DTranspose(f_dim, 1,
kernel_size=4, stride=2,
padding=(1,1,1), bias_attr=False),
nn.Sigmoid()
)
def forward(self, x):
x = paddle.reshape(x, shape=)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.layer5(x)
return x
#----------------------------------------------------
G = Generator()
optimizer_g = optim.Adam(learning_rate=g_lr, parameters=G.parameters())
L1_loss = nn.L1Loss()
#-------------------------------------------------
dataset = ShapeNetDataset()
real_vx = dataset
real_vx = real_vx.unsqueeze(0)
print('開始訓練 300回合...')
num_epochs = 300
for ep in range(num_epochs+1):
#print(ep)
G.train()
noise = get_noise()
gen_vx = G(noise)
loss_g = L1_loss(gen_vx, real_vx) * 100
loss_g.backward()
optimizer_g.step()
optimizer_g.clear_grad()
if(ep%60 == 0):
gen_vx = gen_vx.squeeze(0)
vx = gen_vx.numpy()
SavePloat_Voxels(vx, 'c:/oopc/ShapeNet_data/', ep)
#-------------------------------------
#END
在訓練生成器(G)共300回合的在訓練過程中,每60回合儲存一次寫入圖檔(儲存於/ShapeNet_data/裡),如下:
只需不到短短一分鐘...
輸入您的信箱與ID註冊即可享有一切福利!
會員福利
免費電子報
會員搶先看
主題訂閱
好文收藏