生成对抗网络-实践篇
生成?怎么生成?
举个例子:手写数字识别
什么是手写数字识别?就是将一个28乘28的图片(图片内容是数据0-9,每个图片仅有一个数字)输入到一个模型中,模型会返回它认为的这张图像上0写的哪一个值。
从例子中我们可以看出输出的值,是远远小于输入的值的。(输入784,输出1)
既然可以从784到1,那么为什么不可以从1到784,也就是说我给模型一个数值3,给我生成784张写着3的图片。
完成这个任务的模型就是生成模型。
但是我们会发现一个问题,如果给定一个3,那么生成的784张图片全是一模一样的,这显然不行,因为既然784张完全一样,那我还不如就要一张好了。所以现在的问题就变成了要让生成的图片有多样性。
对抗?怎么对抗?
接着上面的问题来说,如果一个模型A接受到了3,那么无论怎么样,它生成的都会是一样的。可是要是这个模型A看不见3呢,它也许会生成一个6,当然也可能是一个篮球,当然这也不符合我们的要求,我们是要多样化,但是你不能太离谱,起码生成的得是个数字。这个时候,有一个模型B走过来看了看A生成的6和篮球,又看了看自己手中的3,对A说篮球零分,数字六70分。显然下次模型A不会在生成篮球了,很大可能会生成数字。到这里我们就解决了刚才的问题,既可以让模型生成的图片有多样性,而且图片符合我们的预期。
上面例子的关键是有一个模型B知道我们要什么,而且能给模型A反馈。
模型A:我们称它为生成器 (generator)。
同时,我们把模型B称为鉴别器 (discriminator)
生成器的作用是生成图片,并且能够让鉴别器认为这就是真的图片
鉴别器的作用是看生成器生成的图片和真实的图片,判断生成的图片是不是真的图片
由生成器和鉴别器组成的网络就被称作生成对抗网络(Generative Adversarial Network,GAN)
生成器想要生成图片骗过鉴别器,鉴别器想要辨别出假的图片,由此可以看出它们是竞争关系
既然是竞争关系,那么必然不可能让一家独大,只有你来我往这样才会持久。所以这就证明了这两个模型是交替训练,而不是训练好一个模型之后再去训练另一个模型。
注:
- 分类是对数据的简化。分类神经网络把较多的输入值缩减成很少的输出值,每个输出值对应一个类别。
- 生成是对数据的扩展。一个生成神经网络将少量的输入种子值扩展成大量的输出值,例如图像像素值。
- 生成对抗网络(GAN)由两个神经网络组成,一个是生成器,另一个是鉴别器,它们被设计为竞争对手。鉴别器经过训练后,可将训练集中的数据分类为真实数据,将生成器产生的数据分类为伪造数据;生成器在训练后,能创建可以以假乱真的数据来欺骗鉴别器。
- 标准的 GAN 训练循环有3个步骤。(1)用真实的训练数据集训练鉴别器;(2)用生成的数据训练鉴别器;(3)训练生成器生成数据,并使鉴别器以为它是真实数据。
动手构建一个GAN
因为01分类最简单,所以我们在这里就使用01分类
既然是01分类真实的数据肯定不是0就是1
#在这里我们给出三段代码,一个是真实数据,一个是01格式的数据,一个是噪声#01格式数据import numpy as np
defone_zeros():
data = np.array([1,0,1,0])return data
defreal_data():
real = np.array([
np.random.uniform(0.8,1.0),
np.random.uniform(0,0.2),
np.random.uniform(0.8,1.0),
np.random.uniform(0,0.2),])return real
defg_random(size):
random_data = np.random.rand(size)return random_data
鉴别器
接下来实现鉴别器,我们不妨想想实现一个鉴别器需要什么?毫无疑问的是,首先确定输入输出,根据上文中的数据可以看出输入的4,那么输出应该是什么,既然是鉴别器,肯定是用判别我输入的格式是不是1010这种,那么输出应该是1,输出是真或者是假,显然使用1代表真,0代表假更合适。ok,目前已经确定了输入输出,我们还要想一下鉴别器应该怎么工作。假设经过一个最简单的三层神经网络,那么第一层, 和第三层已经确定了,神经元个数分别是4和1,中间那一层应该是几,嗯,这个的话,一般来说只要不是太离谱都可以,我们这里设为3,当然你也可以设置为2,或者是1000。当然一般来说不会有人设置为1000。好了,目前我们已经明白了怎么写,下面就一起来coding吧,
classdiscriminator(nn.Layer):def__init__(self):super().__init__()
self.model = nn.Sequential(
nn.Linear(4,3),
nn.Sigmoid(),
nn.Linear(3,1),
nn.Sigmoid())defforward(self,x):
x = self.model(x)return x
写完之后,我们当然想要知道,这个鉴别器有没有用,下面该写训练函数了,思路仍然是先考虑输入输出,输入应该有需要预测的数据和目标数据,输出是什么,既然是训练,其实可以没有输出函数,那么接下来思考一下函数的功能,既然要训练了肯定要有损失函数,然后梯度清零,损失回传,梯度更新。结束,开始coding
deftrain(model,inputs,targets):
outputs = model(inputs)
loss_function = nn.MSELoss()
loss = loss_function(outputs,targets)if(count%10==0):
loss_list.append(loss.item())if(count%1000==0):print(count)
optim = paddle.optimizer.SGD(learning_rate=0.01,parameters=model.parameters())
optim.clear_grad()
loss.backward()
optim.step()
然后实例化就可
d = discriminator()
count =0
loss_list =[]for i inrange(10000):#float64不行
count +=2
inputs1 = paddle.to_tensor(real_data(),dtype="float32")
targets1 = paddle.to_tensor([1.0],dtype="float32")
train(d,inputs1,targets1)
inputs2 = paddle.to_tensor(g_random(4),dtype="float32")
targets2 = paddle.to_tensor([0.0],dtype="float32")
train(d,inputs2,targets2)
生成器
有了刚才鉴别器的经验,我们可以很轻松的写出生成器,生成器的输入输出刚好和判别器相反,所以我们完全可以拿来直接用,只不过输入输出翻一下就可
classgeneraotr(nn.Layer):def__init__(self):super().__init__()
self.model = nn.Sequential(
nn.Linear(1,3),
nn.Sigmoid(),
nn.Linear(3,4),
nn.Sigmoid())defforward(self,x):
x = self.model(x)return x
对于生成器的训练函数来说,我们需要借助鉴别器来帮它训练,因为它自己没有办法判断自己的生成是不是对的。所以生成器训练函数的输入应该有生成器,鉴别器,输入的数据(种子),目标数据,知道了这些就可以写代码了
deftrain_G(G,D,inputs,outputs):
g_output = G.forward(inputs)
d_output = D.forward(g_output)
loss_fun = nn.MSELoss()
loss = loss_fun(d_output,outputs)if(count%10==0):
loss_list_G.append(loss.item())if(count%1000==0):print(count)
optim = paddle.optimizer.SGD(learning_rate=0.01,parameters=model.parameters())
optim.clear_grad()
loss.backward()
optim.step()
当然我也可以是实例化一下看看效果
D = discriminator()
G = generaotr()
count =0
loss_list_G =[]for i inrange(10000):#float64不行
count +=1
targets1 = paddle.to_tensor(real_data(),dtype="float32")
inputs1 = paddle.to_tensor([42],dtype="float32")
train_G(G,D,inputs1,targets1)
训练GAN
我们首先拿真实数据训练鉴别器,标签是真,然后使用生成器生成的数据训练鉴别器,标签为假,然后训练生成器,目标是真
G = generaotr()
D = discriminator()
count =0
list_list =[]
loss_list_G =[]for i inrange(10000):
count +=1#用真实的数据训练鉴别器
inputs1 = paddle.to_tensor(real_data(),dtype="float32")
targets1 = paddle.to_tensor([1.0],dtype="float32")
train(D,inputs1,targets1)#用生成器训练鉴别器
inputs2 = G.forward(paddle.to_tensor([0.5],dtype="float32")).detach()
targets2 = paddle.to_tensor([0.0],dtype="float32")
train(D,inputs2,targets2)#训练生成器
inputs3 = paddle.to_tensor([0.5],dtype="float32")
train_G(G,D,targets2,targets1)
不出意外的话,损失应该最后会在0.25处,其实也就是鉴别器看不出生成器生成的数据是真还是假,因为是均方损失,所以0.5的平方是0.25
版权归原作者 君苏 所有, 如有侵权,请联系我们删除。