当前位置: 首页 > news >正文

#4【CVPR2024】SHIP:图像融合的一种协同高阶交互范式


📜 Probing Synergistic High-Order Interaction in Infrared and Visible Image Fusion


🍕 源码: https://github.com/zheng980629/SHIP

在这里插入图片描述
先前融合规则与我们提出的范式之间的比较。之前的工作要么(a)缺乏明确的交互,要么(b)仅实现了 2 n d 2^{n d} 2nd阶空间交互;而(c)我们的SHIP融合了高阶空间和通道交互,以探索模态之间在空间细粒度细节和全局统计中的协同相关性,逐步整合并区分互补信息

如何将二阶交互扩展到任意高阶而又不会显著增加计算量呢?论文并不仅仅只是将低阶计算平庸地升阶,而是考虑了计算量的问题,这就为以后潜在的实际应用增添了可能性

🍟 贡献:
  • 本研究中的新型协同高阶交互范式(SHIP)探索了红外与可见光图像融合中复杂的高阶交互。通过在空间和通道维度上融入高阶交互,SHIP作为一种开创性方法,研究了模态之间的协同相关性
  • 该范式研究了涉及空间细粒度细节和全局统计的高阶交互,协同整合互补信息,并从源模态中区分相互依赖性
  • 展示了其在全色锐化任务中的有效性

🍭 理解空间和通道上的阶数
  • 普通卷积(vanilla convolution):传统的卷积操作通过对输入图像的局部区域进行加权求和来提取特征。然而,这种操作本质上无法捕捉特定位置与其邻近区域之间的空间交互。换句话说,卷积核的权重是固定的,无法根据输入内容动态调整,因此难以建模复杂的空间依赖关系。

  • 动态卷积:动态卷积通过根据输入生成动态权重来改进普通卷积。这种改进引入了一阶空间交互,即卷积核的权重会根据输入内容自适应调整。

  • 自注意力机制:Transformer 通过自注意力机制实现了二阶空间交互。其核心是通过矩阵乘法计算查询(queries)、键(keys)和值(values)之间的关系。

  • SE 模块:SE 模块通过一阶统计量来重新校准通道响应。具体来说,它首先对每个通道进行全局平均池化(squeeze),然后通过全连接层学习通道权重(excitation),最后用这些权重对特征图进行加权。


在这里插入图片描述
所提出的协同高阶交互范式(SHIP)的详细框架包括在L次迭代中执行的交替空间和通道高阶交互。具体来说,空间高阶交互充分挖掘了两种模态之间的协作,并通过高阶建模整合了空间细粒度的互补信息。随后,基于全局一阶统计量(均值)的通道高阶相互作用进一步研究了全局统计量,区分了可见光和红外模态之间的相互依赖性


🍥 高阶空间交互

I F = SHIP ⁡ L ( ψ ( I R ) , ϕ ( I V ) ) I_{\mathcal{F}}=\operatorname{SHIP}_L\left(\psi\left(I_{\mathcal{R}}\right), \phi\left(I_{\mathcal{V}}\right)\right) IF=SHIPL(ψ(IR),ϕ(IV))整体结构也是比较简单的,就是一个相同的模块重复处理了好多次得到结果,效果好不好全靠模块设计

