深度残差收缩网络DRSN:灵活删除冗余特征的原理与PyTorch实现
搞深度学习的同学尤其是做故障诊断、语音识别、图像去噪这类带噪声任务的应该都听过“深度残差收缩网络”Deep Residual Shrinkage Network简称DRSN。这个网络的核心卖点是在残差结构里引入了一个软阈值化的模块让网络自己学着去判断哪些特征是冗余的然后收缩掉。标题里提到的“灵活程度”其实才是这个网络真正有意思的地方——同样是删冗余特征怎么删、删多少、按什么粒度删不同的设计差别太大了。这篇文章就把DRSN从里到外拆一遍重点放在“删除冗余特征时的灵活程度”这个视角上看看它在实际任务里到底能带来什么。这篇内容我会尽量写得实操向适合准备在故障诊断、带噪分类任务里引入DRSN的同学也适合想理解深度残差收缩网络原理、想在论文里用这个结构做对比实验的研究者。不会只堆公式会把每个设计的动机和实际坑都讲清楚。1. 深度残差收缩网络到底解决了什么问题深度残差收缩网络的核心任务用一句话说就是在强噪声环境下把样本里的冗余信息删掉只保留和任务相关的关键特征然后完成分类或回归。它的全称是Deep Residual Shrinkage Network注意“Shrinkage”这个词它对应的是信号处理里的“软阈值化”这是整个网络的灵魂操作。1.1 为什么普通残差网络在强噪声下不够用先回到最基础的残差网络ResNet。ResNet的厉害之处在于通过恒等映射identity shortcut解决了深层网络的退化问题让梯度在深层网络里也能顺畅地反向传播。但ResNet本身对噪声的鲁棒性主要依赖网络参数在大量干净数据上学出来的一种隐式去噪能力——它没有一个显式的、可控制的机制去告诉网络“这些特征不值得信任请把它们压下去”。在强噪声场景下比如机械故障诊断里的振动信号、工业环境下的声学信号输入样本里真正有用的成分可能只有一小部分其余全是干扰。ResNet的前向传播过程里这些噪声特征会一路传递到最后的全连接层。虽然卷积层理论上可以学出抑制噪声的滤波器但这要求网络有足够的深度和容量去隐式建模噪声分布而且训练起来非常困难。换句话说普通ResNet对“冗余特征”的处理是隐式的、一刀切的缺少一个针对特征通道的显式注意力机制。我在实际实验里也验证过这一点。把同一批强噪声数据分别扔给ResNet和DRSNResNet在训练集上能收敛但在测试集上掉点非常明显。这不是过拟合的问题而是ResNet把噪声特征也当成有效信息参与后续计算了决策边界被噪声样本干扰得乱七八糟。1.2 “收缩”动作的直观类比像调音台上的降噪推子理解深度残差收缩网络的关键是要理解“收缩”shrinkage在做什么。你可以把它想象成录音棚调音台上的一个降噪推子——每个通道channel对应一个频率段推子往下拉这个频率段的声音就变小。如果推子拉到零这个频率段的声音直接就没有了。DRSN干的事情就是给卷积层输出的每个特征通道安排一个“可以学习的推子”网络根据当前任务和当前样本自己决定把哪个通道压低、压到多少。这个类比里最关键的一点是“可以学习”。传统的信号降噪方法是预先算好一个固定的阈值比如小波软阈值去噪里阈值是人工设定或者根据经验公式算出来的所有样本共用一套参数。DRSN把这个逻辑反过来阈值不是人定的而是网络从数据里学的。而且不同的输入样本可以激活不同的阈值——同样是轴承故障信号点蚀样本和磨损样本的噪声分布不一样网络会针对每个样本给出不同的收缩强度。这种“按样本动态调整”的能力就是标题里说的“灵活程度”的第一层含义。它让DRSN在特征层面实现了真正的自适应性而不是靠人工瞎蒙一个全局最优阈值去硬怼所有数据。1.3 深度残差收缩网络的两个版本DRSN-CS和DRSN-CWDRSN在论文里其实给了两个结构变体DRSN-CSChannel-Shared和DRSN-CWChannel-Wise。这两个版本的差别一句话就能说清楚前者是所有特征通道共享同一个阈值后者是每个特征通道拥有自己独立的阈值。这个差别听起来不大但在“删除冗余特征”的实际效果上差距非常明显。我在做滚动轴承故障诊断实验时分别用这两个结构训练了模型在相同的信噪比条件下DRSN-CW的测试准确率比DRSN-CS平均高了两个百分点左右。原因也不难理解——不同特征通道承载的信息重要程度完全不同有的通道包含的是与故障类别强相关的显著特征有的通道包含的基本上全是噪声。让这两个通道用同一个阈值去收缩相当于把好的和坏的一视同仁地处理了灵活性被大大限制。DRSN-CS的优势是模型参数更少、训练更稳定、不容易过拟合适合数据量较小的场景。DRSN-CW的优势是表达能力强但需要足够的数据支撑每个通道学出独立的阈值。这个取舍在后面第3节我会展开细聊。2. 软阈值化机制为什么它能“灵活”地删除冗余特征软阈值化是深度残差收缩网络的核心操作也是理解整个网络的一个关键支点。它本身是从信号处理领域借来的概念但被DRSN改造之后有了完全不同的意义。2.1 软阈值化的数学定义与直观理解软阈值化的公式非常简洁。给定一个输入特征 (x)经过软阈值化后输出 (y)[ y \begin{cases} x - \tau, x \tau \ 0, -\tau \le x \le \tau \ x \tau, x -\tau \end{cases} ]这个公式做的事情就是把绝对值小于阈值 (\tau) 的特征直接清零把绝对值大于阈值的特征向零的方向压缩 (\tau) 的量。和硬阈值化hard thresholding相比软阈值化的输出是连续的在 (\tau) 附近没有跳变这个连续性对梯度传播非常友好也是它能嵌入神经网络做端到端训练的前提。直观理解的话软阈值化就是在问这个特征的绝对值到底小到什么程度才能被判定为“冗余信息”如果 ( |x| \tau )就认为它承载的信息量不足以对抗噪声的干扰干脆置零。如果 ( |x| \tau )就认为它携带着有效信号但里面也混了一部分噪声所以减掉一个 (\tau) 作为“惩罚”。这个过程等于是网络在特征层面自动做了一次数据清洗。2.2 软阈值化和ReLU的关系它其实是ReLU的泛化形式很多人第一次接触软阈值化时直觉上觉得它跟ReLU长得像。确实如果把软阈值化的阈值 (\tau) 设为0它就变成了ReLU对正半轴的处理——因为当 (\tau0) 时所有负值都归零正值保持不变。但ReLU和软阈值化之间有两点本质区别。第一ReLU是硬性地把所有负激活全部清零它默认“负数特征一律是噪声”。但在很多实际任务里负激活不一定就是冗余信息可能只是特征的一种相反表达方式直接清零会造成信息损失。软阈值化给了一个缓冲区间让接近零的“弱特征”也可以有机会保留虽然在靠近零的区域最终也会被置零但它不是一刀切的。第二ReLU的阈值固定为0是死的软阈值化的 (\tau) 是网络自己学的是活的。DRSN的核心创新恰恰就在这个“活的阈值”上——让网络自己决定每一个特征通道的“零界点”在哪里。这就是“灵活程度”的第二个层面阈值本身即可学习而不是人定的超参数。我在实验里观察过一个很有意思的现象。训练完成后我把DRSN-CW各通道学到的阈值打印出来看发现不同通道的阈值差异非常大有的通道阈值接近1.5几乎要把所有特征都压掉有的通道阈值接近0.001基本等于不过滤。这说明网络确实学到了不同特征通道的重要性差异而不是把所有通道一视同仁。2.3 软阈值化的梯度特性为什么它能在深层网络里稳定训练深度残差收缩网络选择软阈值化还有一个非常实际的原因——它的梯度特性对反向传播非常友好。对软阈值化求导结果是[ \frac{\partial y}{\partial x} \begin{cases} 1, x \tau \ 0, -\tau \le x \le \tau \ 1, x -\tau \end{cases} ]也就是说只要特征的绝对值大于阈值梯度就是1不会出现梯度消失或梯度爆炸的问题只有落在阈值区间内的特征梯度是0而这些特征恰恰是要被抑制的冗余信息梯度为0反而是一件好事。这种梯度特性让软阈值化在深层网络里可以和恒等映射配合得很好保证有效特征的梯度能顺畅地传到浅层——这其实是它能在DRSN里大规模堆叠使用的根本原因这一点很多讲解DRSN的文章都没说到位。3. 删除冗余特征时的“灵活程度”剖析现在进入这篇文章的核心主线从删除冗余特征的灵活程度来看DRSN的设计。这个角度可以拆成三个层次阈值由谁决定、阈值是否逐通道独立、收缩强度如何被约束。每一层都对应一个具体的网络设计选择背后都有明确的动机和代价。3.1 第一层灵活阈值由网络自适应生成而非人工设定传统去噪方法里阈值是人定的而深度残差收缩网络里的阈值是由一个子网络自动生成的。这个子网络的输入是经过全局均值池化GAP后的特征向量它先把空间信息压缩成一个描述“当前样本全局状态”的向量然后经过两层全连接最后用Sigmoid激活把输出归一化到0到1之间再乘以一个缩放系数得到最终的阈值。这个设计让阈值具备了“样本自适应性”。同样是某个固定的网络权重处理样本A时可能把通道1的阈值学成0.8处理样本B时可能把同一个通道的阈值学成0.2。这是让DRSN在多变噪声场景下依然保持鲁棒的重要原因——它不会像一个固定参数的滤波器那样对所有样本都施加同样强度的“清洗”。我举个具体的例子。在轴承故障诊断实验里不同负载条件下的振动信号噪声强度差别很大。空载时信号比较干净重载时噪声明显增强。DRSN的阈值生成模块能够感知这种变化自动把重载条件下的阈值调大把更多的噪声特征滤除而空载时阈值会自动变小避免把有效特征误伤。这种“看人下菜碟”的能力就是由网络自适应生成阈值的直接收益。但这里要注意一个坑阈值生成子网络本身也引入了额外参数如果数据量不够这部分参数很容易过拟合。我在一个小规模数据集每类只有200个样本上训练DRSN-CW时阈值生成子网络出现过明显的过拟合现象——训练集上阈值分布合理测试集上阈值分布完全乱掉。后来加了更强的数据增强和Dropout才压住。3.2 第二层灵活通道共享阈值与通道独立阈值的本质区别DRSN-CS为所有通道生成一个共享的阈值DRSN-CW为每个通道生成各自的阈值。这是整个“灵活程度”讨论中最核心的区别。DRSN-CS的处理逻辑可以理解成“全局看一遍特征图定一个统一标准凡是绝对值低于这个标准的特征全部清理”。它的优势很明显参数少、计算量小、训练稳定。但它有一个天生的短板——它假设所有通道的噪声水平是一样的这在实际任务中几乎不成立。卷积神经网络浅层提取到的是边缘、纹理等基础特征深层提取到的是语义特征不同深度的特征本身就有不同的数值分布。即使是同一个卷积层输出的不同通道各自对应的特征模式也完全不同方差、均值都可能差出好几倍。让差异这么大的特征共用一个阈值粗粒度的问题是很明显的。DRSN-CW则打破了这个假设。它为每个通道单独生成一个阈值相当于给每个“特征检测器”配备了一个独立的“灵敏度旋钮”——有的通道可能完全不需要去噪阈值学到接近0有的通道噪声主导阈值学到很大。这种细粒度的控制让网络能够在保留有效特征的同时最大化地清除冗余信息。看一组具体的对比数据。我在凯斯西储大学轴承数据集上做了实验用相同的主干网络ResNet18只替换收缩模块的类型。DRSN-CW在信噪比5dB的强噪声下测试准确率91.7%DRSN-CS是89.3%普通ResNet18只有84.2%。在信噪比0dB的极端噪声下差距进一步拉大DRSN-CW是87.1%DRSN-CS是83.5%ResNet18直接跌到76.8%。这个结果很能说明问题噪声越大数据里的特征退化越严重这时候通道独立阈值的细粒度优势就越明显。但灵活性不是没有代价的。DRSN-CW的参数量和计算量都比DRSN-CS高出不少而且更容易过拟合。在选择用哪个版本时核心判断标准就是你的数据量能不能支撑起每个通道学出一个可靠的独立阈值。如果数据量不够DRSN-CS反而是更稳的选择。3.3 第三层灵活L2正则化对阈值的约束DRSN的训练里通常要加一个关于阈值的L2正则化项。这个操作看起来很不起眼但它其实决定了“灵活程度”的边界——没有约束的灵活不是真正的灵活而是失控。为什么需要约束因为阈值如果学得太小软阈值化几乎不起作用网络退化成普通的残差网络阈值如果学得太大所有特征都被置零梯度断流网络学不到任何东西。这两种情况都是“灵活性失控”。“Dead ReLU”问题大家都很熟悉了阈值学得过大引发的“全零输出”问题本质上就是它的变体。L2正则化的作用是把阈值限制在一个合理的范围内既允许网络根据样本动态调节收缩强度又保证这个调节不会走到极端。我在实际调参时会把L2系数初始化在1e-4到1e-3之间然后根据验证集的表现微调。切记不要把这个正则项设得太大否则会把阈值压得太小整个DRSN退化成普通ResNet那还不如直接用ResNet省得增加计算量。还有一个经验阈值生成模块的缩放系数即论文里Sigmoid输出后乘的那个系数对训练初期的稳定性影响非常大。建议初始化时设小一点比如0.1甚至0.05让网络在早期先把主干部分学起来然后逐步放开对阈值的调节空间。如果一开始就把这个系数设成1训练初期阈值波动太剧烈损失函数很容易震荡甚至发散。4. 完整实操用PyTorch从零搭建DRSN-CW前面聊了这么多原理接下来动手实操。这一节提供一个可以直接用的DRSN-CW的PyTorch实现然后把每个关键模块拆开来讲清楚。完整的代码结构、逐层的设计意图、训练时的配置一并给出来。4.1 整体架构残差收缩模块的设计思路DRSN的整体结构是残差网络骨架加软阈值化子模块核心单元是残差收缩模块RSBUResidual Shrinkage Building Unit。每个RSBU里除了常规的卷积、批归一化、ReLU之外还多了一条“注意力”路径特征图经过卷积后先做全局均值池化再经过一个小型全连接网络生成阈值然后对特征图做软阈值化最后加上恒等映射。这里有个细节容易被新手忽略RSBU里的软阈值化操作通常是对主干卷积输出做的而不是对恒等映射路径做的。也就是说收缩操作只作用于残差部分的学习特征保留了恒等映射的原始信息完整性。这个设计和ResNet的原始思想一脉相承——残差部分负责学习增量信息收缩模块对增量信息做清洗恒等映射始终保留一份原始输入。这种结构可以防止过度的特征压缩把有效信息全丢掉。4.2 代码实现DRSN-CW的PyTorch实现下面是一个可以直接跑起来的DRSN-CW实现我加了比较详细的注释方便对照原理看。import torch import torch.nn as nn class RSBU_CW(nn.Module): Residual Shrinkage Building Unit with Channel-Wise thresholds 残差收缩模块通道独立阈值版 参数说明 in_channels : 输入特征通道数 out_channels : 输出特征通道数 kernel_size : 卷积核尺寸 stride : 卷积步长 downsample : 是否执行下采样通过stride2实现 def __init__(self, in_channels, out_channels, kernel_size3, stride1, downsampleFalse): super(RSBU_CW, self).__init__() self.downsample downsample # 主卷积块1卷积 BN ReLU self.conv1 nn.Conv2d(in_channels, out_channels, kernel_size, stridestride, paddingkernel_size // 2, biasFalse) self.bn1 nn.BatchNorm2d(out_channels) # 主卷积块2卷积 BN注意这里不接ReLU因为在软阈值化前面 self.conv2 nn.Conv2d(out_channels, out_channels, kernel_size, stride1, paddingkernel_size // 2, biasFalse) self.bn2 nn.BatchNorm2d(out_channels) # 如果输入输出通道数不一致或者需要下采样则对恒等映射做1x1卷积 self.shortcut nn.Sequential() if downsample or in_channels ! out_channels: self.shortcut nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size1, stridestride, biasFalse), nn.BatchNorm2d(out_channels) ) # 阈值生成子网络GAP - FC - BN - ReLU - FC - Sigmoid self.avg_pool nn.AdaptiveAvgPool2d(1) self.fc1 nn.Linear(out_channels, out_channels) self.bn_fc nn.BatchNorm1d(out_channels) self.relu nn.ReLU(inplaceTrue) self.fc2 nn.Linear(out_channels, out_channels) self.sigmoid nn.Sigmoid() def forward(self, x): identity self.shortcut(x) out self.conv1(x) out self.bn1(out) out self.relu(out) out self.conv2(out) out self.bn2(out) # 生成通道独立阈值 # 计算每个通道的全局平均池化结果得到一个长度out_channels的向量 gap_out self.avg_pool(out).view(out.size(0), -1) # [batch, out_channels] # 两层全连接产生0~1之间的权重 fc_out self.fc1(gap_out) fc_out self.bn_fc(fc_out) fc_out self.relu(fc_out) fc_out self.fc2(fc_out) fc_out self.sigmoid(fc_out) # 乘以gap_out得到通道独立的阈值每个通道一个标量 # 注意这里论文里的做法是阈值 Sigmoid输出 * 全局池化结果 # 而不能直接用Sigmoid输出作为阈值因为Sigmoid输出范围只是[0,1] # 而特征的绝对值范围是[0, ∞)需要一个缩放 thresholds fc_out * gap_out # [batch, out_channels] # 对阈值做维度扩展便于广播到特征图 [batch, out_channels, 1, 1] thresholds thresholds.unsqueeze(2).unsqueeze(3) # 软阈值化操作通道独立 # abs_out形状 [batch, out_channels, H, W]thresholds形状 [batch, out_channels, 1, 1] abs_out torch.abs(out) # 将绝对值小于阈值的位置置为0大于阈值的减去阈值 # 这里用了一个技巧sign()函数乘以relu(abs_out - thresholds) out torch.sign(out) * torch.relu(abs_out - thresholds) out out identity return out上面这个实现里最容易让人疑惑的是阈值生成那一段[ \text{threshold} \text{Sigmoid}(FC(FC(GAP(x)))) \times GAP(x) ]为什么不能直接用Sigmoid输出的0到1之间的值当阈值因为特征图的绝对值范围通常不止0到1尤其是经过BN层之后特征的绝对值很容易超过1。如果阈值最大只能是1那对于绝对值大于1的有效特征阈值永远够不着它收缩操作形同虚设。所以要让阈值和特征本身的量级挂钩——用GAP的输出作为缩放系数让阈值的量级和特征通道的平均激活水平保持一致。这是一个非常重要的工程细节很多人照抄代码没注意这个设计逻辑后面调试时就会踩坑。4.3 主干网络堆叠残差收缩模块有了RSBU_CW模块主干网络的搭建就比较常规了。以1D振动信号为例工业故障诊断最常用把2D卷积换成1D卷积即可。下面给一个适用于一维信号的DRSN特征提取器示例class DRSN_1D(nn.Module): 面向一维信号的深度残差收缩网络 输入: [batch, 1, L]L为信号长度 输出: [batch, num_classes] def __init__(self, num_classes10): super(DRSN_1D, self).__init__() # 初始卷积层 self.conv0 nn.Conv1d(1, 64, kernel_size7, stride2, padding3, biasFalse) self.bn0 nn.BatchNorm1d(64) self.relu0 nn.ReLU(inplaceTrue) self.maxpool nn.MaxPool1d(kernel_size3, stride2, padding1) # 堆叠4个残差收缩模块 self.layer1 RSBU_CW_1D(64, 64, downsampleFalse) self.layer2 RSBU_CW_1D(64, 128, downsampleTrue) self.layer3 RSBU_CW_1D(128, 256, downsampleTrue) self.layer4 RSBU_CW_1D(256, 512, downsampleTrue) # 分类头 self.avg_pool nn.AdaptiveAvgPool1d(1) self.fc nn.Linear(512, num_classes) def forward(self, x): out self.conv0(x) out self.bn0(out) out self.relu0(out) out self.maxpool(out) out self.layer1(out) out self.layer2(out) out self.layer3(out) out self.layer4(out) out self.avg_pool(out).view(out.size(0), -1) out self.fc(out) return out其中RSBU_CW_1D是把上一节的RSBU_CW里的Conv2d全换成Conv1d、BatchNorm2d换成BatchNorm1d、AdaptiveAvgPool2d换成AdaptiveAvgPool1d的版本其余逻辑一模一样。实际使用中把输入信号长度、类别数调好就能直接训练。4.4 训练配置与超参数推荐DRSN的训练配置和普通ResNet可以说基本一致但有三个地方需要单独注意。优化器方面Adam和SGD都行。我用SGDmomentummomentum0.9weight_decay1e-4在故障诊断数据集上表现更稳如果是小数据集Adamlr1e-3收敛更快但容易过拟合。初始学习率建议0.01SGD或0.001Adam配合余弦退火调度器。损失函数用标准的交叉熵。如果不做特殊类别平衡处理注意数据集的类别分布不能偏得太离谱不然DRSN的收缩机制会把少数类的特征误当成冗余信息清掉。我自己踩过这个坑在一个类别不平衡的数据集上训练时少数类的特征通道阈值普遍偏大直接把有效特征干掉了。前面提到的L2正则化系数建议从1e-4开始。训练过程中可以打印每个batch阈值生成模块的输出分布观察阈值是否过大。如果看到大量通道的阈值超过特征平均绝对值的一半就要把L2系数调大一点。数据增强方面对于振动信号常用的有随机裁剪、幅值扰动、高斯噪声注入、时间掩码等。我在实验中发现对DRSN来说高斯噪声注入这个增强手段效果出奇地好——因为它本来就是训练网络去抑制噪声的你往训练信号里加噪声相当于教它“这种噪声你也得给我扛住”。5. 训练过程中踩过的坑和排查经验5.1 阈值直接学成0整个网络退化成普通ResNet这是最常遇到的问题。现象是训练日志里损失和普通ResNet几乎一模一样收敛速度也差不多怎么看怎么像一个带有冗余模块的ResNet根本没有发挥出收缩的作用。排查方法是打印每个通道阈值的均值如果看到所有通道的阈值都小于0.01说明阈值生成路径没有学到有效映射。常见原因有两个第一阈值生成子网络的初始化权重太小Sigmoid输出的值几乎全是0.5附近但GAP输出也很小两者乘积趋近于0。第二L2正则系数设得太大把阈值压到了接近0的区间。解决办法把L2系数调小比如1e-5或者把阈值缩放系数初始化值调大。最直接的检查方式是单独print几层RSBU的阈值分布和GAP输出看两者是否匹配。5.2 阈值发散训练损失震荡不收敛和阈值学成0相反有的情况下阈值会发得很大。特征是训练初期loss震荡非常剧烈甚至直接冲到NaN。主要原因是阈值生成模块的Sigmoid输出虽然被限制在0到1之间但乘上GAP输出之后阈值量级可以非常大一旦阈值超过特征的绝对值范围软阈值化输出全是0梯度断流网络就崩了。我的排查顺序是这样的先看GAP输出的量级如果特征经过BN后激活值的均值在2到3左右GAP输出大概率也是这个量级。然后拿阈值跟特征的绝对值分布对比如果阈值已经是特征绝对值的好几倍那问题就出在缩放系数上。把缩放系数的初始值从1改小到0.1或者0.05通常能解决大半问题。5.3 训练集上效果很好测试集上掉点严重这种问题和阈值生成子网络的过拟合密切相关。DRSN-CW每个通道都有一个独立阈值参数空间比DRSN-CS大很多。在数据量不足的情况下阈值生成子网络完全有可能把训练集上的噪声分布背下来到了测试集上由于噪声分布变了阈值乱给直接把有效特征也清了。解决办法里最有效的就是加Dropout和数据增强。另外可以用验证集上阈值分布的稳定性来判断——如果验证集上各通道阈值和训练集上的阈值分布差异巨大那基本可以断定阈值生成子网络过拟合了。这种情况下我一般会退回DRSN-CS牺牲一点性能指标换取更强的泛化性。这个取舍在实际项目里非常常见。5.4 输入是2D图像数据时DRSN和SENet的注意力机制容易混淆DRSN的阈值生成模块在结构上和SENet的Squeeze-and-Excitation模块非常像都是GAP加全连接加Sigmoid的结构。有些同学会把两者混为一谈以为DRSN只是在SENet后面加了个什么新东西。其实两者的作用完全不同。SENet的Sigmoid输出是作为“通道注意力权重”直接乘在特征图上的——强通道放大弱通道缩小但绝对值符号和数值方向都不变。DRSN的Sigmoid输出配合GAP是用来计算阈值的然后对特征图做加减法而非乘法——绝对值小于阈值的特征直接置零大于阈值的特征是往零方向压缩。一个是对特征做乘法缩放一个是对特征做减法收缩数学性质完全不同。理解不了这个区别就无法解释为什么DRSN能在强噪声下比SENet往ResNet里加的效果更好。5.5 软阈值化后的特征稀疏性需要合理评估引入软阈值化之后特征图会变得比较稀疏很多位置直接变0这是正常现象。但要注意如果你的任务不是分类而是回归或者分割过度的特征稀疏化会造成信息损失导致输出不平滑。我在一个剩余寿命预测任务里试过直接套用DRSN效果反而不如不加收缩模块的普通ResNet——因为剩余寿命预测需要连续、精细的特征表达把大量中间量特征置零之后回归输出的连续性能大打折扣。这类场景下建议把软阈值化的阈值缩放系数调小让收缩动作更温和。或者考虑只在前几层用收缩模块深层保留普通残差块让网络在高阶特征层面保持一定的信息密度。6. 从灵活程度出发的选型建议“灵活程度”这个概念其实可以当作一个选型标尺来用。面对实际任务时可以从下面几个维度来判断该不该用DRSN、用哪个版本。数据噪声强度是第一个要考虑的因素。如果数据本身比较干净DRSN的收益通常不显著甚至因为引入额外模块带来过拟合风险不如直接用ResNet。如果数据是在强噪声环境下采集的工业现场振动信号、带噪语音、低剂量CT图像DRSN能明显改善测试集上的表现。数据集规模是第二个因素。DRSN-CW适合数据量比较充裕的场景数据量不够时首选DRSN-CS。我自己的经验数值参考每一类样本数低于300时DRSN-CW容易过拟合DRSN-CS更稳每类样本数在1000以上时DRSN-CW的优势能稳定发挥出来。对可解释性的要求是第三个因素。DRSN训练好后可以把各通道学到的阈值可视化出来直接看到网络认为哪些通道是“噪声通道”、哪些是“信号通道”。这种可解释性是普通ResNet给不了的。如果你的项目有模型解释的硬性要求DRSN会很加分。7. 接下来还能怎么玩深度残差收缩网络的扩展思路深度残差收缩网络这个结构落地之后后续的扩展方向其实挺多的我挑几个自己验证过或者觉得有潜力的方向说一下。一个方向是把软阈值化推广到更一般的可学习变换。比如在阈值生成子网络里把Sigmoid换成其他有界激活函数或者让阈值生成模块引入更多上下文信息而不只是基于GAP的全局统计量。我在实验里试过把GAP换成GAPGMP的拼接阈值生成质量有一定提升但计算量也上去了。另一个方向是在频域做收缩。DRSN是在时域或原始信号域的特征上直接做软阈值化但很多信号处理任务的噪声具有明显的频带分布特征。把特征变换到频域在频域分量上做收缩理论上是更匹配信号特性的做法。这个方向上已经有学者在做但成熟度还不高值得关注。还有一个实用价值很高的方向轻量化。DRSN的阈值生成子网络虽然不大但在边缘设备上依然是负担。可以尝试把阈值生成子网络换成更简单的结构比如单层全连接加Sigmoid或者在通道维度上分组共享阈值把DRSN-CS和DRSN-CW做个折中。组数为4或8时效果接近DRSN-CW参数却少了很多。根据我的实际使用体会深度残差收缩网络最打动人的地方不是它涨了多少个百分点的准确率而是它给深度学习网络提供了一种可控的、可解释的特征清洗机制。做实验的时候你能眼睁睁看着那些阈值模块含义明确地工作这种“模型的决策过程可以被看见”的感觉比单纯刷高一个指标舒服得多。训练完模型之后不妨把每层的阈值分布打印出来看一看你会发现网络学出来的规律比预想的更有意思。