主要内容

训练生成对抗网络(GAN)

这个例子展示了如何训练生成式对抗网络(GAN)来生成图像。

生成式对抗网络(generative adversarial network, GAN)是一种深度学习网络,能够生成与输入真实数据具有相似特征的数据。

GAN由两个一起训练的网络组成:

  1. 生成器——给定一个随机值向量(潜在输入)作为输入,该网络生成与训练数据相同结构的数据。

  2. 鉴别器——给定一批包含训练数据和生成器生成数据的观测数据,该网络试图将这些观测数据分类为“真实”或“生成”。

为了训练一个GAN,需要同时训练两个网络,使两个网络的性能最大化:

  • 训练生成器生成“骗过”鉴别器的数据。

  • 训练鉴别器区分真实数据和生成数据。

为了优化发生器的性能,当给定生成的数据时,最大限度地减少鉴别器的损失。也就是说,生成器的目标是生成鉴别器分类为“真实”的数据。

为了优化鉴别器的性能,当给定几批真实数据和生成数据时,尽量减少鉴别器的损失。也就是说,鉴别器的目的是不被生成器“愚弄”。

理想情况下,这些策略会产生一个生成令人信服的真实数据的生成器,以及一个学习了训练数据特征的强特征表示的鉴别器。

负荷训练数据

下载并提取数据集[1]。

url =“http://download.tensorflow.org/example_images/flower_photos.tgz”;downloadFolder = tempdir;文件名= fullfile (downloadFolder,“flower_dataset.tgz”);imageFolder = fullfile (downloadFolder,“flower_photos”);如果~存在(imageFolder“dir”) disp (下载花卉数据集(218mb)…) websave(文件名,url);解压(文件名,downloadFolder)结束

创建一个包含鲜花照片的图像数据存储。

datasetFolder = fullfile (imageFolder);imd = imageDatastore (datasetFolder,...“IncludeSubfolders”,真正的);

增加数据以包括随机水平翻转,并将图像大小调整为64 * 64。

增量= imageDataAugmenter (“RandXReflection”,真正的);augimds = augmentedImageDatastore([64 64],imds,“DataAugmentation”、增压器);

定义发电机网络

定义以下网络架构,由1 × 1 × 100的随机值数组生成图像:

这个网络:

  • 将1 × 1 × 100数组的噪声转换为7 × 7 × 128数组使用项目和重塑层。

  • 使用一系列带有批处理归一化和ReLU层的转置卷积层将得到的数组升级为64 × 64 × 3数组。

将此网络架构定义为一个层图,并指定以下网络属性。

  • 对于转置卷积层,指定5 × 5滤波器,每个层的滤波器数量减少,步幅为2,并裁剪每个边缘的输出。

  • 对于最终的转置卷积层,指定生成图像的三个RGB通道对应的三个5 × 5滤波器,以及前一层的输出尺寸。

  • 在网络的末端,包括一个tanh层。

要投射和重塑噪声输入,使用自定义层projectAndReshapeLayer,作为支持文件附加到本示例中。金宝app的projectAndReshapeLayer层使用完全连接的操作放大输入,并将输出重塑为指定的大小。

filterSize = 5;numFilters = 64;numLatentInputs = 100;projectionSize = [4 4 512];layersGenerator = [imageInputLayer([1 1 numLatentInputs],“归一化”“没有”“名字”“在”) projectAndReshapeLayer (projectionSize numLatentInputs,“项目”);transposedConv2dLayer (filterSize 4 * numFilters,“名字”“tconv1”) batchNormalizationLayer (“名字”“bnorm1”) reluLayer (“名字”“relu1”) transposedConv2dLayer (2 * numFilters filterSize,“步”2,“种植”“相同”“名字”“tconv2”) batchNormalizationLayer (“名字”“bnorm2”) reluLayer (“名字”“relu2”) transposedConv2dLayer (filterSize numFilters,“步”2,“种植”“相同”“名字”“tconv3”) batchNormalizationLayer (“名字”“bnorm3”) reluLayer (“名字”“relu3”) transposedConv2dLayer (filterSize 3“步”2,“种植”“相同”“名字”“tconv4”) tanhLayer (“名字”的双曲正切));lgraphGenerator = layerGraph (layersGenerator);

为了使用自定义的训练循环来训练网络并使其能够自动区分,将层图转换为dlnetwork对象。

dlnetGenerator = dlnetwork (lgraphGenerator);

定义鉴别器网络

定义下面的网络,它对真实的和生成的64 × 64图像进行分类。

