主要内容

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

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

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

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

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

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

A.有条件的生成式对抗网络(generative adversarial network, CGAN)是一种在训练过程中利用标签的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 = true, LabelSource =“foldernames”);

查看类个数。

类=类别(imds.Labels);numClasses =元素个数(类)
numclass=5

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

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

定义发电机网络

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

这个网络:

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

  • 将分类标签转换为嵌入向量,并将其重塑为4乘4数组。

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

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

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

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

  • 对于转置卷积层,指定5 × 5滤波器,每个层的滤波器数量减少,步幅为2,和“相同”产量的裁剪。

  • 对于最终的转置卷积层,指定一个3个5 × 5滤波器,对应生成图像的3个RGB通道。

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

若要投影和重塑噪波输入,请使用完全连接的层,然后使用重塑操作,该操作指定为功能层,其功能由feature2image函数,作为支持文件附加到本示例中。金宝app要嵌入分类标签,请使用自定义层嵌入层作为支持文件附加到本示例中。金宝app要访问这些支持文件,请将示例作为金宝app活动脚本打开。

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

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

dlnetGenerator = dlnetwork (lgraphGenerator)
dlnetGenerator =带有属性的dlnetwork: Layers: [19×1 net.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,Normalization=“没有”) dropoutLayer (dropoutProb) concatenationLayer(3 2名=“猫”) convolution2dLayer (filterSize numFilters,跨步= 2,填充=“相同”)leakyReluLayer(比例)卷积2Dlayer(过滤器尺寸,2*numFilters,步长=2,填充=“相同”)batchNormalizationLayer leakyReluLayer(缩放)卷积2dLayer(filterSize,4*numFilter,步长=2,填充=“相同”) batchNormalizationLayer leakyReluLayer(scale)卷积2dlayer (filterSize,8*numFilters,Stride=2,Padding=“相同”) batchNormalizationLayer leakyrelullayer (scale) convolution2dLayer(4,1)];lgraphDiscriminator = layerGraph (layersDiscriminator);layers = [featureInputLayer(1) embed layer (embedddingdimension,numClasses) fulllyconnectedlayer (prod(inputSize(1:2))) functionLayer(@(X) feature2image(X,[inputSize(1:2) 1])),Formattable=true,Name=“emb_reshape”)];lgraphDiscriminator=添加层(lgraphDiscriminator,层);lgraphDiscriminator=连接层(lgraphDiscriminator,“emb_reshape”,“猫/ in2”);

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

dlnetDiscriminator = 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'}InputNames:{'conv_5'}初始化:1

定义模型梯度和损失函数

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

指定培训选项

500个纪元的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。

翻转系数=0.5;

火车模型

使用自定义训练循环训练模型。循环训练数据并在每次迭代时更新网络参数。要监视训练进度,请使用保留的随机值数组显示一批生成的图像,以输入生成器和网络分数。

使用minibatchqueue在培训过程中对小批量图像进行处理和管理。为每个mini-batch:

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

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

  • 使用尺寸标签格式化图像数据“SSCB”(spatial, spatial, channel, batch)。

  • 使用维度标签格式化标签数据“卑诗省”(批处理、通道)。

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

这个minibatchqueue对象,默认情况下,将数据转换为dlarray具有底层类型的对象

augimds。MiniBatchSize = MiniBatchSize;executionEnvironment =“汽车”;兆贝可= minibatchqueue (augimds,...MiniBatchSize = MiniBatchSize,...PartialMiniBatch =“丢弃”,...MiniBatchFcn=@preprocessData,...迷你批处理格式=[“SSCB”“卑诗省”],...OutputEnvironment = executionEnvironment);

初始化亚当优化器的参数。

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

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

f=图形;f位置(3)=2*f位置(3);

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

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

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

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

自定义情节的外观。

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

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

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

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

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

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

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

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

为每个mini-batch:

  • 使用dlfevalmodelGradients函数。

  • 使用adamupdate函数。

  • 画出两个网络的比分。

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

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

