主要内容

训练条件生成对抗网络(CGAN)

这个例子展示了如何训练一个条件生成对抗网络来生成图像。

生成式对抗网络(GAN)是一种深度学习网络,它可以生成与输入训练数据具有相似特征的数据。

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

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

  2. 判别器-给定的数据批次包含来自训练数据的观察结果,以及来自生成器的生成数据,该网络试图将观察结果分类为“真正的”“生成”

一个有条件的生成对抗网络(CGAN)是一种GAN,它在训练过程中也利用了标签。

  1. 生成器——给定一个标签和随机数组作为输入,该网络生成的数据具有与相同标签对应的训练数据观察相同的结构。

  2. 判别器——给定的批标记数据包含来自训练数据和生成器生成的数据的观察结果,该网络试图将观察结果分类为“真正的”“生成”

为了训练一个有条件的GAN,同时训练两个网络以最大化两者的性能:

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

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

为了使生成器的性能最大化,在给定生成的标记数据时,使鉴别器的损失最大化。也就是说,生成器的目标是生成标识器分类的标记数据“真正的”

为了最大化鉴别器的性能,在给定真实和生成的标记数据批次时,最小化鉴别器的损失。也就是说,鉴别器的目标是不被生成器“愚弄”。

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

负荷训练数据

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

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

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

datasetFolder = fullfile(imageFolder);imds = imageDatastore(datasetFolder, inclesubfolders =true,LabelSource=“foldernames”);

查看类的个数。

classes = categories(imds.Labels);numClasses = numel(类)
numClasses = 5

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

augmenter = imageDataAugmenter(RandXReflection=true);augimds = augmentedImageDatastore([64 64],imds,DataAugmentation=augmenter);

定义发电机网络

定义以下双输入网络,它生成给定大小为100的随机向量和相应的标签的图像。

这个网络:

  • 使用全连接层将大小为100的随机向量转换为4 × 4 × 1024数组,然后执行重塑操作。

  • 将类别标签转换为嵌入向量,并将它们重新塑造为4 × 4数组。

  • 沿着通道维度连接来自两个输入的结果图像。输出是一个4 × 4 × 1025的数组。

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

将此网络体系结构定义为层图,并指定以下网络属性。

  • 对于分类输入,使用50的嵌入维数。

  • 对于转置卷积层,指定5 × 5滤波器,每层滤波器数量递减,步幅为2,和“相同”对输出进行裁剪。

  • 对于最后的转置卷积层,指定三个5乘5滤波器,对应于生成图像的三个RGB通道。

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

要投影和重塑噪声输入,请使用一个完全连接层,然后使用函数层指定的重塑操作feature2image函数,作为支持文件附加到本示例中。万博1manbetx要嵌入分类标签,请使用自定义层embeddingLayer作为支持文件附在本示例中。万博1manbetx要访问这些支持文件,请将示例作为万博1manbetx活动脚本打开。

numLatentInputs = 100;embeddingDimension = 50;numFilters = 64;filterSize = 5;projectionSize = [4 4 1024];layersGenerator = [featureInputLayer(numLatentInputs) fullyConnectedLayer(prod(projectionSize)) functionLayer(@(X) feature2image(X,projectionSize), formatable =true) concatenationLayer(3,2,Name=“猫”);转置conv2dlayer (filterSize,2*numFilters,Stride=2,裁剪= .“相同”) batchNormalizationLayer reluLayer转置conv2dlayer (filterSize,numFilters,Stride=2,裁剪=“相同”) batchNormalizationLayer relullayer转置conv2dlayer (filterSize,3,Stride=2,裁剪=“相同”) tanhLayer);lgraphGenerator = layerGraph(layergenerator);layers = [featureInputLayer(1) embeddingLayer(embeddingDimension,numClasses) fullyConnectedLayer(prod(projectionSize(1:2))) functionLayer(@(X) feature2image(X,[projectionSize(1:2) 1]),Formattable=true,Name=“emb_reshape”));lgraphGenerator = addLayers(lgraphGenerator,layers);lgraphGenerator = connectLayers(lgraphGenerator,“emb_reshape”“猫/ in2”);

要使用自定义训练循环训练网络并启用自动区分,请将层图转换为adlnetwork对象。

