前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >梵高《星夜》的『现代版』

梵高《星夜》的『现代版』

作者头像
WolframChina
发布2018-05-31 10:45:33
6180
发布2018-05-31 10:45:33
举报
文章被收录于专栏:WOLFRAMWOLFRAM

荷兰后印象派画家——梵高是表现主义的先驱,并深深影响了二十世纪的绘画艺术,尤其是野兽派与德国表现主义。梵高的作品,如《星夜》、《向日葵》与《麦田群鸦》等,现已跻身于全球最著名、广为人知与昂贵的艺术作品的行列。今天,让我们用神经算法把你的图片赋上你心怡的艺术色彩!

在这里要讨论的是利用 Wolfram 语言来进行艺术风格的转换。在下面的文档中也能找到这个范例:

NetTrain >> 应用 >> 计算机视觉 >> 风格转移(http://reference.wolfram.com/language/ref/NetTrain.html.en)

代码

创建一幅新图像,内容来自一幅给定的图像,风格则来自另一幅给定的图像。这是根据 Gatys 等在《艺术风格的神经算法》(A Neural Algorithm of Artistic Style) 中描述的方法来实现的。内容和风格图像如下:

为了生成这两幅图像的混合品,先获取预先训练过的图像分类网络:

代码语言:javascript
复制
vggNet = NetModel["VGG-16 Trained on ImageNet Competition Data"];

获取将被用作风格和内容图像的特征提取器的子网络:

代码语言:javascript
复制
featureNet = Take[vggNet, {1, "relu4_1"}]

其中用到了三个损失函数。第一个损失函数确保合成图像中的 "content" 与内容图像的相似:

代码语言:javascript
复制
contentLoss = NetGraph[{MeanSquaredLossLayer[]}, {1 -> NetPort["LossContent"]}]

第二个损失函数确保合成图像中的 "style" 与风格图像的相似。风格相似性被定义为输入和输出的 Gram 矩阵间的均方差:

代码语言:javascript
复制
gramMatrix = NetGraph[{FlattenLayer[-1], TransposeLayer[1 -> 2],   DotLayer[]}, {1 -> 3, 1 -> 2 -> 3}];
styleLoss = NetGraph[{gramMatrix, gramMatrix, MeanSquaredLossLayer[]},{NetPort["Input"] -> 1, NetPort["Target"] -> 2, {1, 2} -> 3,  3 -> NetPort["LossStyle"]}]

第三个损失函数确保合成图像中相邻像素间亮度的幅值变化为较小的值。这使得合成图像看起来更自然:

代码语言:javascript
复制
l2Loss = NetGraph[{ThreadingLayer[(#1 - #2)^2 &], SummationLayer[]}, {{NetPort["Input"], NetPort["Target"]} -> 1 -> 2}];tvLoss = NetGraph[<|
   "dx1" -> PaddingLayer[{{0, 0}, {1, 0}, {0, 0}}, "Padding" -> "Fixed" ],
   "dx2" ->  PaddingLayer[{{0, 0}, {0, 1}, {0, 0}}, "Padding" -> "Fixed"],
   "dy1" ->  PaddingLayer[{{0, 0}, {0, 0}, {1, 0}}, "Padding" -> "Fixed" ],
   "dy2" ->  PaddingLayer[{{0, 0}, {0, 0}, {0, 1}}, "Padding" -> "Fixed"],
   "lossx" -> l2Loss, "lossy" -> l2Loss, "tot" -> TotalLayer[]|>,
 {{"dx1", "dx2"} -> "lossx", {"dy1", "dy2"} -> "lossy",
   {"lossx", "lossy"} -> "tot" -> NetPort["LossTV"]}]

定义一个函数,为任意内容和风格的图像创建最终的训练网络。该函数同时生成了一个随机初始图像:

代码语言:javascript
复制
createTransferNet[net_, content_Image, styleFeatSize_] := Module[{dims = Prepend[3]@Reverse@ImageDimensions[content]},NetGraph[<|"Image" -> ConstantArrayLayer["Array" -> RandomReal[{-0.1, 0.1}, dims]],"imageFeat" -> NetReplacePart[net, "Input" -> dims],"content" -> contentLoss,"style" -> styleLoss,"tv" -> tvLoss|>,{"Image" -> "imageFeat",{"imageFeat", NetPort["ContentFeature"]} -> "content",{"imageFeat", NetPort["StyleFeature"]} -> "style","Image" -> "tv"},"StyleFeature" -> styleFeatSize   ] ]

定义一个 NetDecoder 来可视化预测的图像:

代码语言:javascript
复制
meanIm = NetExtract[featureNet, "Input"][["MeanImage"]]

{0.48502, 0.457957, 0.407604}

decoder = NetDecoder[{"Image", "MeanImage" -> meanIm}]

训练数据由从内容和风格图像中提取的特征组成。定义特征提取函数:

代码语言:javascript
复制
extractFeatures[img_] := NetReplacePart[featureNet, "Input" ->NetEncoder[{"Image", ImageDimensions[img], 
 "MeanImage" ->meanIm}]][img];

创建由单个内容和风格特征实例组成的训练集:

代码语言:javascript
复制
trainingdata = <|
  "ContentFeature" -> {extractFeatures[contentImg]},
   "StyleFeature" -> {extractFeatures[styleImg]}
  |>

创建训练集,其输入维度对应于内容和人风格图像的维度:

代码语言:javascript
复制
net = createTransferNet[featureNet, contentImg, 
   Dimensions@First@trainingdata["StyleFeature"]];

在训练时,对三个损失函数进行加权,以确定内容和风格的相对重要性。对于不同内容和风格的图像,这些值可能需要更改。创建损失规范,定义由这三个损失组合而成的最终损失:

代码语言:javascript
复制
perPixel = 1/(3*Apply[Times, ImageDimensions[contentImg]]);lossSpec = {"LossContent" -> Scaled[6.*10^-5], 
   "LossStyle" -> Scaled[0.5*10^-14], 
   "LossTV" -> Scaled[20.*perPixel]};

用 NetTrain 优化图像,用 LearningRateMultipliers 冻结网络中除 ConstantArrayLayer 之外的所有参数。最好是在 GPU 上进行训练,因为用 CPU 进行训练可能要花一个小时才能得到好结果。可以用 计算->放弃计算 在任何时候终止训练:

代码语言:javascript
复制
trainedNet = NetTrain[net,
  trainingdata, lossSpec,
  LearningRateMultipliers -> {"Image" -> 1, _ -> None},
  TrainingProgressReporting -> 
   Function[decoder[#Weights[{"Image", "Array"}]]],
  MaxTrainingRounds -> 300, BatchSize -> 1,
  Method -> {"ADAM", "InitialLearningRate" -> 0.05},
  TargetDevice -> "GPU"
  ]

从训练过的网络中的 ConstantArrayLayer 提取最终图像:

代码语言:javascript
复制
decoder[NetExtract[trainedNet, {"Image", "Array"}]]

现代版《星夜》出现了......

你可以尝试其他美图噢!更多细节请点击“阅读原文”参见【Wolfram社区】的原文。

+

=

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WOLFRAM 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档