传统的注意力机制
O S ( ( F V ) 2 ) = F V S 1 = softmax ⁡ ( Q ⊗ K T d k ) ⊗ V = A ⊗ V \mathcal{O}_S\left(\left(F_{\mathcal{V}}\right)^2\right)=F_{\mathcal{V}_S}^1=\operatorname{softmax}\left(\frac{\mathbf{Q} \otimes \mathbf{K}^T}{\sqrt{d_k}}\right) \otimes \mathbf{V}=\mathbf{A} \otimes \mathbf{V} OS((FV)2)=FVS1=softmax(dk QKT)V=AV文中提出了一种近似形式
A i j = ⟨ q i , k j ⟩ \mathbf{A}_{i j}=\left\langle\mathbf{q}_i, \mathbf{k}_j\right\rangle Aij=qi,kj A = F − 1 ( F ( F V W Q ) ⊙ F ( F R W K ) ‾ ) \mathbf{A}=\mathcal{F}^{-1}\left(\mathcal{F}\left(F_{\mathcal{V}} \mathbf{W}^Q\right) \odot \overline{\mathcal{F}\left(F_{\mathcal{R}} \mathbf{W}^K\right)}\right) A=F1(F(FVWQ)F(FRWK)) O S ( ( F V ) 2 ) = F V S 1 = Norm ⁡ ( A ) ⊙ ( F R W V ) \mathcal{O}_S\left(\left(F_{\mathcal{V}}\right)^2\right)=F_{\mathcal{V}_S}^1=\operatorname{Norm}(\mathbf{A}) \odot\left(\mathrm{F}_{\mathcal{R}} \mathbf{W}^{\mathrm{V}}\right) OS((FV)2)=FVS1=Norm(A)(FRWV)本质上就是把矩阵乘法转到频域中变为点乘,再转回去空间域,其实说不上创新,而且在计算上面是不是变得高效也难说呀 O S ( ( F V S i − 1 ) 2 ) = F V S i = Attention ⁡ ( Q i , K i , V i ) , Q i = F V S i − 1 W Q i , K i = F R W K i , V i = F R W v i \begin{aligned} & \mathcal{O}_S\left(\left(F_{\mathcal{V}_S}^{i-1}\right)^2\right)=F_{\mathcal{V}_S}^i=\operatorname{Attention}\left(\mathbf{Q}_i, \mathbf{K}_i, \mathbf{V}_i\right), \\ & \mathbf{Q}_i=F_{\mathcal{V}_S}^{i-1} \mathbf{W}^{\mathbf{Q}_i}, \mathbf{K}_i=F_{\mathcal{R}} \mathbf{W}^{\mathbf{K}_i}, \mathbf{V}_i=F_{\mathcal{R}} \mathbf{W}^{\mathbf{v}_i} \end{aligned} OS((FVSi1)2)=FVSi=Attention(Qi,Ki,Vi),Qi=FVSi1WQi,Ki=FRWKi,Vi=FRWvi F V → O S ( ( F V ) 2 ) → F V S 1 → O S ( ( F V S 1 ) 2 ) → F V S 2 ⋯ → O S ( ( F V S i ) 2 ) → F V S i + 1 … O S ( ( F V S L − 1 ) 2 ) → F V S L \begin{aligned} & F_{\mathcal{V}} \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}}\right)^2\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^1 \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^1\right)^2\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^2 \cdots \\ & \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^i\right)^2\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^{i+1} \ldots \mathcal{O}_S\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^{L-1}\right)^2\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^L \end{aligned} FVOS((FV)2)FVS1OS((FVS1)2)FVS2OS((FVSi)2)FVSi+1OS((FVSL1)2)FVSL之前的多个自注意力模块堆叠集中在索引上,集中在一个模态,另一个模态的键值对并没有因为模块的堆叠而更新,而本文可以提高到任意阶:
O S ( ( F V i − 1 ) j ) = F V s j i = Norm ⁡ ( F V s j − 1 i W Q j ) ⊙ ( F R s j − 1 i W V ) F V s j − 1 i = Norm ⁡ ( F V s i − 2 i W Q j − 1 ) , F R s j − 1 i = F R s j − 2 i W V j − 1 i \begin{aligned} & \mathcal{O}_S\left(\left(F_{\mathcal{V}}^{i-1}\right)^j\right)=F_{\mathcal{V}_s^j}^i=\operatorname{Norm}\left(F_{\mathcal{V}_s^{j-1}}^i \mathbf{W}^{\mathbf{Q} \mathbf{j}}\right) \odot\left(F_{\mathcal{R}_s^{j-1}}^i \mathbf{W}^{\mathbf{V}}\right)\\ & F_{\mathcal{V}_s^{j-1}}^i=\operatorname{Norm}\left(F_{\mathcal{V}_s^{i-2}}^i \mathbf{W}^{\mathbf{Q} \mathbf{j}-1}\right), F_{\mathcal{R}_s^{j-1}}^i=F_{\mathcal{R}_s^{j-2}}^i \mathbf{W}^{\mathbf{V}_{\mathbf{j}-1}^{\mathbf{i}}} \end{aligned} OS((FVi1)j)=FVsji=Norm(FVsj1iWQj)(FRsj1iWV)FVsj1i=Norm(FVsi2iWQj1),FRsj1i=FRsj2iWVj1i F V → O S ( ( F V ) N ) → F V S 1 → O S ( ( F V s 1 ) N ) → F V S 2 … → O S ( ( F V S i ) N ) → F V S i + 1 … O S ( ( F V S L − 1 ) N ) → F V S L \begin{aligned} & F_{\mathcal{V}} \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}}\right)^N\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^1 \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}_s}^1\right)^N\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^2 \ldots \\ & \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}_S}^i\right)^N\right) \rightarrow F_{\mathcal{V}_{\mathcal{S}}}^{i+1} \ldots \mathcal{O}_S\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^{L-1}\right)^N\right) \rightarrow F_{\mathcal{V}_S}^L \end{aligned} FVOS((FV)N)FVS1OS((FVs1)N)FVS2OS((FVSi)N)FVSi+1OS((FVSL1)N)FVSL

