金字塔每层的通道数为:[16, 32, 64, 96, 128, 196],16为第一层,196为第6层。第一层分辨率最大,为输入图像尺寸的一半,之后每升高一层,分辨率变为上一层的一半。第6层分辨率最小。PWC一共6层金字塔。以输入图像为(256,448)为例子,那么第一层为(128,224),第6层为(4,7)
第6层
先从第5层开始,也就是分辨率最低的开始,这一层的操作和其他层都不一样。第5层首先做一个corr,
corr = self.corr(c1[6], c2[6], 6)
然后直接预测
upfeat, flow = self.predict_flow(corr, None, None, None, 6)
然后把flow放一个列表里,用来计算这一层的loss
flow_pyr.append(flow)
最后上采样
up_flow = self.deconv(flow, 6, 'up_flow')
up_feat = self.deconv(upfeat, 6, 'up_feat')
5~3层
首先对上一层的光流值进行乘系数,然后在warp,这里的lvl=5,4,3,
scaler = 20. / 2**lvl # scaler values are 0.625, 1.25, 2.5, 5.0
warp = self.warp(c2[lvl], up_flow * scaler, lvl)
然后做corr
corr = self.corr(c1[lvl], warp, lvl)
然后预测光流,这里的输入不光是cost volume,还有上一层上菜样之后的光流和特征
upfeat, flow = self.predict_flow(corr, c1[lvl], up_flow, up_feat, lvl)
第2层
这里最后不再对生成的光流进行上采样,而是对光流进行context处理,第二层的分辨率为(64,112),金字塔第一层我们不用。
flow = self.refine_flow(upfeat, flow, 2)
flow_pyr.append(flow)
上然上采样至输入图片分辨率,这里flow_pred_lvl=2,lvl_height为当前光流场的高. 不需要乘系数,下面有解释
scaler = 2**self.opts['flow_pred_lvl']
size = (lvl_height * scaler, lvl_width * scaler)
flow_pred = tf.image.resize_bilinear(flow, size, name="flow_pred")
网络输出的的是每一层的光流和最终光流
return flow_pred, flow_pyr
首先对光流真实值进行下采样,这里不需要乘以系数
scaled_flow_gt = tf.image.resize_bilinear(y, (lvl_height, lvl_width))
####scaled_flow_gt /= tf.cast(gt_height / lvl_height, dtype=tf.float32)
以最小分辨率为例,光流真实值的高为256,当前层的光流值的高为4,那么系数就是64.
norm = tf.norm(scaled_flow_gt - y_hat_pyr_lvl, ord=norm_order, axis=3) [8,4,7]
tf.reduce_sum(norm, axis=(1, 2)) [8]
level_loss = tf.reduce_mean(tf.reduce_sum(norm, axis=(1, 2))) []
维度从[8,,4,7]->[8]->[]
然后计算损失
total_loss += opts['alphas'][lvl] * tf.pow(level_loss + opts['epsilon'],1)
其中这里的系数为[0.32, 0.08, 0.02, 0.01, 0.005, 0.0025]
其中分辨率最低(也就是第6层)光流场的loss,对应0.32
scale_gt=gt/20
以第6层到第5层为例,warp需要把乘0.625,理由如下:
这是因为,第六层预测出来的光流场与scaled_flow_gt6非常接近(因为使用如下的损失函数),而scaled_flow_gt6与scale_gt的差距只有分辨率的差距。
layer {
name: "loss6"
type: "L1Loss"
bottom: "predict_flow6"
bottom: "scaled_flow_gt6"
top: "loss6"
loss_weight: 0.32
l1_loss_param {
l2_per_location: true
}
因此,在第5层,需要用到光流场的时候,首先对第6层乘以20,那么就获得了正确的预测值,然后因为第5层的分辨率是输入的1/32,所以需要除以32,因此,20/32=0.625.就是这么来的
因此,其实金字塔的每一层输出的光流场乘以20之后,在放大分辨率都可以当成真实的光流场使用,其实金字塔就是一个不断细化的过程。