这个例子展示了如何训练生成性对抗网络来生成图像。
生成式对抗网络(generative adversarial network, GAN)是一种深度学习网络,能够生成与输入真实数据具有相似特征的数据。
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');如果~exist(imageFolder,'dir') disp ('正在下载花卉数据集(218MB)…') websave(文件名,url);解压(文件名,downloadFolder)结束
创建包含花的照片的图像数据存储。
datasetFolder=fullfile(imageFolder);imds=imageDatastore(datasetFolder,...“IncludeSubfolders”,真正的);
增强数据以包括随机水平翻转,并调整图像大小以具有64乘值64。
增强器=图像数据增强器(“随机选择”,真正的);Augimds = AugmentedimageDataStore([64 64],IMDS,“DataAugmentation”,增强者);
定义以下网络架构,它从大小为100的随机向量生成图像。
该网络:
将大小为100的随机向量转换为7乘7乘128的数组规划和重塑层。
使用具有批量归一化和Relu层的一系列转换卷积层将产生的数组升高到64×64×3阵列。
将此网络体系结构定义为图层图,并指定以下网络属性。
对于转置卷积层,指定5 × 5滤波器,每个层的滤波器数量减少,步幅为2,裁剪每个边缘的输出。
对于最终转置卷积层,指定与生成图像的三个RGB通道对应的三个5-5-5滤波器,以及前一层的输出大小。
在网络的末尾,包括一个tanh层。
要投射和重塑噪声输入,使用自定义层ProjectAndreshapelayer.
,附加到该示例作为支持文件。金宝app的ProjectAndreshapelayer.
对象使用完全连接的操作放大输入并将输出重塑为指定的大小。
filterSize = 5;numFilters = 64;numLatentInputs = 100;projectionSize = [4 4 512];layersGenerator = [featureInputLayer(numLatentInputs,“名字”,“在”) projectAndReshapeLayer (projectionSize numLatentInputs,“名字”,“项目”);transposedConv2dLayer(过滤器化,4*numFilters,“名字”,“tconv1”batchnormalizationlayer(“名字”,'bnorm1') reluLayer (“名字”,'relu1')TransposedConv2dlayer(过滤,2 * NumFilters,“步”2,'裁剪',“一样”,“名字”,“tconv2”batchnormalizationlayer(“名字”,'bnorm2') reluLayer (“名字”,“relu2”)transposedConv2dLayer(过滤器化、numFilters、,“步”2,'裁剪',“一样”,“名字”,“tconv3”batchnormalizationlayer(“名字”,“bnorm3”) reluLayer (“名字”,“relu3”)transposedConv2dLayer(过滤器化,3,“步”2,'裁剪',“一样”,“名字”,'tconv4')坦莱尔(“名字”,的双曲正切)];Lgroggenerator = LayerGraph(层Generator);
为了使用自定义的训练循环来训练网络并使其能够自动区分,将层图转换为dlnetwork.
对象
dlnetGenerator=dlnetwork(lgraphGenerator);
定义以下网络,该网络分类真实和生成的64×64图像。
创建一个网络,该网络获取64×64×3图像,并使用一系列卷积层返回标量预测分数,这些卷积层具有批标准化和泄漏ReLU层。使用dropout向输入图像添加噪声。
对于退出层,指定退出概率为0.5。
对于卷积层,指定5乘5的过滤器,每个层的过滤器数量增加。还指定2的跨距和输出的填充。
对于泄漏的Relu层,指定0.2的等级。
对于最后一层,指定一个带有4 × 4过滤器的卷积层。
要输出[0,1]范围内的概率,请使用sigmoid.
功能模型梯度
函数,列在模型梯度函数该示例的部分。
dropoutProb = 0.5;numFilters = 64;规模= 0.2;inputSize = [64 64 3];filterSize = 5;layersDiscriminator = [imageInputLayer(inputSize,'正常化',“没有”,“名字”,“在”)DropoutLayer(DropoutProb,“名字”,'退出')卷积2dlayer(filterSize、NumFilter、,“步”2,'填充',“一样”,“名字”,“conv1”) leakyReluLayer(规模、“名字”,“lrelu1”)卷积2dlayer(过滤,2 * numfilters,“步”2,'填充',“一样”,“名字”,“conv2”batchnormalizationlayer(“名字”,“bn2”) leakyReluLayer(规模、“名字”,'lrelu2') convolution2dLayer (filterSize 4 * numFilters,“步”2,'填充',“一样”,“名字”,“conv3”batchnormalizationlayer(“名字”,“bn3”) leakyReluLayer(规模、“名字”,'lrelu3') convolution2dLayer (filterSize 8 * numFilters,“步”2,'填充',“一样”,“名字”,“conv4”batchnormalizationlayer(“名字”,“bn4”) leakyReluLayer(规模、“名字”,'lrelu4')卷积2层(4,1,“名字”,“conv5”)];Lgraphdiscriminator = DaterGraph(LayersDiscriminator);
为了使用自定义的训练循环来训练网络并使其能够自动区分,将层图转换为dlnetwork.
对象
dlnetDiscriminator = dlnetwork (lgraphDiscriminator);
创建函数模型梯度
,列于模型梯度函数示例的一部分,将生成器和鉴别器网络、一小批输入数据、一组随机值和翻转因子作为输入,并返回与网络中可学习参数和两个网络分数相关的损失梯度。
500个纪元的128个小批量列车。对于更大的数据集,您可能不需要为那么多的纪元进行训练。
numEpochs = 500;miniBatchSize = 128;
指定Adam优化的选项。对于两个网络,指定:
学习率为0.0002
梯度衰减因子0.5
平方梯度衰减因子为0.999
学习= 0.0002;梯度Dayfactor = 0.5;squaredgradientdecayfactor = 0.999;
如果鉴别器学习区分真实的和生成的图像太快,那么生成器可能无法训练。为了更好地平衡鉴别器和生成器的学习,可以通过随机翻转标签给真实数据添加噪声。
指定A.Flipfactor.
值0.3翻转真实标签的30%(总标签的15%)。注意,这不会影响生成器,因为所有生成的图像仍然被正确地标记。
flipFactor = 0.3;
每100次迭代显示生成的验证图像。
validationFrequency = 100;
使用小型批处理队列
处理和管理迷你批次的图像。为每个mini-batch:
使用自定义小批量预处理功能preprocessMiniBatch
(在本例的最后定义)在范围内重新缩放图像[-1,1]
.
丢弃任何小于128个观测值的部分小批。
使用标注标签格式化图像数据'SSCB'
(空间、空间、通道、批次)。默认情况下小型批处理队列
对象将数据转换为dlarray
具有底层类型的对象仅有一个的
.
在可用的GPU上进行训练。当'outputenvironment'
选择小型批处理队列
是“汽车”
,小型批处理队列
将每个输出转换为GPUArray.
如果GPU可用。使用GPU需要并行计算工具箱™ 以及支持CUDA®的NVIDIA®GPU,具有3.0或更高的计算能力。
augimds。MiniBatchSize = MiniBatchSize;executionEnvironment =“汽车”;mbq=小批量队列(augimds,...'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.
对象。
如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“gpu”dlZValidation = gpuArray (dlZValidation);结束
初始化训练进度图。创建一个图形并调整其大小,使其具有两倍的宽度。
f =图;f.Position (3) = 2 * f.Position (3);
为生成的图像和网络分数创建子图。
imageAxes=子批次(1,2,1);scoreAxes=子批次(1,2,2);
初始化分数图的动画行。
lineScoreGenerator=动画线(scoreAxes,'颜色'0.447 - 0.741 [0]);lineScoreDiscriminator = animatedline (scoreAxes,'颜色', [0.85 0.325 0.098]);传奇(“发电机”,'鉴别者');ylim([0 1])包含(“迭代”)伊拉贝尔(“分数”) 网格在…上
训练甘。对于每个epoch,洗牌数据存储并循环小批数据。
为每个mini-batch:
使用德尔费瓦尔
和模型梯度
函数。
使用阿达木酯
函数。
画出两个网络的比分。
以后validationFrequency
迭代,显示一批生成的图像,用于固定的保持发生器输入。
训练可能需要一些时间来运行。
迭代= 0;start = tic;%循环epochs。为历元=1:numEpochs%重置和洗牌数据存储。洗牌(MBQ);%循环在迷你批次。而Hasdata(MBQ)迭代=迭代+ 1;%读取迷你批次数据。dlX =下一个(兆贝可);为发电机网络产生潜在的输入。转换为% dlarray,并指定尺寸标签'CB'(通道,批次)。%如果在GPU上进行训练,则将潜在输入转换为gpuArray。Z=randn(numLatentInputs,miniBatchSize,'单身的');dlZ = dlarray (Z,“CB”);如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“gpu”dlZ = gpuArray (dlZ);结束%评估模型梯度和生成器状态使用的% dlfeval和模型梯度函数% 例子。[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...dlfeval(@modelGradients, dlnetGenerator, dlnetDiscriminator, dlX, dlZ, flipFactor);dlnetGenerator。状态= stateGenerator;%更新鉴别器网络参数。[DlnetDiscriminator,trailingavgdiscriminator,trailingavgsqdiscriminator] =...adamupdate (dlnetDiscriminator gradientsDiscriminator,...trailingAvgDiscriminator trailingAvgSqDiscriminator,迭代,...学习,梯度dayfactor,squaredgradientdecayfactor);%更新生成器网络参数。[dlnetGenerator, trailingAvgGenerator trailingAvgSqGenerator] =...数据更新(dlnetGenerator、梯度生成器、,...trailingAvgGenerator trailingAvgSqGenerator,迭代,...学习,梯度dayfactor,squaredgradientdecayfactor);%每次validationFrequency迭代,使用%保留发电机输入。如果mod(iteration,validationFrequency) == 0 || iteration == 1%使用保持的发电机输入生成图像。dlxgeneratedValidation =预测(DlnetGenerator,DLZValidation);在[0 1]范围内平铺并重新缩放图像。我= imtile (extractdata (dlXGeneratedValidation));I =重新调节(我);%显示图像。子批次(1,2,1);图像(imageAxes,I)xticklabels([]);yticklabels([]);标题(“生成的图像”);结束%更新分数图。子批次(1,2,2)添加点(lineScoreGenerator、迭代、,...双(收集(摘录(刻度))))));addpoints(LineScoredIscriminator,迭代,...双(收集(提取物)));%使用培训进度信息更新标题。D =持续时间(0,0,toc(开始),'格式','hh:mm:ss'); 头衔(...“时代:”+时代+", "+...“迭代:”+迭代+", "+...“已过:”+ drawnow字符串(D))结束结束
这里,鉴别器学习了一种强大的特征表示,可以在生成的图像中识别出真实的图像。反过来,生成器学习了一个类似的强特征表示,允许它生成与训练数据相似的图像。
训练图显示了生成器和鉴别器网络的得分。要了解更多关于如何解释网络分数,请看监控GAN培训进度并识别常见故障模式.
要生成新图像,请使用预测
函数在带有dlarray
包含一批随机载体的对象。要将图像显示在一起,请使用imtile
函数并使用rescale.
函数。
创建一个dlarray
对象包含一批25个随机矢量输入到生成器网络。
numObservations = 25;ZNew = randn (numLatentInputs numObservations,'单身的');dlZNew=dlarray(ZNew,“CB”);
要使用GPU生成图像,还需要将数据转换为GPUArray.
对象。
如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“gpu”dlZNew=gpuArray(dlZNew);结束
生成新的图像使用预测
使用发电机和输入数据。
dlXGeneratedNew =预测(dlnetGenerator dlZNew);
显示图像。
i = Imtile(提取数据(DLXGeneratedNew));I =重新调节(我);图图像(i)轴从标题(“生成的图像”)
功能模型梯度
将生成器和鉴别器作为输入dlnetwork.
对象dlnetGenerator
和dlnetDiscriminator
,迷你批次输入数据dlX
,一个随机值数组dlZ
,以及实际标签翻转的百分比Flipfactor.
,并返回关于网络中的学习参数,发电机状态和两个网络的分数的丢失渐变。因为鉴别器输出不在范围内[0,1],所以模型梯度
函数应用s型函数将其转换为概率。
函数[gradientsGenerator, gradientsDiscriminator, stateGenerator, scoreGenerator, scoreDiscriminator] =...ModelGRADENTERS(DLNETGENERATOR,DLNETDISCRIMINATOR,DLX,DLZ,FLIPFORTOR)%用鉴别器网络计算真实数据的预测。dlYPred = forward(dlnetDiscriminator, dlX);%计算具有鉴别器网络的生成数据的预测。向前(dlXGenerated stateGenerator] = (dlnetGenerator, dlZ);dlYPredGenerated = forward(dlnetDiscriminator, dlXGenerated);%将鉴别器输出转换为概率。probGenerated =乙状结肠(dlYPredGenerated);probReal =乙状结肠(dlYPred);%计算鉴别器的分数。记分鉴别器=(平均值(probReal)+平均值(1-probGenerated))/2;%计算生成器的分数。刻录物=平均值(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、,'etaindata',真正的);gradientsDiscriminator = dlgradient(lossDiscriminator, dlnetDiscriminator.Learnables);结束
生成器的目标是生成鉴别器分类为的数据“真实的”
.为了最大限度地提高来自发生器的图像被鉴别器分类为真实图像的概率,最小化负对数似然函数。
考虑到输出 判别者:
输入图像属于类的概率是概率“真实的”
.
输入图像属于类的概率是概率“生成”
.
注意乙状体运算
发生在模型梯度
函数。发电机的损耗函数由下式给出
哪里 包含生成图像的鉴别器输出概率。
鉴别器的目的是不被生成器“愚弄”。为了最大限度地提高鉴别器在真实图像和生成图像之间成功鉴别的概率,最小化相应的负对数似然函数的和。
鉴别器的损失函数由下式给出
哪里 包含真实图像的鉴别器输出概率。
要在0到1的范围内衡量生成器和鉴别器实现各自目标的程度,可以使用分数的概念。
发电机分数是与生成的图像的鉴别器输出对应的概率的平均值:
鉴别器分数是与真实和生成的图像的鉴别器输出对应的概率的平均值:
分数与损失成反比,但实际上包含相同的信息。
函数[lossGenerator, lossDiscriminator] = ganLoss(probReal,probGenerated)%计算鉴别器网络的损耗。lossDiscriminator=-mean(log(probReal))-mean(log(1-probGenerated));%计算发电机网络的损耗。lossGenerator =意味着(日志(probGenerated));结束
的preprocessMiniBatch
函数使用以下步骤预处理数据:
从传入的单元格数组中提取图像数据并连接到一个数字数组中。
重新调整图像的范围[-1,1]
.
函数X = preprocessMiniBatch(数据)%连接mini-batchX=cat(4,数据{:});%重新归类范围[-1 1]中的图像。X =重新调节(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。
阿达木酯
|dlarray
|德尔费瓦尔
|dlgradient
|dlnetwork.
|向前
|小型批处理队列
|预测