主要内容

基于深度学习的神经风格迁移

这个例子展示了如何使用预先训练的vgg19网络将一个图像的风格外观应用到另一个图像的场景内容[1]

加载数据

加载样式图像和内容图像。本例以梵高的代表作《星夜》为风格图,以灯塔的照片为内容图。

styleImage = im2double (imread (“starryNight.jpg”));contentImage = imread (“lighthouse.png”);

以蒙太奇的方式显示样式图像和内容图像。

imshow (imtile ({styleImage, contentImage},“写成BackgroundColor”' w '));

负荷特征提取网络

在本例中,您使用一个经过修改的预训练的vgg19深度神经网络来提取不同层的内容和样式图像的特征。这些多层特征用于计算各自的内容和样式损失。网络利用综合损耗生成程式化的传输图像。

为了得到一个预先训练的vgg19网络,安装vgg19(深度学习工具箱).如果您没有安装所需的支持包,那么该软件将提供下载链接。金宝app

网= vgg19;

为了使vgg19网络适合于特征提取,将网络中所有的全连接层都去掉。

lastFeatureLayerIdx = 38;层= net.Layers;层=层(1:lastFeatureLayerIdx);

VGG-19网络的最大池化层会导致衰落效应。为了减少褪色效果和增加梯度流,将所有最大池化层替换为平均池化层[1]

l = 1:lastFeatureLayerIdx如果isa(层,“nnet.cnn.layer.MaxPooling2DLayer”) layers(l) = averagePooling2dLayer(layer.)PoolSize,“步”层。步,“名字”, layer.Name);结束结束

用修改过的图层创建一个图层图。

lgraph = layerGraph(层);

将特征提取网络可视化。

