论文:Deep Image Matting - CVPR2017

源码:Github - Deep-Image-Matting(TensorFlow 实现)

粗略理解了一下 Deep Image Matting,CVPR2017,对应的代码实现 - TensorFlow 实现. 该实现的过程,源码作者介绍了大致过程 - Deep Image Matting复现过程总结 这里转载,非常感谢!

博文主要组成:

[1] - 论文梳理

[2] - 创建新的训练集

[3] - 想要训练什么样的网络

[4] - 模型结构和训练技巧

[5] - 损失函数

[6] - 作者在训练过程中的技巧

[7] - 论文阅读阶段遗留的几个问题

[8] - 论文复现

[9] - 数据准备和预处理阶段

[10] - 我们有什么?

[11] - 如何整理数据?

[12] - 为什么先融合再resize会产生ground truth飘移

[13] - 训练阶段

[14] - References

1. 论文梳理

首先需要理清的是,image matting到底是用于解决什么样的问题? matting问题的核心是一个表达式:

$$I_i = \alpha_i F_i + (1 - \alpha_i) B_i, \alpha \in [0, 1] $$ (1)

即通过 alpha 控制透明度来使前景FG和背景BG融合的技术. 有不少人把deep image matting理解为’深度抠图’,其实抠图用到的是 backgournd removal 技术[1],它关注的是如何寻找确定的前景和背景,即alpha等于0和1的部分. matting 想解决的则像是如何完美的将两张图融入到一起,即 alpha 不等于1的部分(我的理解,可能有误). 认识这点对后面损失函数权重的配比至关重要.

1.1. 创建新的训练集

要以深度学习的方式来解决这个问题,就需要寻找大量的训练数据. 已经公开的 matting 领域的 benchmark - alphamatting 2 的训练集只有27张训练样本,远远达不到深度学习的要求. 作者从视频中采取了400多张图,并用PS人工抠出了它的前景图,然后将每一张图分别融合到100个不同的背景里,最后得到了49300个训练样本. (在申请作者数据的时候,得到的文件中会包含一份纠错说明,提到论文的数据有误,实际上并没有那么多).

1.2. 想要训练什么样的网络

文章想要最终实现的效果如下图: 输入原始的RGB图片和对应的trimap(确定的前景alpha=1,确定的背景alpha=0,和不确定的边缘——unknown region, alpha=0.5),输出预测的 alpha,即没有 unknown region 的 trimap.

1.3. 模型结构和训练技巧


左边为典型的encoder和decoder结构,在 segmentation 和很多以图得图的GAN中比较常见. encoder 用 pre-trained的VGG16,把 fc6 从全连接换成了卷积,并在输入增加了第四通道channel4,用来存放输入的trimap,因为channel4而增加的weights全部初始化为0. decoder 用简单的 unpool 和 convolution 的组合来做 upsampling 和空间结构推断. 右边的 refine network是为了解决第一阶段预测输出边缘 blur 的情况.

1.3.1. 损失函数

损失函数为两个loss的加权组合:alpha loss 和 compositional loss. alpha loss是预测alpha和实际alpha的误差, conpositional loss 是将预测的 alpha 通过公式(1) 与相应的背景和前景融合后,与ground truth RGB图的误差. 只有trimap中 unknown region 区域的预测误差才会被反向传播(这是 matting 与 background removal的区别,matting 需要 trimap 作为用户交互接口,只需预测 matting中不确定的区域,而 backgournd removal则需要将整张图的误差反响传播),即 trimap 中为纯背景和纯前景的部分不计入模型预测范围,只需要把这两部分直接复制到输出的alpha即可.(注意误差都是pixel-wise的)

1.3.2 作者在训练过程中的技巧

[1] - 从原图中随机crop 320,480,640的训练patch,然后统一resize到320,作为网络输入(这里的操作必须对于你训练的那个样本的background,foreground,alpha同步操作)

[2] - 随机翻转(同上)

[3] - trimap 由 alpha 以随机大小 kernel 的 dilation

[4] - 操作生成

