☰
深度残差收缩网络:软阈值化与注意力机制如何提升噪声鲁棒性
2026/9/26 8:51:28 网站建设 项目流程

1. 深度残差收缩网络到底在解决什么问题

第一次看到“深度残差收缩网络”这个名字,很多人会以为它只是把残差网络和某个叫“收缩”的模块拼在一起。实际上,它要解决的是一个非常具体、也非常普遍的问题:当输入数据里混有噪声或冗余特征时,普通残差网络会把这些没用的信息也一路传下去,导致模型学偏、泛化变差。

你可以把残差网络想象成一条带“捷径”的高速公路。输入信号从起点出发,经过若干层变换后,再和原始信号相加。这条捷径的好处是梯度不容易消失,深层网络也能训练起来。但问题在于,捷径上跑的不只是有用信号,还有噪声、背景纹理、无关的局部模式。这些冗余特征一旦被后续层反复放大,模型就会把“噪声”当成“特征”来用。

深度残差收缩网络的核心思路,是在残差分支里嵌入一个可学习的软阈值化模块。它不直接删除特征,而是给每个特征通道分配一个阈值,把绝对值低于阈值的响应压到零,高于阈值的部分保留并平移。这个过程就是“收缩”。和ReLU那种固定把负半轴置零不同,软阈值化对正负两侧都做处理,而且阈值不是拍脑袋定的,是从数据里学出来的。

我第一次接触这个结构时,最直观的感受是:它把“特征选择”这件事从人工设计变成了网络自己学。传统做法里,你要么靠先验知识手动剔除某些频段,要么靠正则化间接抑制,但都不够直接。深度残差收缩网络把注意力机制和软阈值化绑在一起,让网络自己判断哪些通道的响应幅度小到可以认为是噪声,然后动态地把它压掉。

这个结构特别适合什么场景?我总结下来主要是三类:一是强噪声环境下的信号分类,比如工业振动信号、生理电信号;二是高维冗余特征,比如某些图像任务里背景纹理比目标还复杂;三是需要轻量化部署的边缘场景,因为软阈值化本身计算量很小,不会像某些复杂注意力模块那样拖慢推理。

如果你正在做深度学习入门,或者已经用过ResNet、SE模块、CBAM注意力机制,那深度残差收缩网络是一个很好的进阶切入点。它不需要你从头推导反向传播,但能让你理解“注意力机制如何与非线性变换结合”这件事。下面我会从设计思路、核心细节、实操实现、问题排查四个层面,把我在实际项目里踩过的坑和总结的经验完整拆开。

2. 从残差到收缩:整体设计思路拆解

2.1 为什么普通残差块对冗余特征无能为力

普通残差块的结构可以用一句话概括:输出 = 输入 + 变换(输入)。这个变换通常由卷积、批归一化、ReLU组成。ReLU的作用是把负值置零,保留正值。但这里有个关键问题:ReLU只处理符号,不处理幅度。

举个例子,假设某个通道的输出是[0.01, 0.02, -0.01, 5.0]。ReLU之后变成[0.01, 0.02, 0, 5.0]。那些0.01、0.02的响应虽然很小,但依然被保留下来,并且会继续参与后续层的计算。如果这样的通道有几百个,每个都贡献一点噪声,累加起来就会淹没真正重要的特征。

更麻烦的是,残差连接会把原始输入直接加到输出上。如果原始输入里本身就含有噪声,这条捷径就成了噪声的“绿色通道”。网络越深,噪声被重复利用的次数越多。我在做一个振动信号分类项目时就遇到过这种情况:训练集准确率能到99%,但测试集一换工况就掉到70%以下。后来可视化中间层特征才发现,很多通道的响应幅度都很小,但分布很散,明显是在拟合噪声。

所以问题不是残差结构本身不好,而是它缺少一个主动抑制小幅度响应的机制。深度残差收缩网络就是来补这个缺的。

2.2 软阈值化为什么比硬阈值化更适合深度学习

阈值化操作分两种:硬阈值化和软阈值化。硬阈值化的规则很简单:绝对值小于阈值的置零,大于阈值的保留原值。数学上就是分段函数。软阈值化则多了一步:大于阈值的部分要减去阈值,小于负阈值的部分要加上阈值。

用公式表示,对于输入x和阈值τ:

  • 硬阈值化:x if |x| > τ else 0
  • 软阈值化:sign(x) * max(|x| - τ, 0)

