图像语义分割-CVPR2020-CPNet:结合不同类别的上下文信息先验--场景语义分割--注意力机制--Context Prior for Scene Segmentation--关键创新点代码复现

Context Prior for Scene Segmentation-设计注意力机制模块加入上下文先验信息–关键创新点代码复现-tensorflow2.x、keras。

论文Context Prior for Scene Segmentation
代码github暂未开源
最近在研究注意力机制与先验信息,查阅到这篇论文,但是暂未开源代码,便根据对论文内容的理解复现论文方法,使用TensorFlow2.x版本,基于Keras编写代码

论文介绍

摘要

最近的语义分割工作广泛探索了上下文相关性,以实现更准确的细分结果。但是,大多数方法很少区分不同类型的上下文依赖项,这可能会有损场景理解。在这项工作中,我们直接监督特征聚合以清楚地区分类内和类间上下文信息。具体来说,我们在Affinity Loss监督下开发出上下文先验。 给定输入图像和相应的gt,Affinity Loss将构建理想的类似的特征图,以监督上下文先验的学习。 所学习的上下文先验提取属于同一类别的像素,而相反的先验则专注于不同类别的像素。 通过嵌入到传统的深度CNN中,提出的上下文先验层可以选择性地捕获类内和类间上下文相关性,从而实现可靠的特征表示。 为了验证有效性,我们设计了有效的上下文先验网络(CPNet)。大量的定量和定性评估表明,所提出的模型与最新的语义分割方法相比具有良好的表现。 更具体地说,我们的算法在ADE20K上达到46.3%的mIoU,在PASCAL-Context上达到53.9%的mIoU,在Cityscapes上达到81.3%的mIoU【参考博客

关键点

CPlayer
提出以上模块,说的是通过生成的Ideal Affinity Map向网络中加入像素值的先验信息去监督网络对类内和内间学习(我的理解就是相当于把原标签转为另一种表达方式与网络的某一层输出的特征图求损失,其实相比于其他分割网络最后输入的损失计算,换汤不换药!!!)。该模块可加在任意主干网络后,用于对主干网络生成的特征图进行再一次的特征提取。

开整代码

导入依赖包

from tensorflow import keras
from tensorflow.keras import layers
import tensorflow.keras.backend as K
from CoordConv2 import Coord_Conv2d
import tensorflow as tf

Aggregation模块

在这里插入图片描述
把3X3的卷积核分成3X1和1X3两个,效果相似,参数计算大量减少。


