这个例子展示了如何训练生成式对抗网络来生成图像。
生成性对抗网络(GAN)是一种深度学习网络,能够生成与输入真实数据具有相似特征的数据。
GAN由两个一起训练的网络组成:
生成器——给定一个随机值向量(潜在输入)作为输入,该网络生成与训练数据相同结构的数据。
鉴别器——给定一批包含从训练数据和从生成器生成的数据的观测值的数据,这个网络试图将这些观测值分类为“真正的”
或“生成”
.
要训练一个GAN,同时训练两个网络,以最大限度地提高这两个网络的性能:
训练生成器生成“愚弄”鉴别器的数据。
训练鉴别器区分真实数据和生成的数据。
为了优化生成器的性能,在给定生成的数据时,使鉴别器的损失最大化。也就是说,生成器的目标是生成鉴别器分类为的数据“真正的”
.
为了优化鉴别器的性能,在给定批次的真实数据和生成的数据时,将鉴别器的损失降至最低。也就是说,鉴别器的目标是不被生成器“愚弄”。
理想情况下,这些策略会产生一个生成令人信服的真实数据的生成器,以及一个学习了训练数据特征的强特征表示的鉴别器。
下载并提取花数据集[1]。
url =“http://download.tensorflow.org/example_images/flower_photos.tgz”;downloadFolder=tempdir;filename=fullfile(downloadFolder,“flower_dataset.tgz”);imageFolder = fullfile (downloadFolder,“flower_photos”);如果~存在(imageFolder“dir”)disp(“正在下载花卉数据集(218MB))websave(文件名、url);untar(文件名,下载文件夹)终止
创建一个包含鲜花照片的图像数据存储。
datasetFolder = fullfile (imageFolder);imd = imageDatastore (datasetFolder IncludeSubfolders = true);
增加数据以包括随机水平翻转,并将图像大小调整为64 * 64。
augmenter=imageDataAugmenter(randxrelection=true);augimds=augmentedImageDatastore([64],imds,DataAugmentation=augmenter);
定义下面的网络架构,它从大小为100的随机向量生成图像。
这个网络:
使用完全连接的层,然后执行整形操作,将大小为100的随机向量转换为7×7×128阵列。
使用一系列带有批处理归一化和ReLU层的转置卷积层将得到的数组升级为64 × 64 × 3数组。
将此网络架构定义为一个层图,并指定以下网络属性。
对于转置卷积层,指定5乘5个过滤器,每个层的过滤器数量减少,跨步为2,并在每条边上裁剪输出。
对于最终的转置卷积层,指定生成图像的三个RGB通道对应的三个5 × 5滤波器,以及前一层的输出尺寸。
在网络的末端,包括一个tanh层。
若要投影和重塑噪波输入,请使用完全连接的层,然后使用重塑操作,该操作指定为功能层,其功能由feature2image
函数,作为支持文件附加到本示例中。万博1manbetx要访问此函数,请将此示例作为活动脚本打开。
filterSize=5;numFilters=64;numLatentInputs=100;projectionSize=[4 512];layersGenerator=[featureInputLayer(numLatentInputs)fullyConnectedLayer(prod(projectionSize))functionLayer(@(X)feature2image(X,projectionSize),Formattable=true)TransposeConv2Layer(filterSize,4*numFilters)批次规格化Layer reluLayer TransposcedConv2Layer(filterSize,2*numFilters,Strip=2,裁剪=“相同”) batchNormalizationLayer reluLayer转置conv2dlayer (filterSize,numFilters,Stride=2,裁剪=“相同”) batchNormalizationLayer reluLayer转置conv2dlayer (filterSize,3,Stride=2,裁剪=“相同”)tanhLayer];lgraphGenerator=layerGraph(LayerGenerator);
要使用自定义训练循环训练网络并启用自动微分,请将层图转换为dlnetwork
对象。
dlnetGenerator = dlnetwork (lgraphGenerator);
定义下面的网络,它对真实的和生成的64 × 64图像进行分类。
创建一个网络,它接收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,Normalization=“没有”) dropoutLayer (dropoutProb) convolution2dLayer (filterSize numFilters,跨步= 2,填充=“相同”)leakyReluLayer(比例)卷积2Dlayer(过滤器尺寸,2*numFilters,步长=2,填充=“相同”)batchNormalizationLayer leakyReluLayer(缩放)卷积2dLayer(filterSize,4*numFilter,步长=2,填充=“相同”)batchNormalizationLayer leakyReluLayer(缩放)卷积2dLayer(filterSize,8*numFilter,步长=2,填充=“相同”) batchNormalizationLayer leakyrelullayer (scale) convolution2dLayer(4,1)];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;
如果鉴别器学习辨别真实图像和生成图像的速度过快,则生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,请通过随机翻转标签向真实数据添加噪声。
指定一个flipFactor
值0.3以翻转30%的真实标签(总标签的15%)。请注意,这不会影响生成器,因为所有生成的图像仍正确标记。
翻转系数=0.3;
每100次迭代显示生成的验证图像。
验证频率=100;
使用minibatchqueue
处理和管理小批量图像。对于每个小批量:
使用自定义小批量预处理功能预处理小批量
(在本例末尾定义)以重新缩放范围内的图像[1]
.
丢弃观察值少于128的任何部分小批次。
使用尺寸标签格式化图像数据“SSCB”
(spatial, spatial, channel, batch)。默认情况下,minibatchqueue
对象将数据转换为dlarray
具有基础类型的对象单
.
如果GPU可用,则在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 (numLatentInputs numValidationImages,“单身”);
将数据转换为dlarray
对象并指定标注标签“CB”
(通道、批次)。
dlZValidation=dlarray(ZValidation,“CB”);
对于GPU培训,将数据转换为gpuArray
物体。
如果(executionEnvironment = =“汽车”&&canUseGPU)| |执行环境==“图形”dlZValidation=gpuArray(dlZValidation);终止
初始化训练进度图。创建一个图形,并将其大小调整为两倍的宽度。
f=图形;f位置(3)=2*f位置(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([01])xlabel(“迭代”) ylabel (“分数”网格)在
训练GAN。对于每个历元,洗牌数据存储并循环小批量数据。
对于每个小批量:
使用dlfeval
和modelGradients
函数。
使用以下命令更新网络参数:adamupdate
函数。
绘制两个网络的分数。
在每一个验证频率
迭代,显示一批生成的图像为固定的保留发生器输入。
跑步训练可能需要一些时间。
迭代= 0;开始=抽搐;%循环纪元。对于时代= 1:numEpochs重置和洗牌数据存储。洗牌(兆贝可);%循环小批。虽然Hasdata (mbq) iteration = iteration + 1;%读取小批数据。dlX=下一个(mbq);%为发电机网络生成潜在输入。转换为% dlarray,并指定尺寸标签“CB”(通道,批次)。%如果在GPU上训练,则将潜在输入转换为gpuArray。Z = randn (numLatentInputs miniBatchSize,“单身”);dlZ=dlZ阵列(Z,“CB”);如果(executionEnvironment = =“汽车”&&canUseGPU)| |执行环境==“图形”dlZ=gpuArray(dlZ);终止%使用评估模型梯度和生成器状态%dlfeval和列在末尾的modelGradients函数%的例子。[gradientsGenerator,gradientsDiscriminator,stateGenerator,scoreGenerator,scoreDiscriminator]=...dlfeval(@modelGradients,dlnetGenerator,dlnetDiscriminator,dlX,dlZ,flipFactor);dlnetGenerator.State=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(迭代,验证频率)==0 | |迭代==1%生成图像使用保留发生器输入。dlXGeneratedValidation =预测(dlnetGenerator dlZValidation);%平铺并重新缩放[0 1]范围内的图像。I=imtile(提取数据(dlXGeneratedValidation));I=重新缩放(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”);标题(...”时代:“+纪元+", "+...“迭代:“+迭代+", "+...”经过:“+字符串(D)现在开始终止终止
在这里,鉴别器学习了一个强特征表示法,它在生成的图像中识别真实图像。反过来,生成器学习了一个类似的强特征表示法,它可以生成类似于训练数据的图像。
训练图显示生成器和鉴别器网络的分数。要了解有关如何解释网络分数的更多信息,请参阅监控GAN培训进度,识别常见故障模式.
要生成新的图像,请使用预测
函数在生成器上使用dlarray
对象,包含一批随机向量。要同时显示图像,请使用imtile
函数并使用重新调节
函数。
创建一个dlarray
对象,该对象包含一批25个随机向量以输入到生成器网络。
numObservations=25;ZNew=randn(numLatentInputs,numObservations,“单身”);dlZNew = dlarray (ZNew,“CB”);
要使用GPU生成图像,还需要将数据转换为gpuArray
物体。
如果(executionEnvironment = =“汽车”&&canUseGPU)| |执行环境==“图形”dlZNew = gpuArray (dlZNew);终止
使用预测
函数的生成器和输入数据。
dlXGeneratedNew=预测(dlnetGenerator,dlZNew);
显示图像。
我= imtile (extractdata (dlXGeneratedNew));I =重新调节(我);数字图像(I)轴关标题(“生成的图像”)
这个函数modelGradients
将生成器和鉴别器作为输入dlnetwork
物体dlnetGenerator
和dlnetDiscriminator
,输入数据的一小批dlX
,一个随机值数组dlZ
,以及要翻转的实际标签的百分比flipFactor
,并返回损失相对于网络中的可学习参数、生成器状态和两个网络的分数的梯度。因为鉴别器输出不在[0,1]范围内,所以modelGradients
函数应用sigmoid函数将其转换为概率。
作用[gradientsGenerator,gradientsDiscriminator,stateGenerator,scoreGenerator,scoreDiscriminator]=...模型梯度(dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor)%使用鉴别器网络计算实际数据的预测。dlYPred=转发(dlnetDiscriminator,dlX);%用鉴别器网络计算生成数据的预测。[dlXGenerated,stateGenerator]=转发(dlnetGenerator,dlZ);dlYPredGenerated=转发(dlnetDiscriminator,dlXGenerated);%将鉴别器输出转换为概率。probGenerated=sigmoid(dlYPredGenerated);probReal=sigmoid(dlYPred);%计算鉴别器的得分。scoreDiscriminator = (mean(probReal) + mean(1-probGenerated)) / 2;%计算生成器的得分。scoreGenerator =意味着(probGenerated);%随机翻转真实图像的一部分标签。numObservations =大小(probReal 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);终止
生成器的目标是生成鉴别器分类的数据“真正的”
. 为了最大化来自发生器的图像被鉴别器分类为真实图像的概率,最小化负对数似然函数。
给定输出 鉴频器:
输入图像属于类的概率是多少“真正的”
.
输入图像属于类的概率是多少“生成”
.
请注意,sigmoid操作
发生在modelGradients
函数。发电机的损耗函数为
在哪里 包含生成图像的鉴别器输出概率。
鉴别器的目标是不被生成器“愚弄”。为了最大限度地提高鉴别器成功鉴别真实图像和生成图像的概率,最小化相应的负对数似然函数之和。
给出了该鉴别器的损失函数
在哪里 包含真实图像的鉴别器输出概率。
要在0到1的范围内衡量生成器和鉴别器实现各自目标的程度,可以使用分数的概念。
生成器得分是生成图像的鉴别器输出对应的概率的平均值:
鉴别器得分是对真实图像和生成图像的鉴别器输出对应的概率的平均值:
分数与损失成反比,但实际上包含相同的信息。
作用[lossGenerator,lossDiscriminator]=ganLoss(probReal,probGenerated)%计算鉴别器网络的损耗。lossDiscriminator = -mean(log(probReal)) -mean(log(1-probGenerated));%计算发电机网络的损耗。lossGenerator=-平均值(log(probGenerated));终止
这个预处理小批量
函数使用以下步骤对数据进行预处理:
从传入的单元格数组中提取图像数据并连接到数字数组中。
将图像重新缩放到范围内[1]
.
作用X=预处理小批量(数据)%串联小批量X =猫(4、数据{:});%在[-1 1]范围内重新缩放图像。X =重新调节(X, 1, 1, InputMin = 0, InputMax = 255);终止
TensorFlow团队。花http://download.tensorflow.org/example_images/flower_photos.tgz
Radford、Alec、Luke Metz和Soumith Chintala.《深层卷积生成对抗网络的无监督表征学习》,预印本,2015年11月19日提交。http://arxiv.org/abs/1511.06434.
dlnetwork
|向前地
|预测
|dlarray
|梯度
|dlfeval
|adamupdate
|minibatchqueue