netG = dlnetwork(lgraphGenerator)
dlnetGenerator = dlnetwork with properties: Layers: [19×1 nnet.cnn.layer.Layer] Connections: [18×2 table] Learnables: [19×3 table] State: [6×3 table] InputNames: {'input' 'input_1'} OutputNames: {'layer_2'} Initialized: 1 .初始化

定义鉴别器网络

定义以下双输入网络,给出一组图像和相应的标签,对真实的和生成的64 × 64图像进行分类。

创建一个网络,将64 × 64 × 1图像和相应的标签作为输入,并使用一系列具有批处理归一化和泄漏ReLU层的卷积层输出标量预测分数。使用dropout为输入图像添加噪声。

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

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

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

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

dropoutProb = 0.75;numFilters = 64;量表= 0.2;inputSize = [64 64 3];filterSize = 5;layersDiscriminator = [imageInputLayer(inputSize,归一化=“没有”) dropoutLayer(dropoutProb) concatenationLayer(3,2,Name=“猫”) convolution2dLayer (filterSize numFilters,跨步= 2,填充=“相同”) leakyReluLayer(scale) convolution2dLayer(filterSize,2*numFilters,Stride=2,Padding=“相同”) batchNormalizationLayer leakyReluLayer(scale) convolution2dLayer(filterSize,4*numFilters,Stride=2,Padding=“相同”) batchNormalizationLayer leakyReluLayer(scale) convolution2dLayer(filterSize,8*numFilters,Stride=2,Padding=“相同”) batchNormalizationLayer leakyReluLayer(scale) convolution2dLayer(4,1)];lgraphDiscriminator = layerGraph(layersDiscriminator);layers = [featureInputLayer(1) embeddingLayer(embeddingDimension,numClasses) fullyConnectedLayer(prod(inputSize(1:2))) functionLayer(@(X) feature2image(X,[inputSize(1:2) 1]), formatable =true,Name=“emb_reshape”));lgraphDiscriminator = addLayers(lgraphDiscriminator,layers);lgraphDiscriminator = connectLayers(lgraphDiscriminator,“emb_reshape”“猫/ in2”);

要使用自定义训练循环训练网络并启用自动区分,请将层图转换为adlnetwork对象。

netD = dlnetwork(lgraphDiscriminator)
dlnetDiscriminator = dlnetwork with properties: Layers: [19×1 nnet.cnn.layer.Layer] Connections: [18×2 table] Learnables: [19×3 table] State: [6×3 table] InputNames: {'imageinput' 'input'} OutputNames: {'conv_5'} Initialized: 1 .初始化

定义模型损失函数

创建函数modelLoss,列于模型损失函数部分,该示例将生成器和鉴别器网络、一小批输入数据和一组随机值作为输入,并返回相对于网络中的可学习参数和一组生成的图像的损失梯度。

指定培训项目

使用500个epoch的128个小批量进行训练。

numEpochs = 500;miniBatchSize = 128;

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

  • 学习率为0.0002

  • 梯度衰减因子为0.5

  • 平方梯度衰减因子为0.999

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

每100次迭代更新一次训练进度图。

validationFrequency = 100;

如果鉴别器学习区分真实图像和生成图像的速度太快,那么生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,随机翻转一部分真实图像的标签。指定翻转因子为0.5。

flipFactor = 0.5;

火车模型

使用自定义训练循环训练模型。遍历训练数据并在每次迭代中更新网络参数。为了监控训练进度,使用输入到生成器的随机值数组和网络分数显示一批生成的图像。

使用minibatchqueue在训练过程中处理和管理小批量图像。对于每个小批量:

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

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

  • 用尺寸标签格式化图像数据“SSCB”(空间,空间,通道,批次)。

  • 使用尺寸标签格式化标签数据“公元前”(批处理、通道)。

  • 如果有GPU,可以在GPU上进行训练。当OutputEnvironment选择minibatchqueue“汽车”minibatchqueue将每个输出转换为gpuArray如果GPU可用。使用GPU需要并行计算工具箱™和受支持的GPU设备。万博1manbetx有关受支持设备的信息,请参见万博1manbetxGPU计算要求(并行计算工具箱)

minibatchqueue对象默认情况下,将数据转换为dlarray具有基础类型的对象

augimds。MiniBatchSize = MiniBatchSize;executionEnvironment =“汽车”;MBQ = minibatchqueue(增加,...MiniBatchSize = MiniBatchSize,...PartialMiniBatch =“丢弃”...MiniBatchFcn = @preprocessData,...MiniBatchFormat = [“SSCB”“公元前”),...OutputEnvironment = executionEnvironment);

初始化Adam优化器的参数。

velocityD = [];trailingAvgG = [];trailingAvgSqG = [];trailingAvgD = [];trailingAvgSqD = [];

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

F =数字;f.Position(3) = 2*f.Position(3);

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

imageAxes = subplot(1,2,1);scoreAxes = subplot(1,2,2);

初始化分数图的动画线条。

lineScoreGenerator = animatedline(scoreAxes,Color=[0 0.447 0.741]);lineScoreDiscriminator = animatedline(scoreAxes,Color=[0.85 0.325 0.098]);

自定义图的外观。

传奇(“发电机”“鉴频器”);Ylim ([0 1]) xlabel(“迭代”) ylabel (“分数”网格)

为了监控训练进度,创建一个包含25个随机向量的保留批和一组对应的标签1到5(对应于重复5次的类)。

numValidationImagesPerClass = 5;ZValidation = randn(numLatentInputs,numValidationImagesPerClass*numClasses,“单身”);TValidation = single(repmat(1:numClasses,[1 numValidationImagesPerClass]));

将数据转换为dlarray对象,并指定维度标签“CB”(频道,批处理)。

ZValidation = dlarray(ZValidation,“CB”);TValidation = dlarray(TValidation,“CB”);

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

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

训练有条件GAN。对于每个纪元,洗牌数据并在小批量数据上循环。

对于每个小批量:

  • 评估损失的梯度相对于可学习参数,发电机状态,和网络得分使用dlfevalmodelLoss函数。

  • 方法更新网络参数adamupdate函数。

  • 绘制两家电视台的得分图。

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

跑步训练需要一些时间。

迭代= 0;开始= tic;%遍历epoch。epoch = 1:numEpochs重置和洗牌数据。洗牌(兆贝可);在小批上循环。Hasdata (mbq)迭代=迭代+ 1;读取小批数据。[X,T] = next(mbq);为发电机网络生成潜在输入。转换为% darray,并指定尺寸标签“CB”(通道,批)。%如果在GPU上训练,则将潜在输入转换为gpuArray。Z = randn(numLatentInputs,miniBatchSize,“单身”);Z = dlarray(Z,“CB”);如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”Z = gpuArray(Z);结束相对于可学习的知识,评估损失的梯度%参数,生成器状态和使用的网络分数% dlfeval和modelLoss函数。[~, ~, gradientsG、gradientsD stateG, scoreG,得分)=...dlfeval (@modelLoss netG,经济技术开发区X, T, Z, flipFactor);netG。State = stateG;更新鉴别器网络参数。[netD,trailingAvgD,trailingAvgSqD] = adamupdate(netD, gradientsD,...trailingAvgD, trailingAvgSqD,迭代,...learnRate, gradientDecayFactor, squaredGradientDecayFactor);更新发电机网络参数。[netG, trailingAvgG trailingAvgSqG] =...adamupdate (netG gradientsG,...trailingAvgG, trailingAvgSqG,迭代,...learnRate, gradientDecayFactor, squaredGradientDecayFactor);%每次验证频率迭代,显示批生成的图像使用%保留的发电机输入。如果mod(迭代,validationFrequency) == 0 ||迭代== 1使用保留的生成器输入生成图像。XGeneratedValidation = predict(netG,ZValidation,TValidation);平铺和重新缩放范围[0 1]的图像。I = imtile(extractdata(XGeneratedValidation),...GridSize = [numValidationImagesPerClass numClasses]);I = rescale(I);显示图片。次要情节(1、2、1);图像(imageAxes,我)xticklabels ([]);yticklabels ([]);标题(“生成的图像”);结束更新分数图。次要情节(1、2、2)addpoints (lineScoreGenerator、迭代、双(scoreG));addpoints (lineScoreDiscriminator、迭代、双(得分));用培训进度信息更新标题。。D = duration(0,0,toc(start),Format=“hh: mm: ss”);标题(...”时代:“+ epoch +”、“+...“迭代:“+迭代+”、“+...”经过:“+字符串(D))现在绘制结束结束

