这个例子展示了如何训练生成对抗网络来生成图像。
生成式对抗网络(GAN)是一种深度学习网络,可以生成与输入真实数据具有相似特征的数据。
GAN由两个一起训练的网络组成:
生成器——给定一个随机值向量(潜在输入)作为输入,该网络生成与训练数据具有相同结构的数据。
判别器-给定的数据批次包含来自训练数据的观察结果,以及来自生成器的生成数据,该网络试图将观察结果分类为“真正的”
或“生成”
.
为了训练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);
增加数据以包括随机水平翻转,并将图像大小调整为64 × 64。
augmenter = imageDataAugmenter(RandXReflection=true);augimds = augmentedImageDatastore([64 64],imds,DataAugmentation=augmenter);
定义以下网络架构,它从大小为100的随机向量生成图像。
这个网络:
使用全连接层将大小为100的随机向量转换为7 × 7 × 128的数组,然后进行重塑操作。
使用一系列带有批处理归一化和ReLU层的转置卷积层将生成的数组升级为64 × 64 × 3数组。
将此网络体系结构定义为层图,并指定以下网络属性。
对于转置卷积层,指定5 × 5滤波器,每层滤波器数量递减,步幅为2,并在每条边上裁剪输出。
对于最后的转置卷积层,指定三个5乘5的滤波器,对应于生成图像的三个RGB通道,以及前一层的输出大小。
在网络的末端,包括一个tanh层。
要投影和重塑噪声输入,请使用一个完全连接层,然后使用函数层指定的重塑操作feature2image
函数,作为支持文件附加到本示例中。金宝app要访问此函数,请将此示例作为活动脚本打开。
filterSize = 5;numFilters = 64;numLatentInputs = 100;projectionSize = [4 4 512];layersGenerator = [featureInputLayer(numLatentInputs) fullyConnectedLayer(prod(projectionSize)) functionLayer(@(X) feature2image(X,projectionSize),Formattable=true) transposedConv2dLayer(filterSize,4*numFilters) batchNormalizationLayer reluLayer transposedConv2dLayer(filterSize,2*numFilters,Stride=2,裁剪=“相同”) batchNormalizationLayer reluLayer转置conv2dlayer (filterSize,numFilters,Stride=2,裁剪=“相同”) batchNormalizationLayer relullayer转置conv2dlayer (filterSize,3,Stride=2,裁剪=“相同”) tanhLayer);lgraphGenerator = layerGraph(layergenerator);
要使用自定义训练循环训练网络并启用自动区分,请将层图转换为adlnetwork
对象。
dlnetGenerator = dlnetwork(lgraphGenerator);
定义下面的网络,它对真实的和生成的64- x64图像进行分类。
创建一个接受64 × 64 × 3图像的网络,并使用一系列带有批处理归一化和泄漏ReLU层的卷积层返回标量预测分数。使用dropout为输入图像添加噪声。
对于退出层,指定退出概率为0.5。
对于卷积层,指定5 × 5滤波器,每层滤波器的数量不断增加。还指定一个步幅为2和输出的填充。
对于泄漏的ReLU层,指定0.2的刻度。
对于最后一层,指定一个带有4 × 4过滤器的卷积层。
要输出范围[0,1]中的概率,请使用乙状结肠
在modelGradients
函数中列出的模型梯度函数部分的示例。
dropoutProb = 0.5;numFilters = 64;量表= 0.2;inputSize = [64 64 3];filterSize = 5;layersDiscriminator = [imageInputLayer(inputSize,归一化=“没有”) dropoutLayer(dropoutProb) convolution2dLayer(filterSize,numFilters,Stride=2,Padding=“相同”) 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);
要使用自定义训练循环训练网络并启用自动区分,请将层图转换为adlnetwork
对象。
dlnetDiscriminator = dlnetwork(lgraphDiscriminator);
创建函数modelGradients
,列于模型梯度函数部分,该示例将生成器和鉴别器网络、一小批输入数据、随机值数组和翻转因子作为输入,并返回相对于网络中可学习参数的损失梯度以及两个网络的分数。
使用500个epoch的128个小批量进行训练。对于较大的数据集,您可能不需要训练那么多的epoch。
numEpochs = 500;miniBatchSize = 128;
指定Adam优化的选项。对于这两个网络,指定:
学习率为0.0002
梯度衰减因子为0.5
平方梯度衰减因子为0.999
learnRate = 0.0002;gradientDecayFactor = 0.5;squaredGradientDecayFactor = 0.999;
如果鉴别器学习区分真实图像和生成图像的速度太快,那么生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,通过随机翻转标签向真实数据添加噪声。
指定一个flipFactor
值为0.3翻转30%的真实标签(占总标签的15%)。请注意,这不会损害生成器,因为所有生成的图像仍然被正确标记。
flipFactor = 0.3;
每100次迭代显示生成的验证图像。
validationFrequency = 100;
使用minibatchqueue
处理和管理小批量的图像。对于每个小批量:
使用自定义小批量预处理功能preprocessMiniBatch
(在本例结束时定义)来重新缩放范围内的图像[1]
.
丢弃任何小于128个观察值的部分小批。
用尺寸标签格式化图像数据“SSCB”
(空间,空间,通道,批次)。默认情况下,minibatchqueue
对象将数据转换为dlarray
具有基础类型的对象单
.
如果有GPU,可以在GPU上进行训练。当OutputEnvironment
选择minibatchqueue
是“汽车”
,minibatchqueue
将每个输出转换为gpuArray
如果GPU可用。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU,具有3.0或更高的计算能力。
augimds。MiniBatchSize = MiniBatchSize;executionEnvironment =“汽车”;MBQ = minibatchqueue(增加,...MiniBatchSize = MiniBatchSize,...PartialMiniBatch =“丢弃”,...MiniBatchFcn = @preprocessMiniBatch,...MiniBatchFormat =“SSCB”,...OutputEnvironment = executionEnvironment);
使用自定义训练循环训练模型。遍历训练数据并在每次迭代中更新网络参数。为了监控训练进度,可以使用输入到生成器的随机值数组以及分数图来显示一批生成的图像。
初始化Adam的参数。
trailingAvgGenerator = [];trailingAvgSqGenerator = [];trailingAvgDiscriminator = [];trailingAvgSqDiscriminator = [];
为了监控训练进度,使用输入生成器的固定随机向量显示一批生成的图像,并绘制网络分数。
创建一个包含随机值的数组。
numValidationImages = 25;ZValidation = randn(numLatentInputs,numValidationImages,“单身”);
将数据转换为dlarray
对象,并指定维度标签“CB”
(频道,批处理)。
dlZValidation = dlarray(ZValidation,“CB”);
对于GPU训练,将数据转换为gpuArray
对象。
如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZValidation = gpuArray(dlZValidation);结束
初始化训练进度图。创建一个图形,并将其大小调整为宽度的两倍。
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 (“分数”网格)在
训练GAN。对于每个纪元,洗牌数据存储并在小批数据上循环。
对于每个小批量:
评估模型梯度使用dlfeval
和modelGradients
函数。
方法更新网络参数adamupdate
函数。
绘制两家电视台的得分图。
在每一个validationFrequency
迭代,为固定的生成器输入显示一批生成的图像。
跑步训练需要一些时间。
迭代= 0;开始= tic;%遍历epoch。为epoch = 1:numEpochs重置和洗牌数据存储。洗牌(兆贝可);在小批上循环。而Hasdata (mbq)迭代=迭代+ 1;读取小批数据。dlX = next(mbq);为发电机网络生成潜在输入。转换为% darray,并指定尺寸标签“CB”(通道,批)。%如果在GPU上训练,则将潜在输入转换为gpuArray。Z = randn(numLatentInputs,miniBatchSize,“单身”);dlZ = dlarray(Z,“CB”);如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray(dlZ);结束使用评估模型梯度和发电机状态的末尾列出的modelGradients函数%的例子。[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...dlfeval(@modelGradients, dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor);dlnetGenerator。状态=状态生成器;更新鉴别器网络参数。[dlnetDiscriminator, trailingAvgDiscriminator trailingAvgSqDiscriminator] =...adamupdate (dlnetDiscriminator gradientsDiscriminator,...trailingAvgDiscriminator, trailingAvgSqDiscriminator,迭代,...learnRate, gradientDecayFactor, squaredGradientDecayFactor);更新发电机网络参数。[dlnetGenerator, trailingAvgGenerator trailingAvgSqGenerator] =...adamupdate (dlnetGenerator gradientsGenerator,...trailingAvgGenerator, trailingAvgSqGenerator,迭代,...learnRate, gradientDecayFactor, squaredGradientDecayFactor);%每次验证频率迭代,显示批生成的图像使用%保留的发电机输入。如果mod(迭代,validationFrequency) == 0 ||迭代== 1使用保留的生成器输入生成图像。dlXGeneratedValidation = predict(dlnetGenerator,dlZValidation);平铺和重新缩放范围[0 1]的图像。I = imtile(extractdata(dlXGeneratedValidation));I = rescale(I);显示图片。次要情节(1、2、1);图像(imageAxes,我)xticklabels ([]);yticklabels ([]);标题(“生成的图像”);结束更新分数图。次要情节(1、2、2)addpoints (lineScoreGenerator,迭代,...双(收集(extractdata (scoreGenerator))));addpoints (lineScoreDiscriminator迭代,...双(收集(extractdata (scoreDiscriminator))));用培训进度信息更新标题。。D = duration(0,0,toc(start),Format=“hh: mm: ss”);标题(...”时代:“+ epoch +”、“+...“迭代:“+迭代+”、“+...”经过:“+字符串(D))现在绘制结束结束
在这里,鉴别器已经学习了一种强大的特征表示,可以在生成的图像中识别真实图像。反过来,生成器已经学习了一个类似的强特征表示,允许它生成类似于训练数据的图像。
训练图显示了生成器和鉴别器网络的分数。要了解更多关于如何解释网络分数的信息,请参见监控GAN培训进度,识别常见故障模式.
要生成新图像,请使用预测
函数在生成器上使用dlarray
对象,其中包含一批随机向量。要一起显示图像,请使用imtile
函数重新缩放图像重新调节
函数。
创建一个dlarray
对象,该对象包含要输入到生成器网络的25个随机向量。
numObservations = 25;ZNew = randn(numLatentInputs,numObservations,“单身”);dlZNew = dlarray(ZNew,“CB”);
要使用GPU生成图像,还需要将数据转换为gpuArray
对象。
如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZNew = gpuArray(dlZNew);结束
方法生成新图像预测
函数使用生成器和输入数据。
dlXGeneratedNew = predict(dlnetGenerator,dlZNew);
显示图像。
I = imtile(extractdata(dlXGeneratedNew));I = rescale(I);图像(I)轴从标题(“生成的图像”)
这个函数modelGradients
将生成器和鉴别器作为输入dlnetwork
对象dlnetGenerator
而且dlnetDiscriminator
,一小批输入数据dlX
,一个随机值的数组dlZ
,以及真实标签翻转的百分比flipFactor
,并返回损失相对于网络中可学习参数的梯度、发电机状态以及两个网络的分数。由于鉴别器输出不在范围[0,1]内,因此modelGradients
函数应用sigmoid函数将其转换为概率。
函数[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...modelGradients(dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor)用鉴别器网络计算真实数据的预测。。dlYPred = forward(dlnetDiscriminator, dlX);用鉴别器网络计算生成数据的预测。[dlXGenerated,stateGenerator] = forward(dlnetGenerator,dlZ);dlYPredGenerated = forward(dlnetDiscriminator, dlXGenerated);将鉴别器输出转换为概率。probGenerated = sigmoid(dlYPredGenerated);probReal = sigmoid(dlYPred);计算鉴别器的分数。scoreDiscriminator = (mean(probReal) + mean(1-probGenerated)) / 2;计算发电机的得分。scoreGenerator = mean(probGenerated);随机翻转真实图像标签的一小部分。numObservations = size(probReal,4);idx = randperm(numObservations,floor(flipFactor * numObservations));把标签翻过来。probReal(:,:,:,idx) = 1 - probReal(:,:,:,idx);计算GAN损耗。[lossGenerator, lossDiscriminator] = ganLoss(probReal,probGenerated);对于每个网络,计算与损失相关的梯度。gradientsGenerator = dlgradient(lossGenerator, dlnetGenerator.Learnables,RetainData=true);gradientsDiscriminator = dlgradient(lossDiscriminator, dlnetDiscriminator.Learnables);结束
生成器的目标是生成鉴别器分类为的数据“真正的”
.为了最大化来自生成器的图像被鉴别器分类为真实的概率,最小化负对数似然函数。
给定输出 鉴别器:
输入图像属于这个类的概率是多少“真正的”
.
输入图像属于这个类的概率是多少“生成”
.
注意s形运算
发生在modelGradients
函数。发电机的损失函数由
在哪里 包含所生成图像的鉴别器输出概率。
鉴别器的目标是不被生成器“愚弄”。为了最大化鉴别器成功鉴别真实图像和生成图像的概率,最小化对应的负对数似然函数的和。
鉴别器的损失函数由
在哪里 包含真实图像的鉴别器输出概率。
为了在0到1的范围内衡量生成器和鉴别器实现各自目标的情况,可以使用分数的概念。
生成器得分是所生成图像的鉴别器输出对应的概率的平均值:
鉴别器得分是与真实图像和生成图像的鉴别器输出相对应的概率的平均值:
分数与损失成反比,但实际上包含了相同的信息。
函数[lossGenerator, lossDiscriminator] = ganLoss(probReal,probGenerated)计算鉴别器网络的损失。lossDiscriminator = -mean(log(probReal)) -mean(log(1-probGenerated));计算发电机网络的损失。lossGenerator = -mean(log(probGenerated));结束
的preprocessMiniBatch
函数按照以下步骤对数据进行预处理:
从传入单元格数组中提取图像数据并连接到数值数组中。
将图像重新缩放到该范围内[1]
.
函数X = preprocessMiniBatch(数据)连接迷你批X = cat(4,data{:});重新缩放范围为[-1 1]的图像。(X,-1,1,InputMin=0,InputMax=255);结束
TensorFlow团队。花http://download.tensorflow.org/example_images/flower_photos.tgz
雷德福,亚历克,卢克·梅茨,还有南史密斯·钦塔拉。深度卷积生成对抗网络的无监督表示学习预印本,提交于2015年11月19日。http://arxiv.org/abs/1511.06434。
dlnetwork
|向前
|预测
|dlarray
|dlgradient
|dlfeval
|adamupdate
|minibatchqueue