情节(lgraph)标题(“特征提取网络”

为了使用自定义的训练循环来训练网络并使其能够自动区分,将层图转换为dlnetwork对象。

dlnet = dlnetwork (lgraph);

数据进行预处理

将样式图像和内容图像调整为较小的尺寸以更快地处理。

图象尺寸= [384512];styleImg = imresize (styleImage、图象尺寸);contentImg = imresize (contentImage、图象尺寸);

预先训练的VGG-19网络对信道均值减去的图像进行分类。从网络的第一层图像输入层得到信道均值。

imgInputLayer = lgraph.Layers (1);meanVggNet = imgInputLayer.Mean (1 1:);

通道均值的值适用于像素值范围为[0,255]的浮点数据类型的图像。将样式图像和内容图像转换为数据类型范围[0,255]。然后,从样式图像和内容图像中减去频道均值。

styleImg = rescale(single(styleImg),0,255) - meanVggNet;contentImg = rescale(single(contentImg),0,255) - meanVggNet;

初始化传输图像

转换图像是样式转换的结果。您可以使用样式图像、内容图像或任何随机图像初始化传输图像。初始化样式图像或内容图像会使样式转换过程产生偏差,从而生成更类似于输入图像的转换图像。相比之下,初始化白噪声消除了偏差,但需要更长的时间在程式化的图像上收敛。为了更好的样式化和更快的收敛,本例将输出传输图像初始化为内容图像和白噪声图像的加权组合。

noiseRatio = 0.7;randImage = randi([-20,20],[imageSize 3]);transferImage = noiseRatio。* randImage + (1-noiseRatio)。* contentImg;

定义损耗函数和样式传递参数

内容丢失

内容丢失的目的是使传输图像的特征与内容图像的特征相匹配。内容损失计算为每个内容特征层的内容图像特征与传输图像特征之间的均方根差[1] Y ˆ 预测的特征图是否为传输图像和 Y 为内容图像的预测特征图。 W c l 内容层权重为 l t h 层。 H W C 分别为特征图的高度、宽度和通道。

l c o n t e n t l W c l × 1 H W C j Y ˆ j l - Y j l 2

指定内容特征提取层名称。从这些层中提取的特征用于计算内容损失。在VGG-19网络中,使用更深层次的特征比使用浅层次的特征更有效。因此,将内容特征提取层指定为第四卷积层。

styleTransferOptions。contentFeatureLayerNames = {“conv4_2”};

指定内容特征提取层的权重。

styleTransferOptions。contentFeatureLayerWeights = 1;

风格的损失

样式丢失的目的是使传输图像的纹理与样式图像的纹理相匹配。图像的样式表示用Gram矩阵表示。因此,我们将风格损失计算为风格图像的Gram矩阵与传输图像的Gram矩阵的均方根差[1] Z Z ˆ 分别为风格图像和传输图像的预测特征图。 G Z G Z ˆ 分别为风格特征和转移特征的Gram矩阵。 W 年代 l 款式层重量是否适合 l t h 层风格。

G Z ˆ j Z ˆ j × Z ˆ j

G Z j Z j × Z j

l 年代 t y l e l W 年代 l × 1 2 H W C 2 G Z ˆ l - G Z l 2

指定样式特征提取层的名称。从这些层中提取的特征用于计算样式损失。

styleTransferOptions。年代tyleFeatureLayerNames = {“conv1_1”“conv2_1”“conv3_1”“conv4_1”“conv5_1”};

指定样式特征提取层的权重。为简单样式图像指定小权重,并为复杂样式图像增加权重。

styleTransferOptions。年代tyleFeatureLayerWeights = [0.5,1.0,1.5,3.0,4.0];

全部损失

总损失是内容损失和风格损失的加权组合。 α β 分别为内容损失和风格损失的权重因素。

l t o t 一个 l α × l c o n t e n t + β × l 年代 t y l e

指定权重因素αβ内容丢失和风格丢失。的比例αβ应该在1e-3还是1e-4附近[1]

styleTransferOptions。α= 1;styleTransferOptions。β= 1 e3;

指定培训选项

训练2500次迭代。

numIterations = 2500;

为Adam优化指定选项。设置学习率为2,收敛速度更快。您可以通过观察输出图像和损失来实验学习速率。初始化尾随平均梯度和尾随平均梯度平方衰减率[]

learningRate = 2;trailingAvg = [];trailingAvgSq = [];

培训网络

转换样式图像、内容图像和传输图像dlarray(深度学习工具箱)具有底层类型的对象和尺寸的标签SSC的

dlStyle = dlarray (styleImg,SSC的);dlContent = dlarray (contentImg,SSC的);dlTransfer = dlarray (transferImage,SSC的);

在可用的GPU上进行训练。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU。有关更多信息,请参见GPU支金宝app持情况(并行计算工具箱).对于GPU训练,将数据转换为gpuArray

如果canUseGPU dlContent = gpuArray(dlContent);dlStyle = gpuArray (dlStyle);dlTransfer = gpuArray (dlTransfer);结束

从内容图像中提取内容特征。

numContentFeatureLayers =元素个数(styleTransferOptions.contentFeatureLayerNames);contentFeatures =细胞(1、numContentFeatureLayers);[contentFeatures{}): =前进(dlnet dlContent,“输出”, styleTransferOptions.contentFeatureLayerNames);

从样式图像中提取样式特征。

numStyleFeatureLayers =元素个数(styleTransferOptions.styleFeatureLayerNames);styleFeatures =细胞(1、numStyleFeatureLayers);[styleFeatures{}): =前进(dlnet dlStyle,“输出”, styleTransferOptions.styleFeatureLayerNames);

使用自定义训练循环训练模型。每一次迭代:

  • 利用内容图像、样式图像和传输图像的特征计算内容损失和样式损失。要计算损失和梯度,请使用helper函数imageGradients(定义在金宝app支持功能这个例子的一部分)。

  • 使用。更新传输图像adamupdate(深度学习工具箱)函数。

  • 选择最佳风格的传输图像作为最终输出图像。

图minimumLoss = inf;迭代= 1:numIterations使用dlfeval和% imageGradients函数列在例子的最后。(校友,亏损)= dlfeval (@imageGradients、dlnet dlTransfer, contentFeatures, styleFeatures, styleTransferOptions);[dlTransfer, trailingAvg trailingAvgSq] = adamupdate (dlTransfer,研究生,trailingAvg trailingAvgSq,迭代,learningRate);如果的损失。来t一个llo年代年代< minimumLoss minimumLoss = losses.totalLoss; dlOutput = dlTransfer;结束%在第一次迭代和每50次之后显示转移图像%的迭代。后处理步骤在“Postprocess”中描述% Transfer Image for Display"一节。如果mod(iteration,50) == 0 || (iteration == 1) transferImage = gather(extractdata(dlTransfer));transferImage = transferImage + meanVggNet;transferImage = uint8 (transferImage);transferImage = imresize(transferImage,size(contentImage,[1 2]));图像(transferImage)标题([“迭代后的图像传输”num2str(迭代)])轴图像drawnow结束结束

后处理转移图像显示

获取更新的传输图像。

transferImage =收集(extractdata (dlOutput));

将网络训练的平均值添加到传输图像中。

transferImage = transferImage + meanVggNet;

一些像素值可能超过内容和样式图像的原始范围[0,255]。您可以通过将数据类型转换为uint8

transferImage = uint8 (transferImage);

将传输图像的大小调整为内容图像的原始大小。

transferImage = imresize(transferImage,size(contentImage,[1 2]));

以蒙太奇方式显示内容图像、传输图像和样式图像。

imshow (imtile ({contentImage、transferImage styleImage},...“GridSize”3 [1],“写成BackgroundColor”' w '));

金宝app支持功能

计算图像损失和梯度

imageGradients辅助函数使用内容图像、样式图像和传输图像的特性返回损失和渐变。

函数(渐变,亏损)= imageGradients (dlnet、dlTransfer contentFeatures, styleFeatures, params)%初始化传输图像特征容器。numContentFeatureLayers =元素个数(params.contentFeatureLayerNames);numStyleFeatureLayers =元素个数(params.styleFeatureLayerNames);transferContentFeatures =细胞(1、numContentFeatureLayers);transferStyleFeatures =细胞(1、numStyleFeatureLayers);%提取传输图像的内容特征。[transferContentFeatures{}): =前进(dlnet dlTransfer,“输出”, params.contentFeatureLayerNames);%提取传输图像的风格特征。[transferStyleFeatures{}): =前进(dlnet dlTransfer,“输出”, params.styleFeatureLayerNames);%计算内容损失。克洛斯= contentLoss (transferContentFeatures contentFeatures params.contentFeatureLayerWeights);%计算样式丢失。斯洛斯已经分居= styleLoss (transferStyleFeatures styleFeatures params.styleFeatureLayerWeights);计算最终损失作为内容和样式损失的加权组合。= (params损失。α* cLoss) + (params.beta * sLoss);计算关于转移图像的梯度。梯度= dlgradient(损失、dlTransfer);提取各种损失。的损失。来t一个llo年代年代=gather(extractdata(loss)); losses.contentLoss = gather(extractdata(cLoss)); losses.styleLoss = gather(extractdata(sLoss));结束

计算内容丢失

contentLoss辅助函数计算内容图像特征和传输图像特征之间的加权均方根差。

函数loss = contentLoss(transferContentFeatures,contentFeatures,contentWeights) loss = 0;if (transferContentFeatures{1,i} - contentFeatures{1,i}).^2, if (transferContentFeatures{1,i} - contentFeatures{1,i}).^2,“所有”);损失=损失+ (contentWeights(i)*temp);结束结束

计算风格损失

styleLosshelper函数计算风格图像特征的Gram矩阵与传输图像特征的Gram矩阵的加权均方根差。

函数loss = 0; / /丢失丢失= 0;i=1:numel(styleFeatures) tsf = transferStyleFeatures{1,i};科幻小说= styleFeatures {1,};[w h, c] =大小(sf);gramStyle = computeGramMatrix (sf);gramTransfer = computeGramMatrix (tsf);sLoss = mean((gramTransfer - gramStyle).^2,“所有”) / ((h * w * c) ^ 2);loss = loss + (styleWeights(i)*sLoss);结束结束

计算格拉姆矩阵

computeGramMatrix助手函数由styleLoss辅助函数来计算特征图的Gram矩阵。

函数[H,W,C] = size(featureMap);reshapedFeatures =重塑(featureMap H * W C);repedfeatures ' * repedfeatures;结束

参考文献

Leon A. Gatys, Alexander S. Ecker和Matthias Bethge。《艺术风格的神经算法》预印本,2015年9月2日提交。https://arxiv.org/abs/1508.06576

另请参阅

(深度学习工具箱)|(深度学习工具箱)|(深度学习工具箱)|(深度学习工具箱)

相关的话题