当前位置: 首页 > 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…...

synchronized 学习

学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

大数据学习(132)-HIve数据分析

​​​​🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言&#x1f4…...

2023赣州旅游投资集团

单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

微服务通信安全:深入解析mTLS的原理与实践

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...

SQL注入篇-sqlmap的配置和使用

在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...