[5] - Refinement很好理解,这里不展开解释了.

1.4. 论文阅读阶段遗留的几个问题

[1] - 训练mini batch的size

[2] - crop的安全性是怎么解决的?因为以 unknown region 为中心随机crop,很可能会出现crop超出边界的情况

[3] - compositional 值的scale是0~255,而 alpha loss 的 scale 是0~1,如果不对compositional loss除以255的话,会出现loss严重倾向于compositional loss的情况

[4] - 在网络结构上是否有其他技巧,比如 PReLU,batch_normalization

2. 论文复现

2.1. 数据准备和预处理阶段

由于有来自xx公司的数据,所以实验没有建立在作者数据的基础上. 预处理阶段需要注意的很多很多,大致流程如下图:

能离线处理的数据就尽量离线处理,比如把所有的backgournd都提前整理好,具体文件夹结构的组织方式可以去看在github[5] 上上传的data_structure说明. 对这个图简单解释一下:

2.1.1. 我们有什么?

[1] - 训练数据的alpha

[2] - 训练数据的RGB(即图中的eps,这个数据是foreground的来源,需要在程序中与alpha组合产生foreground,再matting到背景上实现真正的输入RGB)

[3] background(来自 pascal voc 和 coco )

2.1.2. 如何整理数据?

[1] - 把 alpha 和 eps 都resize到最长边为640,同时保留长宽比.

[2] - 因为 crop 的最大size为 640x640,所以把 background 都 resize 到最短边为1280,同时保留长宽比.

[3] - 把 alpha 和 eps 都 center padding 到背景里,这样无论怎样 crop,只要是以 trimap 的unknown region为中心,就不会出现crop出边界的情况(另一种解决方案,不 resize 背景,直接将 alpha 和 eps center pad 进背景,假设 crop 出边界,把出界的那条边拉回来即可. 比如 crop 左边出界了,则设置 crop 左边的起始位置为0.作者应该采用的是这种方式,因为从作者分享的代码来看没有针对background做特殊操作).

前三点都是离线准备好的,即不是在网络训练的时候进行,下面的步骤都是在网络训练的时候同时进行.

[1] - 通过对 alpha 进行 random dilation 得到 trimap

[2] - 以 trimap 中的 unknown region 任取一点为中心对 alphap,eps,trimap 进行crop (size也是从320,480,640中随机选择)

[3] - 如果 size 选择到的不是320,则对所有数据 resize 到320作为网络输入. 此时我们拥有了ground truth background, ground truth alpha, ground truth trimap, ground truth eps. 还缺了什么?缺了ground truth foreground

[4] - 通过公式(1)对此时的 alpha 和 eps 进行 composition 得到ground truth foreground.

[5] - 通过公式(1)对此时的 alpha,eps 和 BGcomposition 得到 ground truth RGB.

[6] - ground truth RGB 减去 global mean,然后 concatenate trimap 作为网络的 4 通道输入,剩余的作为计算Loss 的原料.

至此,数据准备和预处理阶段完成. 这里值得提的有四点(我犯过的错误):

[1] - 离线数据不到最后一步千万不要用 jpg 格式保存,用 png,因为 jpg 是有损压缩,对于这种像素级精度都要求很高的项目来说,中间以 jpg 保存一次就非常致命了. 可以在最后一步保存为 jpg 因为即便出现误差,也是ground truth 的整体飘移,飘移后的数据依然保持一致性,不会对网络的训练造成影响.

[2] - 任何 resize 操作不能发生在用公式(1) 之后,这也是为什么要组织上图那样精细的数据预处理的原因. 这样会造成ground truth漂移,会产生训练数据的不一致性. 下面有举例说明.

[3] - 其他 resize 可以采用默认的双线性插值. 但是trimap最好用 nearest 插值的方式resize,因为其他方式几乎都会改变像素值,而对于 trimap 必须保证 unknown region 为128,而 nearest 插值不会生成新的像素值,只会在原始图像的像素中提取,而且 trimap 对 nearest 插值带来的锯齿不敏感(因为trimap本身就是非常语义模糊的),所以对于 trimap,nearest 是最理想的resize方式.

