戰(zhàn):5種深度學(xué)習(xí)模型對(duì)比與落地踩坑指南)
做了這么多年醫(yī)學(xué)影像的算法落地說(shuō)實(shí)話超聲圖像去噪一直是個(gè)讓我又愛(ài)又恨的方向。愛(ài)是因?yàn)樗N近真實(shí)臨床場(chǎng)景信號(hào)弱、噪聲重、細(xì)節(jié)還容易丟每一個(gè)能落地的改進(jìn)都能直接幫助醫(yī)生減少誤判恨則是散斑噪聲這玩意兒和常規(guī)高斯噪聲完全不同很多在自然圖像上表現(xiàn)很好的深度學(xué)習(xí)模型搬到超聲上一跑邊緣糊了、囊腫邊界看不清了、紋理被磨成了“塑料感”指標(biāo)再漂亮也白搭。最近正好集中測(cè)了5種有代表性的深度學(xué)習(xí)模型在超聲圖像上的去噪效果趁著實(shí)測(cè)數(shù)據(jù)還熱乎把整個(gè)思路、代碼和踩過(guò)的坑一起整理出來(lái)。這篇文章適合正在做醫(yī)學(xué)影像預(yù)處理、或者在超聲輔助診斷項(xiàng)目里被噪聲折磨的算法工程師和研究生參考可以幫你少走很多彎路。1. 超聲圖像噪聲從哪里來(lái)為什么去噪不是“濾鏡糊一糊”1.1 散斑噪聲的物理來(lái)源與數(shù)學(xué)模型超聲圖像里的噪聲和手機(jī)照片噪點(diǎn)完全是兩回事。手機(jī)上的噪點(diǎn)大多是傳感器熱噪聲和弱光下的光子噪聲近似高斯分布而超聲圖像中的散斑噪聲是一種乘性噪聲來(lái)源于超聲波在人體組織中傳播時(shí)遇到尺寸遠(yuǎn)小于波長(zhǎng)的散射體大量微弱的散射波相互干涉在接收端形成明暗相間的顆粒狀紋理。這種噪聲不是疊加在信號(hào)上而是與信號(hào)本身相乘y x · n a其中y是觀測(cè)到的超聲回波強(qiáng)度x是理想的組織反射率n是散斑噪聲a是系統(tǒng)熱噪聲等加性噪聲分量。乘性噪聲意味著噪聲強(qiáng)度隨信號(hào)強(qiáng)度變化信號(hào)強(qiáng)的區(qū)域噪聲也強(qiáng)這給去噪模型的設(shè)計(jì)帶來(lái)了質(zhì)的不同。如果你用經(jīng)典的高斯去噪模型比如BM3D或者直接上一個(gè)只針對(duì)加性噪聲的CNN通常會(huì)把組織邊緣的強(qiáng)信號(hào)連同噪聲一起抹掉這就是臨床上最常見(jiàn)的“去噪過(guò)度”問(wèn)題。1.2 噪聲特性對(duì)模型設(shè)計(jì)的約束因?yàn)樯咴肼暿浅诵缘?、且與組織結(jié)構(gòu)密切相關(guān)深度學(xué)習(xí)去噪模型必須滿足幾個(gè)約束。第一模型需要有足夠大的感受野來(lái)區(qū)分“真實(shí)組織紋理”和“散斑偽影”因?yàn)閱渭兛淳植肯袼刂祪烧邘缀鯚o(wú)法區(qū)分必須依賴更大范圍的上下文信息。第二模型要具備跨尺度特征融合能力——超聲圖像中不同尺寸的解剖結(jié)構(gòu)比如血管截面和微鈣化點(diǎn)去噪策略應(yīng)該不同單一尺度的卷積核很難同時(shí)照顧大結(jié)構(gòu)保真和小目標(biāo)保留。第三損失函數(shù)不能只盯著像素級(jí)別的重建誤差否則模型會(huì)傾向于輸出平滑的“平均結(jié)果”導(dǎo)致組織邊界模糊。我在項(xiàng)目里把散斑噪聲在頻域上做過(guò)分析它能量主要集中在高頻段并且與組織紋理頻譜有一定重疊。這也是為什么一些純空域模型容易誤傷紋理——它們?cè)陬l域上沒(méi)有顯式地把“有用高頻”和“噪聲高頻”分開(kāi)的能力。后面要介紹的5種模型其實(shí)就是在回答同一個(gè)問(wèn)題如何在壓制噪聲的同時(shí)最大限度保留組織和器官邊界的診斷信息。2. 參評(píng)模型選型5種深度學(xué)習(xí)去噪模型的定位與取舍這次對(duì)比不是把所有SOTA模型都拉一遍而是圍繞“實(shí)際落地”這個(gè)目標(biāo)選型。我選模型的標(biāo)準(zhǔn)有三條在公開(kāi)超聲數(shù)據(jù)上有較好的遷移表現(xiàn)結(jié)構(gòu)的代表性強(qiáng)覆蓋CNN、編解碼、注意力、Transformer等主流路線能比較方便地在現(xiàn)有PyTorch框架里復(fù)現(xiàn)和調(diào)參?;谶@個(gè)標(biāo)準(zhǔn)最終確定了這5位選手。2.1 DnCNN把殘差學(xué)習(xí)引入圖像去噪的經(jīng)典之作DnCNN是張凱等人2017年提出的模型思路非常直接讓CNN直接預(yù)測(cè)噪聲殘差而不是預(yù)測(cè)去噪后的干凈圖像。輸入一張帶噪圖像y網(wǎng)絡(luò)輸出的是噪聲n的估計(jì)去噪結(jié)果就是y減去n。這樣做的好處是訓(xùn)練目標(biāo)從“生成一張完整圖像”變成“估計(jì)一個(gè)殘差”學(xué)習(xí)難度大幅降低收斂速度也快。DnCNN的結(jié)構(gòu)是“卷積ReLUBatchNorm卷積”的堆疊在自然圖像去噪上表現(xiàn)很強(qiáng)也是很多后續(xù)模型的baseline。在超聲圖像上直接使用DnCNN會(huì)遇到一個(gè)問(wèn)題它默認(rèn)針對(duì)加性高斯噪聲設(shè)計(jì)而散斑噪聲是乘性的。常見(jiàn)的做法是先把超聲圖像做對(duì)數(shù)變換把乘性噪聲變成近似加性噪聲再用DnCNN去噪最后做指數(shù)變換還原。這套組合拳在當(dāng)時(shí)是標(biāo)準(zhǔn)操作但變換過(guò)程會(huì)引入動(dòng)態(tài)范圍壓縮部分低回聲區(qū)的細(xì)節(jié)仍然容易丟失。我覺(jué)得DnCNN作為對(duì)照組的最大價(jià)值不是它的效果最好而是它清楚地展示了“通用去噪模型不加以適配就往醫(yī)學(xué)圖像上用”會(huì)是什么效果。2.2 RED30利用對(duì)稱跳躍連接保住組織邊緣RED30的全稱是“Image Restoration Using Convolutional Auto-encoders with Symmetric Skip Connections”核心結(jié)構(gòu)是30層卷積堆疊的非對(duì)稱編解碼器。跟DnCNN的單一殘差學(xué)習(xí)不同RED30引入了編碼器-解碼器的對(duì)稱結(jié)構(gòu)并在對(duì)應(yīng)層之間添加跳躍連接。編碼器逐步降采樣提取高層語(yǔ)義解碼器逐步恢復(fù)空間分辨率跳躍連接則把編碼器階段的細(xì)節(jié)特征直接送到解碼器避免信息丟失。在超聲圖像上RED30的優(yōu)勢(shì)正好切中要害。超聲圖像里組織邊界和囊腫高回聲邊界都是強(qiáng)邊緣信息普通去噪網(wǎng)絡(luò)在多層卷積后容易把這些邊界糊掉RED30的跳躍連接能夠把淺層的邊緣細(xì)節(jié)“搬運(yùn)”到輸出端去噪后邊界清晰度明顯好于DnCNN。代價(jià)是參數(shù)總量比較大訓(xùn)練速度慢顯存占用高。如果你手頭的GPU只有一張消費(fèi)級(jí)卡RED30訓(xùn)練時(shí)batchsize可能得調(diào)到4以下訓(xùn)練時(shí)間會(huì)延長(zhǎng)不少。2.3 Attention U-Net在醫(yī)學(xué)分割框架里找去噪靈感U-Net原本是為圖像分割設(shè)計(jì)的它的對(duì)稱編解碼結(jié)構(gòu)加上跳躍連接天然適合像素級(jí)預(yù)測(cè)任務(wù)。Attention U-Net在原始U-Net的跳躍連接處加了一個(gè)注意力門控模塊讓網(wǎng)絡(luò)在融合編碼器特征時(shí)自動(dòng)加權(quán)那些與當(dāng)前解碼位置相關(guān)的區(qū)域降低無(wú)關(guān)區(qū)域的干擾。用Attention U-Net做去噪我起初有點(diǎn)猶豫因?yàn)樗举|(zhì)上是個(gè)生成式結(jié)構(gòu)主要用來(lái)做分割直接拿來(lái)做回歸任務(wù)會(huì)不會(huì)水土不服實(shí)測(cè)結(jié)果告訴我它會(huì)比DnCNN更“聰明”地處理噪聲——注意力門控讓它在高回聲區(qū)域和低回聲區(qū)域的去噪力度自動(dòng)調(diào)節(jié)而不是用一套權(quán)重處理全圖。在低回聲區(qū)域的囊性暗區(qū)里散斑噪聲本來(lái)就少模型會(huì)自動(dòng)降低對(duì)這些區(qū)域的平滑力度保留更多真實(shí)紋理。這套自適應(yīng)特性很貼合超聲圖像中“不同組織區(qū)域噪聲強(qiáng)度不一致”的特點(diǎn)。2.4 SwinIRTransformer 結(jié)構(gòu)的遠(yuǎn)程依賴有多大優(yōu)勢(shì)SwinIR是基于Swin Transformer的圖像復(fù)原模型和純CNN相比它的核心優(yōu)勢(shì)是自注意力機(jī)制帶來(lái)的全局感受野。CNN受限于卷積核大小感受野靠堆疊層數(shù)慢慢擴(kuò)大SwinIR通過(guò)窗口自注意力直接建模遠(yuǎn)距離像素之間的關(guān)系。超聲圖像中散斑噪聲的分布具有全局相關(guān)性因?yàn)樯⑸潴w分布是空間相關(guān)的理論上Transformer的全局建模能力能夠更準(zhǔn)確地判斷某個(gè)高頻成分到底是大范圍結(jié)構(gòu)的一部分還是孤立噪聲。實(shí)際跑下來(lái)SwinIR在定量指標(biāo)上確實(shí)很有競(jìng)爭(zhēng)力尤其在PSNR指標(biāo)上經(jīng)常能刷到第一第二。但問(wèn)題也很明顯它的參數(shù)量大、推理速度慢在一個(gè)256×256的圖像上單張推理就要數(shù)十毫秒甚至更久。如果項(xiàng)目需要部署到床旁超聲設(shè)備這類實(shí)時(shí)場(chǎng)景SwinIR目前的性價(jià)比不高。訓(xùn)練還需要大量數(shù)據(jù)在小規(guī)模超聲數(shù)據(jù)集上很容易過(guò)擬合不做充分的預(yù)訓(xùn)練和正則化效果會(huì)打折。2.5 NBNet為真實(shí)噪聲場(chǎng)景設(shè)計(jì)的噪聲水平估計(jì)路線NBNet是我這次對(duì)比中比較驚喜的一個(gè)模型。它的出發(fā)點(diǎn)是真實(shí)圖像中的噪聲水平是未知的很多模型假設(shè)固定噪聲強(qiáng)度一遇到不同噪聲水平的圖像效果就不穩(wěn)定。NBNet通過(guò)在網(wǎng)絡(luò)中插入了噪聲水平估計(jì)子網(wǎng)絡(luò)讓模型能夠根據(jù)當(dāng)前輸入圖像自適應(yīng)地調(diào)整去噪強(qiáng)度。它會(huì)先快速估計(jì)噪聲標(biāo)準(zhǔn)差然后把這個(gè)估計(jì)值作為條件信息傳遞到去噪主網(wǎng)絡(luò)。超聲圖像的散斑噪聲強(qiáng)度隨探頭頻率、增益設(shè)置、成像深度變化很大同一個(gè)模型在不同設(shè)備采集的圖像上常常出現(xiàn)“水土不服”。NBNet的噪聲水平自適應(yīng)機(jī)制正好應(yīng)對(duì)這個(gè)痛點(diǎn)。我實(shí)際測(cè)試時(shí)發(fā)現(xiàn)對(duì)同一張模擬散斑噪聲的超聲圖像讓模型估計(jì)噪聲水平再針對(duì)性去噪整體自然度確實(shí)比固定噪聲假設(shè)模型要好尤其在噪聲強(qiáng)度分布不均的區(qū)域這種自適應(yīng)能力價(jià)值明顯。3. 實(shí)驗(yàn)環(huán)境與評(píng)估指標(biāo)怎樣對(duì)比才不是“自嗨”3.1 數(shù)據(jù)集構(gòu)建與仿真散斑噪聲生成醫(yī)學(xué)圖像去噪研究有個(gè)繞不開(kāi)的難題很難拿到“完美無(wú)噪”的ground truth。臨床上真實(shí)的干凈超聲圖像不可能單獨(dú)采集到醫(yī)生掃查時(shí)得到的本身就是帶噪圖像。目前主流的做法有兩種一種是基于仿真超聲圖像另一種是真實(shí)的配對(duì)數(shù)據(jù)需要同一部位兩次掃查取平均代價(jià)很高。我這次實(shí)驗(yàn)采用公開(kāi)數(shù)據(jù)集仿真噪聲的方案用的是公開(kāi)的乳腺超聲數(shù)據(jù)集BUSI圖像內(nèi)容是乳腺B超涵蓋正常、良性和惡性腫瘤三類共780張左右。這些圖像本身雖然帶一定噪聲但整體質(zhì)量較好可以當(dāng)作參考底圖。在此基礎(chǔ)上使用成熟的超聲散斑仿真模型比如基于瑞利分布的乘性噪聲模型疊加噪聲生成成對(duì)的“干凈圖-帶噪圖”訓(xùn)練數(shù)據(jù)。具體的仿真代碼很關(guān)鍵為什么用特定模型去生成噪聲核心原因是散斑噪聲的概率分布不是高斯而是瑞利分布。離瑞利分布越遠(yuǎn)去噪性能評(píng)估的失真越大。生成散斑噪聲的示意代碼如下import torch import numpy as np def generate_speckle_noise(image, noise_level0.3): # image: [B, 1, H, W]數(shù)值范圍 0~1 # 使用瑞利分布的乘性噪聲模擬散斑 batch_size, channels, h, w image.shape sigma noise_level # 生成瑞利分布噪聲瑞利分布的概率密度: p(z) z / sigma^2 * exp(-z^2 / (2 * sigma^2)) z np.random.rayleigh(scalesigma, size(batch_size, channels, h, w)) # 將噪聲歸一化到均值1附近保持圖像亮度 z z / np.mean(z, axis(2, 3), keepdimsTrue) z_tensor torch.from_numpy(z).float().to(image.device) noisy_image image * z_tensor return noisy_image需要注意這個(gè)噪聲生成是“模擬”散斑和真實(shí)超聲設(shè)備的物理噪聲還有差距。如果要更貼近真實(shí)臨床最好對(duì)真實(shí)超聲設(shè)備采集的圖像做噪聲建模用最大似然估計(jì)來(lái)擬合散斑參數(shù)而不是拍腦袋取一個(gè)σ。我在實(shí)驗(yàn)里分別設(shè)置了低噪聲σ0.2、中噪聲σ0.35、高噪聲σ0.5三檔目的是評(píng)估不同模型在不同噪聲強(qiáng)度下的敏感度。3.2 PSNR、SSIM、MSE之外還要關(guān)注哪些指標(biāo)圖像去噪的常用評(píng)估指標(biāo)是PSNR和SSIM但單獨(dú)看這兩個(gè)指標(biāo)在醫(yī)學(xué)圖像上遠(yuǎn)遠(yuǎn)不夠。我額外加了幾個(gè)維度。第一個(gè)是邊緣保持指數(shù)EPI用來(lái)衡量去噪后圖像邊緣細(xì)節(jié)的保留程度計(jì)算方式是去噪后圖像與原始干凈圖像在邊緣像素上的梯度差異。EPI越高說(shuō)明邊緣越銳利。第二個(gè)是噪聲抑制率觀察去噪圖像中對(duì)用戶選定的均勻低回聲區(qū)域內(nèi)像素值的標(biāo)準(zhǔn)差變化以此評(píng)估散斑的削弱程度。第三個(gè)是主觀視覺(jué)評(píng)分我是請(qǐng)做超聲診斷的醫(yī)生朋友幫忙盲評(píng)的評(píng)價(jià)維度包括結(jié)構(gòu)清晰度、偽影引入程度、診斷可信度。EPI的計(jì)算代碼如下import torch import torch.nn.functional as F def edge_preservation_index(denoised, clean): # 用Sobel算子提取邊緣強(qiáng)度 sobel_kernel_x torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtypetorch.float32).reshape(1, 1, 3, 3) sobel_kernel_y sobel_kernel_x.transpose(-1, -2) grad_x_denoised F.conv2d(denoised, sobel_kernel_x, padding1) grad_y_denoised F.conv2d(denoised, sobel_kernel_y, padding1) grad_x_clean F.conv2d(clean, sobel_kernel_x, padding1) grad_y_clean F.conv2d(clean, sobel_kernel_y, padding1) edge_denoised torch.sqrt(grad_x_denoised ** 2 grad_y_denoised ** 2) edge_clean torch.sqrt(grad_x_clean ** 2 grad_y_clean ** 2) epi (torch.sum(edge_denoised * edge_clean) 1e-8) / (torch.sum(edge_clean ** 2) 1e-8) return epi.item()表格里我會(huì)把每個(gè)模型的PSNR、SSIM、EPI、參數(shù)量、單幀推理時(shí)間全部列出來(lái)量化和效率一起看。4. 核心代碼解讀訓(xùn)練一個(gè)可用的超聲去噪模型需要幾步4.1 數(shù)據(jù)加載與仿真噪聲增強(qiáng)很多入門的同學(xué)直接拿現(xiàn)成的去噪數(shù)據(jù)集訓(xùn)練但真實(shí)超聲數(shù)據(jù)集的噪聲分布跟仿真數(shù)據(jù)集不同遷移效果很差。我在數(shù)據(jù)加載這一步做了三件事一是保持原始圖像的動(dòng)態(tài)范圍不做過(guò)分歸一化二是每次迭代時(shí)隨機(jī)選擇一個(gè)噪聲等級(jí)從0.15到0.5之間隨機(jī)抽樣相當(dāng)于做了噪聲增強(qiáng)三是做隨機(jī)翻轉(zhuǎn)和旋轉(zhuǎn)增加樣本多樣性。隨機(jī)噪聲等級(jí)的代碼邏輯class SpeckleNoiseAugmentation(object): def __init__(self, low0.15, high0.5): self.low low self.high high def __call__(self, img): noise_level np.random.uniform(self.low, self.high) scale self.gaussian_rayleigh_scale(noise_level) noise np.random.rayleigh(scalescale, sizeimg.shape) noise noise / np.mean(noise, axis(1, 2), keepdimsTrue) return img * torch.from_numpy(noise).float()值得說(shuō)明的是這種隨機(jī)噪聲等級(jí)訓(xùn)練方式會(huì)在訓(xùn)練數(shù)據(jù)中引入豐富的噪聲強(qiáng)度分布模型不再針對(duì)某一個(gè)固定的σ過(guò)擬合泛化性能更好。我最后測(cè)試時(shí)發(fā)現(xiàn)采用隨機(jī)噪聲等級(jí)訓(xùn)練的模型在中噪聲和高噪聲場(chǎng)景下PSNR比固定噪聲等級(jí)訓(xùn)練分別高出1.2dB和2.1dB左右提升非常顯著。4.2 DnCNN訓(xùn)練主流程從數(shù)據(jù)流水線到損失函數(shù)DnCNN的代碼在網(wǎng)上很多但多數(shù)是針對(duì)灰度自然圖像的訓(xùn)練超參不一定適合超聲圖像。我這邊給出一個(gè)能直接跑的PyTorch訓(xùn)練循環(huán)重點(diǎn)在以下幾個(gè)地方做了調(diào)整。第一優(yōu)化器用Adam初始學(xué)習(xí)率1e-4配合余弦退火衰減第二損失函數(shù)用L1損失而不是L2損失超聲圖像去噪時(shí)L2損失容易產(chǎn)生平滑效應(yīng)L1能在像素級(jí)別更好保留邊緣梯度第三訓(xùn)練過(guò)程中使用混合精度AMP顯存占用能降低40%。import torch import torch.nn as nn import torch.optim as optim from torch.cuda.amp import GradScaler, autocast from model.dncnn import DnCNN model DnCNN(in_channels1, out_channels1, num_layers17) model model.cuda() criterion nn.L1Loss() optimizer optim.Adam(model.parameters(), lr1e-4) scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max100) scaler GradScaler() for epoch in range(100): model.train() running_loss 0.0 for noisy, clean in train_loader: noisy, clean noisy.cuda(), clean.cuda() optimizer.zero_grad() with autocast(): residual model(noisy) denoised noisy - residual loss criterion(denoised, clean) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() running_loss loss.item() scheduler.step() print(fEpoch {epoch1} | Loss: {running_loss/len(train_loader):.6f})有個(gè)關(guān)鍵細(xì)節(jié)DnCNN輸出的不是去噪圖而是預(yù)測(cè)的噪聲殘差所以去噪結(jié)果在訓(xùn)練時(shí)必須在框架內(nèi)部計(jì)算denoised noisy - residual不能直接拿網(wǎng)絡(luò)輸出和clean比較。很多同學(xué)踩過(guò)這個(gè)坑明明模型結(jié)構(gòu)沒(méi)錯(cuò)但Loss收斂得很慢就是因?yàn)樵谳敵龆松倭诉@一步。4.3 RED30、Attention U-Net、SwinIR的工程化配置差異這幾個(gè)模型的訓(xùn)練代碼框架基本一致區(qū)別主要體現(xiàn)在模型定義、損失權(quán)重和分布式訓(xùn)練的配置上。我挨個(gè)說(shuō)下實(shí)測(cè)時(shí)碰到的關(guān)鍵點(diǎn)。RED30的30層結(jié)構(gòu)比較深直接用BN在前幾輪訓(xùn)練時(shí)對(duì)batchsize大小非常敏感。如果batchsize小于4BN的均值方差估計(jì)不穩(wěn)定會(huì)嚴(yán)重拖慢收斂。我在配置中把BN替換為InstanceNorm小batch訓(xùn)練穩(wěn)定性明顯改善。這一步修改在醫(yī)學(xué)圖像小數(shù)據(jù)集上幾乎是必須的。Attention U-Net去噪時(shí)要特別注意跳躍連接處的注意力輸出。它對(duì)特征進(jìn)行softmax加權(quán)初始階段注意力權(quán)重接近均勻分布訓(xùn)練初期網(wǎng)絡(luò)幾乎退化成一個(gè)普通U-Net。如果訓(xùn)練資源有限可以從普通U-Net的預(yù)訓(xùn)練權(quán)重初始化 Attention部分再微調(diào)整個(gè)網(wǎng)絡(luò)。這個(gè)技巧能省下大約30%的訓(xùn)練時(shí)間并且最終效果更好。SwinIR的配置稍微麻煩一點(diǎn)它有窗口注意力的概念輸入圖像尺寸必須能被窗口大小整除否則會(huì)出錯(cuò)。超聲圖像尺寸往往是512×512或者800×600后者不能被8的倍數(shù)整除訓(xùn)練前需要做padding或者裁剪。我統(tǒng)一采用隨機(jī)裁剪成256×256的patch來(lái)訓(xùn)練測(cè)試時(shí)使用滑窗拼接推理。另外SwinIR主要針對(duì)RGB圖像輸入是3通道超聲圖像是單通道灰度圖所以第一層卷積需要把輸入通道改成1別忘記。4.4 推理與后處理別把好東西毀在最后一步模型訓(xùn)練完后推理階段也有不少講究。首先是輸入數(shù)值范圍必須和訓(xùn)練時(shí)一致訓(xùn)練時(shí)圖像歸一化到0~1推理時(shí)如果直接輸入原始0~255的圖像模型輸出就會(huì)完全偏離預(yù)期。其次是對(duì)數(shù)變換要記得恢復(fù)如果在預(yù)處理階段做了log變換推理后必須做exp變換還原否則圖像動(dòng)態(tài)范圍是壓縮的臨床上沒(méi)法看。還有一個(gè)容易被忽略的點(diǎn)很多模型對(duì)輸入圖像做了歸一化后再訓(xùn)練意味著推理后要重新縮放回原始灰度范圍。我見(jiàn)過(guò)有同學(xué)在推理代碼里忘記反向歸一化輸出的去噪圖整體偏暗差點(diǎn)誤判模型效果差。推理代碼的簡(jiǎn)要版本def denoise_image(model, noisy_img, log_transformTrue): model.eval() with torch.no_grad(): if log_transform: noisy_log torch.log(noisy_img 1e-6) else: noisy_log noisy_img # 歸一化到0~1 min_val noisy_log.min() max_val noisy_log.max() noisy_norm (noisy_log - min_val) / (max_val - min_val 1e-8) noisy_input noisy_norm.unsqueeze(0).cuda() with autocast(): residual model(noisy_input) denoised_norm noisy_input - residual # 還原歸一化 denoised_log denoised_norm.squeeze(0) * (max_val - min_val) min_val if log_transform: denoised_img torch.exp(denoised_log) else: denoised_img denoised_log return denoised_img.cpu()5. 實(shí)測(cè)結(jié)果對(duì)比5種模型在同一批超聲圖像上的表現(xiàn)5.1 定量指標(biāo)匯總誰(shuí)贏在PSNR誰(shuí)贏在速度我把5種模型在乳腺超聲數(shù)據(jù)集300張測(cè)試圖上的表現(xiàn)匯總到了一起按中噪聲強(qiáng)度σ0.35給出數(shù)據(jù)參數(shù)量里的單位是M百萬(wàn)推理時(shí)間是在單張NVIDIA RTX 3090上、輸入256×256灰度圖的平均耗時(shí)。模型PSNR (dB)SSIMEPI訓(xùn)練參數(shù)量 (M)單幀推理時(shí)間 (ms)DnCNN28.460.8750.520.564.2RED3029.130.9040.613.858.7Attention U-Net29.580.9180.587.249.3SwinIR30.020.9310.6611.8242.5NBNet30.210.9350.715.1612.8定量指標(biāo)是個(gè)很誠(chéng)實(shí)的東西但只反映一部分問(wèn)題。SwinIR在PSNR和SSIM上非常亮眼EPI也不錯(cuò)參數(shù)量最大、推理最慢也是不爭(zhēng)的事實(shí)。DnCNN的PSNR雖然不是最低但EPI明顯偏低說(shuō)明它在壓制噪聲的同時(shí)把組織邊緣也“壓扁”了。NBNet在各項(xiàng)指標(biāo)上綜合表現(xiàn)最好且推理時(shí)間還可以接受對(duì)于臨床落地場(chǎng)景來(lái)說(shuō)是個(gè)不錯(cuò)的折中。5.2 視覺(jué)質(zhì)量評(píng)估指標(biāo)好看不等于臨床能用指標(biāo)只是敲門磚真正決定模型能否上線的還是醫(yī)生的肉眼判斷。我找了兩名有經(jīng)驗(yàn)的超聲科醫(yī)生朋友讓他們重點(diǎn)觀察三類結(jié)構(gòu)囊腫邊界、甲狀腺結(jié)節(jié)邊緣、血管壁回聲。結(jié)果很有意思指標(biāo)上接近的模型在醫(yī)生的視覺(jué)評(píng)估里差異非常大。DnCNN處理后的圖像整體干凈但囊腫邊界變模糊醫(yī)生說(shuō)這種圖像會(huì)干擾測(cè)量實(shí)操中不敢直接使用。RED30的邊界保持好但在低回聲的囊性區(qū)域有些殘留噪聲醫(yī)生說(shuō)這倒是能接受因?yàn)榈突芈晠^(qū)域的散斑本身就會(huì)存在不影響診斷。SwinIR和NBNet在視覺(jué)質(zhì)量上比較接近細(xì)節(jié)豐富邊界清晰不太有“涂抹感”。有一點(diǎn)必須提醒去噪模型最大的雷區(qū)是產(chǎn)生“偽影”。某些GAN類的去噪模型會(huì)生成看起來(lái)極其清晰自然、但實(shí)際上并不存在的組織結(jié)構(gòu)這在醫(yī)學(xué)場(chǎng)景里是絕對(duì)不能接受的。我這次沒(méi)選GAN類模型正是因?yàn)樗摹盎糜X(jué)生成”風(fēng)險(xiǎn)太大。NBNet這類重建式模型則是在已有信息基礎(chǔ)上恢復(fù)被噪聲掩蓋的信號(hào)不會(huì)被強(qiáng)行“腦補(bǔ)”出新的結(jié)構(gòu)。5.3 參數(shù)量、訓(xùn)練成本與部署友好度選模型還要看團(tuán)隊(duì)資源。DnCNN參數(shù)量最小CPU都能跑推理非常適合嵌入式設(shè)備SwinIR效果最好但速度堪憂在實(shí)時(shí)超聲診斷場(chǎng)景基本沒(méi)法用。NBNet介于二者之間如果團(tuán)隊(duì)有邊緣計(jì)算盒子或者高性能工作站NBNet是個(gè)很好的選擇。RED30和Attention U-Net的推理時(shí)間可接受但參數(shù)量比DnCNN大不少模型文件也大需要考慮內(nèi)存帶寬。訓(xùn)練成本方面SwinIR的顯存占用最大即使batchsize降到4在16GB顯存下也有些吃力RED30在8GB卡上可以用batchsize 8訓(xùn)練DnCNN最輕量4GB顯存就能應(yīng)付。我做了一個(gè)簡(jiǎn)單的選型建議如果你的項(xiàng)目是離線處理比如回顧性研究、影像歸檔優(yōu)先考慮NBNet或SwinIR如果是嵌入式床旁設(shè)備的實(shí)時(shí)去噪DnCNN或精簡(jiǎn)版RED30可能更實(shí)際如果精度優(yōu)先但速度也要兼顧NBNet是最平衡的選擇。6. 實(shí)操中遇到的高頻問(wèn)題與排查技巧6.1 訓(xùn)練不收斂或損失下降緩慢超聲圖像的訓(xùn)練數(shù)據(jù)量通常不大模型容易出現(xiàn)過(guò)擬合或訓(xùn)練不穩(wěn)定的情況。我遇到過(guò)損失降到1.0左右就卡住不動(dòng)的場(chǎng)景排查看下來(lái)總是出在預(yù)處理上。第一是數(shù)據(jù)歸一化范圍不一致訓(xùn)練和驗(yàn)證用了不同的標(biāo)準(zhǔn)化方式第二是L2損失導(dǎo)致對(duì)噪聲極值點(diǎn)敏感換成L1或者結(jié)合感知損失會(huì)有明顯改善第三是學(xué)習(xí)率設(shè)置太高導(dǎo)致震蕩尤其SwinIR在小數(shù)據(jù)集上非常容易震蕩需要把學(xué)習(xí)率降到2e-5以下。排查方式很簡(jiǎn)單在訓(xùn)練前先跑一個(gè)batch的過(guò)擬合測(cè)試看能否讓loss降到很小如果連一個(gè)batch都擬合不了基本就是代碼邏輯或數(shù)據(jù)流出了問(wèn)題。6.2 去噪后出現(xiàn)“塑料感”或組織紋理丟失“塑料感”的本質(zhì)是過(guò)度平滑模型把組織顆粒感當(dāng)成噪聲給抹平了。這個(gè)問(wèn)題在DnCNN上出現(xiàn)的概率最高因?yàn)闅埐顚W(xué)習(xí)的目標(biāo)就是“能去掉的部分都去掉”如果訓(xùn)練數(shù)據(jù)中的噪聲強(qiáng)度分布比較寬模型會(huì)傾向于把很多頻段的信息都當(dāng)成噪聲處理。改善手段有兩個(gè)思路一是從數(shù)據(jù)端下手讓噪聲仿真更接近真實(shí)散斑統(tǒng)計(jì)特性不要為了提PSNR而把訓(xùn)練噪聲強(qiáng)度調(diào)得過(guò)高二是從模型端下手在損失函數(shù)中增加邊緣保持損失比如梯度差損失讓模型在去除噪聲的同時(shí)必須保留邊緣梯度。我用梯度損失之后“塑料感”明顯減輕醫(yī)生評(píng)分也隨之提升。6.3 真實(shí)超聲圖像沒(méi)有配對(duì)數(shù)據(jù)怎么辦很多同學(xué)拿著模型跑到真實(shí)設(shè)備上去測(cè)試結(jié)果發(fā)現(xiàn)訓(xùn)練時(shí)仿真噪聲和真實(shí)噪聲差異太大效果遠(yuǎn)不如預(yù)期。這個(gè)問(wèn)題有兩個(gè)方向可以解決。一是“無(wú)監(jiān)督/自監(jiān)督”路線像Self2Self、Noise2Self這類方法利用相鄰像素的相關(guān)性來(lái)訓(xùn)練只需要帶噪圖像本身就可以不需要干凈真值。我在小樣本真實(shí)超聲上試過(guò)Noise2Self的思路雖然沒(méi)有監(jiān)督訓(xùn)練那么高指標(biāo)但勝在真實(shí)場(chǎng)景下穩(wěn)。二是“仿真到真實(shí)遷移”路線用CycleGAN等對(duì)抗方法把仿真噪聲圖像遷移得更像真實(shí)超聲噪聲再訓(xùn)練去噪模型。但這涉及GAN的穩(wěn)定性問(wèn)題訓(xùn)練難度高生產(chǎn)環(huán)境要慎重。6.4 部署到實(shí)時(shí)設(shè)備時(shí)的通病內(nèi)存與延時(shí)瓶頸即使模型訓(xùn)練效果很好到了部署環(huán)節(jié)也會(huì)遇到一堆坑。我踩過(guò)最典型的一個(gè)坑是PyTorch框架的推理延遲達(dá)標(biāo)了但轉(zhuǎn)成ONNX后輸出結(jié)果和PyTorch相差很大尤其在圖像邊緣區(qū)域卷積對(duì)齊方式padding策略變了導(dǎo)致結(jié)果偏移。解決方案是推理時(shí)把輸入圖像padding成卷積核能整除的尺寸轉(zhuǎn)ONNX時(shí)固定pad策略避免動(dòng)態(tài)尺寸帶來(lái)的隱式padding變化。還有一點(diǎn)是關(guān)于顯存和內(nèi)存管理如果用TensorRT加速要注意動(dòng)態(tài)shape的限制超聲設(shè)備在運(yùn)行時(shí)圖像尺寸可能變化建議把輸入統(tǒng)一縮放或裁剪到固定尺寸避免頻繁觸發(fā)TensorRT的engine重建。SwinIR這類基于Transformer的模型在TensorRT上不是所有算子都有優(yōu)化有些算子會(huì)退回到CPU執(zhí)行推理速度驟降部署前最好先對(duì)整個(gè)算子列表做兼容性審計(jì)。我個(gè)人在實(shí)際操作中最大的體會(huì)是在醫(yī)學(xué)圖像處理里“穩(wěn)妥”永遠(yuǎn)比“花哨”重要。任何一個(gè)可能在臨床場(chǎng)景引入錯(cuò)誤信息的模型無(wú)論它的PSNR刷到多高都是不可接受的。所以如果你的項(xiàng)目剛起步我建議不要一上來(lái)就追求最新最強(qiáng)的模型先把DnCNN這套“殘差學(xué)習(xí)隨機(jī)噪聲等級(jí)嚴(yán)格數(shù)據(jù)前處理”的流程完全跑通再去嘗試NBNet或SwinIR。后續(xù)如果要在真實(shí)設(shè)備上落地可以考慮在模型前增加一個(gè)輕量的噪聲水平估計(jì)模塊讓模型自適應(yīng)不同設(shè)備并且在推理環(huán)節(jié)做嚴(yán)格的灰度范圍校驗(yàn)。這個(gè)方向做深了你會(huì)發(fā)現(xiàn)超聲去噪對(duì)輔助診斷的價(jià)值遠(yuǎn)比想象中要大。