主要内容

快速列车式换乘网络

这个例子展示了如何训练网络将一张图像的样式传输到另一张图像。它基于[1]中定义的体系结构。

此示例类似于使用深度学习的神经风格迁移但是,一旦你训练网络使用样式图像s,它的工作速度就会更快。这是因为,要获得样式图像Y,你只需要将输入图像X转发给网络。

下面是训练算法的高级图表。它使用三个图像来计算损失:输入图像X,转换图像Y和样式图像S。

注意,损失函数使用预先训练的网络VGG-16从图像中提取特征。可以找到它的实现和数学定义风格传递损失部分。

负荷训练数据

下载并提取COCO 2014列车图片和说明文字https://cocodataset.org/#download点击“2014列车图片”。将数据保存到指定的文件夹中imageFolder.将图像提取到imageFolder.2014年的COCO被可可财团

创建目录来存储COCO数据集。

imageFolder = fullfile (tempdir,“可可”);如果~存在(imageFolder“dir”mkdir (imageFolder);结束

创建一个包含COCO映像的映像数据存储。

imd = imageDatastore (imageFolder,“IncludeSubfolders”,真正的);

训练需要很长时间。如果您希望以牺牲结果网络的准确性为代价来减少训练时间,那么可以通过设置来选择图像数据存储的一个子集分数到较小的值。

分数= 1;numObservations =元素个数(imds.Files);imd =子集(imd, 1:地板(numObservations *分数);

要调整图像的大小并将它们全部转换为RGB,请创建一个增强图像数据存储。

augimds = augmentedImageDatastore([256 256],imds,“ColorPreprocessing”,“gray2rgb”);

阅读样式图像。

styleImage = imread (“starryNight.jpg”);styleImage = imresize(styleImage,[256 256]);

显示所选样式图像。

图imshow (styleImage)标题(“风格形象”

定义图像转换网络

定义图像转换网络。这是一个图像对图像的网络。该网络由3部分组成:

  1. 网络的第一部分将一个大小为[256x256x3]的RGB图像作为输入,并将其下采样为一个大小为[64x64x128]的特征映射。

  2. 网络的第二部分由支持函数中定义的五个相同的剩余块组成residualBlock。

  3. 网络的第三部分(也是最后一部分)将特征映射上采样到图像的原始大小,并返回转换后的图像。最后一部分使用upsampleLayer,这是一个附加到这个示例的自定义层,作为支持文件。

层= [%第一部分。imageInputLayer([256 256 3],标准化=“没有”32岁的)convolution2dLayer(9[9]填充=“相同”) groupNormalizationLayer (“channel-wise”reluLayer convolution2dLayer([3 3],64,Stride=2,Padding= .“相同”) groupNormalizationLayer (“channel-wise”) reluLayer convolution2dLayer([3 3],128,Stride=2,Padding= .“相同”) groupNormalizationLayer (“channel-wise”) reluLayer (Name =“relu_3”%第二部分。residualBlock (“1”) residualBlock (“2”) residualBlock (“3”) residualBlock (“4”) residualBlock (“5”%第三部分。64年upsampleLayer convolution2dLayer(3[3],填充=“相同”) groupNormalizationLayer (“channel-wise”) reluLayer upsampleLayer convolution2dLayer([3 3],32,Padding=“相同”) groupNormalizationLayer (“channel-wise”3) reluLayer convolution2dLayer(9日,填充=“相同”));lgraph = layerGraph(层);

在剩余块中添加丢失的连接。

lgraph = connectLayers (lgraph,“relu_3”,“add_1 / in2”);lgraph = connectLayers (lgraph,“add_1”,“add_2 / in2”);lgraph = connectLayers (lgraph,“add_2”,“add_3 / in2”);lgraph = connectLayers (lgraph,“add_3”,“add_4 / in2”);lgraph = connectLayers (lgraph,“add_4”,“add_5 / in2”);

在图中可视化图像转换网络。

图绘制(lgraph)标题(“变换网络”

创建一个dlnetwork对象从图层图。

netTransform = dlnetwork (lgraph);

风格失去网络

本例使用预先训练的VGG-16深度神经网络来提取不同层的内容和风格图像的特征。这些多层特性用于计算各自的内容和样式损失。

要获得预先训练的VGG-16网络,请使用vgg16函数。如果您没有安装所需的支持包,那么该软件将提供下载链接。

netLoss = vgg16;

为了提取计算损失所需的特征,只需要前24层。提取并转换为图层图。

lossLayers = netLoss.Layers(桥);lgraph = layerGraph (lossLayers);

转换为一个dlnetwork

netLoss = dlnetwork (lgraph);

定义模型损失函数

创建函数modelLoss,列于损失函数模型部分的示例。该函数将丢失网络、图像转换网络、小批输入图像、包含样式图像Gram矩阵的数组、与内容丢失相关的权重和与样式丢失相关的权重作为输入。该函数返回总损耗、与内容相关的损耗和与风格相关的损耗、总损耗相对于图像转换器的可学习参数的梯度、图像转换器网络的状态和转换后的图像。

指定培训选项

像[1]一样,用小批次大小为4进行2次训练。

numEpochs = 2;miniBatchSize = 4;

将增强图像数据存储的读取大小设置为小批处理大小。

augimds。MiniBatchSize = MiniBatchSize;

指定ADAM优化的选项。指定学习速率为0.001,梯度衰减因子为0.01,梯度衰减因子平方为0.999。

learnRate = 0.001;gradientDecayFactor = 0.9;squaredGradientDecayFactor = 0.999;

指定在计算总损失时给予样式损失的权重和给予内容损失的权重。

注意,为了在内容丢失和样式丢失之间找到一个很好的平衡,您可能需要尝试不同的权重组合。

weightContent = 1的军医;weightStyle = 3 e-8;

选择训练进度的情节频率。这指定了每次绘图更新之间有多少次迭代。

plotFrequency = 10;

火车模型

为了能够计算训练过程中的损失,计算样式图像的Gram矩阵。

将样式图像转换为dlarray

S = dlarray(单(styleImage),“SSC”);

为了计算Gram矩阵,将风格图像输入VGG-16网络,提取四个不同层的激活。

[SActivations1, SActivations2 SActivations3 SActivations4] =前进(netLoss,年代,...输出= [“relu1_2”“relu2_2”“relu3_3”“relu4_3”]);

使用支持函数计算每组激活的Gram矩阵createGramMatrix

SGram {1} = createGramMatrix (SActivations1);SGram {2} = createGramMatrix (SActivations2);SGram {3} = createGramMatrix (SActivations3);SGram {4} = createGramMatrix (SActivations4);

训练地块由两个人物组成:

  1. 图示训练期间的损失情况

  2. 包含图像转换网络的输入图像和输出图像的图

初始化训练地块。您可以在支持函数中查看初始化的详细信息initializeFigures。这个函数返回:轴ax₁损失在哪里,坐标轴ax2你在哪里绘制验证图像,动画线lineLossContent哪个包含内容丢失,动画线lineLossStyle哪个包含样式丢失和动画线lineLossTotal其中包括全部损失。

(ax₁,ax2 lineLossContent、lineLossStyle lineLossTotal] = initializeStyleTransferPlots;

初始化ADAM优化器的平均梯度和平均平方梯度超参数。

averageGrad = [];averageSqGrad = [];

计算训练迭代的总次数。

numIterations =地板(augimds.NumObservations * numEpochs / miniBatchSize);

训练前初始化迭代次数和定时器。

迭代= 0;开始=抽搐;

火车模型。如果有GPU,请使用GPU进行训练。使用GPU需要并行计算工具箱™和支持的GPU设备。有关支持的设备的信息,请参见GPU计算的需求(并行计算工具箱).这可能需要很长时间才能运行。

循环遍历各个时代。我= 1:numEpochs重置和洗牌数据存储。重置(augimds);augimds = shuffle (augimds);在小批量上循环。Hasdata (augimds)迭代=迭代+ 1;读取小批数据。data =阅读(augimds);忽略最后的部分小批历。如果(数据,1)< miniBatchSize大小继续结束从数据存储中提取图像到单元格数组中。。数据图像= {:1};沿着第四维度连接图像。。X =猫(4、图像{:});X =单(X);将小批数据转换为dlarray并指定尺寸标签“SSCB”(空间、空间、通道、批处理)。X = dlarray (X,“SSCB”);如果在GPU上训练,那么将数据转换为GPU array。如果canUseGPU X = gpuArray(X);结束评估模型损失,梯度和网络状态使用。的末尾列出的modelLoss函数%的例子。(损失、lossContent lossStyle、渐变状态,Y] = dlfeval (@modelLoss,...netLoss netTransform X, SGram、weightContent weightStyle);netTransform。年代tate = state;%更新网络参数。[netTransform, averageGrad averageSqGrad] =...adamupdate (netTransform、渐变averageGrad averageSqGrad,迭代,...learnRate、gradientDecayFactor squaredGradientDecayFactor);%每个plotfrequency迭代,绘制训练进度。如果addpoints(lineLossTotal,迭代,double(loss)) addpoints(lineLossContent,迭代,double(lossContent)) addpoints(lineLossStyle,迭代,double(lossStyle))使用小批处理的第一个映像作为验证映像。十五= X (:,:,: 1);使用前面计算的转换后的验证映像。青年志愿= Y (:,:,: 1);要使用imshow函数,转换为uint8。validationImage = uint8(收集(extractdata(十五)));transformedValidationImage = uint8(收集(extractdata(青年志愿)));绘制输入图像和输出图像并增加大小imshow (imtile ({validationImage, transformedValidationImage}),父= ax2);结束%显示从开始培训到完成培训的时间。D =持续时间(0,0,toc(开始),格式=“hh: mm: ss”);completionPercentage =圆(迭代/ numIterations * 100, 2);标题(ax₁,”时代:“+我+”,迭代:“+迭代+“的”+ numIterations +”(“+ completionPercentage +“%)”+”,过去:“+ drawnow字符串(D))结束结束

使风格化图像

训练完成后,就可以对所选的任何图像使用图像转换器。

加载您想要转换的图像。

imFilename =“peppers.png”;我= imread (imFilename);

将输入图像的大小调整为图像转换器的输入尺寸。

[256256] im = imresize (im);

把它转换成dlarray。

X = dlarray(单(im),“SSCB”);

使用GPU转换为gpuArray如果有的话。

如果canUseGPU X = gpuArray(X);结束

若要将样式应用于图像,请使用函数将其转发传递给图像转换器预测。

Y =预测(netTransform X);

将图像缩放到[0 255]的范围内。首先,使用函数双曲正切要重新调节Y到[-1 1]的范围。然后,移动和缩放输出到[0 255]范围内。

Y = 255 *(双曲正切(Y) + 1) / 2;

准备Y策划。使用的函数extractdata来提取数据dlarray。使用gather函数将Y从GPU转移到本地工作区。

Y = uint8(收集(extractdata (Y)));

在风格化图像(右)旁边显示输入图像(左)。

图m = imtile({im,Y});imshow (m)

损失函数模型

这个函数modelLoss以损耗网络为输入netLoss,图像转换网络netTransform,一个小批量的输入图像X,一个包含样式图像的Gram矩阵的数组SGram,与内容损失相关的权重contentWeight以及与风格损失相关的重量styleWeight.函数返回与内容相关的总损失lossContent以及与风格相关的损失lossStyle,总损耗相对于图像转换器的可学习参数的梯度梯度,图像转换网络的状态状态,以及变换后的图像Y

函数(损失、lossContent lossStyle、渐变状态,Y] =...modelLoss(netLoss,netTransform,X,SGram,contentWeight,styleWeight) [Y,state] = forward(netTransform,X);Y = 255 *(双曲正切(Y) + 1) / 2;[损失,lossContent, lossStyle] = styleTransferLoss (netLoss Y X, SGram contentWeight, styleWeight);梯度= dlgradient(损失、netTransform.Learnables);结束

风格传递损失

这个函数styleTransferLoss以损耗网络为输入netLoss,一个小批量的输入图像X,一小批转换后的图像Y,一个包含样式图像的Gram矩阵的数组SGram,与内容和样式相关的权重contentWeight而且styleWeight,分别。它返回全部损失损失单独的组成部分:内容丢失lossContent风格的丧失lossStyle。

内容损失是衡量输入图像之间在空间结构上有多大差异的一种方法X输出图像Y

另一方面,风格损失告诉你风格形象之间在风格外观上有多大的差异年代输出图像Y

下面的图表解释了算法styleTransferLoss实现了总损失的计算。

首先,函数传递输入图像X,变换后的图像Y和风格图像年代到经过预先训练的VGG-16网络。这个预先训练过的网络从这些图像中提取出一些特征。然后利用输入图像X和输出图像Y的空间特征计算内容损失,利用输出图像Y和风格图像s的风格特征计算风格损失,最后将内容和风格损失相加得到总损失。

内容丢失

对于小批处理中的每个图像,内容丢失函数比较原始图像和由层输出的转换图像的特征relu3_3.特别是,它计算激活之间的均方误差,并返回迷你批处理的平均损失:

lossContent 1 N n 1 N 的意思是 ϕ X n - ϕ Y n 2 ,

在哪里 X 包含输入图像, Y 包含转换后的图像, N 是小批量的尺寸,和 ϕ 表示在层提取的激活relu3_3。

风格的损失

为了计算样式损失,对于小批处理中的每一张图像:

  1. 提取层上的激活relu1_2,relu2_2,relu3_3而且relu4_3

  2. 对于四种激活的每一种 ϕ j 计算克拉姆矩阵 G ϕ j

  3. 计算对应的克矩阵之间的平方差。

  4. 将每个层的四个输出相加 j 从上一步开始。

为了得到整个小批的样式损失,计算每个图像的样式损失的平均值 n mini-batch:

lossStyle 1 N n 1 N j 1 4 G ϕ j X n - G ϕ j 年代 2 ,

在哪里 j 是层的索引,和 G 为克矩阵。

全部损失

函数[损失,lossContent, lossStyle] = styleTransferLoss (netLoss, Y, X,...SGram、weightContent weightStyle)%提取激活。YActivations =细胞(1、4);YActivations [YActivations {1}, {2}, YActivations {3}, YActivations {4}] =...转发(netLoss Y“输出”,[“relu1_2”“relu2_2”“relu3_3”“relu4_3”]);XActivations =前进(netLoss X,“输出”,“relu3_3”);计算激活之间的均方误差。lossContent = mean((YActivations{3} - XActivations).^2,“所有”);把所有四次激活的损失相加。。lossStyle = 0;G = createGramMatrix(YActivations{j});lossStyle = lossStyle + sum((G - SGram{j}).^2,“所有”);结束在小批量中平均损失。miniBatchSize =大小(X, 4);lossStyle = lossStyle / miniBatchSize;%应用权重。lossContent = weightContent * lossContent;lossStyle = weightStyle * lossStyle;计算总损失。loss = lossContent + lossStyle;结束

剩余块

residualBlock函数返回一个六层数组。它由卷积层、实例归一化层、ReLu层和添加层组成。请注意,groupNormalizationLayer(“channel-wise”)只是一个实例规范化层。

函数layers = residualBlock(name) layers = [convolution2dLayer([3 3], 128,Padding= .“相同”、名称=“convRes_”+名称+“_1”) groupNormalizationLayer (“channel-wise”、名称=“normRes_”+名称+“_1”) reluLayer (Name =“reluRes_”+名称+“_1”3) convolution2dLayer([3], 128年,填充=“相同”、名称=“convRes_”+名称+“_2”) groupNormalizationLayer (“channel-wise”、名称=“normRes_”+名称+“_2”) additionLayer (Name =“加”+名字)];结束

格拉姆矩阵

这个函数createGramMatrix接受单个层的激活作为输入,并返回小批处理中每个图像的样式表示输入是一个大小为[H, W, C, N]的特征图,其中H为高度,W为宽度,C为通道数,N为小批量大小。函数输出一个数组G的大小(C, C, N)。每个子数组G (:,:, k)是否对应于 k t h 小批处理中的映像。每个条目 G , j , k 表示通道之间的相关性 c 而且 c j ,因为通道中的每个入口 c 将通道中相应位置的项相乘 c j

G , j , k 1 C × H × W h 1 H w 1 W ϕ k h , w , c ϕ k h , w , c j ,

在哪里 ϕ k 激活了吗 k t h 小批处理中的映像。

Gram矩阵包含哪些特征一起被激活的信息,但没有关于特征在图像中出现的位置的信息。这是因为高度和宽度的总和丢失了关于空间结构的信息。损失函数使用这个矩阵作为图像的风格表示。

函数G = createGramMatrix(activation) [h,w,numChannels] = size(activation,1:3);特点=重塑(激活,h * w, numChannels, []);featuresT = permute(features,[2 1 3]);G = dlmtimes(featuresT,features) / (h*w*numChannels);结束

参考文献

  1. 约翰逊、贾斯汀、亚历山大·阿拉希和李飞飞。“实时风格转换和超分辨率的感知损失。”欧洲计算机视觉会议.施普林格可汗,2016。

另请参阅

||||||

相关的话题

Baidu
map