概要

分类是对数据的简化。分类神经网络把较多的输入值缩减成很少的输出值,每个输出值对应一个类别。

生成是对数据的扩展。一个生成神经网络将少量的输入种子值扩展成大量的输出值,例如图像像素值。

生成对抗网络(GAN)由两个神经网络组成,一个是生成器,另一个是鉴别器,它们被设计为竞争对手。鉴别器经过训练后,可将训练集中的数据分类为真实数据,将生成器产生的数据分类为伪造数据;生成器在训练后,能创建可以以假乱真的数据来欺骗鉴别器。

标准的GAN训练循环有3个步骤:

  1. 鉴别器展示一个真实的数据样本,告诉它该样本的分类应该是1.0
  2. 鉴别器展示一个生成器的输出,告诉它该样本的分类应该是0.0
  3. 鉴别器展示一个生成器的输出,告诉生成器结果应该是1.0

1010数据生成范例

该范例主要用于介绍生成对抗网络的基本架构,训练好的生成器应该能够生成符合“1010”格式的数据

鉴别器和生成器

这里设计的鉴别器的网络结构很简单,是一个输入为4,隐藏层为3,输出层为1的MLP,用于计算输入数据有多大概率为真(1010格式)

设计的生成器需要配合鉴别器的学习速度。因为我们不希望在训练过程中生成器和鉴别器中的任何一个领先另一个太多,这样学习将无法正常进行

许多情况下,采取复制鉴别器结构并倒置的方法来构建生成器,这里的生成器就是一个输入为1,隐藏层为3,输出层为4的MLP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# C1010.py

import torch
import torch.nn as nn

import pandas
import matplotlib.pyplot as plt

class Discrimainator(nn.Module):

def __init__(self) -> None:
super().__init__()

self.model=nn.Sequential(
nn.Linear(4,3),
nn.Sigmoid(),
nn.Linear(3,1),
nn.Sigmoid()
)

self.loss_function=nn.MSELoss()

self.optimiser=torch.optim.SGD(self.parameters(),lr=0.01)

self.counter=0
self.progress=[]

def forward(self,inputs):
return self.model(inputs)

def train(self,inputs,targets):
outputs=self.forward(inputs)
loss=self.loss_function(outputs,targets)

self.counter+=1
if(self.counter%10==0):
self.progress.append(loss.item())
if(self.counter%10000==0):
print("counter = ",self.counter)

self.optimiser.zero_grad()
loss.backward()
self.optimiser.step()

def plot_progress(self):
df=pandas.DataFrame(self.progress,columns=['loss'])
df.plot(ylim=(0,1.0),figsize=(16,8),alpha=0.1,marker='.',grid=True,yticks=(0,0.25,0.5))

class Generator(nn.Module):
def __init__(self) -> None:
super().__init__()

self.model=nn.Sequential(
nn.Linear(1,3),
nn.Sigmoid(),
nn.Linear(3,4),
nn.Sigmoid()
)

self.optimiser=torch.optim.SGD(self.parameters(),lr=0.01)

self.counter=0
self.progress=[]

def forward(self,inputs):
return self.model(inputs)

def train(self,D,inputs,targets):
g_output=self.forward(inputs)
d_output=D.forward(g_output)

loss=D.loss_function(d_output,targets)

self.counter+=1
if(self.counter%10==0):
self.progress.append(loss.item())

self.optimiser.zero_grad()
loss.backward()
self.optimiser.step()

def plot_progress(self):
df=pandas.DataFrame(self.progress,columns=['loss'])
df.plot(ylim=(0,1.0),figsize=(16,8),alpha=0.1,marker='.',grid=True,yticks=(0,0.25,0.5))

数据生成和训练

此处生成器输入设定为0.5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import torch

import matplotlib.pyplot as plt
import random
import numpy

import C1010

if torch.cuda.is_available():
torch.set_default_tensor_type(torch.cuda.FloatTensor)
print("using cuda:",torch.cuda.get_device_name())

device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

def generate_real():
return torch.cuda.FloatTensor(
[random.uniform(0.8,1.0),
random.uniform(0.0,0.2),
random.uniform(0.8,1.0),
random.uniform(0.0,0.2)])

D=C1010.Discrimainator()
G=C1010.Generator()

image_list=[]

for i in range(10000):
D.train(generate_real(),torch.cuda.FloatTensor([1.0]))
D.train(G.forward(torch.cuda.FloatTensor([0.5])).detach(),torch.cuda.FloatTensor([0.0]))
G.train(D,torch.cuda.FloatTensor([0.5]),torch.cuda.FloatTensor([1.0]))
if(i%1000==0):
image_list.append(G.forward(torch.cuda.FloatTensor([0.5])).cpu().detach().numpy())

D.plot_progress()
G.plot_progress()

plt.figure(figsize=(16,8))
plt.imshow(numpy.array(image_list).T,interpolation='none',cmap='Blues')