------问对了问题 ,就成功了一半
Tags: 深度学习
CNN
图片风格化
一、分析别人做法
支撑我们做图像风格化的方法主要源于两篇论文,《A Neural Algorithm of Artistic Style》
(Gatys)和《Texture Networks Feed-forward Synthesis of Textures and Stylized Images》
(Prisma team),前者是理论基础,后者是对前者的一种改进,实现了性能上的突飞猛进。
Gatys的风格化版本,是训练一张噪声图片的每一个像素点,使得此图与content图和style图的差距最近。代价函数就是content差距与style差距按比例求和,不断改变噪声图片像素点,使之逐渐减小。求content差距的方法,是采用将噪点图和content图分别丢进vgg19
模型,在relu4_2
层提取出各自数值求差距。求style差距的方法,是采用将噪点图和style图分别丢进vgg19模型,在relu1_1
,relu2_1
,relu3_1
,relu4_1
,relu5_1
分别求差并求平均。这个版本能很好的实现风格与内容的融合,但是唯一的缺陷就是训练速度太慢,在gpu上跑几百轮也得1分钟,更别提cpu。
而后者Prisma Team的版本,则巧妙的避开了训练的部分,他采用了一个generator
网络,输入一张content图,经过函数变换,输出一张新图,这个新图就是前者Gatys版本里的噪声图片了。所以,代价函数跟前者是一模一样的,不过每次更新的是generator网络里的参数,这样下来再放入一张全新的测试图片时,会经过函数变换,刷一遍就得到带有风格的图片。即把漫长的训练留给自己,让用户用飞快的速度只刷一遍得到效果。
二、自己如何实现
我们最初是实现的Gatys的版本,但也是因为速度限制,转而分成两路,一路学习prisma论文,用tensorflow实现。另一路调优一个现成的mxnet版本(速度为6秒左右一张图)。在学习prisma论文的过程中,我们深刻的理解了一定要完全看懂再动手的道理,不然会踩很多坑,我们先用单图训练多轮的方式写代码并调通到有效果,再改成多图多轮的方式,反复修整代码。
具体的实现思路:
1.跑通程序
至少跑出一张图(基本要求!!!)
2.优化与试错:
做尽可能多的科学尝试,拒绝撞大运!
- 调整参数(确定范围,调整起决定性作用的参数)
- 调整模型
- 调整数据集
- 调整代码写法(代码刚调通时出现过训练速度奇慢的问题,一张图花费上十秒,经检查发现是对checkpoint的运用有误,且在一个sess里循环着套多个sess,这样就使得训练速度奇慢,删减无用代码,多写注释)
做尽可能多的科学尝试,拒绝撞大运!
3.时刻明确衡量指标:
- 指标:速度(训练速度+生成速度)、效果
- 目标:
Prisma是10s/1pics,排除网络因素耗时5s/1pics
微信平台要求5s以内传完,所以排除网络因素,上限是2s/1pics - 衡量方法:
a.速度:在cpu上跑多张图测出平均值
b.效果:选取3个风格,10张图,询问3个人(能否看出来风格)
c.总之都是要多次测试取平均值 - 训练调优的本质:
人为梯度下降,loss = 0.6 *速度 +0.4 *效果。即代价函数是与指标呈比例相关的,速度这个指标更重要所以取权重为0.6。如果最终得分超过0.8就算合格通过。
三、实现过程中遇到了哪些问题,怎么解决这些问题
【现象】
在刚开始进行训练的时候,结果并不如我们所料,往风格方向变化,反而会在几轮训练后变成一张空白图,这张图的Rgb值为Mean_pixel。
而在“脸比较白”的时候,训练个几十轮也不会变成这样,而且会有风格的效果,只不过是色调很单一,一张图基本上都是一个颜色。
都是同样的训练方式,多图训练,多轮训练,训练集大小为50-100左右。
【过程】
然而当时我们并没有想太多,这固然是一个很奇怪的问题,但是可以出结果,也许应该多试一下,我们抱着这样的想法。可是这样“撞大运“的心情显然是与科学方法不适应的。
出现了预期不同的情况,第一步就应针对这一现象,提出正确的问题。
何谓正确的问题,首先它应该对于解决问题、对于弄清楚问题原因有帮助。
这个问题,本身是可以被验证被回答的,必然存在着数学的,实验性的方法来解决它。
【提问(大问题)】
- generator的结果为什么会为
全零
?- 没有变成零的情况下生成的图片为什么
色调单一
?- 训练方法和训练集有没有什么问题?
这些问题是我们考虑了现象后提出了,它指出了我们现在存在的问题,需要解决,但是,对与怎么解决没有提供思路。
【分析(小问题)】
1.generator的结果为什么会为零?
- loss函数的收敛情况,当结果为零后,loss有没有变化?结果为零时,loss是否小?
- 0(值为全零的图)是否是一个极点?
- 这一模型中的loss函数的有没有极限?是否是线性的?
- 图片从一个有值的数组经过近30层的generator后变成全零的过程中,是在哪里,受什么影响,怎么变成零的?
已知的是,神经网络的学习过程,是由一个Loss函数
来指导的,在loss下降最快的方向调整参数,那么应明确loss函数的变化。前面几个问题是要确定这样的Loss函数能不能找到内容和风格拟合的图结果,最后一个问题,是具体分析generator中哪里有问题,关于这个问题,又可以有很多问题和方法,以及对使用的五层模型的认识,这是后话。
2.没有变成零的情况下生成的图片为什么色调单一?
- 结果图在三个通道上的分布是均衡的吗?有没有向某个通道偏移?
- 往某个通道上偏移的度和三个通道上具体的数值是什么?
图片本身,生成器最后的结果是一个四维的数组([1,256,256,3])
,颜色由这个数组的值决定,最终问题一定是可以通过这些数值观察到的。
3.训练方法和数据集有没问题?有什么问题?
- 训练数据/次数怎么对训练结果产生影响?
- 数据集的大小和分类怎么影响数据结果?
对于这些问题的探索方式其实有些像高中生物里一再强调的那样:控制变量法
和多次实验取平均值
。
特别是对于神经网络的训练来讲,有很多随机
的条件,所以不可能完全复原某一次的结果,正如物理中的不确定原理,不过同样的,数学上确定的趋势在多次实验后是不会变的。
另一个例子
之后我们又遇到过一个问题, 现象是每次重载检查点
后,loss函数会突变
,图片也会突变。
首先,根据现象推断代码的问题出现在检查点部分;
然后,验证问题是不是就在这个部分,可以用数学以及程序的方法比较检查点前后的异同;
之后,怎样解决问题 ,要弄清楚为什么那里错了,错在了具体什么地方,STFC,嗯,看代码。
四、学会分析和描述问题
在做实验的过程中遇到问题是难免的,但是在遇到问题的时候,我们不能只看到问题表面的现象,要学会分析
和描述
问题的本质。
1. 分析问题
首先是分析,当看到某一个特殊的实验现象
时,要及时记录
下它,然后找到它的特殊点
,根据自己的经验和直观判断划定几个可能导致这个现象的因素。然后找到这个现象对应的问题,特别是要问出关键
的问题,问对了问题,就成功了一半
。但是往往这个提出的问题是一个比较大的,难以直接解答的问题,也无法直接验证。所以这就需要我们根据上面提到的自己分析出的可能原因,将一个大的问题进行细化
,问出一些可以逐步求解并验证的子问题
,然后逐一解决子问题,验证猜想
,最后如果所有的子问题都得以解决,那么原来的问题基本就能得到解决了。如果还是不能解决原来的问题,那么应该反思思考一下是否自己问的问题和原来的问题就是不等价的,是两个不同的问题。这样在不断地问问题的过程中,就能很好的锻炼自己对问题的逻辑分析判断能力,能够看清问题的本质。
2. 描述问题
当我们在向别人描述自己的问题时,要尽量使用数据说话
,要有一个具体的量化标准
,不能仅凭自己的感觉,使用一些诸如“好像是”、“可能吧”、“我觉得”这样的主观词汇。就像写论文,别人在写summary或conclude的时候,总是要将自己的实验结果与他人的实验结果作对比,然后使用具体的数字比如使用多大数据集,测试多少次,最后在多次试验中总的正确率是多少,代价函数的数量级在什么水平,变化趋势是怎么样的等,来描述自己的实验结果在同等条件下,较其他实验方案,算法优在哪里,这样别人才能有一个直观的认识,如果只是自己觉得好,但是没有一个对比对照
和量化
,那么是很难描述清楚和使人信服的。也很难将问题描述清楚,让别人能够看懂和听懂。如果自己实验完成的结果非常好,但是讲出来别人听不懂,那么也是没有意义的,等于白讲。所以学会清晰地描述问题,阐述观点也是很重要的。
(注:感谢您的阅读,希望本文对您有所帮助。如果觉得不错欢迎分享转载,但请先点击 这里 获取授权。本文由 版权印 提供保护,禁止任何形式的未授权违规转载,谢谢!)