在这里,鉴别器已经学习了一种强大的特征表示,可以在生成的图像中识别真实图像。反过来,生成器已经学习了一个类似的强特征表示,允许它生成类似于训练数据的图像。每一列对应一个类。

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

生成新图像

要生成特定类的新图像,请使用预测函数在生成器上使用dlarray对象,该对象包含一批随机向量和与所需类对应的标签数组。将数据转换为dlarray对象,并指定维度标签“CB”(频道,批处理)。对于GPU预测,将数据转换为gpuArray对象。要一起显示图像,请使用imtile函数重新缩放图像重新调节函数。

创建一个包含36个随机值的数组,对应于第一个类。

numObservationsNew = 36;idxClass = 1;ZNew = randn(numLatentInputs,numObservationsNew,“单身”);TNew = repmat(single(idxClass),[1 numObservationsNew]);

将数据转换为dlarray具有维度标签的对象“SSCB”(空间,空间,通道,批)。

ZNew = dlarray(ZNew,“CB”);TNew = darray (TNew,“CB”);

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

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

使用预测功能与发电机网络。

XGeneratedNew = predict(netG,ZNew,TNew);

在图中显示生成的图像。

figure I = imtile(extractdata(XGeneratedNew));I = rescale(I);imshow (I)标题(”类:“+类(idxClass))

在这里,生成器网络生成以指定类为条件的图像。

模型损失函数

这个函数modelLoss将生成器和鉴别器作为输入dlnetwork对象netG而且netD,一小批输入数据X,对应的标签T,和一个随机值的数组Z,并返回损失相对于网络中可学习参数、发电机状态和网络分数的梯度。

如果鉴别器学习区分真实图像和生成图像的速度太快,那么生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,随机翻转一部分真实图像的标签。

函数[lossG, lossD gradientsG、gradientsD stateG, scoreG,得分)=...modelLoss (netG,经济技术开发区X, T, Z, flipFactor)用鉴别器网络计算真实数据的预测。。YReal = forward(netD,X,T);用鉴别器网络计算生成数据的预测。[XGenerated,stateG] = forward(netG,Z,T);YGenerated = forward(netD,XGenerated,T);计算概率。probGenerated = sigmoid(YGenerated);probReal = sigmoid(YReal);计算生成器和鉴别器得分。scoreG = mean(probGenerated);scores = (mean(probReal) + mean(1-probGenerated)) / 2;翻转标签。numObservations = size(YReal,4);idx = randperm(numObservations,floor(flipFactor * numObservations));probReal(:,:,:,idx) = 1 - probReal(:,:,:,idx);计算GAN损耗。[lossG, lossD] = ganLoss(probReal,probGenerated);对于每个网络,计算与损失相关的梯度。gradientsG = dlgradient(lossG,netG.Learnables,RetainData=true);gradientsD = dlgradient(lossD,net . learnables);结束

GAN损耗函数

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

给定输出 Y 鉴别器:

  • Y ˆ σ Y 输入图像属于这个类的概率是多少“真正的”

  • 1 - Y ˆ 输入图像属于这个类的概率是多少“生成”

注意sigmoid运算 σ 发生在modelLoss函数。发电机的损失函数由

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

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

鉴别器的目标是不被生成器“愚弄”。为了最大化鉴别器成功鉴别真实图像和生成图像的概率,最小化对应的负对数似然函数的和。鉴别器的损失函数由

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

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

函数[lossG, lossD] = ganLoss(scoresReal,scoresGenerated)计算鉴别器网络的损失。lossGenerated = -mean(1 - scoresGenerated));lossReal = -mean(log(scoresReal));%组合鉴别器网络的损失。lossD = lossReal + lossGenerated;计算发电机网络的损失。lossG = -mean(log(scoresGenerated));结束

小批量预处理功能

preprocessMiniBatch函数按照以下步骤对数据进行预处理:

  1. 从输入单元格数组中提取图像和标签数据,并将它们连接到数值数组中。

  2. 将图像重新缩放到该范围内[1]

函数[X,T] = preprocessData(XCell,TCell)从单元格和拼接中提取图像数据X = cat(4,XCell{:});从单元格和级联中提取标签数据T = cat(1,TCell{:});重新缩放范围为[-1 1]的图像。(X,-1,1,InputMin=0,InputMax=255);结束

参考文献

另请参阅

||||||

相关的话题