在这里插入图片描述
在不同的空间高阶交互步骤中,每次交互后的特征可视化。例如, F V s 3 2 F_{\mathcal{V}_s^3} ^2 FVs32表示 2 n d 2^{nd} 2nd空间高阶相互作用中三阶相互作用后的特征。这些可视化从两个角度说明了高阶空间相互作用的有效性:(1)在每个高阶相互作用中,特征响应随着顺序的增加而升级,突出了突出的对象;(2) 不同的高阶相互作用产生独特的响应,展示了特征表示的多样性

class spatialInteraction(nn.Module):def __init__(self, channelin, channelout):super(spatialInteraction, self).__init__()# 定义三个卷积序列用于处理融合特征self.reflashFused1 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),  # 3x3卷积,输入通道为channelin,输出通道为channelout,padding为1nn.ReLU(),  # ReLU激活函数nn.Conv2d(channelout, channelout, 3, 1, 1)  # 再次3x3卷积)self.reflashFused2 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout, channelout, 3, 1, 1))self.reflashFused3 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout, channelout, 3, 1, 1))# 定义三个卷积序列用于处理红外特征self.reflashInfrared1 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout, channelout, 3, 1, 1))self.reflashInfrared2 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout, channelout, 3, 1, 1))self.reflashInfrared3 = nn.Sequential(nn.Conv2d(channelin, channelout, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout, channelout, 3, 1, 1))# 定义四个LayerNorm层,用于归一化self.norm1 = LayerNorm(channelout, LayerNorm_type='WithBias')self.norm2 = LayerNorm(channelout, LayerNorm_type='WithBias')self.norm3 = LayerNorm(channelout, LayerNorm_type='WithBias')self.norm4 = LayerNorm(channelout, LayerNorm_type='WithBias')def forward(self, vis, inf, i, j):# 获取可见光图像的尺寸_, C, H, W = vis.size()# 对可见光和红外图像进行快速傅里叶变换(FFT)vis_fft = torch.fft.rfft2(vis.float())inf_fft = torch.fft.rfft2(inf.float())# 计算可见光和红外图像的频域注意力图atten = vis_fft * inf_fftatten = torch.fft.irfft2(atten, s=(H, W))  # 逆FFT变换回空间域atten = self.norm1(atten)  # 归一化fused_OneOrderSpa = atten * inf  # 一阶空间融合特征# 通过第一个融合卷积序列处理一阶融合特征fused_OneOrderSpa = self.reflashFused1(fused_OneOrderSpa)fused_OneOrderSpa = self.norm2(fused_OneOrderSpa)  # 归一化infraredReflash1 = self.reflashInfrared1(inf)  # 处理红外特征fused_twoOrderSpa = fused_OneOrderSpa * infraredReflash1  # 二阶空间融合特征# 通过第二个融合卷积序列处理二阶融合特征fused_twoOrderSpa = self.reflashFused2(fused_twoOrderSpa)fused_twoOrderSpa = self.norm3(fused_twoOrderSpa)  # 归一化infraredReflash2 = self.reflashInfrared2(infraredReflash1)  # 处理红外特征fused_threeOrderSpa = fused_twoOrderSpa * infraredReflash2  # 三阶空间融合特征# 通过第三个融合卷积序列处理三阶融合特征fused_threeOrderSpa = self.reflashFused3(fused_threeOrderSpa)fused_threeOrderSpa = self.norm4(fused_threeOrderSpa)  # 归一化infraredReflash3 = self.reflashInfrared3(infraredReflash2)  # 处理红外特征fused_fourOrderSpa = fused_threeOrderSpa * infraredReflash3  # 四阶空间融合特征# 将最终融合特征与原始可见光图像相加fused = fused_fourOrderSpa + vis# 返回融合后的特征和处理后的红外特征return fused, infraredReflash3

