MATLAB实现⾃编码器(六)——变分⾃编码器(VAE)官⽹代码的改进
本⽂内容参考了
是对官⽅⽹页的改进,该⽹页的翻译可见。
1.Load Data
下载数据并解压,然后加载,没有变化
2.Construct Network
与官⽅⽹页相⽐,改进了代码,更加细致,同时增加了解析
2.1.Overview
⾃动编码器包含两个部分:编码器和解码器。 编码器接受图像输⼊并输出压缩表⽰(编码),压缩表⽰是⼤⼩为latent_dim的⽮量,在此⽰例中为20。 解码器获取压缩表⽰,对其进⾏解码,然后重新创建原始图像。
变分⾃编码器的结构如下图所⽰,后⾯带有具体部分的意义
2.1.1编码器
⾯板[a]显⽰尺⼨为28 x 28的图像输⼊。
⾯板[b]是独热向量形式的标签输⼊。下⼀部分将对此进⾏说明。
在⾯板[c]中,标签输⼊被嵌⼊到向量中,并被整形为28 x 28。
输⼊的图像和重塑的标签覆盖在⾯板[d]中。
在⾯板[e]中,分层图像被卷积并向下采样。
在⾯板[f]中,神经⽹络返回潜在空间的均值和⽅差。请注意,本演⽰假定图像可以被压缩为⽮量。我们还假设向量(潜空间)具有正态分布。如果采⽤其他类型的分布,则可以⾃定义分布的类型,这可能会产⽣更好的结果。
从⾯板的正态分布中抽样随机值[g]。
2.1.2解码器
如⾯板[h]所⽰,标签信息输⼊到解码器。
如⾯板[i]中所⽰,使⽤编码器估算的均值和⽅差对随机值进⾏采样。
在⾯板[j]中,将随机值和标签信息连接在⼀起。
在⾯板[k]中,连接的向量按⽐例放⼤为28×28。
在⾯板[l]中,将输⼊图像重构为最终输出图像。
2.2.Define an encoder ([a], [d], [e], and [f])
编码器使⽤卷积层,relu层和完全连接层将图像和标签信息压缩到潜在空间上。
latentDim =20;%压缩表⽰的⼤⼩
imageSize =[28281];%输⼊图像的⼤⼩
numClasses =size(countcats(YTrain),1);%定义输⼊图像的种类数(在此演⽰中:10)
encoderLG =layerGraph([
imageInputLayer(imageSize,'Name','input_encoder','Normalization','none')%图像输⼊层
concatenationLayer(3,2,'Name','cat')% a layer to gather the two-input %收集两个输⼊的层
convolution2dLayer(3,32,'Padding','same','Stride',2,'Name','conv1')%卷积层1,32个3*3的卷积核,全0填充,步长为2
reluLayer('Name','relu1')%激活函数层1
convolution2dLayer(3,64,'Padding','same','Stride',2,'Name','conv2')%卷积层2,32个3*3的卷积核,全0填充,步长为2
reluLayer('Name','relu2')%激活函数层2
fullyConnectedLayer(2* latentDim,'Name','fc_encoder')%编码器输出潜在空间上值的均值和⽅差
]);
2.3.Define an encoder ([b] and [c])
类别(class)信息被转换为独热向量,其中与⽬标图像相对应的索引为1(其余为0),具体见下图。
标签输⼊被转换为嵌⼊向量,并被整形为28×28。 下⾯的⽰例为4 x 4。
要嵌⼊和调整标签输⼊的形状,请使⽤附加到此⽰例作为⽀持⽂件的⾃定义层embedAndReshapeLayer。
embeddingDimension =50;%标签调整后的⼤⼩
encoderLabel =[%对标签进⾏编码
imageInputLayer([11],'Name','labels','Normalization','none')
embedAndReshapeLayer(imageSize,embeddingDimension,numClasses,'emb')];
lgraphDiscriminator =addLayers(encoderLG,encoderLabel);%标签编码层添加到编码器中
lgraphDiscriminator =connectLayers(lgraphDiscriminator,'emb','cat/in2');%标签编码的输出是cat层的两个输⼊之⼀
analyzeNetwork(lgraphDiscriminator)%分析整个编码器⽹络
2.4.Construct decoder ([i], [j], [k] and [l])
在此演⽰中,我使⽤ReLu层进⾏激活,但Leaky ReLu倾向于在GAN(⽣成对抗⽹络)中使⽤。
解码器将21 x 1的输⼊⽐例放⼤为28 x 28。 上采样如下图所⽰。
其中转置卷积层的介绍见
decoderLG =layerGraph([
imageInputLayer([11 latentDim],'Name','i','Normalization','none')%潜在维度在最后⼀部分中定义
concatenationLayer(3,2,'Name','cat')%收集两个输⼊的层
transposedConv2dLayer(7,64,'Cropping','same','Stride',7,'Name','transpose1')%转置卷积层进⾏上采样,64个7*7的卷积核,步长为7 reluLayer('Name','relu1')%激活层
transposedConv2dLayer(3,64,'Cropping','same','Stride',2,'Name','transpose2')
reluLayer('Name','relu2')
transposedConv2dLayer(3,32,'Cropping','same','Stride',2,'Name','transpose3')
reluLayer('Name','relu3')
transposedConv2dLayer(3,1,'Cropping','same','Name','transpose4')
]);
2.5.Construct decoder ([g] and [h])
如编码器中所述,标签输⼊被嵌⼊到向量中并被整形以⽤作解码器的输⼊。
embeddingDimension =20;%标签调整后的⼤⼩
projectionSize =[11];
layers =[%对标签进⾏编码和整形
imageInputLayer([11],'Name','labels','Normalization','none')
embedAndReshapeLayer(projectionSize(1:2),embeddingDimension,numClasses,'emb')];
lgraphGenerator =addLayers(decoderLG,layers);
lgraphGenerator =connectLayers(lgraphGenerator,'emb','cat/in2');%标签编码的输出是cat层的两个输⼊之⼀
analyzeNetwork(lgraphGenerator)%分析整个解码器⽣成⽹络
2.6.图层转换
要使⽤⾃定义训练循环训练两个⽹络并启⽤⾃动微分,将层图转换为dlnetwork对象。
encoderNet =dlnetwork(lgraphDiscriminator);
decoderNet =dlnetwork(lgraphGenerator);
3.Define Model Gradients Function定义模型梯度函数
梯度函数的介绍与原⽹页⼀致,但是将原来解码编码过程图替换为新的图⽚,可以结合⼆者进⾏理解。
4.Specify Training Options指定训练选项
这⼀部分没有变化,见原⽹页代码。
5.Train Model模型训练
增加了不进⾏训练的选项,可以直接调⽤保存好的⽹络(有点迁移学习的味道),没有进⾏具体的翻译,暂且搁置。cpu版的电脑不建议进⾏训练,耗时太长!!
doTraining=1;%设置为1进⾏PC训练
decoderif doTraining==1
for epoch =1:numEpochs % the tranining data is learned in total of "numEpochs" times
tic;
for i =1:numIterations
iteration = iteration +1;
idx =(i-1)*miniBatchSize+1:i*miniBatchSize;% the mini-batch is not shuffled
XBatch =XTrain(:,:,:,idx);%Obtain the next mini-batch from the training set.
XBatch =dlarray(single(XBatch),'SSCB');% conver the mini-batch data to use VAE
YBatch =permute(YTrain(idx),[2341]);%exchange the dimension in the TValidation
% For example, the 2nd dimension goes to 4th dimension
YBatch =dlarray(single(YBatch),'SSCB');% Convert the mini-batch to a dlarray object,
% making sure to specify the dimension labels 'SSCB'(spatial, spatial, channel, batch).
%if your GPU is available for the training,convert the dlarray to a gpuArray object.
if(executionEnvironment =="auto"&& canUseGPU)|| executionEnvironment =="gpu"
XBatch =gpuArray(XBatch);
end
% Evaluate the model gradients using the dlfeval and modelGradients functions.
[infGrad, genGrad]=dlfeval(...
@modelGradients, encoderNet, decoderNet, XBatch,YBatch);
% Update the network learnables and the average gradients for both networks, using the adamupdate function.
[decoderNet.Learnables, avgGradientsDecoder, avgGradientsSquaredDecoder]=...
adamupdate(decoderNet.Learnables,...
genGrad, avgGradientsDecoder, avgGradientsSquaredDecoder, iteration, lr);
[encoderNet.Learnables, avgGradientsEncoder, avgGradientsSquaredEncoder]=...
adamupdate(encoderNet.Learnables,...
infGrad, avgGradientsEncoder, avgGradientsSquaredEncoder, iteration, lr);
end
elapsedTime = toc;
% estimate the mean and variace with log scale on the latent space
% assuming it has a normal distribution
[z, zMean, zLogvar]=sampling(encoderNet, XTraindl,YTraindl);
% decode the compressed value to the image-shape value
xPred =sigmoid(forward(decoderNet,z,YTraindl));
% calculate the ELBO loss. the loss decreases when the
elbo =ELBOloss(XTraindl, xPred, zMean, zLogvar);
addpoints(lineLossTrain,iteration,double(gather(extractdata(elbo))))
title("Loss During Training: Epoch - "+ epoch +"; Iteration - "+ iteration)
drawnow
end
else
load encoderNet; load encoderNet
end
6.Visualize Results可视化结果
更加细致,三部分作了具体介绍
6.1.Encode-Decode
要可视化和解释结果,请使⽤帮助程序可视化功能。 这些帮助器功能在本⽰例的最后定义。VisualizeReconstruction函数显⽰从每个类中随机选择的⼀位,并在通过⾃动编码器后对其进⾏重构。
visualizeReconstruction(XTest, YTest, encoderNet, decoderNet)
6.2.Display the distribution of the latent space after dimension reduction with t-SNE
VisualizeLatentSpace函数采⽤将测试图像通过编码器⽹络后⽣成的均值和⽅差编码(每个维度为20),并对包含每个图像编码的矩阵执⾏t-SNE。 然后,您可以可视化由均值定义的潜在空间以及以t-
SNE为特征的⼆维⽅差。
有关t-SNE的详细信息,请参阅下⾯的补充⽂件或Federico Errica博⼠撰写的页⾯。
visualizeLatentSpace(XTest, YTest, encoderNet)
6.3.Synthesizing digits using the conditional VAE constructed in this script
该功能是新增加的,⾸先检查训练数据中每个数字被压缩到的潜在空间。 然后使⽤每个数字的潜在空间来合成每个数字。
将合成数字保存到GIF⽂件中。
numRepeat=30;%重复合成过程的次数。每⼀次操作合成⼀百个数字。
TileForGif=generateDigits(decoderNet,encoderNet,XTrain,YTrain,numRepeat);% this fumction was made in the end of this script
fig=figure;set(gcf,'visible','on')% impose the figure outside the script
filename ='conditional_VAE.gif';% Specify the output file name
for i=1:numRepeat
imshow(TileForGif(:,:,:,i))
title(sprintf('pattern: %d',i))
pause(.1)
drawnow
frame =getframe(fig);
[A,map]=rgb2ind(frame.cdata,256);
if i ==1
imwrite(A,map,filename,'gif','LoopCount',Inf,'DelayTime',.1);
else
imwrite(A,map,filename,'gif','WriteMode','append','DelayTime',.1);
end
end
7.下⼀步
可变⾃动编码器只是⽤于执⾏⽣成任务的众多可⽤模型之⼀。 它们适⽤于图像较⼩且具有明确定义的特征的数据集(例如MNIST)。 对于具有较⼤图像的更复杂的数据集,⽣成对抗⽹络(GAN)往往会表现更好,并⽣成噪声较⼩的图像。 有关显⽰如何实施GAN⽣成
64×64RGB图像的⽰例,请参阅。
8.Helper Functions帮助函数
相关函数请看⽂章
有些改进,更加具体
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论