[4] - resize alpha 的时候,先把数据类型转换成uint8,resize过后再转换回 float32,因为 misc.imresize 操作会对 float 型的数据 rescale,所以你输入图片最大的像素值是32,输出可能直接就被 rescale 到 255了.

2.1.3. 为什么先融合再resize会产生ground truth飘移

先融合再 resize 和先resize再融合的结果分别为:

两张图看似一样,但是一作差就会发现:

所以如果先融合,再 resize,此时你得到的 foreground 对应的都不是当初原原本本的 alpha 了(resize产生的误差),这对于神经网络的训练极为不利,因为网络努力拟合的方向不是真正它应该去的方向(出现了些许飘移). 从 adobe 公司提供的组合 compositional 的代码可以发现,ground truth RGB是提前离线生成的,也就是说先mat了,而在后面的预处理阶段还有resize操作. 假设作者真的犯了这个错误而没意识到,那可能是文章中模型需要第二阶段refinement的原因. 也就是说如果不犯这个错误的话,可能就不需要第二阶段的refinement网络了(这是我个人的推测).

2.2. 训练阶段

训练阶段没有太多可以谈的. 谈谈我实现过程中与作者不一致的地方.

[1] - 一开始我选择用 deconvolution 代替 unpool 操作,因为 tensorflow 没有现成的unpool函数,虽然有opensource 的,但是都会对网络输入的 batch size产生限制. 即你训练用mini batch size为 5,那么预测阶段也只能 5 个一起预测,非常不便. 但是实验中发现,虽然用 deconvolution 能对单一的有样本过拟合,但是却很难在整个训练集上拟合,考虑到用 deconvolution 后,网络的复杂度其实是高于作者用的网络的,所以不能在整个网络上拟合是非常奇怪的事. 我能想到唯一的解释就是训练时间不够. 最终 deconvolution 的实验在学习率为1e-5 的情况下跑了5天,模型能非常好的预测 general shape,但是一直无法拟合边缘,后来放弃了deconvolution 的做法.

[2] - 用了batch normalization. 虽然原文没提到这一点,但是仅仅是因为不用 batch norm,模型最后都会预测出全黑的结果,所以加上了这个正则化方法,相应的把学习率调整到了1e-4,拟合变得非常快. 用了unpool之后拟合只需要7小时.

[3] - 之前说 unpool 有限制输入 batch size 的问题,后来为什么又用 unpool 了?因为参考了 segmentation 的论文发现,其实在这种以图预测图的任务中,可以认为每一个像素都是一个训练样本,这样即便 batch size 为一,模型在一次训练中也进行了大量的预测,这点是与 classification 任务不同的地方. 所以最后索性设置batch size 为 1,将 deconvolution 换成了unpool, 模型成功拟合了,泛化略微没有作者表现的那么好. 具体请参考我关于这个项目的github页面[5].

[4] - 出于某些原因,在github上的代码里对纯背景和纯前景的地方也进行了误差的反向传播,权重设为了0.5. 实验证明,是否对 bg 和 fg 区域进行反向传播对模型的上限没有影响. 如果不想那两部分的误差有影响,只需将权重设置为0.

这篇论文的复现恐怕要到此为止了,训练阶段的第一点,即 “排除了作者预处理上的失误后,我们能不能不用refinement 网络而达到原论文的水平”暂时没时间去验证也因为公司接下来不会用这个项目,所以才能以博客和开源的方式在这里把复现过程分享给各位,欢迎大家发表自己的意见.

Github 页面 - https://github.com/Joker316701882/Deep-Image-Matting

3. Reference

[1] - https://clippingmagic.com/

[2] - http://alphamatting.com/

[3] - http://www.juew.org/publication/CVPR09_evaluation_final_HQ.pdf

[4] - http://docs.opencv.org/2.4/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

[5] - https://github.com/Joker316701882/Deep-Image-Matting

Last modification:May 10th, 2019 at 05:41 pm