迭代= 0;开始=抽搐;%循环纪元。时代= 1:numEpochs重置和洗牌数据。洗牌(兆贝可);%循环小批。Hasdata (mbq) iteration = iteration + 1;%读取小批数据。[dlX, dlT] =下一个(兆贝可);为发电机网络产生潜在的输入。转换为% dlarray,并指定尺寸标签“CB”(通道,批次)。%如果在GPU上训练,则将潜在输入转换为gpuArray。Z = randn (numLatentInputs miniBatchSize,“单身”);dlZ = dlarray (Z,“CB”);如果(executionEnvironment = =“汽车”&&canUseGPU)| |执行环境==“图形”dlZ = gpuArray (dlZ);结束%使用评估模型梯度和生成器状态的% dlfeval和模型梯度函数%的例子。[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...dlfeval(@modelGradients, dlnetGenerator, dlnetDiscriminator, dlX, dlT, dlZ, flipFactor);dlnetGenerator。状态= stateGenerator;%更新标识器网络参数。[dlnetDiscriminator, trailingAvgDiscriminator trailingAvgSqDiscriminator] =...adamupdate(dlnetDiscriminator、Gradients Discriminator、,...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 dlTValidation);在[0 1]范围内平铺并重新缩放图像。I=imtile(提取数据(DLX生成验证),...GridSize = [numValidationImagesPerClass numClasses]);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对象,该对象包含与所需类相对应的一批随机向量和标签数组。将数据转换为dlarray对象并指定维度标签“CB”(频道,批处理)。对于GPU预测,将数据转换为gpuArray对象。要同时显示图像,请使用imtile函数并使用重新调节函数。

创建一个由36个随机值向量组成的数组,对应于第一个类。

numObservationsNew = 36;idxClass = 1;Z = randn (numLatentInputs numObservationsNew,“单身”);T = repmat(single(idxClass),[1 numObservationsNew]); / /查询当前节点

将数据转换为dlarray具有标注标签的对象“SSCB”(空间、空间、通道、批处理)。

dlZ = dlarray (Z,“CB”);dlT = dlarray (T)“CB”);

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

如果(executionEnvironment = =“汽车”&&canUseGPU)| |执行环境==“图形”dlZ = gpuArray (dlZ);dlT = gpuArray (dlT);结束

使用预测与发电机网络一起工作。

dlXGenerated=预测(dlnetGenerator、dlZ、dlT);

在绘图中显示生成的图像。

图I = imtile(extractdata(dlXGenerated));I =重新调节(我);imshow (I)标题(”类:“+类(idxClass))

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

模型梯度函数

这个函数modelGradients将生成器和鉴别器作为输入dlnetwork物体dlnetGeneratordlnetDiscriminator,输入数据的一小批dlX,对应的标签dlT,以及一个随机值数组dlZ,并返回损失相对于网络中可学习参数、生成器状态和网络得分的梯度。

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

函数[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...模型梯度(dlnetGenerator, dlnetDiscriminator, dlX, dlT, dlZ, flipFactor)%用鉴别器网络计算真实数据的预测。dlYPred = forward(dlnetDiscriminator, dlX, dlT);%用鉴别器网络计算生成数据的预测。[dlXGenerated, statgenerator] = forward(dlnetGenerator, dlZ, dlT);dlYPredGenerated = forward(dlnetDiscriminator, dlXGenerated, dlT);%计算概率。probGenerated=sigmoid(dlYPredGenerated);probReal=sigmoid(dlYPred);%计算生成器和鉴别器分数。scoreGenerator =意味着(probGenerated);scoreDiscriminator = (mean(probReal) + mean(1-probGenerated)) / 2;%翻转标签。numObservations =大小(dlYPred 4);idx = randperm(numObservations,floor(flipFactor * numObservations));proreal (:,:,:,idx) = 1 - proreal (:,:,:,idx);%计算氮化镓损耗。[lossGenerator, lossDiscriminator] = ganLoss(probReal, probGenerated);%对于每个网络,计算相对于损失的梯度。gradientsGenerator = dlgradient(lossGenerator, dlnetGenerator.Learnables,RetainData=true);gradientsDiscriminator = dlgradient(lossDiscriminator, dlnetDiscriminator.Learnables);结束

氮化镓损失函数

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

考虑到输出 Y 鉴频器:

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

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

注意乙状结肠手术 σ 发生在modelGradients函数。发电机的损耗函数为

lossGenerator = - 的意思是 ( 日志 ( Y ˆ 生成的 ) ) ,

在哪里 Y ˆ G E N E R A. T E D 包含生成图像的鉴别器输出概率。

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

lossDiscriminator = - 的意思是 ( 日志 ( Y ˆ 真正的 ) ) - 的意思是 ( 日志 ( 1. - Y ˆ 生成的 ) ) ,

在哪里 Y ˆ R E A. L 包含真实图像的鉴别器输出概率。

函数[lossGenerator, lossDiscriminator] = ganLoss(scoresReal,scoresGenerated)%计算鉴别器网络的损耗。lossGenerated = -mean(log(1 - scoresGenerated));lossReal =意味着(日志(scoresReal));%综合鉴别器网络的损失。lossDiscriminator = lossReal + lossGenerated;%计算发电机网络的损耗。lossGenerator =意味着(日志(scoresGenerated));结束

Mini-Batch预处理功能

这个预处理小批量函数使用以下步骤对数据进行预处理:

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

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

函数[X, T] = preprocessData(伊势亚TCell)%从单元格提取图像数据并连接X=cat(4,XCell{:});%从单元格中提取标签数据并连接猫(T = 1, TCell {:});%在[-1 1]范围内重新缩放图像。X =重新调节(X, 1, 1, InputMin = 0, InputMax = 255);结束

参考文献

另见

||||||

相关的话题