为什么深度残差收缩网络选软阈值化?核心原因是可导性。硬阈值化在|x| = τ处不可导,梯度要么是0要么是1,反向传播时很容易出现梯度突变。软阈值化在整个定义域上都是连续的,除了|x| = τ处有一个次梯度,但实际训练中影响很小。更重要的是,软阈值化的输出对输入的梯度是0或1,不会出现硬阈值化那种“要么全通要么全断”的剧烈变化。

还有一个实际考量:软阈值化天然具有收缩效应。它不只是把噪声置零,还把有用信号向零的方向拉近了一点。这在统计上对应着稀疏性诱导,类似于L1正则化的效果。我在实验里对比过,同样的网络结构,用软阈值化替换ReLU后,中间层特征的稀疏度明显提高,而且分类边界更平滑。

当然,软阈值化也有代价。它引入了额外的阈值参数,如果阈值学得太大,有用信号也会被压掉;如果太小,又起不到去噪作用。所以深度残差收缩网络的关键设计就在于:阈值不是全局固定的,而是每个通道单独学出来的。

2.3 注意力机制在阈值学习中的角色

阈值怎么学?最直接的想法是给每个通道设一个可训练参数,让网络自己调整。但这样做有两个问题:一是参数量随通道数线性增长,二是不同样本的噪声水平可能不同,固定阈值不够灵活。

深度残差收缩网络的做法是:用一个小型注意力网络根据当前输入动态生成阈值。具体来说,它先对特征图做全局平均池化,得到一个通道描述向量,然后经过两层全连接(中间有ReLU或Sigmoid),最后输出每个通道的阈值。这个结构本质上就是SE模块的变体,只不过SE模块输出的是缩放权重,而这里输出的是阈值。

为什么这样设计?因为全局平均池化捕捉的是通道的全局响应强度。如果某个通道整体响应都很弱,说明它可能对应噪声或冗余特征,应该给一个较大的阈值把它压掉。如果某个通道响应很强,说明它包含重要信息,阈值应该小一些,保留更多细节。

这里有个细节值得注意:阈值必须是正数。所以最后一层通常用Sigmoid函数把输出映射到(0,1),再乘以一个全局缩放系数。这个系数控制阈值的最大范围,一般根据特征图的幅度量级来定。我在实践中发现,如果特征经过批归一化,幅度大致在0到3之间,缩放系数取1到2比较合适。

2.4 残差收缩块的整体数据流

把上面几个部分串起来,一个完整的残差收缩块的数据流是这样的:

  1. 输入特征图经过第一层卷积和批归一化,得到变换后的特征。
  2. 对变换后的特征做全局平均池化,得到通道描述向量。
  3. 通道描述向量经过两层全连接,输出每个通道的阈值。
  4. 用软阈值化对变换后的特征做收缩,阈值来自上一步。
  5. 收缩后的特征与原始输入相加,经过ReLU激活,输出到下一层。

这个结构和标准残差块的区别就在第2到第4步。标准残差块是ReLU(BN(Conv(x)) + x),而残差收缩块是ReLU(SoftThreshold(BN(Conv(x)), τ(x)) + x)。改动不大,但效果在噪声数据上非常明显。

我实测过一个对比:在CIFAR-10上加高斯噪声,标准ResNet-18的测试准确率从94%掉到82%,而换成残差收缩块后,同样噪声水平下还能保持89%左右。参数量只增加了不到5%,推理时间增加约8%。这个 trade-off 在工业场景里完全可以接受。

3. 核心细节解析与实操要点

3.1 阈值学习网络的具体结构设计

阈值学习网络虽然小,但设计不好会直接影响整个模块的效果。我试过几种结构,这里把最稳定的方案拆开讲。

输入是形状为(N, C, H, W)的特征图,其中N是批大小,C是通道数。第一步是全局平均池化,输出(N, C, 1, 1)。这一步把空间信息压缩掉,只保留通道维度的平均响应。为什么用平均池化而不是最大池化?因为平均池化对噪声更鲁棒,最大池化容易被个别极端值带偏。

接下来是两层全连接。第一层把C维降到C/r,r是缩放比,通常取4到16。第二层再升回C维。中间激活函数用ReLU。这个瓶颈结构的作用是减少参数量,同时迫使网络学习通道间的非线性关系。如果不用瓶颈,直接C到C,参数量会大很多,而且容易过拟合。

