此示例显示如何训练条件生成的对抗性网络来生成图像。
生成式对抗网络(generative adversarial network, GAN)是一种深度学习网络,它可以生成与输入训练数据具有相似特征的数据。
GAN由两个一起训练的网络组成:
生成器——给定一个随机值向量作为输入,该网络生成与训练数据相同结构的数据。
鉴别器——给定一批包含从训练数据和从生成器生成的数据的观测值的数据,这个网络试图将这些观测值分类为“真实的”
或“生成”
.
一个条件生成的对抗网络(Cgan)是一种GAN,在培训过程中也能够利用标签。
生成器——给定一个标签和随机数组作为输入,该网络生成与对应于同一标签的训练数据观测相同结构的数据。
鉴别器——给定一批包含训练数据和生成器生成数据的观测值的标记数据,该网络试图将这些观测值分类为“真实的”
或“生成”
.
为了训练一个有条件的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 =元素个数(类)
numClasses = 5
增强数据以包括随机水平翻转,并调整图像大小以具有64乘值64。
增量= imageDataAugmenter (RandXReflection = true);augimds = augmentedImageDatastore([64 64],imds, dataugmentation =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要嵌入分类标签,请使用自定义层embeddingLayer
将此示例附加为支持文件。金宝app要访问这些支持文件,请将示例打开金宝app为实时脚本。
numLatentInputs = 100;embeddingDimension = 50;numFilters = 64;filterSize = 5;projectionSize = [4 4 1024];layersGenerator = [featureInputLayer(numLatentInputs) fulllyconnectedlayer (prod(projectionSize)) functionLayer(@(X) feature2image(X,projectionSize),Formattable=true) concatenationLayer(3,2,Name=“猫”);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;Scale = 0.2;InputSize = [64 64 3];filterSize = 5;LayersDiscriminator = [ImageInputLayer(InputSize,Normalization =“没有”) dropoutLayer (dropoutProb) concatenationLayer(3 2名=“猫”) convolution2dLayer (filterSize numFilters,跨步= 2,填充=“相同”) leakyReluLayer(规模)convolution2dLayer (2 * numFilters filterSize,跨步= 2,填充=“相同”) batchNormalizationLayer leakyReluLayer(scale)卷积2dlayer (filterSize,4*numFilters,Stride=2,Padding=“相同”) 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 = addLayers (lgraphDiscriminator层);lgraphDiscriminator = connectLayers (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' 'input'} OutputNames: {'conv_5'} Initialized: 1
创建函数modelGradients
,列于模型梯度函数这个例子的一部分,它以生成器和鉴别器网络、一小批输入数据和一个随机值数组作为输入,并返回相对于网络中的可学习参数和生成的图像数组的损失梯度。
500个纪元的128个小批量列车。
numEpochs = 500;miniBatchSize = 128;
指定Adam优化的选项。对于两个网络,使用:
学习率为0.0002
梯度衰减因子0.5
平方梯度衰减因子为0.999
学习= 0.0002;梯度Dayfactor = 0.5;squaredgradientdecayfactor = 0.999;
每100次迭代更新训练进度图。
validationFrequency = 100;
如果鉴别者学会过快地区分真实和生成的图像,则发电机可以无法训练。为了更好地平衡鉴别器和发电机的学习,随机翻转一部分真实图像的标签。指定翻转因子为0.5。
flipFactor = 0.5;
使用自定义训练循环训练模型。在每次迭代时循环训练数据并更新网络参数。为了监控训练的进展,使用一组随机值来显示一批生成的图像,输入到生成器和网络分数中。
使用minibatchqueue
在培训过程中对小批量图像进行处理和管理。为每个mini-batch:
使用自定义小批量预处理功能preprocessMiniBatch
(在本例的最后定义)在范围内重新缩放图像[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,......MiniBatchFormat = [“SSCB”“公元前”],......outputenvironment = executionEnvironment);
初始化亚当优化器的参数。
velocityDiscriminator = [];trailingAvgGenerator = [];trailingAvgSqGenerator = [];trailingAvgDiscriminator = [];trailingAvgSqDiscriminator = [];
初始化训练进度图。创建一个图形,并将其大小调整为两倍的宽度。
f =图;f.Position (3) = 2 * f.Position (3);
创建生成的图像和得分图的子图。
imageaxes =子图(1,2,1);scoreaxes =子图(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])包含(“迭代”) ylabel (“分数”网格)在
为了监视培训进度,创建一个25个随机载体和相应的一组标签1到5(对应于类别)重复五次。
numValidationImagesPerClass = 5;ZValidation = randn (numLatentInputs numValidationImagesPerClass * numClasses,“单身的”);TValidation = single(repmat(1:numClasses,[1 numValidationImagesPerClass]));
将数据转换为dlarray
对象并指定维度标签“CB”
(频道,批处理)。
dlZValidation = dlarray (ZValidation,“CB”);dlTValidation = dlarray (TValidation,“CB”);
对于GPU训练,将数据转换为GPUArray.
对象。
如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZValidation = gpuArray (dlZValidation);dlTValidation = gpuArray (dlTValidation);结束
训练条件甘。对于每个epoch,将数据和循环扫描迷你批次数据。
为每个mini-batch:
使用dlfeval.
和modelGradients
函数。
使用adamupdate
函数。
画出两个网络的比分。
毕竟validationFrequency
迭代,显示一批生成的图像,用于固定的保持发生器输入。
跑步训练可能需要一些时间。
迭代= 0;开始=抽搐;%循环epochs。为时代= 1:numEpochs重置和洗牌数据。洗牌(MBQ);%循环在迷你批次。而Hasdata(MBQ)迭代=迭代+ 1;%读取迷你批次数据。[dlX, dlT] =下一个(兆贝可);为发电机网络产生潜在的输入。转换为% dlarray,并指定尺寸标签“CB”(通道,批次)。%如果在GPU上培训,则将潜在输入转换为GPUArray。Z = randn (numLatentInputs miniBatchSize,“单身的”);dlZ = dlarray (Z,“CB”);如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray (dlZ);结束%评估模型梯度和生成器状态使用的% dlfeval和模型梯度函数%的例子。[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =......dlfeval(@modelGradients, dlnetGenerator, dlnetDiscriminator, dlX, dlT, 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 dlTValidation);在[0 1]范围内平铺并重新缩放图像。我= imtile (extractdata (dlXGeneratedValidation),......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.
对象。
如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray (dlZ);dlt = gpuarray(dlt);结束
使用预测
功能与发电机网络。
dlXGenerated =预测(dlnetGenerator, dlZ dlT);
在绘图中显示生成的图像。
图I = imtile(extractdata(dlXGenerated));I =重新调节(我);imshow (I)标题(”类:“+类(idxClass))
在这里,生成器网络根据指定的类生成图像。
这个函数modelGradients
将生成器和鉴别器作为输入dlnetwork
对象dlnetgenerator
和dlnetDiscriminator
,输入数据的一小批dlX
,对应的标签dlT
,以及一个随机值数组dlZ
,并返回损失相对于网络中可学习参数、生成器状态和网络得分的梯度。
如果鉴别者学会过快地区分真实和生成的图像,则发电机可以无法训练。为了更好地平衡鉴别器和发电机的学习,随机翻转一部分真实图像的标签。
函数[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =......模型梯度(dlnetGenerator, dlnetDiscriminator, dlX, dlT, dlZ, flipFactor)%用鉴别器网络计算真实数据的预测。dlYPred = forward(dlnetDiscriminator, dlX, dlT);%用鉴别器网络计算生成数据的预测。[DLXGENERATED,STATEGGENERATOR] =向前(DLNETGENERATOR,DLZ,DLT);dlypredgenerated =前进(Dlnetdiscriminator,DLxgenerated,DLT);%计算概率。probGenerated =乙状结肠(dlYPredGenerated);probReal =乙状结肠(dlYPred);%计算发电机和鉴别器分数。scoreGenerator =意味着(probGenerated);scoreDiscriminator = (mean(probReal) + mean(1-probGenerated)) / 2;%翻转标签。numobservations = size(dlypred,4);idx = randperm(numobservations,backs(flipfactor * numobservations));probreal(::::,idx)= 1 - probreal(::::,IDX);%计算氮化镓损耗。[lossGenerator, lossDiscriminator] = ganLoss(probReal, probGenerated);每个网络的%,相对于损耗计算梯度。gradientsGenerator = dlgradient(lossGenerator, dlnetGenerator.Learnables,RetainData=true);gradientsDiscriminator = dlgradient(lossDiscriminator, dlnetDiscriminator.Learnables);结束
生成器的目标是生成鉴别器分类的数据“真实的”
.为了最大限度地提高来自发生器的图像被鉴别器分类为真实图像的概率,最小化负对数似然函数。
考虑到输出 鉴频器:
输入图像属于类的概率是概率“真实的”
.
输入图像属于类的概率是概率“生成”
.
注意琴状操作
发生在modelGradients
函数。发电机的损耗函数为
在哪里 包含生成图像的鉴别器输出概率。
判别者的目标是由发电机“被愚弄”。为了最大化鉴别器在真实和生成的图像之间成功区分的概率,最小化相应的负对数似章的总和。鉴别者的损失函数是给出的
在哪里 包含真实图像的鉴别器输出概率。
函数[lossGenerator, lossDiscriminator] = ganLoss(scoresReal,scoresGenerated)%计算鉴别器网络的损耗。lossGenerated = -mean(log(1 - scoresGenerated));lossReal =意味着(日志(scoresReal));%综合鉴别器网络的损失。lossDiscriminator = lossReal + lossGenerated;%计算发电机网络的损耗。lossGenerator =意味着(日志(scoresGenerated));结束
的preprocessMiniBatch
函数使用以下步骤对数据进行预处理:
从输入单元格数组中提取图像和标签数据,并将它们连接到数字数组中。
重新调整图像的范围[1]
.
函数[X, T] = preprocessData(伊势亚TCell)%从单元格提取图像数据并连接猫(X = 4,伊势亚{:});%从单元格中提取标签数据并连接猫(T = 1, TCell {:});%重新归类范围[-1 1]中的图像。X =重新调节(X, 1, 1, InputMin = 0, InputMax = 255);结束
dlnetwork
|向前
|预测
|dlarray
|dlgradient
|dlfeval.
|adamupdate