对抗生成网络GAN

一、GAN -Generative Adversarial Network

 

1.思想

二人零和博弈思想,博弈上方的利益之和是一个常数。例如,AB两人掰手腕,假设总空间是一定的。那么在这个空间中,如果A力气比B大,A得到的空间就会相对多一些,B相对要少一些,反之亦然。在GAN中,两个博弈者分别是生成模型G和判别模型D,它们分别有各自的功能。

 

生成模型和判别模型的相同点:

两个模型都可以看作为一个黑匣子,接受输入之后产生一个输出。

又可以看作为一个函数,作为输入和输出之间的映射。

 

生成模型和判别模型的不同点:

生成模型G功能:类似一个样本生成器,接受一个是噪声/样本的输入,将输入包装成一个逼真的样本作为输出。

判别模型D功能:类似一个二分类器(如同0-1分类器),来判断输入的样本是真是假,即输出值大于0.5还是小于0.5.

生成模型G目的:用来造样本的,目的是是自己造样本的能力足够强,强到判别网络无法判断生成的样本是真的还是假的样本

判别模型D目的:能判别出来 一张图时来时真是样本还是假样本集。若输入为真样本,网络输出接近1;输入为假样本,输出接近0。这样的话就达到了很好的判别目的。

 

有了这个理解我们再来看看为什么叫做对抗网络了。判别网络说,我很强,来一个样本我就知道它是来自真样本集还是假样本集。生成网络就不服了,说我也很强,我生成一个假样本,虽然我生成网络知道是假的,但是你判别网络不知道呀,我包装的非常逼真,以至于判别网络无法判断真假,那么用输出数值来解释就是,生成网络生成的假样本进去了判别网络以后,判别网络给出的结果是一个接近0.5的值,极限情况就是0.5,也就是说判别不出来了,这就是纳什平衡了。

 

2.为什么用它,他能做什么

由这个分析可以发现,生成网络与判别网络的目的正好是相反的,一个说我能判别的好,一个说我让你判别不好。所以叫做对抗,叫做博弈。那么最后的结果到底是谁赢呢?这就要归结到设计者,也就是我们希望谁赢了。作为设计者的我们,我们的目的是要得到以假乱真的样本,那么很自然的我们希望生成样本赢了,也就是希望生成样本很真,判别网络能力不足以区分真假样本位置。

 

3.如何训练

单独交替迭代训练

文字描述:

1.假设现在生成网络模型已经有了(当然可能不是最好的生成网络),那么给一堆随机数组,就会得到一堆假的样本集(因为不是最终的生成模型,那么现在生成网络可能就处于劣势,导致生成的样本就不咋地,可能很容易就被判别网络判别出来了说这货是假冒的),但是先不管这个,假设我们现在有了这样的假样本集,真样本集一直都有,现在我们人为的定义真假样本集的标签,因为希望真样本集的输出尽可能为1,假样本集为0,很明显这里我们就已经默认真样本集所有的类标签都为1,而假样本集的所有类标签都为0. 有人会说,在真样本集里面的人脸中,可能张三人脸和李四人脸不一样呀,对于这个问题我们需要理解的是,我们现在的任务是什么,我们是想分样本真假,而不是分真样本中那个是张三label、那个是李四label。况且我们也知道,原始真样本的label我们是不知道的。回过头来,我们现在有了真样本集以及它们的label(都是1)、假样本集以及它们的label(都是0),这样单就判别网络来说,此时问题就变成了一个有监督的二分类问题了,直接送到神经网络模型中训练就完事了。假设训练完了,下面我们来看生成网络。

