这个例子展示了如何训练一个网络的风格一个图像转移到另一个图像。它是基于[1]中定义的架构。
这个例子是类似的使用深度学习神经风格转移,但它工作速度一旦训练网络风格形象s .这是因为,获得的程式化形象Y你只需要做一个传球前进的输入图像X的网络。
找一个高级图下面的训练算法。它使用三个图像计算损失:输入图像X, Y和风格形象S转换后的图像。
请注意,损失函数使用pretrained网络VGG-16从图像中提取特征。你可以找到它的实现和数学定义风格传递损失这个例子。
下载并提取可可2014训练图像和字幕https://cocodataset.org/下载通过单击“2014训练图像”。数据保存在指定的文件夹imageFolder
。图像提取到imageFolder
。可可2014年收集的可可财团。
创建目录来存储可可数据集。
imageFolder = fullfile (tempdir,“可可”);如果~存在(imageFolder“dir”mkdir (imageFolder);结束
创建一个包含可可图像的图像数据存储。
imd = imageDatastore (imageFolder,“IncludeSubfolders”,真正的);
培训需要花很长时间运行。如果你想减少训练时间为代价的准确性产生的网络,然后选择一个子集的图像数据存储设置分数
一个较小的值。
分数= 1;numObservations =元素个数(imds.Files);imd =子集(imd, 1:地板(numObservations *分数);
调整图像和它们都转换为RGB,创建一个增强图像数据存储。
augimds = augmentedImageDatastore (imd (256 256),“ColorPreprocessing”,“gray2rgb”);
阅读风格形象。
styleImage = imread (“starryNight.jpg”);styleImage = imresize (styleImage (256 256));
显示所选的风格形象。
图imshow (styleImage)标题(“风格形象”)
定义图像变压器网络。这是一个image-to-image网络。网络由三部分组成:
网络的第一部分将作为输入的RGB图像大小[256 x256x3], downsamples特征地图大小[64 x64x128]。
的第二部分网络包括五个相同的残块中定义的支持功能金宝appresidualBlock。
网络的第三部分,也是最后一部分upsamples特性映射到原始图像并返回转换后的图像的大小。最后一个部分使用upsampleLayer
,这是一个自定义层附加到这个例子作为支持文件。金宝app
层= [%第一部分。imageInputLayer ([256 256 3),“名字”,“输入”,“归一化”,“没有”32岁的)convolution2dLayer (9 [9]“填充”,“相同”,“名字”,“conv1”)groupNormalizationLayer (“channel-wise”,“名字”,“norm1”)reluLayer (“名字”,“relu1”3)convolution2dLayer([3], 64年,“步”2,“填充”,“相同”,“名字”,“conv2”)groupNormalizationLayer (“channel-wise”,“名字”,“norm2”)reluLayer (“名字”,“relu2”3)convolution2dLayer([3], 128年,“步”2,“填充”,“相同”,“名字”,“conv3”)groupNormalizationLayer (“channel-wise”,“名字”,“norm3”)reluLayer (“名字”,“relu3”)%第二部分。residualBlock (“1”)residualBlock (“2”)residualBlock (“3”)residualBlock (“4”)residualBlock (“5”)%第三部分。upsampleLayer (“up1”3)convolution2dLayer([3], 64年,“步”,1“填充”,“相同”,“名字”,“upconv1”)groupNormalizationLayer (“channel-wise”,“名字”,“norm6”)reluLayer (“名字”,“relu5”)upsampleLayer (“呼吁”3)convolution2dLayer([3], 32岁“步”,1“填充”,“相同”,“名字”,“upconv2”)groupNormalizationLayer (“channel-wise”,“名字”,“norm7”)reluLayer (“名字”,“relu6”3)convolution2dLayer(9日,“填充”,“相同”,“名字”,“conv_out”));lgraph = layerGraph(层);
添加缺失的连接残块。
lgraph = connectLayers (lgraph,“relu3”,“add1 / in2”);lgraph = connectLayers (lgraph,“add1”,“add2 / in2”);lgraph = connectLayers (lgraph,“add2”,“add3 / in2”);lgraph = connectLayers (lgraph,“add3”,“add4 / in2”);lgraph = connectLayers (lgraph,“add4”,“折扣/ in2”);
可视化图像变压器网络在一个阴谋。
图绘制(lgraph)标题(“变换网络”)
创建一个dlnetwork
对象的层图。
dlnetTransform = dlnetwork (lgraph);
这个示例使用pretrained VGG-16深层神经网络提取图像内容和风格的特性在不同的层。这些多层功能用于计算各自的内容和风格的损失。
得到一个pretrained VGG-16网络,使用vgg16
函数。如果你没有安装所需的支持包,然后软件提供一个下载链接。金宝app
netLoss = vgg16;
提取计算所需的功能损失只需要第一个24层。提取和转换为一层图。
lossLayers = netLoss.Layers(桥);lgraph = layerGraph (lossLayers);
转换为一个dlnetwork
。
dlnetLoss = dlnetwork (lgraph);
创建styleTransferLoss
函数中定义风格传递损失这个例子。
这个函数styleTransferLoss
作为输入失去网络dlnetLoss
,mini-batch输入图像转换dlX,
mini-batch转换图像海底
数组,包含克矩阵的风格形象dlSGram
,与内容相关的重量损失contentWeight
和重量与风格相关的损失styleWeight
。函数返回的总损失损失
和个人部分:内容丢失lossContent
和风格损失lossStyle。
的styleTransferLoss
函数使用支持功能金宝appcreateGramMatrix
在风格的计算损失。
的createGramMatrix
函数作为输入的特性提取损失网络并返回一个风格为每个图像在mini-batch表示。你可以找到格拉姆矩阵的实现和数学定义的部分格拉姆矩阵。
创建函数modelGradients
中列出,模型梯度函数部分的例子。这个函数作为输入失去网络dlnetLoss
,图像变压器网络dlnetTransform
mini-batch的输入图像dlX
数组,包含克矩阵的风格形象dlSGram
,与内容相关的重量损失contentWeight
和重量与风格相关的损失styleWeight
。该函数返回梯度
失去对图像的可学的参数变压器,变压器图像网络的状态,转换后的图像海底,
总损失损失
,与内容相关的损失lossContent
和与风格相关的损失lossStyle。
火车mini-batch大小为4 2时代[1]。
numEpochs = 2;miniBatchSize = 4;
设置读取大小mini-batch增强图像数据存储的大小。
augimds。MiniBatchSize = MiniBatchSize;
指定的选项为亚当的优化。指定一个学习的速度梯度衰减系数为0.01,0.001和0.999平方梯度衰减系数。
learnRate = 0.001;gradientDecayFactor = 0.9;squaredGradientDecayFactor = 0.999;
火车在GPU如果一个是可用的。使用GPU需要并行计算工具箱™和支持GPU设备。金宝app支持设备的信息,请参阅金宝appGPU的金宝app支持版本(并行计算工具箱)。
executionEnvironment =“汽车”;
指定体重的风格和内容给出的一个损失计算的总损失。
注意,为了找到一个好的平衡内容和风格,你可能需要尝试不同的组合权重。
weightContent = 1的军医;weightStyle = 3 e-8;
选择的情节频率训练进展。这将指定每个情节之间有多少的迭代更新。
plotFrequency = 10;
为了能够计算出损失在训练,计算矩阵克风格的图像。
转换图像风格dlarray
。
dlS = dlarray(单(styleImage),SSC的);
为了计算格拉姆矩阵、饲料的风格形象VGG-16网络的激活和提取四个不同的层次。
[dlSActivations1, dlSActivations2 dlSActivations3 dlSActivations4] =前进(dlnetLoss dlS,…“输出”,(“relu1_2”“relu2_2”“relu3_3”“relu4_3”]);
计算每组的格拉姆矩阵激活使用支持功能金宝appcreateGramMatrix
。
dlSGram {1} = createGramMatrix (dlSActivations1);dlSGram {2} = createGramMatrix (dlSActivations2);dlSGram {3} = createGramMatrix (dlSActivations3);dlSGram {4} = createGramMatrix (dlSActivations4);
培训情节包含两个数据:
图显示一个阴谋培训期间的损失
图包含一个输入和一个输出图像的图像变压器网络
初始化培训的阴谋。你可以检查支持函数中初始化的细节金宝appinitializeFigures。
这个函数返回:轴ax₁
你把损失,轴在哪里ax2
你图验证图片,动画行吗lineLossContent
它包含内容,动画lineLossStyle
其中包含样式损失和动画行吗lineLossTotal
它包含的总损失。
(ax₁, ax2 lineLossContent、lineLossStyle lineLossTotal] = initializeStyleTransferPlots ();
初始化的平均梯度和平均平方梯度hyperparameters亚当优化器。
averageGrad = [];averageSqGrad = [];
计算训练迭代的总数。
numIterations =地板(augimds.NumObservations * numEpochs / miniBatchSize);
初始化迭代数量和计时器前培训。
迭代= 0;开始=抽搐;
火车模型。这可能需要很长时间才能运行。
%循环时期。为我= 1:numEpochs%重置和洗牌数据存储。重置(augimds);augimds = shuffle (augimds);%在mini-batches循环。而hasdata (augimds)迭代=迭代+ 1;% mini-batch读取的数据。data =阅读(augimds);%忽略时代的最后部分mini-batch。如果(数据,1)< miniBatchSize大小继续结束%提取图像数据存储单元阵列。数据图像= {:1};%连接图像在第四维度。X =猫(4、图像{:});X =单(X);%转换mini-batch dlarray和指定的数据维度标签%的SSCB(空间、空间、通道、批)。dlX = dlarray (X,“SSCB”);%如果训练在GPU,然后将数据转换成gpuArray。如果(executionEnvironment = =“汽车”& & canUseGPU) | | executionEnvironment = =“图形”dlX = gpuArray (dlX);结束%评估模型梯度和网络状态使用% dlfeval modelGradients函数结束时上市%的例子。(梯度、州、海底、失去、lossContent lossStyle] = dlfeval (@modelGradients,…dlnetLoss、dlnetTransform dlX, dlSGram、weightContent weightStyle);dlnetTransform。=状态;%更新网络参数。[dlnetTransform, averageGrad averageSqGrad] =…adamupdate (dlnetTransform、渐变averageGrad averageSqGrad,迭代,…learnRate、gradientDecayFactor squaredGradientDecayFactor);%每个plotFequency迭代,情节的培训进度。如果国防部(迭代,plotFrequency) = = 0 addpoints (lineLossTotal、迭代、双(收集(extractdata(损失))))addpoints (lineLossContent、迭代、双(收集(extractdata (lossContent)))) addpoints (lineLossStyle、迭代、双(收集(extractdata (lossStyle))))%使用的第一形象mini-batch作为验证的形象。dlV = dlX (:,:,: 1);%使用转换后的图像验证计算。dlVY =海底(:,:,:1);%使用函数imshow uint8转换。validationImage = uint8(收集(extractdata (dlV)));transformedValidationImage = uint8(收集(extractdata (dlVY)));%画出输入图像和输出图像,增加大小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。
dlX = dlarray(单(im),“SSCB”);
使用GPU皈依gpuArray
如果一个人是可用的。
如果canUseGPU dlX = gpuArray (dlX);结束
应用样式的图片,把它转发给图像变压器使用函数预测。
海底=预测(dlnetTransform dlX);
重新调节图像的范围(0 255)。首先,使用函数双曲正切
要重新调节海底
(1)范围。然后,和规模输出转移到重新进入255年[0]范围内。
Y = 255 *(双曲正切(海底)+ 1)/ 2;
准备Y
策划。使用的函数extractdata
提取的数据dlarray。
使用聚集函数Y的GPU转移到本地工作区。
Y = uint8(收集(extractdata (Y)));
显示输入图像(左)旁边的程式化形象(右)。
图m = imtile ({im, Y});imshow (m)
这个函数modelGradients
作为输入失去网络dlnetLoss
,图像变压器网络dlnetTransform
mini-batch的输入图像dlX
数组,包含克矩阵的风格形象dlSGram
,与内容相关的重量损失contentWeight
和重量与风格相关的损失styleWeight
。它将返回梯度
失去对图像的可学的参数变压器,变压器图像网络的状态,转换后的图像海底
,总损失损失
,与内容相关的损失lossContent
和与风格相关的损失lossStyle。
函数(梯度、州、海底、失去、lossContent lossStyle] =…modelGradients (dlnetLoss、dlnetTransform dlX、dlSGram contentWeight, styleWeight)[海底、州]=前进(dlnetTransform dlX);海底= 255 *(双曲正切(海底)+ 1)/ 2;[损失,lossContent, lossStyle] = styleTransferLoss (dlnetLoss,海底,dlX dlSGram, contentWeight, styleWeight);梯度= dlgradient(损失、dlnetTransform.Learnables);结束
这个函数styleTransferLoss
作为输入失去网络dlnetLoss
mini-batch的输入图像dlX,
mini-batch转换图像海底
数组,包含克矩阵的风格形象dlSGram
,与内容相关的权重和风格contentWeight
和styleWeight,
分别。它返回的总损失损失
和个人部分:内容丢失lossContent
和风格损失lossStyle。
损失是多少的测量内容输入图像之间的空间结构有差异X
和输出图像Y
。
另一方面,风格告诉你损失之间有多少不同风格外观风格的形象年代
和输出图像Y
。
下面的图表说明了算法styleTransferLoss
实现计算的总损失。
首先,函数将输入图像X
,转换后的图像Y
和风格的形象年代
VGG-16 pretrained网络。这pretrained网络从这些图像中提取一些特性。然后算法计算损失的内容使用的空间特性输出图像的输入图像X和Y .此外,计算风格损失通过输出图像Y的文体特征和风格的形象s .最后,它获得的总损失增加的内容和风格的损失。
mini-batch中的每个图像的内容损失函数比较原始图像的特性和转换后的图像输出的层relu_3_3
。特别是,它计算激活并返回之间的均方误差的平均损失mini-batch:
在哪里
包含输入图像,
包含了转换后的图像,
是mini-batch大小,
代表了激活提取层relu_3_3。
计算风格损失,为每个mini-batch单张图片:
提取层的激活relu1_2
,relu2_2
,relu3_3
和relu4_3
。
为每个四个激活 计算格拉姆矩阵 。
计算平方矩阵对应的克之间的区别。
每层加起来四个输出 从上一步。
获取整个mini-batch风格损失,计算每个图像风格的平均损失 mini-batch:
在哪里
层的索引,
格拉姆矩阵。
函数[损失,lossContent, lossStyle] = styleTransferLoss (dlX dlnetLoss,海底,…dlSGram、weightContent weightStyle)%提取激活。dlYActivations =细胞(1、4);dlYActivations [dlYActivations {1}, {2}, dlYActivations {3}, dlYActivations {4}] =…转发(dlnetLoss,海底,“输出”,(“relu1_2”“relu2_2”“relu3_3”“relu4_3”]);dlX dlXActivations =前进(dlnetLoss,“输出”,“relu3_3”);%计算激活之间的均方误差。lossContent =意味着((dlYActivations {3} - dlXActivations)。^ 2,“所有”);%增加损失的所有四个激活。lossStyle = 0;为j = 1:4 G = createGramMatrix (dlYActivations {j});lossStyle = lossStyle +总和((G - dlSGram {j}) ^ 2,。“所有”);结束% mini-batch平均损失。miniBatchSize =大小(dlX 4);lossStyle = lossStyle / miniBatchSize;%应用权重。lossContent = weightContent * lossContent;lossStyle = weightStyle * lossStyle;%计算全损。损失= lossContent + lossStyle;结束
的residualBlock
函数返回一个数组的六层。归一化层,它由卷积层,实例ReLu层和附加层。请注意,groupNormalizationLayer (“channel-wise”)
只是一个实例归一化层。
函数层= residualBlock(名字)层= [convolution2dLayer (3 [3], 128,“步”,1“填充”,“相同”,“名字”,“convRes”+名称+“_1”)groupNormalizationLayer (“channel-wise”,“名字”,“normRes”+名称+“_1”)reluLayer (“名字”,“reluRes”+名称+“_1”3)convolution2dLayer([3], 128年,“步”,1“填充”,“相同”,“名字”,“convRes”+名称+“_2”)groupNormalizationLayer (“channel-wise”,“名字”,“normRes”+名称+“_2”)additionLayer (2“名字”,“添加”+名字)];结束
这个函数createGramMatrix
需要作为输入单一层的激活,并返回一个风格表示mini-batch每个图像。
大小的输入特性映射[W H, C, N],其中H是高度,W是宽度,C是通道的数量,N是mini-batch大小。函数输出数组G
的大小(C, C, N)。每个子数组G (:,:, k)
相对应的格拉姆矩阵吗
mini-batch形象。每个条目
的格拉姆矩阵表示通道之间的相关性
和
,因为每个条目在通道
繁殖在通道入口在相应的位置
:
在哪里 的激活吗 mini-batch形象。
格拉姆矩阵包含哪些特性信息激活在一起但没有信息出现在图像的特性。这是因为高度和宽度的总和失去了空间结构的信息。损失函数使用这个矩阵作为一个风格的代表形象。
函数G = createGramMatrix(激活)[h, w, numChannels] =大小(激活,1:3);特点=重塑(激活,h * w, numChannels, []);特点=排列(功能,(2 1 3));G = dlmtimes(功能、特点)/ w (h * * numChannels);结束
约翰逊,贾斯汀,亚历山大Alahi,李菲菲。“知觉损失实时传输和超分辨率风格。”欧洲计算机视觉。施普林格,可汗,2016。
dlnetwork
|向前
|预测
|dlarray
|dlgradient
|dlfeval
|adamupdate