提起前段时间红遍朋友圈的 Prisma,可能许多朋友都还记忆犹新:输入一张自己的照片,再选一个 Prisma 内置的名画滤镜,几秒之后就能得到一张名画风的新照片。
绝大部分用户可能只是通过 Prisma 过了一把当画家的瘾,但对于程序猿们来说,仅仅得到一张风格迥异的新照片似乎还远远不够。
近日,有位外国开发者根据 fast.ai 平台开设的深度学习代码实践课程,亲手实现了一个照片风格转换器,并对几种常见的优化算法的性能进行了综合对比,最终以图表加博客的方式记录下来。
下面就让我们跟随作者的脚步,一起看看究竟哪种算法最高效(程序猿是怎么玩坏 Prisma 的)。原文来自 medium.com ,雷锋网编译。文中相关的代码开源地址和原博客地址见文末。
问题1:什么是风格转换器(style transfer)?
所谓照片风格转换器,就是类似 Prisma 的,转换照片风格的软件 App。他们抽取 A 照片的风格特征(一般都是一张名画),然后将这种特征应用到 B 照片的内容上,从而生成了全新的照片 C。
问题2:怎样分隔一张照片的风格和内容?
使用卷积神经网络(CNN)。由于 AlexNet 已经成功地将 CNN 应用于目标识别(即确定图像中的主体内容),并且在 2012 年主导了最流行的计算机视觉竞赛,因此 CNN 是目前用于图像目标识别的最流行和有效的方法。
简单说,CNN 是通过学习构建在先前图层上的各个过滤器层来识别对象的。例如,第一层通常用来学习识别简单的图案,例如物体的边缘和棱角。中间层可能用来识别更复杂的图案,例如人物的眼镜、汽车的轮胎等。Jason Yosinski 大神曾在下面这个视频中详细介绍了 CNN 的相关内容。
https://www.youtube.com/watch?v=AgkfIQ4IGaM
事实证明,CNN 第一层中的过滤器对应于一张照片的风格,包括画笔描边、纹理等。靠后的图层中的过滤器对应于识别图像中的主体,例如狗,建筑物或一座山等。
例如,将一幅毕加索的画作输入 CNN,并分析第一层(样式层)有多少过滤器被激活,就可以得到该画作的样式表示。同样,通过最后一层(内容层)的分析,我们也可以得到画作内容的表示。
问题3:怎样将风格和内容融合在一起?
这一步很有意思。由于两张照片的风格大不相同,因此它们的样式层中激活的过滤器也就不同,通过分析两个样式层中的过滤器,就能获得两张照片的样式之间的差别。同样,对内容层中过滤器的分析,也能得到两张照片内容的差别。
例如,如图所示,我们想把一张自拍照和毕加索的画作融合。融合后的图像首先以图示中的噪声图像为起点,然后将这张图像输入 CNN ,它会激活样式层和内容层中的一些特定的过滤器。按照上述的方法,通过对比融合照片和毕加索画作的风格层,就可以得到风格损失(style loss);通过对比融合照片和自拍照的内容层,就可以得到内容损失(content loss),将两种损失相加,就得到了总损失。
下面的任务就很清楚了:通过优化算法的介入,我们想办法将这个总损失最小化,最终就得到了一张毕加索风格的自拍照了。
问题4:有哪些常见的优化算法?
到目前为止,我遇到了两种类型的优化算法:一阶的和二阶的。
一阶方法通过梯度(gradient)将目标函数最小化(或者最大化)。应用最广泛的就是梯度下降法(Gradient Descent)及其各种变体,详情见如下链接:
http://sebastianruder.com/optimizing-gradient-descent/
二阶方法是通过二阶导数将目标函数最小化(或者最大化)。由于二阶导数的计算成本很高,因此这里所讨论的二阶算法 L-BFGS(Limited-memory Broyden–Fletcher–Goldfarb–Shanno) 使用了 Hessian 矩阵近似。
由于我们在以下试验中处理的照片颜色灰度都介于 0-255 之间,因此将各算法的学习率(learning rate)都设置为 10,这看起来可能有点大,但效果还可以接受。算法的其他超参数(hyperparameters)都保持默认。测试的硬件环境是:Amazon P2 实例上的单片 K80 GPU。
实验1:100 次循环,300 x 300 像素
如图所示,我们输入了两张 300 x 300 像素的照片,并运行整个优化循环 100 次。虽然 100 次并不足以生成一个效果很好的融合照片,但对我们分析各个优化算法的性能已经足够了。
如图所示,由于学习率设置的略大,因此梯度下降(Gradient Descent)、Adadelta 和 RMSProp 在整个循环中都处于不断的震荡状态,并没有显示出明显的收敛趋势。反观 Adam 和 L-BFGS 算法则能够快速收敛,并且误差也基本相同。
实验2:100 次循环,600 x 600 像素
当参数增多时,L-BFGS 算法应该表现的更好。为此,我们在试验2中增大了图像,并切换了素材。
如图所示,虽然学习率的设置还是略大,但梯度下降和 Adadelta 算法在面对大数据量时显得更稳定,RMSProp 还是始终处于震荡状态。
另外,Adam 算法一开始收敛很快,但后期被 L-BFGS 反超。不知道是不是和循环次数有关,下面我们试着增加循环次数。
实验3:1000 次循环,300 x 300 像素
在实验3中,我们增加了循环次数,依然使用实验2中的照片素材,但像素变为 300 x 300。
如图所示,在略大的学习率设置下,梯度下降、Adadelta 和 RMSProp 始终处于震荡状态无法收敛。但 Adam、Adagrad 和 L-BFGS 三种算法的收敛情况则相对较好,其中效果最好的 L-BFGS 大约比 Adam 的优化效果好 50% ,并且速度也更快。
从最终生成的融合照片的成像效果也能看出来,L-BFGS、Adam 和 Adagrad 的效果要好一些。
实验4:不同的学习率,100 次循环,300 x 300 像素
有说法称过大的学习率可能会导致梯度下降、Adadelta 和 RMSProp 三种算法不收敛,因此在实验 4 中我们减小这三种算法的学习率。
可以看到,所有算法最终都收敛了。可能是得益于较低的学习速率,梯度下降的最终表现要优于 Adadelta 算法。另外,较高的学习率虽然在一开始时帮助 Adam LR 10 取得了较快的收敛速度,但最终效果并不好。而 Adam LR 1 虽然收敛缓慢,但表现很稳定。那么问题来了,如果增加循环次数,Adam LR 1 的表现是否会超过 Adam LR 10 呢?
实验5:不同的学习率,500 次循环,300 x 300 像素
增加循环次数之后,即便在学习速率较小的情况下,梯度下降、Adadelta 和 RMSProp 三种算法也还是出现了震荡。
有趣的是,Adam LR 1 最终果然反超了 Adam LR 10,甚至有超过 L-BFGS 的趋势。
实验6:1000 次循环,300 x 300 像素
这一次我们仅仅对 Adam LR 1 和 L-BFGS 进行了对比,通过进一步增加循环次数,可以看到,Adam LR 1 最终的表现并没有超过 L-BFGS。
从上述试验可以发现:在较大的学习率设置下,梯度下降、Adadelta 和 RMSProp 三种算法不容易收敛,但增大数据量,前两种会有所好转。总体上,L-BFGS 算法的收敛效果最好,速度也最快。
改变学习率。Adam 在学习率较小时,收敛情况提升明显,随着循环次数的增大,收敛效果几乎与 L-BFGS 算法相当,但收敛情况最好的依然是 L-BFGS 算法。
最后作者表示,以上实验只是从参数设置、数据量和迭代次数等方面入手简单探索了几种常见算法的特性,目的只是帮助大家在开发中更好地使用它们。虽然试验结果显示 L-BFGS 算法的收敛速度最快,效果最好,但按照个人习惯,他用 Adam 算法的情况反而更多。另外,究竟哪种算法效果最好,也不能一概而论,还是要根据数据类型和项目要求灵活选择。
源码地址:https://github.com/slavivanov/Style-Tranfer
来源:medium,雷锋网编译
雷锋网相关阅读: