基于深度卷积生成对抗网络(DCGAN)的图像生成模型 matlab代码,要求2019b及以上版本

最近在研究图像生成,发现深度卷积生成对抗网络(DCGAN)真的是个挺有意思的东西。简单来说,DCGAN就是通过两个神经网络互相“打架”来生成逼真的图像。一个叫生成器(Generator),负责生成假图像;另一个叫判别器(Discriminator),负责判断图像是真是假。两者不断博弈,最终生成器就能生成越来越逼真的图像。

今天就来用Matlab实现一个简单的DCGAN模型,顺便聊聊代码里的一些细节。Matlab的版本要求是2019b及以上,毕竟有些函数和特性在旧版本里是没有的。

1. 数据准备

首先,我们需要一些训练数据。假设我们用的是MNIST手写数字数据集。Matlab里可以直接加载这个数据集:

digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos','nndatasets','DigitDataset');
imds = imageDatastore(digitDatasetPath, 'IncludeSubfolders', true, 'LabelSource', 'foldernames');

imageDatastore 是Matlab里用来处理图像数据的一个很好用的工具,支持批量读取和预处理。

2. 定义生成器

生成器的任务是接收一个随机噪声向量,输出一张图像。这里我们用一个简单的卷积神经网络来实现:

layersGenerator = [
    imageInputLayer([1 1 100], 'Normalization', 'none', 'Name', 'in')
    transposedConv2dLayer([7 7], 512, 'Name', 'tconv1')
    reluLayer('Name', 'relu1')
    transposedConv2dLayer([3 3], 256, 'Stride', 2, 'Cropping', 'same', 'Name', 'tconv2')
    reluLayer('Name', 'relu2')
    transposedConv2dLayer([3 3], 128, 'Stride', 2, 'Cropping', 'same', 'Name', 'tconv3')
    reluLayer('Name', 'relu3')
    transposedConv2dLayer([3 3], 1, 'Stride', 2, 'Cropping', 'same', 'Name', 'tconv4')
    tanhLayer('Name', 'tanh')
];

generator = dlnetwork(layersGenerator);

这里用了transposedConv2dLayer来实现反卷积操作,也就是上采样。最终输出的图像大小是28x28,和MNIST数据集里的图像大小一致。

3. 定义判别器

判别器的任务是判断输入的图像是真实的还是生成的。同样用一个卷积神经网络来实现:

layersDiscriminator = [
    imageInputLayer([28 28 1], 'Normalization', 'none', 'Name', 'in')
    convolution2dLayer([3 3], 128, 'Stride', 2, 'Padding', 'same', 'Name', 'conv1')
    leakyReluLayer(0.2, 'Name', 'leakyRelu1')
    convolution2dLayer([3 3], 256, 'Stride', 2, 'Padding', 'same', 'Name', 'conv2')
    leakyReluLayer(0.2, 'Name', 'leakyRelu2')
    convolution2dLayer([3 3], 512, 'Stride', 2, 'Padding', 'same', 'Name', 'conv3')
    leakyReluLayer(0.2, 'Name', 'leakyRelu3')
    convolution2dLayer([3 3], 1, 'Name', 'conv4')
    sigmoidLayer('Name', 'sigmoid')
];

discriminator = dlnetwork(layersDiscriminator);

判别器最后用了一个sigmoidLayer,输出一个0到1之间的值,表示图像为真的概率。

4. 训练过程

训练DCGAN的过程就是让生成器和判别器不断博弈。每次迭代,我们都会更新生成器和判别器的参数:

numEpochs = 50;
miniBatchSize = 128;

for epoch = 1:numEpochs
    while hasdata(imds)
        % 读取一批真实图像
        X = read(imds);
        X = cat(4, X{:});
        X = single(X) / 255 * 2 - 1; % 归一化到[-1, 1]
        
        % 生成一批随机噪声
        Z = randn(1, 1, 100, miniBatchSize, 'single');
        
        % 生成假图像
        X_fake = forward(generator, Z);
        
        % 更新判别器
        dloss = dlfeval(@discriminatorLoss, discriminator, X, X_fake);
        discriminator = dlupdate(@adamupdate, discriminator, dloss);
        
        % 更新生成器
        gloss = dlfeval(@generatorLoss, generator, discriminator, Z);
        generator = dlupdate(@adamupdate, generator, gloss);
    end
    reset(imds);
end

这里用了dlfevaldlupdate来实现自动求导和参数更新。adamupdate是Adam优化器的实现,适合用来训练GAN。

5. 损失函数

判别器的损失函数包括两部分:一部分是判断真实图像为真的损失,另一部分是判断生成图像为假的损失:

function dloss = discriminatorLoss(discriminator, X_real, X_fake)
    Y_real = forward(discriminator, X_real);
    Y_fake = forward(discriminator, X_fake);
    dloss = -mean(log(Y_real) + log(1 - Y_fake));
end

生成器的损失函数则是让生成的图像被判别器判断为真:

function gloss = generatorLoss(generator, discriminator, Z)
    X_fake = forward(generator, Z);
    Y_fake = forward(discriminator, X_fake);
    gloss = -mean(log(Y_fake));
end

6. 生成图像

训练完成后,我们就可以用生成器来生成一些图像了:

Z = randn(1, 1, 100, 10, 'single');
X_fake = forward(generator, Z);
imshow(imtile(extractdata(X_fake), 'GridSize', [2 5]));

imtile 是Matlab里用来拼接多张图像的工具,方便我们查看生成结果。

7. 总结

DCGAN的实现其实并不复杂,关键是要理解生成器和判别器的博弈过程。通过不断调整网络结构和训练参数,我们可以生成越来越逼真的图像。当然,DCGAN还有很多改进的空间,比如加入更多的卷积层、使用不同的损失函数等等。有兴趣的同学可以继续深入研究。

代码就写到这里,希望对大家有所帮助。如果你有更好的想法或者发现代码中的问题,欢迎在评论区讨论!

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