【论文笔记】TINYCD: A (Not So) Deep Learning Model For Change Detection

news2024/10/6 1:34:39

论文

标题:TINYCD: A (Not So) Deep Learning Model For Change Detection

paper:

https://arxiv.org/abs/2207.13159

code:

GitHub - AndreaCodegoni/Tiny_model_4_CD: Official implementation of TINYCD: A (NOT SO) DEEP LEARNING MODEL FOR CHANGE DETECTION

摘要

变化检测(CD)的目的是通过比较在不同时间拍摄的该地点的两幅图像来检测在同一区域发生的变化。CD具有挑战性的部分是跟踪用户想要突出显示的变化,例如新建筑,而忽略由于外部因素造成的变化,如环境、照明条件、雾或季节变化。深度学习领域的最新发展使研究人员在这一领域取得了突出的表现。特别是,不同的时空注意机制允许利用从模型中提取的空间特征,并通过利用两个可用的图像以时间方式将它们关联起来。缺点是这些模型变得越来越复杂和庞大,对于边缘应用来说往往是不可行的。当模型必须应用于工业领域或需要实时性能的应用时,这些都是限制。在这项工作中,我们提出了一种新的模型,称为TinyCD,证明了它既轻便又有效,能够在参数减少13-150倍的情况下实现与当前技术水平相当甚至更好的性能。在我们的方法中,我们利用低层特征的重要性来比较图像。要做到这一点,我们只使用几个主干模块。此策略使我们可以将网络参数的数量保持在较低水平。为了合成从两幅图像中提取的特征,我们引入了一种新的、参数经济的混合块,能够在空间和时间域上对特征进行互相关。最后,为了充分利用计算特征中包含的信息,我们定义了能够执行像素分类的PW-MLP块。

动机

变化检测的主要目的是构建一个模型,能够识别场景中两个不同时间之间发生的变化,CD模型比较时间t1和t2获得的两个共同配准的图像。

现有基于深度学习的变化检测模型都过于复杂和庞大,难以应用于工业场景,边缘应用。

贡献

  • 探索图像比较间浅层特征的有效性,有助于显著减少模型参数量(使用EfficientNet_b4作为主干网络用于提取特征,显著减少参数量和计算量);
  • 将两幅图的特征进行通道交叉混合(分组卷积+串联操作实现);
  • 设计MAMB模块进行跳接,使用注意力机制并生成掩码,逐级精细化;
  • 对每个像素分类生成最终的预测掩码。

我们的工作灵感来自于BIT [【论文笔记】Remote Sensing Image Change Detection with Transformers_m0_61899108的博客-CSDN博客_whu_cd]。事实上,我们认为,每个像素在不同分辨率下包含的信息,即语义标记,对于最终的分类是必不可少的,而且它们比空间注意提供的全局上下文更重要。此外,我们的直觉是,由于我们可以比较两个图像,所以我们只能使用低级别特征来突出及时发生的变化。为此,我们设计了一个暹罗U-Net类型的网络,其中主干由EfficientNetb4的前4个块表示。为了更好地在时空上融合通道中包含的信息,我们引入了一种混合策略,迫使网络以语义一致的方式融合和比较在时间T1和T2提取的特征。最后,为了充分利用每个像素/语义标记中包含的所有信息,我们在每个像素/语义标记上大量应用了多层感知器(MLP)。MLP用于在U-Net结构中创建空间注意掩码跳过连接。并将其应用于分类块中,对每个像素点进行分类。

方法

网络架构 

网络包括4个部分:

  • 预训练的主干网络构成孪生编码器;
  • 混合和注意掩码块(MAMB)和瓶颈混合块组成主干结果;
  • 上采样编码器用于改进低分辨率结果;
  • 像素级分类器。
论文所放的架构图

详细结构: 