创建一个网络,它接收64 × 64 × 3的图像,并使用一系列带有批处理归一化和泄漏ReLU层的卷积层返回标量预测评分。使用dropout为输入图像添加噪声。

  • 对于退出层,指定退出概率为0.5。

  • 对于卷积层,指定5 × 5滤波器,并为每个层增加滤波器的数量。还要指定步幅为2和输出的填充。

  • 对于泄漏的ReLU层,指定一个0.2的刻度。

  • 对于最后一层,指定一个带有4 × 4过滤器的卷积层。

要输出范围[0,1]的概率,使用乙状结肠功能模型梯度函数

dropoutProb = 0.5;numFilters = 64;规模= 0.2;inputSize = [64 64 3];filterSize = 5;layersDiscriminator = [imageInputLayer(inputSize,“归一化”“没有”“名字”“在”) dropoutLayer (0.5,“名字”“辍学”) convolution2dLayer (filterSize numFilters,“步”2,“填充”“相同”“名字”“conv1”) leakyReluLayer(规模、“名字”“lrelu1”) convolution2dLayer (2 * numFilters filterSize,“步”2,“填充”“相同”“名字”“conv2”) batchNormalizationLayer (“名字”“bn2”) leakyReluLayer(规模、“名字”“lrelu2”) convolution2dLayer (filterSize 4 * numFilters,“步”2,“填充”“相同”“名字”“conv3”) batchNormalizationLayer (“名字”“bn3”) leakyReluLayer(规模、“名字”“lrelu3”) convolution2dLayer (filterSize 8 * numFilters,“步”2,“填充”“相同”“名字”“conv4”) batchNormalizationLayer (“名字”“bn4”) leakyReluLayer(规模、“名字”“lrelu4”1) convolution2dLayer(4日,“名字”“conv5”));lgraphDiscriminator = layerGraph (layersDiscriminator);

为了使用自定义的训练循环来训练网络并使其能够自动区分,将层图转换为dlnetwork对象。

dlnetDiscriminator = dlnetwork (lgraphDiscriminator);

定义模型梯度,损失函数和分数

创建函数modelGradients,列于模型梯度函数它以生成器和鉴别器网络、一小批输入数据、随机值数组和翻转因子作为输入,并返回相对于网络中的可学习参数的损失梯度和两个网络的分数。

指定培训选项

500个纪元的128个小批量列车。对于更大的数据集,您可能不需要训练那么多的纪元。

numEpochs = 500;miniBatchSize = 128;

指定Adam优化的选项。对于两个网络,指定

  • 学习率为0.0002

  • 梯度衰减系数为0.5

  • 平方梯度衰减因子为0.999

learnRate = 0.0002;gradientDecayFactor = 0.5;squaredGradientDecayFactor = 0.999;

如果鉴别器学习区分真实的和生成的图像太快,那么生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,可以通过随机翻转标签给真实数据添加噪声。

指定翻转30%的真实标签。这意味着15%的标签在培训期间被翻转。注意,这不会影响生成器,因为所有生成的图像仍然是正确的。

flipFactor = 0.3;

每100次迭代显示生成的验证图像。

validationFrequency = 100;

火车模型

使用minibatchqueue处理和管理小批量图像。为每个mini-batch:

  • 使用自定义小批量预处理功能preprocessMiniBatch(在本例的最后定义)在范围内重新缩放图像[1]

  • 丢弃任何小于128个观测值的部分小批。

  • 使用尺寸标签格式化图像数据“SSCB”(spatial, spatial, channel, batch)。默认情况下,minibatchqueue对象将数据转换为dlarray具有底层类型的对象

  • 在可用的GPU上进行训练。当“OutputEnvironment”选择minibatchqueue“汽车”minibatchqueue将每个输出转换为gpuArray如果有可用的GPU。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU,其计算能力为3.0或更高。

augimds。MiniBatchSize = MiniBatchSize;executionEnvironment =“汽车”;兆贝可= minibatchqueue (augimds,...“MiniBatchSize”miniBatchSize,...“PartialMiniBatch”“丢弃”...“MiniBatchFcn”@preprocessMiniBatch,...“MiniBatchFormat”“SSCB”...“OutputEnvironment”, executionEnvironment);

使用自定义训练循环训练模型。在每次迭代时循环训练数据并更新网络参数。为了监控训练进程,使用随机值的固定数组以及得分图来显示生成的一批图像。

初始化Adam的参数。

trailingAvgGenerator = [];trailingAvgSqGenerator = [];trailingAvgDiscriminator = [];trailingAvgSqDiscriminator = [];

为了监控训练进展,使用输入到生成器中的固定数组的随机值来显示生成的一批图像,并绘制网络分数。

创建一个保留的随机值数组。

numValidationImages = 25;ZValidation = randn (1, 1, numLatentInputs numValidationImages,“单一”);

将数据转换为dlarray对象并指定维度标签“SSCB”(spatial, spatial, channel, batch)。