def Aggregation(x, num_classes):
    x = layers.Conv2D(filters=num_classes, kernel_size=3, padding='same')(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation('relu')(x)
    x1 = layers.DepthwiseConv2D(kernel_size=(1, 3), padding='same')(x)
    x1 = layers.DepthwiseConv2D(kernel_size=(3, 1), padding='same')(x1)
    x2 = layers.DepthwiseConv2D(kernel_size=(3, 1), padding='same')(x)
    x2 = layers.DepthwiseConv2D(kernel_size=(1, 3), padding='same')(x2)
    x = layers.Add()([x1, x2])
    x = layers.BatchNormalization()(x)
    x = layers.Activation('relu')(x)
    return x

CP过程

在这里插入图片描述

def CP(x):
    B, H, W, C = x.shape
    x_origon = x
    x_origon = tf.reshape(x_origon, [-1, H*W, C])
    x = layers.Conv2D(filters=H*W, kernel_size=1, padding='same')(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation('sigmoid')(x)
    x = tf.reshape(x, [-1, H*W, H*W], name='out1') #  论文中P,Context Prior Map
    x1 = tf.matmul(x, x_origon)
    x1 = tf.reshape(x1, [-1, H, W, C])
    x2 = tf.matmul(tf.ones_like(x)-x, x_origon) 
    x2 = tf.reshape(x2, [-1, H, W, C])
    return x, x1, x2

CPModule

在这里插入图片描述

def CPModule(x, num_classes):
    x1 = Aggregation(x, num_classes)
    x2, x3, x4 = CP(x1)
    output = layers.Concatenate()([x, x3, x4])
    return x2, output

x2用于论文提出的AffinityLoss计算,output用于普通的softmax损失计算

Affinity Loss

loss_1

在这里插入图片描述

loss_binary = keras.losses.binary_crossentropy(Ideal_Affinity_Map, Context_Prior_Map)

loss_2

在这里插入图片描述

Tp = K.log(K.sum(tf.multiply(Ideal_Affinity_Map, Context_Prior_Map), axis=1) / (K.sum(Context_Prior_Map, axis=1)+K.epsilon())+K.epsilon())
Tr = K.log(K.sum(tf.multiply(Ideal_Affinity_Map, Context_Prior_Map), axis=1) / (K.sum(Ideal_Affinity_Map,
                                                                                         axis=1)+K.epsilon()) + K.epsilon())
Tj = K.log((K.sum((1.0-Ideal_Affinity_Map)*(1.0-Context_Prior_Map), axis=1)+K.epsilon())/(K.sum(1.0-Ideal_Affinity_Map, axis=1)+K.epsilon())+K.epsilon())
loss = -K.mean(T1+T2+T3)

总损失

在这里插入图片描述

loss+loss_binary

代码汇总

在这里插入图片描述
Ideal Affinity Map的生成论文中是这样描述的
在这里插入图片描述
对于DownSample操作并没有清除的说明用的是什么方法,因此我这儿采用的是多次最大值池化,由于我的标签本就是ONE-HOT标签,所以就不存在论文中提及的one-hot encoding操作。具体标签制作详见我的另一篇博客
由于我的主干网络输出的特征图是32X32大小,直接将标签降到特征图大小会丢掉很多目标特征(所以对原论文说的把标签图下采样到特征图尺寸是否保留目标的特征信息持怀疑态度,或者作者使用了巧妙的下采样方式就另说了),经试验证明,在我使用的标签图中,下采样到128X128大小,目标的特征信息不会损失。但是实验使用cpu做的,[128X128, 128X128]与[128X128, 128X128]的矩阵运算算不了,所以实验采用的是把标签下采样到64X64大小。原标签尺寸为512X512
使用tf.image中的resize函数下采样可避免特征丢失问题!!

def Affinity_loss(y_true, y_pred):
    y_true_down = tf.image.resize(y_true, (256, 256), methord=tf.image.ResizeMethord.NEAREST_NEIGHBOR)
    y_true_down = y_true_down = tf.image.resize(y_true_down , (128, 128), methord=tf.image.ResizeMethord.NEAREST_NEIGHBOR)
    y_true_down = y_true_down = tf.image.resize(y_true_down , (64, 64), methord=tf.image.ResizeMethord.NEAREST_NEIGHBOR)
    y_true_down = y_true_down = tf.image.resize(y_true_down , (32, 32), methord=tf.image.ResizeMethord.NEAREST_NEIGHBOR)
    B_down, H_down, W_down, C_down = y_true_down.shape
    y_true_down = tf.reshape(y_true_down, [-1, H_down*W_down, C_down])
    Ideal_Affinity_Map = tf.matmul(y_true_down, tf.transpose(y_true_down, [0, 2, 1]))
    Ideal_Affinity_Map = tf.cast(Ideal_Affinity_Map, dtype=tf.float32)
    Context_Prior_Map = tf.cast(y_pred, dtype=tf.float32)
    loss_binary = keras.losses.binary_crossentropy(Ideal_Affinity_Map, Context_Prior_Map)
    T1 = K.log(K.sum(tf.multiply(Ideal_Affinity_Map, Context_Prior_Map), axis=1) / (K.sum(Context_Prior_Map, axis=1)+K.epsilon())+K.epsilon())
    T2 = K.log(K.sum(tf.multiply(Ideal_Affinity_Map, Context_Prior_Map), axis=1) / (K.sum(Ideal_Affinity_Map,
                                                                                         axis=1)+K.epsilon()) + K.epsilon())
    T3 = K.log((K.sum((1.0-Ideal_Affinity_Map)*(1.0-Context_Prior_Map), axis=1)+K.epsilon())/(K.sum(1.0-Ideal_Affinity_Map, axis=1)+K.epsilon())+K.epsilon())
    loss = -K.mean(T1+T2+T3)

    return loss+loss_binary

Context_Prior_Map 和 Ideal_Affinity_Map

Context_Prior_Map Context_Prior_Map

Ideal_Affinity_Map

Ideal_Affinity_Map

总结

总的来说,对上下文先验矩阵Ideal_Affinity_Map的预测还是比较接近论文贴出的结果

在这里插入图片描述

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值