代码中所放的架构图(更清晰

模型细节

 

 

实验

数据集: LEVIR-CD和WHU-CD

 LEVIR-CD: LEVIR-CD | LEVIR-CD is a new large-scale remote sensing binary change detection dataset, which would help develop novel deep learning-based algorithms for remote sensing image change detection.

WHU-CD: https://study.rsgis.whu.edu.cn/pages/download/building_dataset.html

预处理后的数据集:

LEVIR-CD 

wget https://www.dropbox.com/s/h9jl2ygznsaeg5d/LEVIR-CD-256.zip

WHU-CD

wget https://www.dropbox.com/s/r76a00jcxp5d3hl/WHU-CD-256.zip

 实验细节

比较结果

 LEVIR-CD数据集:

WHU-CD数据集: 

参数量、计算量、结果比较:

可视化: 

消融实验

是否使用跳接:

 不同的生成方式:

 

 

关键代码 

https://github.com/AndreaCodegoni/Tiny_model_4_CD 

change_classifier.py

# change_classifier.py
# https://github.com/AndreaCodegoni/Tiny_model_4_CD

from typing import List
import torchvision
from models.layers import MixingMaskAttentionBlock, PixelwiseLinear, UpMask, MixingBlock
from torch import Tensor
from torch.nn import Module, ModuleList, Sigmoid


class ChangeClassifier(Module):
    def __init__(
        self,
        bkbn_name="efficientnet_b4",
        pretrained=True,
        output_layer_bkbn="3",
        freeze_backbone=False,
    ):
        super().__init__()

        # Load the pretrained backbone according to parameters:
        self._backbone = _get_backbone(
            bkbn_name, pretrained, output_layer_bkbn, freeze_backbone
        )

        # Initialize mixing blocks:
        self._first_mix = MixingMaskAttentionBlock(6, 3, [3, 10, 5], [10, 5, 1])
        self._mixing_mask = ModuleList(
            [
                MixingMaskAttentionBlock(48, 24, [24, 12, 6], [12, 6, 1]),
                MixingMaskAttentionBlock(64, 32, [32, 16, 8], [16, 8, 1]),
                MixingBlock(112, 56),
            ]
        )

        # Initialize Upsampling blocks:
        self._up = ModuleList(
            [
                UpMask(64, 56, 64),
                UpMask(128, 64, 64),
                UpMask(256, 64, 32),
            ]
        )

        # Final classification layer:
        self._classify = PixelwiseLinear([32, 16, 8], [16, 8, 1], Sigmoid())

    def forward(self, ref: Tensor, test: Tensor) -> Tensor:
        features = self._encode(ref, test)
        latents = self._decode(features)
        return self._classify(latents)

    def _encode(self, ref, test) -> List[Tensor]:
        features = [self._first_mix(ref, test)]
        for num, layer in enumerate(self._backbone):
            ref, test = layer(ref), layer(test)
            if num != 0:
                features.append(self._mixing_mask[num - 1](ref, test))
        return features

    def _decode(self, features) -> Tensor:
        upping = features[-1]
        for i, j in enumerate(range(-2, -5, -1)):
            upping = self._up[i](upping, features[j])
        return upping


def _get_backbone(
    bkbn_name, pretrained, output_layer_bkbn, freeze_backbone
) -> ModuleList:
    # The whole model:
    entire_model = getattr(torchvision.models, bkbn_name)(
        pretrained=pretrained
    ).features

    # Slicing it:
    derived_model = ModuleList([])
    for name, layer in entire_model.named_children():
        derived_model.append(layer)
        if name == output_layer_bkbn:
            break

    # Freezing the backbone weights:
    if freeze_backbone:
        for param in derived_model.parameters():
            param.requires_grad = False
    return derived_model

layers.py

# layers.py

from typing import List, Optional

from torch import Tensor, reshape, stack

from torch.nn import (
    Conv2d,
    InstanceNorm2d,
    Module,
    PReLU,
    Sequential,
    Upsample,
)


class PixelwiseLinear(Module):
    def __init__(
        self,
        fin: List[int],
        fout: List[int],
        last_activation: Module = None,
    ) -> None:
        assert len(fout) == len(fin)
        super().__init__()

        n = len(fin)
        self._linears = Sequential(
            *[
                Sequential(
                    Conv2d(fin[i], fout[i], kernel_size=1, bias=True),
                    PReLU()
                    if i < n - 1 or last_activation is None
                    else last_activation,
                )
                for i in range(n)
            ]
        )

    def forward(self, x: Tensor) -> Tensor:
        # Processing the tensor:
        return self._linears(x)




class MixingBlock(Module):
    def __init__(
        self,
        ch_in: int,
        ch_out: int,
    ):
        super().__init__()
        self._convmix = Sequential(
            Conv2d(ch_in, ch_out, 3, groups=ch_out, padding=1),
            PReLU(),
            InstanceNorm2d(ch_out),
        )

    def forward(self, x: Tensor, y: Tensor) -> Tensor:
        # Packing the tensors and interleaving the channels:
        mixed = stack((x, y), dim=2)
        mixed = reshape(mixed, (x.shape[0], -1, x.shape[2], x.shape[3]))

        # Mixing:
        return self._convmix(mixed)


class MixingMaskAttentionBlock(Module):
    """use the grouped convolution to make a sort of attention"""

    def __init__(
        self,
        ch_in: int,
        ch_out: int,
        fin: List[int],
        fout: List[int],
        generate_masked: bool = False,
    ):
        super().__init__()
        self._mixing = MixingBlock(ch_in, ch_out)
        self._linear = PixelwiseLinear(fin, fout)
        self._final_normalization = InstanceNorm2d(ch_out) if generate_masked else None
        self._mixing_out = MixingBlock(ch_in, ch_out) if generate_masked else None

    def forward(self, x: Tensor, y: Tensor) -> Tensor:
        z_mix = self._mixing(x, y)
        z = self._linear(z_mix)
        z_mix_out = 0 if self._mixing_out is None else self._mixing_out(x, y)

        return (
            z
            if self._final_normalization is None
            else self._final_normalization(z_mix_out * z)
        )


class UpMask(Module):
    def __init__(
        self,
        up_dimension: int,
        nin: int,
        nout: int,
    ):
        super().__init__()
        self._upsample = Upsample(
            size=(up_dimension, up_dimension), mode="bilinear", align_corners=True
        )
        self._convolution = Sequential(
            Conv2d(nin, nin, 3, 1, groups=nin, padding=1),
            PReLU(),
            InstanceNorm2d(nin),
            Conv2d(nin, nout, kernel_size=1, stride=1),
            PReLU(),
            InstanceNorm2d(nout),
        )

    def forward(self, x: Tensor, y: Optional[Tensor] = None) -> Tensor:
        x = self._upsample(x)
        if y is not None:
            x = x * y
        return self._convolution(x)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/14382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于聚类算法:K-means、DBSCA算法完成航空客户价值分析任务 代码+数据

1.任务描述 信息时代的来临使得企业营销焦点从产品中心转变成客户中心。具体地,对不同的客户进行分类管理,给予不同类型的客户制定优化的个性化服务方案,采取不同的营销策略。将有限的营销资源集中于高价值的客户,实现企业利润最大化。因此,如何对客户进行合理的分类成为…

喵 ~ 小程序搭建记录

喵 ~ 小程序搭建记录前言一、搭建分析1. 项目里的页面相关2. 项目里的组件相关3. 项目里的 api 相关4. 项目里的没有用到的东西5. 项目中会用到的 iconfont二、 搭建参考参考博客三、 搭建实现1. 结构搭建2.全局样式导航栏配置tabBar配置四、uniapp项目搭建 请求配置前言 喵 ~…

1702967-37-0,PSMA-617 是prostate特异性膜抗原 (PSMA) 的强有效抑制剂

【产品描述】 Vipivotide tetraxetan (PSMA-617) 是prostate特异性膜抗原 (PSMA) 的强有效抑制剂&#xff0c;其 Ki 值为 0.37 nM。Vipivotide tetraxetan (PSMA-617)由三种成分组成:药效基团Glutamate-urea-Lysine&#xff0c;螯合剂DOTA&#xff08;能够结合68Ga或177Lu&…

智慧住建工程项目监管数字化管理解决方案

在国家“放管服”大背景下&#xff0c;提高各级住房城乡建设主管部门的服务效能和依法治理水平的呼声越来越高。 住建部《“十四五”建筑业发展规划》提出&#xff0c;基于建筑产业互联网平台建设政府监管平台&#xff0c;把“新监管”提到重要位置&#xff0c;打造“工程项目监…

临时回忆啦啦啦啦

设置为private是为了防止其他类使用当前类的日志对象&#xff1b;如果当前类需要被子类继承&#xff0c;并且都使用同一个日志对象时&#xff0c;可设置为protected 。设置为static是为了让每个类中的日志对象只生成一份&#xff0c;日志对象是属于类的&#xff0c;不是属于具体…

MySQL8.0优化 - 索引的数据结构、B+树、常见索引概念、索引的代价

文章目录学习资料索引的数据结构B树常见索引概念聚簇索引特点优点缺点限制二级索引&#xff08;辅助索引、非聚簇索引&#xff09;回表联合索引Innodb的B树索引注意事项1、根页面位置万年不动2、内节点中目录项记录的唯一性3、一个页面最少存储2条记录索引的代价学习资料 【My…

计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序

项目介绍 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的…

mMED影响组蛋白甲基化和表观遗传

2019 年 8 月 8 日&#xff0c;来自美国 NIH 的 Rafael Casellas 与科罗拉多大学 Francisco J. Asturias 在 Cell 杂志上发表文章 《A Pliable Mediator Acts as a Functional Rather Than an ArchitecturalBridge between Promoters and Enhancers》&#xff0c;综合运用 CRIS…

Landsat Collection 2 数据集详细介绍(T1/T2产品差异)

Landsat Collection 2 是对 Landsat 档案的第二次主要再处理工作&#xff0c;它带来了多项数据产品改进&#xff0c;这些改进应用了数据处理、算法开发以及数据访问和分发功能方面的进步。 Landsat Collection 2 包含来自 Landsat 1-9 的 Level-1 数据和来自 Landsat 4-9 的科…

Spring IOC源码:invokeBeanFactoryPostProcessors 后置处理器详解

前言 前面篇幅介绍了Bean配置的解析过程&#xff0c;包括注解、xml配置文件的解析。下面进入refresh方法中另一个重要的节点&#xff0c;即BeanFactoryPostProcessor的注册及其执行过程。 正文 进入refresh&#xff0c;前面篇幅已经介绍了obtainFreshBeanFactory()&#xff…

说出你常用的20个linux命令,你还是只会说ls、cat那20个命令吗?3分钟让你发现新大陆

服务器排障常用命令 &#x1f34a; 博客主页&#xff1a;作者主页 &#x1f34a; 简介&#xff1a;云计算领域优质创作者&#x1f3c6;、在校期间参与众多计算机ICT相关的省赛、国赛&#xff0c;斩获系列荣誉。考取华为资深工程师、红帽工程师、阿里云ACP云计算工程等系列认证。…

java图书推荐协同过滤算法网站

目 录 摘 要 2 Abstract 3 1绪论 6 1.1背景和意义 6 1.2国内外发展现状 6 2系统技术分析 7 2.1技术选型 7 2.2 MVC模式 7 3功能分析 8 3.1系统角色 8 3.2系统用例图 8 3.3系统功能 8 3.3.1网站前台功能 8 3.3.2网站后台功能 13 4系…

使用Android辅助功能AccessibilityService实现微信自动聊天【外挂插件】

本文是使用Android辅助功能AccessibilityService实现微信自动聊天demo&#xff1b; 只是为了跟深入的了解Android辅助功能, 提高自身的动手能力。 请勿用于商用&#xff0c;或非法用途。 动手前&#xff0c;基本的准备要求&#xff1a; 聊天机器人app demo&#xff0c;去操作…

供应PEG试剂Azide-PEG-Acrylamide,N3-PEG-ACA,叠氮-聚乙二醇-丙烯酰胺

1、名称 英文&#xff1a;Azide-PEG-Acrylamide&#xff0c;N3-PEG-ACA 中文&#xff1a;叠氮-聚乙二醇-丙烯酰胺 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a; Acrylate/Acrylamide PEG Azide PEG 4、分子量&#xff1a;可定制&#xff0c;5k、2k、10k、20k、3.4k…

DarkNet网络结构

一、darknet53网络结构图 文字版&#xff1a;卷积(下采样卷积1残差块)(下采样卷积2残差块)(下采样卷积8残差块)(下采样卷积8残差块)(下采样卷积4*残差块) 不难看出&#xff0c;darknet53就是重复堆叠下采样卷积n*残差块(n为残差块的个数)这个结构而组成的。而更基本的结构就是…

数据库视图的基本操作(sql语句)

表视图的增删改查&#xff08;sql语句&#xff09; 概念&#xff1a;视图是一张虚拟表&#xff0c;它是从数据库的一张或多张表中导出的表&#xff0c;其内容由查询语句定义。 作用&#xff1a; 简单性、安全性、逻辑数据独立性&#xff1b;如果应用建立在视图上&#xff0c…

Node.js学习19~37(模块化)

1 模块化的基本概念 1.1 什么是模块化 模块化是指解决一个复杂问题时&#xff0c;自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说&#xff0c;模块是可组合、分解和更换的单元。 编程领域中的模块化 编程领域中的模块化&#xff0c;就是遵守固定的规则&#xf…

【Pytorch with fastai】第 15 章 :深入探讨应用程序架构

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Docker概念基本介绍以及安装

目录 一、Docker概述 1.1Docker是什么 1.2Docker和虚拟机的区别 1.3使用场景 1.4 Docker 三要素&#xff08;核心组件&#xff09; 1.5六大名称空间 1.6 Docker引擎 1.7资源控制——cgroups 1.8容器特性 1.9 容器小的架构体系 二、Docker和虚拟化的区别 三、dock…

MATLAB循环类型

MATLAB 提供以下类型的循环处理循环的要求。点击链接&#xff0c;查看个循环类型的细节&#xff1a; 循环类型描述while 循环一个给定的条件为真时重复语句或语句组。测试条件才执行循环体。for 循环执行的语句序列多次缩写管理循环变量的代码。nested 循环可以使用一个或多个…