🍉 高阶通道交互

传统的SE(squeeze and excitation)模块
Z i = 1 H × W ∑ x = 1 H ∑ y = 1 W F i ( x , y ) O C ( ( F i ) 1 ) = F C i = σ ( W Z 1 i Z i ) ⋅ F i \begin{gathered} Z^i=\frac{1}{H \times W} \sum_{x=1}^H \sum_{y=1}^W F^i(x, y) \\ \mathcal{O}_C\left(\left(F^i\right)^1\right)=F_C^i=\sigma\left(\mathbf{W}^{\mathbf{Z}_1^i} Z^i\right) \cdot F^i \end{gathered} Zi=H×W1x=1Hy=1WFi(x,y)OC((Fi)1)=FCi=σ(WZ1iZi)Fi其中 F i = concat ⁡ [ F V S i , F R S i ] F^i = \operatorname{concat}\left[F_{\mathcal{V}_S}^i, F_{\mathcal{R}_S}^i\right] Fi=concat[FVSi,FRSi] Z c Z_c Zc 表示一阶统计量, σ \sigma σ 表示 Sigmoid 函数。 W Z \mathbf{W}^{\mathbf{Z}} WZ 包括两个线性变换和一个 ReLU 函数。作者将其扩展到了高阶形式: O C ( ( F i ) j ) = F C j i = σ ( W Z j i Z j − 1 i ) ⋅ ( W F j i F j − 1 i ) , Z j − 1 i = σ ( W F j − 1 i Z j − 2 i ) , F j − 1 i = W F j − 1 i F j − 2 i F V → O S ( ( F V ) N ) → O C ( ( F V S 1 ) N ) → O S ( ( F V C 1 ) N ) → O C ( ( F V S 2 ) N ) → … O S ( ( F V C L − 1 ) N ) → O C ( ( F V S L ) N ) \begin{aligned} & \mathcal{O}_C\left(\left(F^i\right)^j\right)=F_{C j}^i=\sigma\left(\mathbf{W}^{\mathbf{Z}_j^i} Z_{j-1}^i\right) \cdot\left(\mathbf{W}^{\mathbf{F}_j^i} F_{j-1}^i\right), \\ & Z_{j-1}^i=\sigma\left(\mathbf{W}^{\mathbf{F}_{j-1}^i} Z_{j-2}^i\right), F_{j-1}^i=\mathbf{W}^{\mathbf{F}_{j-1}^i} F_{j-2}^i \\ & F_{\mathcal{V}} \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}}\right)^N\right) \rightarrow \mathcal{O}_C\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^1\right)^N\right) \rightarrow \mathcal{O}_S\left(\left(F_{\mathcal{V}_{\mathcal{C}}}^1\right)^N\right) \\ & \rightarrow \mathcal{O}_C\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^2\right)^N\right) \rightarrow \ldots \mathcal{O}_S\left(\left(F_{\mathcal{V}_C}^{L-1}\right)^N\right) \rightarrow \mathcal{O}_C\left(\left(F_{\mathcal{V}_{\mathcal{S}}}^L\right)^N\right) \end{aligned} OC((Fi)j)=FCji=σ(WZjiZj1i)(WFjiFj1i),Zj1i=σ(WFj1iZj2i),Fj1i=WFj1iFj2iFVOS((FV)N)OC((FVS1)N)OS((FVC1)N)OC((FVS2)N)OS((FVCL1)N)OC((FVSL)N)具体原理不是很懂,但好像是做一次变换就可以升一次阶数,具体可能需要结合代码来看
在这里插入图片描述
不同阶次在通道索引上的通道交互。这个观察结果为有力证据,表明不同阶次的交互探索了红外和可见模态之间的多样化相互依赖关系