2.对于生成网络,目的是生成尽可能逼真的样本。那么原始的生成网络生成的样本你怎么知道它真不真呢?就是送到判别网络中,所以在训练生成网络的时候,需要联合判别网络一起才能达到训练的目的。就是如果我们单单只用生成网络,那么想想我们怎么去训练?误差来源在哪里?细想一下没有,但是如果我们把刚才的判别网络串接在生成网络的后面,这样我们就知道真假了,也就有了误差了。所以对于生成网络的训练其实是对生成-判别网络串接的训练,就像图中显示的那样。好了那么现在来分析一下样本,原始的噪声数组Z我们有,也就是生成了假样本我们有,此时很关键的一点来了,我们要把这些假样本的标签都设置为1,也就是认为这些假样本在生成网络训练的时候是真样本。那么为什么要这样呢?我们想想,是不是这样才能起到迷惑判别器的目的,也才能使得生成的假样本逐渐逼近为正样本。好了,重新顺一下思路,现在对于生成网络的训练,我们有了样本集(只有假样本集,没有真样本集),有了对应的label(全为1),是不是就可以训练了?有人会问,这样只有一类样本,训练啥呀?谁说一类样本就不能训练了?只要有误差就行。还有人说,你这样一训练,判别网络的网络参数不是也跟着变吗?没错,这很关键,所以在训练这个串接的网络的时候,一个很重要的操作就是不要判别网络的参数发生变化,也就是不让它参数发生更新,只是把误差一直传,传到生成网络那块后更新生成网络的参数。这样就完成了生成网络的训练了。

3.在完成生成网络训练好,那么我们是不是可以根据目前新的生成网络再对先前的那些噪声Z生成新的假样本了,没错,并且训练后的假样本应该是更真了才对。然后又有了新的真假样本集(其实是新的假样本集),这样又可以重复上述过程了。我们把这个过程称作为单独交替训练。我们可以实现定义一个迭代次数,交替迭代到一定次数后停止即可。这个时候我们再去看一看噪声Z生成的假样本会发现,原来它已经很真了。
 

公式:

目标公式:

\underset{G}{min} \underset{D}{max}V(D,G)=E_{x\sim P_{data}(x)}[log(D(x))]+E_{z\sim P_{z} (z)}\left [ log(1-D(G(z))) \right ]

分两步完成最大最小优化,首先优化D,然后再优化G,本质是两个优化,所以可得:

优化判别模型D:

\underset{D}{max}V(D,G)=E_{x\sim P_{data}(x)}[log(D(x))]+E_{z\sim P_{z} (z)}\left [ log(1-D(G(z))) \right ]

优化生成模型G:

\underset{G}{min} V(D,G)=E_{z\sim P_{z} (z)}\left [ log(1-D(G(z))) \right ]这里写图片描述

这张图表明的是GAN的生成网络如何一步步从均匀分布学习到正态分布的。原始数据服从正态分布,但是学习过程中没有让生成网络用正态分布去学习,他也能学到。也就是说,无论x服从何分布,生成网络可能也能学到。这就是GAN可以自动学习真实数据的分布的强大之处。

GAN强大之处还在于可以自动的定义潜在损失函数。

4.小实验

通过随机数组生成mnist图像,实现语言为matlab。

判别模型D和生成模型G网络结构如下:

这里写图片描述
先加载工具DeepLearnToolbox,把它添加到路径,然后运行下面的代码:

clc
clear
%% 构造真实训练样本 60000个样本 1*784维(28*28展开)
load mnist_uint8;

train_x = double(train_x(1:60000,:)) / 255;
% 真实样本认为为标签 [1 0]; 生成样本为[0 1];
train_y = double(ones(size(train_x,1),1));
% normalize
train_x = mapminmax(train_x, 0, 1);

rand('state',0)
%% 构造模拟训练样本 60000个样本 1*100维
test_x = normrnd(0,1,[60000,100]); % 0-255的整数
test_x = mapminmax(test_x, 0, 1);

test_y = double(zeros(size(test_x,1),1));
test_y_rel = double(ones(size(test_x,1),1));

%%
nn_G_t = nnsetup([100 784]);
nn_G_t.activation_function = 'sigm';
nn_G_t.output = 'sigm';

nn_D = nnsetup([784 100 1]);
nn_D.weightPenaltyL2 = 1e-4;  %  L2 weight decay
nn_D.dropoutFraction = 0.5;   %  Dropout fraction 
nn_D.learningRate = 0.01;                %  Sigm require a lower learning rate
nn_D.activation_function = 'sigm';
nn_D.output = 'sigm';
% nn_D.weightPenaltyL2 = 1e-4;  %  L2 weight decay

