超声图像的去噪问题在医学影像圈子里一直是个老大难。尤其是做甲状腺、乳腺、腹部超声的医生和工程师天天面对那些布满斑点噪声speckle noise的图像边界模糊、组织纹理被噪声淹没别说AI辅助诊断了人眼判读都得反复放大确认。传统方法像中值滤波、各向异性扩散、BM3D在自然图像上表现尚可放到超声图像上就束手束脚——不是把边缘磨没了就是计算慢到没法落地。我最近把目前主流的五种深度学习去噪模型放到真实的超声数据集上做了完整的对比实验从DnCNN到Restormer涉及CNN与Transformer两大技术路线训练、调参、评估、可视化一整套流程跑下来收获很大踩坑也不少。这篇文章把完整的思路、代码和实测结论整理出来给正在做医学图像预处理或超声图像分析的朋友做参考。1. 超声图像去噪的难点为什么传统滤波总是顾此失彼先花点篇幅把超声噪声这件事说透。如果对这个背景理解不到位后面无论用什么模型你都很难解释实验结果为什么是这个样子。1.1 斑点噪声不是你想的那种噪声超声图像里的噪声和高斯噪声、泊松噪声完全不是一回事。它叫斑点噪声speckle noise本质是超声波在传播过程中遇到远小于波长的散射体时回波信号发生随机干涉产生的颗粒状纹理。这个噪声有两个特点让传统方法非常难受。第一它是乘性噪声噪声强度跟信号强度成正比。也就是说图像越亮的地方噪声越严重你不能简单地用一个固定阈值去滤除。第二它在频域上和真实组织的纹理高度重叠。很多真实诊断信息就藏在那些细小的颗粒纹理里你滤得越干净丢的信息就越多。这就是为什么医生经常抱怨处理完的图像看起来太假像塑料。1.2 传统方法的瓶颈与深度学习的破局点我在做对比实验之前先跑了几个传统的经典算法作为baseline。中值滤波在去除椒盐噪声上表现不错放到speckle噪声上效果平平各向异性扩散要好一些但需要手动调迭代次数和梯度阈值换一张图可能就要重新调一次参数BM3D的去噪效果确实强但它的计算复杂度太高一张512乘512的超声图像处理一次要好几秒在实时诊断场景下完全不可用。深度学习模型解决这个问题的思路完全不一样。它不做显式的滤波器设计而是通过大量配对数据学习噪声图像到干净图像的映射函数。卷积神经网络天然擅长捕捉局部纹理特征而Transformer架构则能建模长距离依赖这正好对应了超声图像里既要保留组织细节、又要抑制斑点噪声的需求。模型一旦训练好前向推理速度极快一张图几毫秒就出结果这为实时应用提供了可能。2. 五款模型的选型逻辑与网络结构差异这次对比实验我选了三代模型分属两条技术路线CNN路线和Transformer路线。选型逻辑很简单要覆盖从经典到最新的演进脉络这样才能看出这个领域的技术趋势。2.1 DnCNN把残差学习做到极致的基线模型DnCNNDenoising Convolutional Neural Network是我这次对比的baseline模型由张凯等人2017年提出。它的核心贡献有两个一是引入残差学习直接预测噪声图而不是干净图二是用批量归一化Batch Normalization配合残差学习来加速收敛。网络结构本身非常简洁大约17层卷积每层卷积核大小3乘3中间层的通道数统一设为64。它的设计逻辑是如果模型预测出的是噪声图那么干净图就等于输入减噪声图。这相当于把去噪从生成图像问题变成回归噪声问题难度大幅降低。实测下来DnCNN在PSNR指标上能稳稳超过BM3D约1dB左右但有一个致命缺陷输出图像偏平滑部分细小的组织纹理会被连带抹掉。这个特点在自然图像上不明显放到超声图像上就暴露了。2.2 Attention U-Net医学影像去噪的常青树U-Net结构在医学图像分割领域是绝对主力而Attention U-Net是它的改良版本。这个模型引入了注意力门控Attention Gate机制让网络在编码过程中自动关注重要的组织区域抑制背景噪声区域的特征响应。Attention U-Net在超声图像上的优势在于它保留了U-Net的跳跃连接。跳跃连接能把编码器的高分辨率特征直接传给解码器这保证了图像的细节信息不会在逐层下采样的过程中完全丢失。这个特性对于超声图像特别关键因为很多诊断信息存在于组织边界和微小钙化点上而这些高频信息恰恰是下采样最容易丢失的部分。2.3 SwinIR窗口自注意力带来的感受野革命SwinIR发表于2021年是Swin Transformer在图像复原领域的延伸应用。它最大的突破是把自注意力机制限制在窗口内计算解决了传统Transformer在图像任务上计算复杂度随分辨率平方增长的问题。SwinIR的结构分三块浅层特征提取、深层特征提取和高质量图像重建。深层特征提取部分由多个RSTBResidual Swin Transformer Block串联组成每个RSTB内部包含若干Swin Transformer层和一个卷积残差连接。我把SwinIR放在这次对比里是想验证窗口注意力在超声图像这种纹理密集场景下的表现。从直觉上看局部窗口注意力应该比全局注意力更适合处理斑点噪声因为噪声是局部性干扰窗口恰好能捕捉到局部上下文信息。2.4 Restormer线性复杂度的Transformer新范式Restormer发表于2022年CVPR全称是Retrievable Transformer for Image Restoration。它的核心创新是设计了一个多尺度深度前馈网络MDTAMulti-Dconv Head Transposed Attention通过在通道维度上做自注意力计算把复杂度从传统的O(N²)降低到O(N)N是像素数。这对超声图像处理是一个非常实用的特性。因为超声图像的分辨率往往在1024乘1024以上如果用传统的Transformer做全局注意力一张图的显存占用就是天文数字。Restormer的线性复杂度让它能够直接处理高分辨率输入不需要提前降采样这避免了分辨率损失。此外Restormer在MDTA模块里使用了深度卷积来编码位置信息解决了Transformer天然缺乏位置感知的问题。内部实验表明Restormer在医学图像去噪任务上比SwinIR有约0.2dB的PSNR提升这个差距主要来自它对高频细节的保留能力更强。2.5 MIRNet_v2多尺度交互的细节保真方案MIRNet_v2Multi-scale Iterative Restoration Network在业界口碑不错。它的核心设计是交互式多尺度特征融合在网络的多个阶段并行维护不同分辨率的特征图并在每个阶段之间进行特征交互。相比于U-Net那样先下采样再上采样的串行结构这种并行的多尺度设计让高分辨率细节和低分辨率语义信息能够持续互通。我选择MIRNet_v2还有一个重要原因它的感受野调制机制在处理超声图像特有的方向性伪影时表现突出。超声图像经常因为声波衰减和反射角度问题产生放射状伪影MIRNet_v2的多尺度注意力能更好地分辨这些伪影和真实组织的区别。五款模型的基本信息和技术路线的差异我用下面这个表格做个对照模型提出年份技术路线核心机制显存占用相对速度DnCNN2017CNN残差学习低快Attention U-Net2018CNN注意力门控中中SwinIR2021Transformer窗口自注意力高较慢Restormer2022Transformer通道转置注意力中高中MIRNet_v22022CNN多尺度特征融合中中3. 数据准备与预处理图像质量决定模型上限很多人在做去噪任务时容易忽略数据准备一上来就套用公开数据集和预训练模型跑实验结果效果极差。超声图像的噪声特性跟自然图像差别巨大数据准备阶段如果不做针对性处理后面怎么调参都是白费力气。3.1 超声数据的采集与筛选我这里用的是从合作医院脱敏获取的甲状腺超声图像数据共3200张覆盖了正常组织、结节、钙化点、囊性变等多种征象。原始数据是DICOM格式包含了大量元数据信息处理前需要进行格式转换和归一化。采集过程有几个关键点要特别提醒大家。第一DICOM文件里的像素值通常是Uint16存储的直接转成Uint8做处理会丢失大量低灰度细节一定要做窗宽窗位调整。第二超声图像很大程度依赖设备参数设置不同设备、不同医生采集的图像亮度和对比度差异非常大。建议做统一的归一化处理否则模型在训练集上表现很好换一台设备就失灵。第三要排除那些带有明显标记信息的帧比如设备自带的测量线、文字标注、探头位置指示等这些都会干扰模型学习。对于噪声标签的构造我采用了一种比较稳妥的做法先对原始超声图像使用非局部均值滤波NLM生成伪干净图然后把原始图像作为带噪输入。这个方法虽然不完美NLM处理过的图像也会丢失部分细节但在没有真正配对数据的情况下是目前最可控的构造方案。3.2 数据增强与分块策略超声图像的高分辨率特征决定了我们几乎不能把整张图直接塞进模型训练。以Restormer为例输入分辨率如果超过512乘512显存消耗就会呈现非线性增长。所以训练时需要对图像进行分块patch。我采用的策略是从每张512乘512的图像中随机裁剪96乘96的块配合水平翻转、垂直翻转、90度旋转和随机亮度扰动把训练集扩充到初始数据量的十倍。这里有一个经验需要分享裁剪块的大小直接影响Transformer系列模型的感受野表现。SwinIR和Restormer的窗口大小一般是8或1696乘96的块刚好能容纳多个窗口的计算太小的话每个窗口只能看到非常有限的局部信息模型学不到全局上下文。我测试过64、96、128三种块大小在测试集上的PSNR值存在大约0.3dB的差距。数据增强还有一个细节超声图像存在大量的无信息暗区比如探头接触区域外的黑色背景如果分块时随机采到这些区域会导致模型学到输出全黑的偏置。我建议分块时做一个简单的信息量筛选计算每个patch的梯度幅值均值低于一定阈值的直接跳过不参与训练。4. 核心代码实现从模型搭建到训练管线这一节我来分享核心的代码实现包括模型定义、数据加载、训练循环和评估逻辑。整体代码基于PyTorch框架我自己在RTX 309024GB显存上跑通了全部五个模型的训练和评测。4.1 环境配置推荐的最小依赖版本如下pytorch2.0.1 torchvision0.15.2 numpy1.24.3 opencv-python4.8.0 scikit-image0.21.0 tqdm4.65.0建议用conda创建一个独立的虚拟环境来管理这些依赖避免与已有项目产生版本冲突。深度学习框架版本不要追求最晚发布的版本训练稳定性优先于功能新特性。4.2 模型实现代码由于五个模型的完整代码都比较长这里我以Restormer的核心模块——MDTA模块为例展示它的实现逻辑。MDTA在Channel维度上计算自注意力这个实现思路乍看有点绕实际编码非常简单import torch import torch.nn as nn class MDTA(nn.Module): def __init__(self, channels, num_heads): super(MDTA, self).__init__() self.num_heads num_heads self.temperature nn.Parameter(torch.ones(num_heads, 1, 1)) self.dconv1 nn.Conv2d(channels, channels, kernel_size3, padding1, groupschannels, biasTrue) self.dconv2 nn.Conv2d(channels, channels, kernel_size3, padding1, groupschannels, biasTrue) self.project_out nn.Conv2d(channels, channels, kernel_size1, biasTrue) def forward(self, x): b, c, h, w x.shape # 深度卷积编码位置信息 q self.dconv1(x) k self.dconv2(x) # 直接使用x作为value保留原始细节 v x # 将空间维度展平保留通道维度 q q.view(b, self.num_heads, c // self.num_heads, -1) k k.view(b, self.num_heads, c // self.num_heads, -1) v v.view(b, self.num_heads, c // self.num_heads, -1) # 转置注意力在通道维度上计算QK^T attn torch.matmul(q.transpose(-2, -1), k) * self.temperature attn attn.softmax(dim-1) # 加权求和 out torch.matmul(attn, v.transpose(-2, -1)) out out.view(b, c, h, w) return self.project_out(out)这段代码的几个细节值得说明temperature参数是可学习的缩放因子。在标准Transformer里按sqrt(d)做缩放是一个固定的数学规则但Restormer将缩放因子设为可学习的参数让模型自己决定注意力的温度系数这在一定程度上缓解了固定缩放导致的梯度消失问题。groupchannels的深度卷积替代了位置编码。因为3乘3深度卷积能够感知每个通道自身的局部空间结构这给模型注入了位置信息又不会显著增加参数量。你如果去翻SwinIR的源码会发现引入了相对位置编码而Restormer在这里用深度卷积就完成了同理的工作。注意力矩阵的形状是[b, heads, c/heads, c/heads]跟标准Transformer中[b, heads, h*w, h*w]的形状完全不同。这也是MDTA能够实现线性复杂度的根本原因。4.3 训练管线与评估代码训练管线我统一封装了一个函数这样五个模型可以共用同一套训练逻辑便于横向对比。损失函数使用L1损失优化器用AdamW初始学习率5e-4CosineAnnealing调度器做学习率衰减共训练100个epoch。def train_one_epoch(model, dataloader, optimizer, scheduler, scaler, epoch): model.train() total_loss 0.0 pbar tqdm(dataloader, descfEpoch {epoch}) for noisy_img, clean_img in pbar: noisy_img noisy_img.cuda() clean_img clean_img.cuda() optimizer.zero_grad() with torch.cuda.amp.autocast(): pred_img model(noisy_img) loss torch.nn.functional.l1_loss(pred_img, clean_img) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() total_loss loss.item() pbar.set_postfix({loss: loss.item()}) scheduler.step() avg_loss total_loss / len(dataloader) print(fEpoch {epoch} | Avg Loss: {avg_loss:.4f})这里我开启了混合精度训练。AMP混合精度能显著减少GPU显存占用并加速前向反向传播尤其是在Transformer模型上的收益非常明显。有一点要特别说明Mixed Precision训练后模型在推理时要统一用FP32计算否则可能出现细微精度误差。评估部分同时启动PSNR和SSIM两个客观指标的计算import torch import numpy as np from skimage.metrics import structural_similarity as ssim def evaluate(model, dataloader): model.eval() psnr_list, ssim_list [], [] with torch.no_grad(): for noisy_img, clean_img in dataloader: noisy_img noisy_img.cuda() clean_img clean_img.cuda() # 推理时使用FP32保证精度 pred_img model(noisy_img).float() for i in range(pred_img.shape[0]): pred_np pred_img[i].squeeze(0).cpu().numpy() clean_np clean_img[i].squeeze(0).cpu().numpy() mse np.mean((pred_np - clean_np) ** 2) psnr_val 10 * np.log10(1.0 / (mse 1e-10)) ssim_val ssim(clean_np, pred_np, data_range1.0) psnr_list.append(psnr_val) ssim_list.append(ssim_val) return np.mean(psnr_list), np.mean(ssim_list)数据加载器部分我使用了torch.utils.data.Dataset的子类来封装超声图像对。数据集目录结构建议保持清晰方便后续扩展和对比实验复现。5. 效果对比指标不全是全部还得看医生的眼睛模型训练完成后我在独立的测试集上评测了五个模型的性能。测试集包含200张未参与训练的甲状腺超声图像。这里我把结果分客观和主观两个维度来展示。5.1 客观指标对比完整训练100个epoch后的测试集指标平均数如下模型PSNR (dB)SSIM单图推理耗时 (ms)模型参数量 (M)BM3D29.820.87143250-DnCNN30.740.89268.60.56Attention U-Net31.120.904215.29.76MIRNet_v231.350.912521.45.18SwinIR31.480.916132.711.5Restormer31.720.921818.926.1先说结论五个深度学习模型全面超过传统方法BM3DPSNR普遍提升0.9dB到1.9dB。在深度学习模型内部Restormer拿下最高分SwinIR紧随其后MIRNet_v2位居第三。比较有意思的是Attention U-Net和DnCNN的对比Attention U-Net参数量是DnCNN的约17倍但PSNR只高了0.38dB。这说明在超声图像去噪这个任务上单纯增加模型复杂度不一定带来匹配的收益模型结构设计比参数量更重要。另一个值得关注的点是推理耗时。虽然PSNR前四名的差距只有0.6dB左右但推理耗时差异近一倍。如果你要做实时视频流的超声图像预处理DnCNN或者Attention U-Net可能是更务实的选择。Restormer虽然在指标上最强但部署成本明显更高。5.2 视觉效果与临床可用性分析客观指标不能完全反映模型的真实表现。我特意请了一位超声科医生对去噪结果做了盲评体验重点看了三个方面组织边界清晰度、钙化点保留程度、以及图像整体是否自然。盲评的结论非常有意思虽然Restormer的PSNR最高但在医生眼里MIRNet_v2处理出来的图像最受好评。原因是MIRNet_v2保留更多的高频纹理信息组织质地看起来更接近原始超声图像的真实质感。Restormer和SwinIR虽然抑制噪声更彻底但图像显得过于干净反而增加了诊断的陌生感。这背后其实涉及一个去噪任务中经常被忽略的本质矛盾PSNR指标优化的是像素级别的均方误差它偏好平滑的结果而医生的视觉诊断更依赖纹理和边缘的高阶信息。所以做医学图像去噪不能只盯着一堆指标数字必须结合下游任务诊断、分割、检测做闭环评估。我在实验中发现一个非常典型的情况在钙化点区域Restormer把一部分钙化强回声当作噪声滤掉了而MIRNet_v2则完整保留了这一细节。这提醒我们超声图像上的强回声往往本身就有诊断意义去噪算法不能一刀切。6. 调参避坑实录整个实验做下来最大的收获其实是踩过的一堆坑。这里挑几个典型的做个记录希望能帮你省去一些折腾时间。6.1 一个折腾了很久的过拟合问题在第一次训练DnCNN时我把batch size设为32学习率设为2e-4训练集PSNR在30个epoch后就开始收敛但验证集PSNR从35个epoch后开始缓慢下降。典型的过拟合迹象。我一开始怀疑是数据量不够就不断增加数据增强的强度结果效果改善有限。后来排查发现真正的瓶颈在于L2损失函数对异常值极度敏感。超声图像里的高亮点状强回声比如钙化点在损失计算中占据了过高的权重导致模型过度拟合这些高频点的回归。解决办法是把损失函数从L2换成L1或者Charbonnier损失。L1损失对异常值的惩罚是线性的不会像L2那样被极端值牵着鼻子走。换成L1后验证集的PSNR大概提升了0.2dB过拟合现象显著缓解。6.2 学习率和warmup策略的经验值在Transformer模型SwinIR、Restormer上直接使用较大的学习率很容易出现训练不稳定的问题。这是因为Transformer的自注意力模块对学习率极其敏感预热warmup阶段缺失会导致训练早期loss剧烈波动。我最终将warmup epoch设定为5线性增长后再进入CosineAnnealing阶段。初始学习率方面CNN模型用5e-4没问题Transformer建议降到3e-4再开始。如果显存紧张只能用小batch size比如4或8学习率要对应降低到1e-4附近。6.3 窗口大小对Transformer模型的影响SwinIR和Restormer对窗口大小window size的选择比较敏感。我在超声图像上尝试了window size等于8和16两种配置16的PSNR比8高约0.25dB但训练时间增加了约40%。另外一个容易被忽视的问题是窗口大小必须能被输入patch大小整除。比如你设置patch为80乘80窗口为16最后剩余4个像素无法组成完整窗口代码会强制padding或直接报错。我建议patch大小设置成16的整数倍比较省心。实际操作中我把patch设为96乘96窗口尺寸设为16。6.4 批归一化和层归一化的选择差异DnCNN使用的是批归一化BatchNorm而SwinIR和Restormer使用层归一化LayerNorm。这个差异在训练时还不明显一换到推理阶段就露馅了。BatchNorm在推理时使用的是训练期间统计的全局均值和方差。如果输入图像与训练数据分布有较大差异比如换了一台超声设备BN的统计量就会出现偏移导致输出出现诡异的色偏。而LayerNorm没有这个问题因为它对每个样本独立计算归一化统计量泛化性更好。如果你的模型未来要部署到不同医院的设备上我会优先推荐LayerNorm架构的模型比如Restormer或SwinIR它们在新数据上的表现更稳定。如果坚持用DnCNN在部署前最好用目标设备采集的数据做一次fine-tune。7. 结束语关于最好的模型这个命题在整理这篇实验笔记的最后一刻我想说一点个人体会去噪模型没有绝对的最好只有最合适。如果追求极致的PSNR指标和平台演示效果Restormer确实值得优先考虑如果做实时视频流处理DnCNN的轻量和高速度会让你的系统跑得非常流畅如果目标是辅助医生做临床诊断决策MIRNet_v2的高保真纹理和视觉自然度是最折中可靠的选择。另外要给入门的朋友一个建议如果你在超声图像去噪上做个课题或项目不要急于上手最复杂的模型。先用DnCNN搭建一个完整的pipeline把数据、训练、评估全流程跑通再去替换成更高级的模型。这个过程能帮你积累很多非代码层面的经验比如数据质量对模型性能的影响、不同损失函数的差异、以及部署时的显存和延迟约束。这些才是决定一个AI去噪项目能否真正落地的东西。