这篇博客主要是对GAN网络的代码进行一个详细的讲解:

首先是预定义:

clear; clc; %%%clc是清除当前command区域的命令,表示清空,看着舒服些 。而clear用于清空环境变量。两者是不同的。

%%%装载数据集

train_x=load('Normalization_wbc.txt');%train_x就是我们希望GAN网络能够生成与其相似的数据。

[m,n]=size(train_x);%m表示train_x有多少行,n表示有多少列。

%%%定义模型

generator=nnsetup([30,15,30]);%第一个30代表第一层有30个神经元,这是要与train_x的维度相同的,最后一个30也是要与train_x的维度相同。

discriminator=nnsetup([30,15,1]);%第一个30要与生成器的最后一层的神经元个数相同,最后一层是1个神经元,输出的是每个样本来自于真实数据的概率。

%%参数设置

batch_size=m; %batchsize表示一次输入多少样本进行训练,因为我的数据量少,直接全部输入进去就行了。

iteration=100;%迭代多少次,或者说走多少次正向传播。

images_num=m;

batch_num=floor(images_num / batch_size);

learning_rate=0.0001;

其次是根据预定义的网络模型构建神经网络:

function nn=nnsetup(architecture)

nn.architecture= architecture;%%%把预定义的网络结构传递给nn(neuron network)这个结构体

nn.layers_count= numel(nn.architecture);% 计算传递过来的网络结构有多少层

%%%%%%%adam优化器需要设置的参数%%%

nn.t=0;

nn.beta1=0.9;

nn.beta2=0.999;

nn.epsilon=10^(-8);

%%%%%%%%%%%%%%%%%%%%%%%

for  i=2:nn.layers_count

nn.layers{i}.w=normrnd(0,0.02,nn.architecture(i-1),nn.architecture(i));%normrnd是指生成正态分布的随机数,第一个数字0表示均值为0,第二个数字0.02表示sigma=0.02,第三个值表示生成的维度大小。例如第三与第四的值分别为30,15,则表示生成30*15的矩阵。

nn.layers{i}.b = normrnd(0, 0.02, 1, nn.architecture(i));%生成偏置
        nn.layers{i}.w_m = 0;%好像是跟权重偏置有关的参数,但是都设置为了0,好像没啥意义。
        nn.layers{i}.w_v = 0;
        nn.layers{i}.b_m = 0;
        nn.layers{i}.b_v = 0;

end 

end

第3部分:正向传播

function nn=nnff(nn,x)

        nn.layers{1}.a=x;%%%将数据集x作为输入层

        for i=2:nn.layers_count %%%%nn.layers_count在传入nn时,就已经是网络的层数了

                input=nn.layers{i-1}.a;

                w=nn.layers{i}.w;

                b=nn.layers{i}.b;

                nn.layers{i}.z=input * w +repmat(b,size(input,1),1);

                if i~=nn.layers_count

                        nn.layers{i}.a=relu(nn.layers{i}.z);%%%%如果不是最后一层,就过relu激活函数

                else

                        nn.layers{i}.a=sigmoid(nn.layers{i}.z);

                end

        end

end

第四部分:反向传播,反向传播又分为生成器的反传,判别器的反传

A.判别器的反传

function nn=nnbp_d(nn, y_h, y)

%判别器的输入是生成器的最后一层,输出的数据Fake data 和我们手头有的真实数据train_x,即real data

n=nn.layers_count;

nn.layers{n}.d=delta_sigmoid_cross_entropy(y_h,y); %%%%nn.layers{n}.d表示最后一层的残差

for i=n-1:-1:2%%%n是i的初始值,1是终止值,-1是步长。即从i=n开始,每次都加 -1,即减1,直到i等于1为止.

        d=nn.layers{i+1}.d;

        w=nn.layers{i+1}.w;

        z=nn.layers{i}.z;

        nn.layers{i}.d=d*w' .*delta_relu(z);

end

for i=2:n

        d=nn.layers{i}.d;

        a=nn.layers{i-1}.a;

        nn.layers{i}.dw=a'*d /size(d,1);

        nn.layers{i}.db=mean(d,1);

end

end

第五部分,生成器的反传

function g_net=nnbp_g(g_net,d_net)

        n=g_net.layers_count;

        a=g_net.layers{n}.a;

        g_net.layers{n}.d=d_net.layers{2}.d*d_net.layers{2}.w' .* (a .*(1-a));

        for i=n-1:-1:2

                d=g_net.layers{i+1}.d;

                w=g_net.layers{i+1}.w;

                z=g_net.layers{i}.z;

                g_net.layers{i}.d=d*w' .* delta_relu(z);

        end

        %计算偏导数

        for i=2:n

               d=g_net.layers{i}.d;

                a=g_net.layers{i-1}.a;

                g_net.layers{i}.dw=a'*d/size(d,1); 

                g_net.layers{i}.db=mean(d,1);

        end