class channelInteraction(nn.Module):def __init__(self, channelin, channelout):super(channelInteraction, self).__init__()# 初始化各个卷积层,包括通道注意力模块和融合模块self.chaAtten = nn.Sequential(nn.Conv2d(channelin * 2, channelout, kernel_size=1, padding=0, bias=True),  # 1x1卷积nn.ReLU(),nn.Conv2d(channelout, channelin * 2, kernel_size=1, padding=0, bias=True)  # 1x1卷积)# 重构通道注意力模块1、2、3,用于逐步改进注意力特征self.reflashChaAtten1 = nn.Sequential(nn.Conv2d(channelin * 2, channelout, kernel_size=1, padding=0, bias=True),nn.ReLU(),nn.Conv2d(channelout, channelin * 2, kernel_size=1, padding=0, bias=True))self.reflashChaAtten2 = nn.Sequential(nn.Conv2d(channelin * 2, channelout, kernel_size=1, padding=0, bias=True),nn.ReLU(),nn.Conv2d(channelout, channelin * 2, kernel_size=1, padding=0, bias=True))self.reflashChaAtten3 = nn.Sequential(nn.Conv2d(channelin * 2, channelout, kernel_size=1, padding=0, bias=True),nn.ReLU(),nn.Conv2d(channelout, channelin * 2, kernel_size=1, padding=0, bias=True))# 融合模块,用于融合不同通道的特征self.reflashFused1 = nn.Sequential(nn.Conv2d(channelin * 2, channelout * 2, 3, 1, 1),  # 3x3卷积nn.ReLU(),nn.Conv2d(channelout * 2, channelout * 2, 3, 1, 1)  # 3x3卷积)self.reflashFused2 = nn.Sequential(nn.Conv2d(channelin * 2, channelout * 2, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout * 2, channelout * 2, 3, 1, 1))self.reflashFused3 = nn.Sequential(nn.Conv2d(channelin * 2, channelout * 2, 3, 1, 1),nn.ReLU(),nn.Conv2d(channelout * 2, channelout * 2, 3, 1, 1))# 自适应平均池化层,将输入大小调整为 (batch_size, channels, 1, 1)self.avgpool = nn.AdaptiveAvgPool2d(1)# 后处理模块,用于处理融合后的特征self.postprocess = nn.Sequential(InvBlock(DenseBlock, 2 * channelin, channelout),nn.Conv2d(2 * channelout, channelout, 1, 1, 0)  # 1x1卷积,减少通道数)def forward(self, vis, inf, i, j):# 输入:vis和inf是两个不同的特征图(例如,视觉和信息特征图)# 首先将这两个特征图按通道维度拼接vis_cat = torch.cat([vis, inf], 1)# 使用通道注意力机制对拼接后的特征图进行处理chanAtten = self.chaAtten(self.avgpool(vis_cat)).softmax(1)channel_response = self.chaAtten(self.avgpool(vis_cat))# 使用通道注意力对特征图进行加权fused_OneOrderCha = vis_cat * chanAtten# 通过第一个重构模块(reflashFused1)进一步处理fused_OneOrderCha = self.reflashFused1(fused_OneOrderCha)chanAttenReflash1 = self.reflashChaAtten1(chanAtten).softmax(1)fused_twoOrderCha = fused_OneOrderCha * chanAttenReflash1# 通过第二个重构模块(reflashFused2)进一步处理fused_twoOrderCha = self.reflashFused2(fused_twoOrderCha)chanAttenReflash2 = self.reflashChaAtten2(chanAttenReflash1).softmax(1)fused_threeOrderCha = fused_twoOrderCha * chanAttenReflash2# 通过第三个重构模块(reflashFused3)进一步处理fused_threeOrderCha = self.reflashFused3(fused_threeOrderCha)chanAttenReflash3 = self.reflashChaAtten3(chanAttenReflash2).softmax(1)fused_fourOrderCha = fused_threeOrderCha * chanAttenReflash3# 最终的后处理模块,生成最终的输出output = self.postprocess(fused_fourOrderCha)return output

🍫 损失函数

L = L int  + λ L gra  \mathcal{L}=\mathcal{L}_{\text {int }}+\lambda \mathcal{L}_{\text {gra }} L=Lint +λLgra  L i n t = ∥ ( ω V ∘ I V + ω R ∘ I R ) − I F ∥ 1 \mathcal{L}_{\mathrm{int}}=\left\|\left(\omega_{\mathcal{V}} \circ I_{\mathcal{V}}+\omega_{\mathcal{R}} \circ I_{\mathcal{R}}\right)-I_{\mathcal{F}}\right\|_1 Lint=(ωVIV+ωRIR)IF1 ω V = S V / ( S V − S R ) and  S R = 1 − S V \omega_{\mathcal{V}}=S_{\mathcal{V}} /\left(S_{\mathcal{V}}-S_{\mathcal{R}}\right) \text { and } S_{\mathcal{R}}=1-S_{\mathcal{V}} ωV=SV/(SVSR) and SR=1SV L gra  = 1 H W ∥ ∇ I F − max ⁡ ( ∇ I R , ∇ I V ) ∥ 1 \mathcal{L}_{\text {gra }}=\frac{1}{H W}\left\|\nabla I_{\mathcal{F}}-\max \left(\nabla I_{\mathcal{R}}, \nabla I_{\mathcal{V}}\right)\right\|_1 Lgra =HW1IFmax(IR,IV)1损失函数中规中矩,因为重点不在这边,重点在于前面的模块设计。实验部分有兴趣的可以自行去看,我觉得没有什么亮点,就不说了