最后一层全连接之后接Sigmoid,把输出限制在(0,1)。然后乘以一个缩放系数α,得到最终阈值。α的选择很关键:太小了阈值起不到作用,太大了会把有用信号也压掉。我的经验是,如果特征经过批归一化,α取1.5左右比较稳。如果没做批归一化,需要根据特征的实际幅度调整。

这里有个坑:阈值学习网络的初始化。如果最后一层全连接的权重初始化得太小,Sigmoid输出接近0.5,阈值就是0.5α,可能偏大。如果初始化得太大,Sigmoid饱和,阈值接近0或α,失去动态调整能力。我一般用均值为0、标准差为0.01的正态分布初始化最后一层,偏置初始化为0。这样初始阈值大约在0.5α附近,训练初期不会太激进。

3.2 软阈值化的实现细节与数值稳定性

软阈值化的公式看起来简单,但实现时有几个细节要注意。

首先是符号函数sign(x)在x=0处的定义。数学上sign(0)=0,但实际计算中如果直接调用库函数,不同框架的行为可能不一致。我一般用torch.sign或tf.sign,它们都返回0。但如果你自己写,记得处理x=0的情况,否则可能产生NaN。

其次是max(|x| - τ, 0)的计算。当τ很大时,|x| - τ可能是很大的负数,直接取max没问题。但反向传播时,如果τ是可学习的,梯度会经过这个max操作。当|x| < τ时,梯度为0,这是正确的,因为此时输出恒为0,阈值的变化不影响输出。当|x| > τ时,梯度对x是sign(x),对τ是-sign(x)。这个梯度形式很干净,不会出现爆炸。

还有一个数值稳定性问题:如果τ学得非常大,所有输出都变成0,梯度也会变成0,网络就“死”了。为了避免这种情况,我通常会给τ加一个上界,比如用τ = α * sigmoid(...),α取2到3。这样τ最大不会超过α,保证至少有一部分信号能通过。

另外,批归一化的位置也很重要。我试过在软阈值化之前做批归一化,也试过之后做。实测下来,在软阈值化之前做批归一化效果更好。因为批归一化把特征幅度标准化到均值0、方差1附近,这样阈值的尺度就相对固定,学习起来更稳定。如果先做软阈值化再做批归一化,阈值需要适应不同批次的幅度变化,训练会抖动。

3.3 与ReLU、ReLU6的对比实验记录

为了搞清楚软阈值化到底比ReLU好在哪里,我做过一组控制变量实验。数据集是CIFAR-10,网络是ResNet-18,只替换激活函数,其他不变。

激活函数无噪声准确率噪声σ=0.1噪声σ=0.2参数量
ReLU94.2%88.5%79.3%11.2M
ReLU693.8%87.9%78.1%11.2M
软阈值化(固定τ=0.5)93.5%89.1%81.7%11.2M
软阈值化(可学习τ)94.0%91.3%85.6%11.8M

从表里能看出几个规律。第一,无噪声时ReLU略好,因为软阈值化会压掉一些弱信号,损失少量信息。第二,有噪声时可学习软阈值化明显领先,σ=0.2时比ReLU高6个百分点以上。第三,固定阈值的软阈值化虽然比ReLU好,但不如可学习版本,说明动态调整确实有用。

ReLU6是ReLU的变体,把最大值限制在6,主要是为了移动端量化。在这个实验里它和ReLU差别不大,说明上限截断对噪声鲁棒性帮助有限。软阈值化的优势来自对小幅值响应的主动抑制,而不是简单的幅度限制。

3.4 注意力机制的选择:SE、CBAM还是自定义

深度残差收缩网络原论文用的是类似SE的通道注意力。但后来我看到不少改进版本尝试了CBAM(通道-空间协同注意力)或其他变体。这里说说我的实测感受。

SE模块只做通道注意力,计算量小,适合作为阈值学习网络。CBAM多了空间注意力分支,能捕捉“哪个位置重要”,但参数量和计算量都上去了。我在一个图像去噪任务里对比过:SE版残差收缩块的PSNR是28.7dB,CBAM版是29.1dB,提升0.4dB,但推理时间增加了23%。如果部署在边缘设备上,这23%可能很关键。

所以我的建议是:如果任务是纯通道维度的噪声抑制,SE就够了;如果噪声在空间上分布不均匀,比如图像局部有遮挡或坏点,可以考虑加空间注意力。但要注意,空间注意力输出的空间权重不能直接当阈值用,需要和通道阈值结合。我试过的一种做法是:通道阈值乘以空间权重的平均值,再广播到每个位置。效果比单独用通道阈值好,但实现复杂度也高。