dlZValidation = dlarray (ZValidation,“SSCB”);

对于GPU训练,将数据转换为gpuArray对象。

如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZValidation = gpuArray (dlZValidation);结束

初始化训练进度图。创建一个图形,并将其大小调整为两倍的宽度。

f =图;f.Position (3) = 2 * f.Position (3);

为生成的图像和网络分数创建子图。

imageAxes =情节(1、2、1);scoreAxes =情节(1、2、2);

初始化分数图的动画行。

lineScoreGenerator = animatedline (scoreAxes,“颜色”0.447 - 0.741 [0]);lineScoreDiscriminator = animatedline (scoreAxes,“颜色”, [0.85 0.325 0.098]);传奇(“发电机”鉴频器的);ylim([0 1])包含(“迭代”) ylabel (“分数”网格)

训练甘。对于每个epoch,洗牌数据存储并循环小批数据。

为每个mini-batch:

  • 使用dlfevalmodelGradients函数。

  • 使用adamupdate函数。

  • 画出两个网络的比分。

  • 在每一个validationFrequency迭代,显示一批生成的图像为固定的保留发生器输入。

跑步训练可能需要一些时间。

迭代= 0;开始=抽搐;%循环纪元。时代= 1:numEpochs重置和洗牌数据存储。洗牌(兆贝可);%循环小批。Hasdata (mbq) iteration = iteration + 1;%读取小批数据。dlX =下一个(兆贝可);为发电机网络产生潜在的输入。转换为% dlarray,并指定尺寸标签'SSCB'(空间,%空间,通道,批处理)。如果训练在GPU上,然后转换%潜在输入到gpuArray。Z = randn (1, - 1, numLatentInputs大小(dlX, 4),“单一”);dlZ = dlarray (Z,“SSCB”);如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray (dlZ);结束%评估模型梯度和生成器状态使用的% dlfeval和模型梯度函数%的例子。[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...dlfeval(@modelGradients, dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor);dlnetGenerator。状态= stateGenerator;%更新标识器网络参数。[dlnetDiscriminator, trailingAvgDiscriminator trailingAvgSqDiscriminator] =...adamupdate (dlnetDiscriminator gradientsDiscriminator,...trailingAvgDiscriminator trailingAvgSqDiscriminator,迭代,...learnRate、gradientDecayFactor squaredGradientDecayFactor);%更新生成器网络参数。[dlnetGenerator, trailingAvgGenerator trailingAvgSqGenerator] =...adamupdate (dlnetGenerator gradientsGenerator,...trailingAvgGenerator trailingAvgSqGenerator,迭代,...learnRate、gradientDecayFactor squaredGradientDecayFactor);%每次validationFrequency迭代,使用%保留发电机输入如果mod(iteration,validationFrequency) == 0 || iteration == 1%生成图像使用保留发生器输入。dlXGeneratedValidation =预测(dlnetGenerator dlZValidation);在[0 1]范围内平铺并重新缩放图像。我= imtile (extractdata (dlXGeneratedValidation));I =重新调节(我);%显示图像。次要情节(1、2、1);图像(imageAxes,我)xticklabels ([]);yticklabels ([]);标题(“生成的图像”);结束%更新分数图次要情节(1、2、2)addpoints (lineScoreGenerator,迭代,...双(收集(extractdata (scoreGenerator))));addpoints (lineScoreDiscriminator迭代,...双(收集(extractdata (scoreDiscriminator))));%用培训进度信息更新标题。D =持续时间(0,0,toc(开始),“格式”“hh: mm: ss”);标题(...”时代:“+时代+”、“+...“迭代:“+迭代+”、“+...”经过:“+ drawnow字符串(D))结束结束

这里,鉴别器学习了一种强大的特征表示,可以在生成的图像中识别出真实的图像。反过来,生成器也学习了一种类似的强特性表示,它可以生成看起来真实的数据。

训练图显示了生成器和鉴别器网络的得分。要了解更多关于如何解释网络分数,请看监控GAN培训进度,识别常见故障模式

生成新的图片

要生成新的图像,请使用预测函数在生成器上使用dlarray对象,该对象包含一批1 × 1 × 100的随机值数组。要同时显示图像,请使用imtile函数并使用重新调节函数。

创建一个dlarray对象,该对象包含25个1 × 1 × 100的随机值数组,以输入到生成器网络。

ZNew = randn (1, 1, numLatentInputs, 25岁,“单一”);dlZNew = dlarray (ZNew,“SSCB”);

要使用GPU生成图像,还需要将数据转换为gpuArray对象。

如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZNew = gpuArray (dlZNew);结束

生成新的图像使用预测函数的生成器和输入数据。

dlXGeneratedNew =预测(dlnetGenerator dlZNew);

显示图像。

我= imtile (extractdata (dlXGeneratedNew));I =重新调节(我);数字图像(I)轴标题(“生成的图像”

模型梯度函数

这个函数modelGradients将生成器和鉴别器作为输入dlnetwork对象dlnetGeneratordlnetDiscriminator,输入数据的一小批dlX,一个随机值数组dlZ以及实际标签翻转的百分比flipFactor,并返回损失相对于网络中可学习参数、生成器状态和两个网络的分数的梯度。因为鉴别器输出不在[0,1]范围内,modelGradients应用s型函数将其转换为概率。

函数[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...模型梯度(dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor)%用鉴别器网络计算真实数据的预测。dlYPred = forward(dlnetDiscriminator, dlX);%用鉴别器网络计算生成数据的预测。向前(dlXGenerated stateGenerator] = (dlnetGenerator, dlZ);dlYPredGenerated = forward(dlnetDiscriminator, dlXGenerated);%将鉴别器输出转换为概率。probGenerated =乙状结肠(dlYPredGenerated);probReal =乙状结肠(dlYPred);%计算鉴别器的得分。scoreDiscriminator =((意思(probReal) + (1-probGenerated)) / 2);%计算生成器的得分。scoreGenerator =意味着(probGenerated);%随机翻转真实图像的一部分标签。numObservations =大小(probReal 4);idx = randperm(numObservations,floor(flipFactor * numObservations));%翻转标签probReal (:,:,:, idx) = 1-probReal (:,:,:, idx);%计算氮化镓损耗。[lossGenerator, lossDiscriminator] = ganLoss(probReal,probGenerated);%对于每个网络,计算相对于损失的梯度。gradientsGenerator = dlgradient(lossGenerator, dlnetGenerator。可学的,“RetainData”,真正的);gradientsDiscriminator = dlgradient(lossDiscriminator, dlnetDiscriminator.Learnables);结束

GAN损失函数和分数

生成器的目标是生成鉴别器分类为“真实”的数据。为了最大限度地提高来自发生器的图像被鉴别器分类为真实图像的概率,最小化负对数似然函数。

考虑到输出 Y 鉴频器:

  • Y ˆ σ Y 为输入图像属于“实数”类的概率。

  • 1 - Y ˆ 为输入图像属于“生成”类的概率。

注意乙状体运算 σ 发生在modelGradients函数。发电机的损耗函数为

lossGenerator - 的意思是 日志 Y ˆ 生成的

在哪里 Y ˆ G e n e r 一个 t e d 包含生成图像的鉴别器输出概率。

鉴别器的目的是不被生成器“愚弄”。为了最大限度地提高鉴别器在真实图像和生成图像之间成功鉴别的概率,最小化相应的负对数似然函数的和。

给出了该鉴别器的损失函数

lossDiscriminator - 的意思是 日志 Y ˆ 真正的 - 的意思是 日志 1 - Y ˆ 生成的

在哪里 Y ˆ R e 一个 l 包含真实图像的鉴别器输出概率。

要在0到1的范围内衡量生成器和鉴别器实现各自目标的程度,你可以使用分数的概念。

生成器得分是生成图像的鉴别器输出对应的概率的平均值:

scoreGenerator 的意思是 Y ˆ 生成的

鉴别器得分是对真实图像和生成图像的鉴别器输出对应的概率的平均值:

scoreDiscriminator 1 2 的意思是 Y ˆ 真正的 + 1 2 的意思是 1 - Y ˆ 生成的

分数与损失成反比,但实际上包含相同的信息。

函数[lossGenerator, lossDiscriminator] = ganLoss(probReal,probGenerated)%计算鉴别器网络的损耗。lossDiscriminator = -mean(log(probReal)) -mean(log(1-probGenerated));%计算发电机网络的损耗。lossGenerator =意味着(日志(probGenerated));结束

Mini-Batch预处理功能

preprocessMiniBatch函数使用以下步骤对数据进行预处理:

  1. 从传入的单元格数组中提取图像数据并连接到一个数字数组中。

  2. 重新调整图像的范围[1]

函数X = preprocessMiniBatch(数据)%连接mini-batchX =猫(4、数据{:});%在[-1 1]范围内重新缩放图像。X =重新调节(X, 1, 1,“InputMin”0,“InputMax”, 255);结束

参考文献

  1. TensorFlow团队。http://download.tensorflow.org/example_images/flower_photos.tgz

  2. 雷德福,亚历克,卢克·梅茨,和苏史密斯·钦塔拉。基于深度卷积生成对抗网络的无监督表示学习arXiv预印本arXiv: 1511.06434(2015)。

另请参阅

|||||||

相关的话题