本文的源代码中,作者引用了Facebook研究的一个注册器,可以用来组织代码结构,使得整个代码部分更加容易管理:

# 修改自: https://github.com/facebookresearch/fvcore/blob/master/fvcore/common/registry.py  # noqa: E501class Registry():"""提供名称 -> 对象映射的注册表,用于支持第三方用户的自定义模块。创建一个注册表(例如,创建一个骨干网络的注册表):.. code-block:: pythonBACKBONE_REGISTRY = Registry('BACKBONE')注册一个对象:.. code-block:: python@BACKBONE_REGISTRY.register()class MyBackbone():...或者:.. code-block:: pythonBACKBONE_REGISTRY.register(MyBackbone)"""def __init__(self, name):"""构造函数参数:name (str): 注册表的名称"""self._name = name# key: 数据集/模型等的类名,value: 对应的类对象self._obj_map = {}def _do_register(self, name, obj):# 注册一个对象assert (name not in self._obj_map), (f"名为 '{name}' 的对象已经在 '{self._name}' 注册表中注册过了!")self._obj_map[name] = objdef register(self, obj=None):"""使用给定对象的名称 `obj.__name__` 注册该对象。可以作为装饰器使用,也可以不使用装饰器。参见本类的文档字符串了解使用方法。"""if obj is None:# 用作装饰器def deco(func_or_class):name = func_or_class.__name__# print(name)self._do_register(name, func_or_class)return func_or_classreturn deco# 作为函数调用时name = obj.__name__self._do_register(name, obj)def get(self, name):# 获取对应类的对象ret = self._obj_map.get(name)if ret is None:raise KeyError(f"在 '{self._name}' 注册表中没有找到名为 '{name}' 的对象!")return retdef __contains__(self, name):# 判断某个对象是否已经注册return name in self._obj_mapdef __iter__(self):# 迭代器方法return iter(self._obj_map.items())def keys(self):# 获取所有注册的对象的名称return self._obj_map.keys()# 以下是不同模块的注册表实例DATASET_REGISTRY = Registry('dataset')  # 数据集注册表
ARCH_REGISTRY = Registry('arch')        # 网络架构注册表
MODEL_REGISTRY = Registry('model')      # 模型注册表
LOSS_REGISTRY = Registry('loss')        # 损失函数注册表
METRIC_REGISTRY = Registry('metric')    # 指标注册表

相关文章:

#4【CVPR2024】SHIP:图像融合的一种协同高阶交互范式

📜 Probing Synergistic High-Order Interaction in Infrared and Visible Image Fusion 🍕 源码: https://github.com/zheng980629/SHIP 先前融合规则与我们提出的范式之间的比较。之前的工作要么(a)缺乏明确的交互&a…...

虚拟机从零实现机器人控制

1. 系统安装 因Docker不适合需要图形界面的开发,因此使用虚拟机VMware方便可视化界面方式查看效果,相关软件可以从官网下载,这里有一整套免费安装文件百度网盘地址: 2. ROS安装 Ubuntu 22.04:https://docs.ros.org…...

趣味数学300题1981版-八个等式、五个5等于24

八个等式 分析:此问题的求解思路是按照最后一步运算的运算符号进行分类。示例中最后一步的运算是除法,只要被除数与除数相等且不为0,就可以得到结果1.因此我们还可以对于结果等于1的情况列出其他的算式。如果保持最后一步运算为除法运算&…...

Microsoft Office 2024 软件安装教程(免费)

1.通过百度网盘下载Microsoft Office 2024安装包 下载地址为: https://pan.baidu.com/s/1jk1kvQsKFH9dZGF5xfGgiQ?pwdjbkv 提取码: jbkv 。 2.安装环境 Win10~Win11或更高。 3.安装步骤 (1)下载压缩包,解压缩。 (2&#xf…...