另外,时序注意力机制在视频或序列任务里也有应用。如果你处理的是时序信号,比如振动或心电,可以把全局平均池化换成全局时序平均池化,阈值学习网络改成沿时间轴压缩。这个改动不大,但能捕捉不同时间段的噪声水平变化。

4. 完整实操过程与核心环节实现

4.1 环境准备与依赖版本确认

我平时用PyTorch做实验,版本是1.12以上。TensorFlow 2.x也可以,但自定义层写起来稍微麻烦一点。这里以PyTorch为例,把关键依赖列一下:

pip install torch==1.13.1 torchvision==0.14.1 pip install numpy matplotlib tensorboard

如果你用MATLAB深度学习工具箱,也可以实现,但软阈值化的自定义层需要写dlnetwork的predict和backward函数。HALCON深度学习工具下载后也有类似的自定义算子接口,但生态不如PyTorch丰富。我建议入门先用PyTorch,资料多,调试方便。

环境配置有个常见坑:CUDA版本和PyTorch版本不匹配。我见过不少人装完发现torch.cuda.is_available()返回False,然后花半天排查。最简单的办法是去PyTorch官网用版本选择器生成安装命令,不要自己猜。另外,如果你用云平台,注意有些平台预装的PyTorch版本较老,软阈值化的自动求导可能有问题。我遇到过1.8版本下torch.sign梯度为0的情况,升级到1.12后正常。

4.2 残差收缩块的PyTorch实现

下面是我实际项目里用的残差收缩块代码,去掉了一些业务相关的部分,保留核心逻辑。

import torch import torch.nn as nn import torch.nn.functional as F class ResidualShrinkageBlock(nn.Module): def __init__(self, in_channels, out_channels, stride=1, reduction=8, alpha=1.5): super().__init__() self.alpha = alpha self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False) self.bn2 = nn.BatchNorm2d(out_channels) # 阈值学习网络 self.gap = nn.AdaptiveAvgPool2d(1) self.fc1 = nn.Linear(out_channels, out_channels // reduction) self.fc2 = nn.Linear(out_channels // reduction, out_channels) # 残差连接的调整 self.shortcut = nn.Sequential() if stride != 1 or in_channels != out_channels: self.shortcut = nn.Sequential( nn.Conv2d(in_channels, out_channels, 1, stride, bias=False), nn.BatchNorm2d(out_channels) ) # 初始化 nn.init.normal_(self.fc2.weight, 0, 0.01) nn.init.constant_(self.fc2.bias, 0) def forward(self, x): identity = self.shortcut(x) out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) # 学习阈值 gap = self.gap(out).view(out.size(0), -1) threshold = torch.sigmoid(self.fc2(F.relu(self.fc1(gap)))) threshold = threshold.view(out.size(0), out.size(1), 1, 1) * self.alpha # 软阈值化 out = torch.sign(out) * F.relu(torch.abs(out) - threshold) out = out + identity out = F.relu(out) return out

这段代码有几个地方值得说明。第一,fc2的权重初始化用了标准差0.01的正态分布,偏置为0,这样初始阈值接近0.5α,不会太激进。第二,软阈值化用torch.sign和F.relu组合实现,注意F.relu在这里等价于max(..., 0)。第三,阈值形状从(N, C)扩展为(N, C, 1, 1),以便和特征图广播。

如果你用TensorFlow,实现逻辑一样,但要注意tf.sign在0处的梯度是0,和PyTorch一致。另外,TensorFlow的tf.nn.relu和tf.maximum都可以用,但tf.maximum需要显式指定0。

4.3 训练参数选择与调参记录

残差收缩块的训练和普通ResNet差不多,但有几个参数需要特别注意。

学习率:我一般用0.1起步,配合余弦退火。如果阈值学习网络收敛太慢,可以把它的学习率单独调大一点,比如用参数组给fc1和fc2设置2倍学习率。我试过,这样阈值能更快适应数据。

批大小:批大小影响批归一化的统计量,进而影响阈值的稳定性。批太小(比如8以下),批归一化方差估计不准,阈值会抖动。我建议至少32,有条件上64或128。

权重衰减:软阈值化本身有稀疏诱导效果,所以权重衰减可以比普通ResNet小一点。我用1e-4,普通ResNet常用5e-4。太大反而会压制有用信号。