end

第六部分,激活函数与损失函数

%%%sigmoid激活函数

function output=sigmoid(x)

        output=1 ./(1+exp(-x));

end

%%%relu激活函数

function output=relu(x)

        output=max(x,0);

end

%%%Leaky_Relu激活函数

function output = Leaky_ReLU(x)
a=2;
if x>=0
    output=x;
else
    output=x/a;
end
end

%%%%损失函数

%relu对x的导数

function output=delta_relu(x)

        output=max(x,0);

        output(output>0)=1;

end

%%%%sigmoid交叉熵损失函数

function result=sigmoid_cross_entropy(logits,labels)

        result=max(logits,0) -logits .*labels +log(1+exp(-abs(logits)));

        result=mean(result);

end

%%%sigmoid交叉熵对logits的导数

function result=delta_sigmoid_cross_entropy(logits, labels)

        temp1=max(logits,0);

        temp1(temp1>0)=1;

        temp2=logits;

        temp2(temp2>0)=-1;

        temp2(temp2<0)=1;

        result=temp1-labels+exp(-abs(logits)) ./ (1+exp(-abs(logits))) .* temp2;

end

第七部分,Adam优化器

%Adam优化器
function nn = nnapplygrade(nn, learning_rate);
    n = nn.layers_count;
    nn.t = nn.t+1;
    beta1 = nn.beta1;
    beta2 = nn.beta2;
    lr = learning_rate * sqrt(1-nn.beta2^nn.t) / (1-nn.beta1^nn.t);
    for i = 2:n
        dw = nn.layers{i}.dw;
        db = nn.layers{i}.db;
        %使用adam更新权重与偏置
        nn.layers{i}.w_m = beta1 * nn.layers{i}.w_m + (1-beta1) * dw;
        nn.layers{i}.w_v = beta2 * nn.layers{i}.w_v + (1-beta2) * (dw.*dw);
        nn.layers{i}.w = nn.layers{i}.w -lr * nn.layers{i}.w_m ./ (sqrt(nn.layers{i}.w_v) + nn.epsilon);
        nn.layers{i}.b_m = beta1 * nn.layers{i}.b_m + (1-beta1) * db;
        nn.layers{i}.b_v = beta2 * nn.layers{i}.b_v + (1-beta2) * (db .* db);
        nn.layers{i}.b = nn.layers{i}.b -lr * nn.layers{i}.b_m ./ (sqrt(nn.layers{i}.b_v) + nn.epsilon);        
    end
    
end

第八部分, 上正餐,开始训练GAN。

for i=1:iteration

        kk=randperm(images_num);

        images_real=train_x;

        noise=unifrnd(0,1,m,30);

        generator=nnff(generator,noise);

        images_fake=generator.layers{generator.layers_count}.a;

        discriminator=nnff(discriminator,images_fake);

        logits_fake=discriminator.layers{discriminator.layers_count}.z;

        discriminator=nnbp_d(discriminator, logits_fake, ones(batch_size,1));

        generator= nnbp_g(generator, discriminator);

        generator=nnbp_g(generator, discriminator);

        generator=nnapplygrade(generator,learning_rate);

        %%%%%%%开始更新判别器

        generator=nnff(generator,noise);

        images_fake=generator.layers{generator.layers_count}.a;

        images=[images_fake;images_real];

        discriminator=nnff(discriminator,images);

        logits=discriminator.layers{discriminator.layers_count}.z;

        logits = discriminator.layers{discriminator.layers_count}.z;
    labels = [zeros(batch_size,1); ones(batch_size,1)];%预定义一个标签,前面的数据是0,后面的是1,也进行了拼接。
    discriminator = nnbp_d(discriminator, logits, labels);%logits与真实的标签进行对比,注意与第29行代码进行对比。
    discriminator = nnapplygrade(discriminator, learning_rate);%更新了辨别器网络的权重。
    
    %----输出loss损失
    c_loss(i,:) = sigmoid_cross_entropy(logits(1:batch_size), ones(batch_size,1));%这是生成器的损失
    d_loss (i,:)= sigmoid_cross_entropy(logits, labels);%判别器的损失

end

Logo

科技之力与好奇之心,共建有温度的智能世界

更多推荐