Linux 常见指令

linux 常见指令 Alt Enter 全屏 退出全屏 pwd: 显示用户所处路径 ls :显示当前路径下的文件或者目录名称 [ltVM-8-13-centos ~]$ ls 106 [ltVM-8-13-centos ~]$ ls -l ll :显示当前路径下的文件或者目录名称更多属性信息 [ltVM-8-13-cen…...

HTML Application(hta)入门教程

简介 HTA是HTML Application的缩写,又称为HTML应用程序。 hta是一个可执行文件,双击可以直接运行 hta与html非常相似,可直接将文件后缀改为.hta来获得HTA格式的文件。 支持VBS和JavaScript html的权限被限制在网页浏览器内,只有操…...

pytest运行用例的常见方式及参数

标题pytest运行用例方式及参数 用例结构目录 “”" 在最外层目录下执行所有的用例 参数说明: -s:显示用例的打印信息 -v:显示用例执行的详细信息 –alluredir:指定allure报告的路径 –clean-alluredir:清除allure报告的路径 -n:指定并发的进程数 -x:出现一条用…...

XML Schema 元素替换

XML Schema 元素替换 引言 XML(可扩展标记语言)是一种用于存储和传输数据的标记语言。XML Schema 是一种用于定义 XML 文档结构的语言,它描述了 XML 文档的结构、数据类型和约束。在处理 XML 文档时,有时需要对特定的元素进行替换,以满足特定的需求。本文将介绍 XML Sch…...

OpenBMC:BmcWeb app.run

1.监听用户移除signal //src\webserver_run.cpp int run() {...bmcweb::registerUserRemovedSignal();... } //include\user_monitor.hpp inline void onUserRemoved(sdbusplus::message_t& msg) {sdbusplus::message::object_path p;msg.read(p);std::string username …...

hot100_74. 搜索二维矩阵

hot100_74. 搜索二维矩阵 思路 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否…...

光明谷推出AT指令版本的蓝牙音箱SOC 开启便捷智能音频开发新体验

前言 在蓝牙音箱市场竞争日益激烈的当下,开发一款性能卓越且易于上手的蓝牙音箱,成为众多厂商追求的目标。而光明谷科技有限公司推出的 AT 指令版本的蓝牙音箱 SOC,无疑为行业带来了全新的解决方案,以其诸多独特卖点,迅…...

基于windows的docker-desktop安装kubenetes以及dashboard

我们需要k8s环境做各种小实验可以本地安装一个,这里介绍win11如何通过docker-desktop安装k8s以及通过helm安装dashboard。 下载docker-desktop地址https://www.docker.com/get-started/打开【控制面板】->打开【启用和关闭windows功能】->分别勾选【hyper-v】…...

MT7628基于原厂的SDK包, 修改ra1网卡的MAC方法。

1、在/etc/config/wireless文件添加多个WIFI网卡的方法。 2、修改WIFI驱动,在src/embedded/ap/ap.c文件里面,从系统文件信息来修改ra1网卡的MAC内容,添加红色部分源代码。 RTMP_IO_WRITE32(pAd, RMAC_RMACDR, Value); if (idx > 0) …...

网络安全第三次练习

一、实验拓扑 二、实验要求 配置真实DNS服务信息,创建虚拟服务,配置DNS透明代理功能 三、需求分析 1.创建用户并配置认证策略 2.安全策略划分接口 3.ip与策略配置 四、实验步骤 1.划分安全策略接口 2.创建用户并进行策略认证 3.配置安全策略 4.NAT配…...

BFS 和 DFS(深度优先搜索、广度优先搜索)

深度优先搜索(DFS)和广度优先搜索(BFS)是两种常用的图遍历算法,用于解决图相关的问题。它们在搜索问题中具有广泛的应用,如路径搜索、连通性检测等。 以下是具体区别: (图片引自&am…...

Casbin 权限管理介绍及在 Go 语言中的使用入门

引言 在现代软件开发过程中,权限管理是一个至关重要的环节,它关系到系统的安全性和用户体验。Casbin 是一个强大的访问控制库,支持多种访问控制模型,如 ACL(访问控制列表)、RBAC(基于角色的访问…...

Two Sum

声明:博主为算法新手,博客仅作为个人学习记录 作为新手我的做法 (1)数组nums遍历一遍挑选出小于target的值及其下标,值存入temp,下标存到indices (2)遍历temp找到符合temp[i]temp[j]target的两个…...

3.3.2 交易体系构建——缠论操作思路

本节我们基于交易目标(规避下跌趋势,参与上涨趋势)来构建基于上涨趋势的缠论交易体系。建立上涨趋势的缠论交易体系需要以下几个步骤: 识别下跌走势大概率完成的位置 等待出现转折结构 确定交易模型并交易 从概率的角度来说,判断走势结束是个概率事件。为构建成功较高的交…...

[SQL] 事务的四大特性(ACID)

🎄事务的四大特性 以下就是事务的四大特性,简称ACID。 原子性📢事务时不可分割的最小操作单元,要么全部成功,要么全部失败。一致性📢事务完成后,必须使所有的数据都保持一致隔离性&#x1f4e2…...

使用 Three.js 实现流光特效

大家好!我是 [数擎AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | AI…...

华为---RSTP(一)---从STP痛点看RSTP的革新

1. STP的痛点:为什么我们需要RSTP? 第一次接触STP(生成树协议)时,我被它优雅的环路消除机制惊艳到了。但真正把它部署到生产环境后,才发现这个"优雅"的代价有多大。记得有次凌晨割接&#xff0c…...

手把手教你用MBR2GPT无损转换系统盘,告别BIOS拥抱UEFI(附VMware虚拟机设置)

手把手教你用MBR2GPT无损转换系统盘,告别BIOS拥抱UEFI(附VMware虚拟机设置) 在个人电脑和虚拟化环境中,许多用户仍在使用传统的MBR分区方案,却不知这已成为性能和安全性的隐形瓶颈。想象一下,当你新购一块4…...

Codeforces评分预测神器Carrot:从API崩溃到社区自救的技术传奇

Codeforces评分预测神器Carrot:从API崩溃到社区自救的技术传奇 【免费下载链接】carrot A browser extension for Codeforces rating prediction 项目地址: https://gitcode.com/gh_mirrors/carrot1/carrot 想象一下这样的场景:你正在参加一场激烈…...

抖音无水印下载神器:douyin-downloader 终极实战教程

抖音无水印下载神器:douyin-downloader 终极实战教程 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppor…...

如何快速搭建Python管理后台:SQLAdmin终极解决方案

如何快速搭建Python管理后台:SQLAdmin终极解决方案 【免费下载链接】sqladmin SQLAlchemy Admin for FastAPI and Starlette 项目地址: https://gitcode.com/gh_mirrors/sq/sqladmin 你是否曾为FastAPI或Starlette项目的数据管理界面而烦恼?每次都…...

保姆级教程:用Python搞定TOF深度相机数据转点云(附源码与避坑指南)

从深度图到三维世界:Python实战TOF相机点云转换全攻略 深度相机正逐渐成为机器视觉领域的标配工具,而TOF(Time of Flight)技术因其独特的优势备受关注。不同于传统RGB相机只能捕捉平面信息,TOF相机通过测量光线飞行时间…...

手把手教你排查RK3568/RV1126相机ISP报错:从‘isp no free cp buffer’到‘CsiFifoOverflow’的实战修复

嵌入式Camera调试实战:从内核日志到硬件时序的深度排错指南 当你在RK3568或RV1126开发板上调试Camera模组时,是否遇到过ISP突然罢工、MIPI频繁报错的困境?那些晦涩的内核日志就像加密电报,而官方文档往往语焉不详。本文将带你深入…...

D3KeyHelper终极指南:暗黑3玩家的5分钟自动化配置教程

D3KeyHelper终极指南:暗黑3玩家的5分钟自动化配置教程 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper 你是否厌倦了在暗黑破坏神3中反复点…...

Go 内存逃逸调试技巧

Go语言以高效的内存管理著称,但内存逃逸问题却可能成为性能瓶颈的隐形杀手。当变量本应在栈上分配却意外逃逸到堆上时,不仅会增加GC压力,还会降低程序运行效率。本文将深入剖析Go内存逃逸的调试技巧,帮助开发者快速定位问题并优化…...

终极QMC音频解密方案:3分钟破解QQ音乐加密格式

终极QMC音频解密方案:3分钟破解QQ音乐加密格式 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder qmc-decoder是一款高效、免费的专业音频解密工具,专门…...