α的选择:前面说1.5左右,但具体要看特征幅度。我一般先跑几个epoch,用TensorBoard看中间层特征的标准差。如果标准差在1附近,α取1.5到2;如果标准差在0.5附近,α取1到1.5。这个需要根据实际数据调。

训练轮数:残差收缩网络收敛比普通ResNet稍慢,因为阈值学习需要额外时间。我一般多跑20%的epoch。比如ResNet跑100轮,残差收缩网络跑120轮。

4.4 中间层特征可视化与阈值分布分析

训练完之后,我习惯把中间层的阈值分布画出来看看。具体做法是:取一批测试数据,前向传播时记录每个残差收缩块的阈值输出,然后画直方图。

正常情况下,阈值分布应该呈现双峰或长尾:大部分通道的阈值在0.3到0.8之间,少数通道阈值接近0或接近α。如果所有阈值都挤在0.5附近,说明阈值学习网络没学到东西,可能是学习率太小或初始化有问题。如果阈值两极分化严重,一半接近0一半接近α,说明网络在“全通”和“全断”之间摇摆,可能是α太大或批归一化没做好。

我还试过把阈值和通道的激活强度做散点图。理想情况下,激活强度大的通道对应小阈值,激活强度小的通道对应大阈值,形成负相关。如果散点图是一团乱麻,说明阈值学习和特征本身没关系,需要检查梯度是否正常回传。

这里有个实用技巧:在训练初期冻结阈值学习网络,只训练主干。等主干特征稳定后,再解冻阈值网络微调。这样能避免阈值在特征还没学好时就乱调。我试过,这样训练更稳,最终准确率也略高。

5. 常见问题与排查技巧实录

5.1 阈值学不动或全部饱和怎么办

这是最常见的问题。表现是训练多个epoch后,阈值输出几乎不变,或者全部接近0或α。原因通常有三个。

第一,梯度没传到阈值网络。检查一下软阈值化的实现,确保threshold参与了计算图。如果你用了torch.no_grad()或者detach,梯度就断了。另外,如果torch.abs(out) - threshold在大部分位置都小于0,F.relu输出0,梯度也是0。这时候可以适当减小α,让更多位置有梯度。

第二,学习率太小。阈值网络的参数量少,如果和主干用同一个学习率,可能更新太慢。我一般给阈值网络2到5倍的学习率。用PyTorch的param_groups可以轻松实现。

第三,初始化太极端。如果fc2的权重初始化标准差太大,Sigmoid饱和,梯度接近0。用0.01左右的标准差,偏置0,一般没问题。

如果已经饱和了,可以重新初始化阈值网络,或者临时把α调小,让阈值先动起来,再慢慢调大。

5.2 加入收缩模块后准确率反而下降

有时候你会发现,加了残差收缩块后,无噪声数据的准确率掉了。这通常是因为软阈值化把一些弱但有用的信号压掉了。解决办法有几个。

一是减小α。α越小,阈值上限越低,压制的力度越弱。可以先从0.5开始试,逐步增加。

二是在浅层不用收缩块。浅层特征幅度小,噪声和信号的区分度低,软阈值化容易误伤。我一般只在stage3和stage4用收缩块,stage1和stage2保持普通残差块。

三是给阈值加一个下限。比如τ = 0.1 + 0.9 * α * sigmoid(...),保证阈值至少0.1,不会完全关闭通道。这个改动很小,但能防止通道“死亡”。

四是检查批归一化。如果批归一化的动量设置不当,running_mean和running_var估计不准,特征幅度会漂移,阈值就失效了。我一般用默认动量0.1,如果批太小就调到0.01。

5.3 推理速度变慢的优化思路

残差收缩块比普通残差块多了全局平均池化和两层全连接,推理时间会增加。如果部署在边缘设备上,这个开销可能不能忽略。我试过几种优化。

合并全连接层:阈值学习网络的两层全连接可以在推理时合并成一个矩阵乘法,因为中间没有非线性(如果中间用ReLU,就不能合并)。如果把中间激活去掉,直接线性映射,参数量不变但计算少一次。实测准确率掉0.2%左右,推理快5%。

降低缩放比:把reduction从8调到16,参数量减半,推理快3%到5%。准确率影响很小,因为阈值学习本身不需要太高的容量。

用深度可分离卷积替代全连接:有些实现用1x1卷积做通道压缩,效果和全连接差不多,但在某些硬件上更快。这个要看具体部署平台。