nn_G = nnsetup([100 784 100 1]);
nn_G.weightPenaltyL2 = 1e-4;  %  L2 weight decay
nn_G.dropoutFraction = 0.5;   %  Dropout fraction 
nn_G.learningRate = 0.01;                %  Sigm require a lower learning rate
nn_G.activation_function = 'sigm';
nn_G.output = 'sigm';
% nn_G.weightPenaltyL2 = 1e-4;  %  L2 weight decay

opts.numepochs =  1;        %  Number of full sweeps through data
opts.batchsize = 100;       %  Take a mean gradient step over this many samples
%%
num = 1000;
tic
for each = 1:1500
    %----------计算G的输出:假样本------------------- 
    for i = 1:length(nn_G_t.W)   %共享网络参数
        nn_G_t.W{i} = nn_G.W{i};
    end
    G_output = nn_G_out(nn_G_t, test_x);
    %-----------训练D------------------------------
    index = randperm(60000);
    train_data_D = [train_x(index(1:num),:);G_output(index(1:num),:)];
    train_y_D = [train_y(index(1:num),:);test_y(index(1:num),:)];
    nn_D = nntrain(nn_D, train_data_D, train_y_D, opts);%训练D
    %-----------训练G-------------------------------
    for i = 1:length(nn_D.W)  %共享训练的D的网络参数
        nn_G.W{length(nn_G.W)-i+1} = nn_D.W{length(nn_D.W)-i+1};
    end
    %训练G:此时假样本标签为1,认为是真样本
    nn_G = nntrain(nn_G, test_x(index(1:num),:), test_y_rel(index(1:num),:), opts);
end
toc
for i = 1:length(nn_G_t.W)
    nn_G_t.W{i} = nn_G.W{i};
end
fin_output = nn_G_out(nn_G_t, test_x);

函数nn_G_out为:

function output = nn_G_out(nn, x)
    nn.testing = 1;
    nn = nnff(nn, x, zeros(size(x,1), nn.size(end)));
    nn.testing = 0;
    output = nn.a{end};
end

上面的函数中重点是中间交替训练的过程:

  • 重新计算假样本。原因是:为了产生越来越像的样本,假样本需要每次都更新
  • 训练判别网络,一个二分类的神经网络
  • 训练生成网络,一个串联的长网络,也是一个二分类的神经网络(志勇假样本来训练),同时判别网络D部分参数在下一次不能再改变。

就这样调一调参数,最终输出在fin_output里面,多运行几次显示不同运行次数下的结果:

这里写图片描述

可以看到的是结果还是有点像模像样的。

5.实验总结

运行上述简单的网络我发现几个问题:

  • 网络存在着不收敛问题;网络不稳定;网络难训练;读过原论文其实作者也提到过这些问题,包括GAN刚出来的时候,很多人也在致力于解决这些问题,当你实验自己碰到的时候,还是很有意思的。那么这些问题怎么体现的呢,举个例子,可能某一次你会发现训练的误差很小,在下一代训练时,马上又出现极限性的上升的很厉害,过几代又发现训练误差很小,震荡太严重。
  • 其次网络需要调才能出像样的结果。交替迭代次数的不同结果也不一样。比如每一代训练中,D网络训练2回,G网络训练一回,结果就不一样。
  • 这是简单的无条件GAN,所以每一代训练完后,只能出现一个结果,那就是0-9中的某一个数。要想在一代训练中出现好几种结果,就需要使用到条件GAN了。

最后

现在的GAN已经到了五花八门的时候了,各种GAN应用也很多,理解底层原理再慢慢往上层扩展。GAN还是一个很厉害的东西,它使得现有问题从有监督学习慢慢过渡到无监督学习,而无监督学习才是自然界中普遍存在的,因为很多时候没有办法拿到监督信息的。要不Yann Lecun赞叹GAN是机器学习近十年来最有意思的想法。

 

本来是自己写了一些但是,理解的不够透彻,后面学习https://blog.csdn.net/on2way/article/details/72773771,写的太好!

 

 

 

学习https://blog.csdn.net/on2way/article/details/72773771

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值