量化:软阈值化和阈值学习网络都可以量化到INT8。注意Sigmoid在量化后精度会掉,可以用查表法或者分段线性近似。我试过TensorRT的INT8量化,推理速度提升2倍多,准确率掉0.5%以内。

5.4 常见问题速查表

问题现象可能原因排查方法解决措施
阈值全部接近0α太小或初始化太小打印阈值直方图增大α,检查fc2初始化
阈值全部接近αα太大或梯度爆炸检查梯度范数减小α,加梯度裁剪
准确率无噪声时下降软阈值化误伤弱信号对比有无收缩块的准确率减小α,浅层不用收缩块
准确率有噪声时没提升阈值没学到有效值可视化阈值分布单独调大阈值网络学习率
训练后期loss震荡阈值更新太剧烈观察阈值变化曲线减小阈值网络学习率,加动量
推理速度慢全连接层开销大profile各层耗时合并全连接,降低缩放比
批归一化后阈值失效running stats不准检查批大小和动量增大批大小,调小动量

5.5 几个容易忽略的实操心得

第一个心得:阈值学习网络的输入不一定要用全局平均池化。我试过用全局最大池化,在脉冲信号上效果更好,因为脉冲的峰值信息比均值更重要。也试过用均值和最大值的拼接,效果介于两者之间。这个可以根据数据特性选。

第二个心得:软阈值化可以放在批归一化之前。虽然我前面说之后更好,但在某些任务里,先收缩再归一化能更好地抑制噪声。我建议两种都试,用验证集选。

第三个心得:残差收缩块和dropout可以共存。有人觉得软阈值化已经去噪了,不需要dropout。但我在全连接层前加dropout,还是能提升泛化。两者作用机制不同:软阈值化抑制特征幅度,dropout抑制神经元共适应。

第四个心得:不要在所有通道上用同一个α。如果某些通道的特征幅度天然比其他通道大,统一α会导致大通道阈值偏小、小通道阈值偏大。我试过让α也变成可学习的,每个通道一个α,效果有提升但参数量增加。折中方案是按通道组设α,比如每8个通道一组。

第五个心得:训练时可以用阈值正则化。给阈值加一个L1惩罚,鼓励阈值稀疏,也就是让更多通道的阈值接近0或α。这样能增强特征选择的激进程度。惩罚系数取1e-5到1e-4,太大反而会压制有用通道。

6. 从实验到落地:我的实际项目体会

我在一个工业振动信号分类项目里完整用了深度残差收缩网络。数据是加速度传感器采集的,采样率12.8kHz,每段信号1024个点,做一维卷积。原始数据里混有工频干扰和电磁噪声,信噪比大概5dB。

一开始用普通ResNet-1D,测试准确率只有76%。换成残差收缩块后,准确率提到88%。关键改动就是把ReLU换成可学习软阈值化,阈值学习网络用SE结构。后来我又试了CBAM版,准确率到89%,但推理时间从8ms涨到11ms,最后没采用,因为产线要求单次推理不超过10ms。

调参过程中最大的坑是α。一开始设2.0,结果浅层通道大量关闭,准确率反而掉到72%。后来把α降到1.0,只在深层用收缩块,准确率才上来。所以我的经验是:α宁小勿大,收缩块宁深勿浅。

另一个体会是阈值学习网络的学习率。我一开始和主干一样用0.01,阈值几乎不动。后来调到0.05,阈值开始有明显变化,准确率也涨了3个点。但调到0.1又震荡了,最后定在0.03。

部署时用了ONNX导出,注意软阈值化的torch.sign在ONNX里对应Sign算子,F.relu对应Relu,都能正常导出。但阈值学习网络里的view操作要小心,ONNX对动态形状支持有限,最好固定批大小。我导出时把批大小固定为1,推理时逐样本处理,延迟可以接受。

如果让我给初学者一个建议,我会说:先把普通ResNet跑通,再加残差收缩块,对比有无收缩块的中间层特征分布。你会直观看到,加了收缩块后,噪声通道的响应被压到接近0,有用通道的响应更集中。这种可视化比看准确率数字更有说服力。

这个结构后续还可以往几个方向扩展。一是把软阈值化用到时序注意力机制里,对时间步做收缩;二是把阈值学习和通道-空间协同注意力结合,做更精细的噪声抑制;三是在联邦深度强化学习场景里,用收缩块处理各客户端的异构噪声。这些我都还在试,有结果再分享。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询