習(xí)超分辨率實(shí)戰(zhàn):從TDSR項(xiàng)目解析圖像重建全流程)
1. 項(xiàng)目概述從零解析TDSR超分辨率重建最近在整理一些老照片和視頻素材發(fā)現(xiàn)很多早年拍攝的內(nèi)容分辨率實(shí)在感人放到現(xiàn)在的4K甚至8K屏幕上簡(jiǎn)直沒(méi)法看。直接拉伸放大那畫(huà)面糊得跟打了馬賽克一樣。這時(shí)候超分辨率技術(shù)就成了我的救命稻草。而在眾多開(kāi)源方案里TDSRTypical Downscaled Super-Resolution這個(gè)項(xiàng)目引起了我的注意。它不像一些“黑箱”模型只給個(gè)預(yù)訓(xùn)練權(quán)重而是把從數(shù)據(jù)準(zhǔn)備、模型訓(xùn)練到推理測(cè)試的全套源碼都攤開(kāi)給你看。這對(duì)于想真正理解超分辨率技術(shù)背后邏輯甚至想自己動(dòng)手改進(jìn)模型的研究者或開(kāi)發(fā)者來(lái)說(shuō)價(jià)值巨大。簡(jiǎn)單說(shuō)TDSR項(xiàng)目提供了一個(gè)基于深度學(xué)習(xí)的、典型的圖像超分辨率重建方案的完整實(shí)現(xiàn)你可以用它來(lái)學(xué)習(xí)、研究或者直接拿來(lái)修復(fù)你的低分辨率圖像讓模糊變清晰。2. 核心思路與技術(shù)選型剖析2.1 為什么是“Typical Downscaled”TDSR這個(gè)名字本身就點(diǎn)明了它的核心方法論。在超分辨率研究領(lǐng)域一個(gè)經(jīng)典且基礎(chǔ)的訓(xùn)練數(shù)據(jù)構(gòu)建方式就是“降質(zhì)-重建”。我們很難直接獲取同一場(chǎng)景的高分辨率HR和低分辨率LR圖像對(duì)。TDSR采用的“Typical Downscaled”思路就是人為地對(duì)高清圖像進(jìn)行一系列標(biāo)準(zhǔn)的降質(zhì)處理如雙三次下采樣、添加噪聲、模糊等來(lái)模擬生成對(duì)應(yīng)的低清圖像。這樣我們就擁有了海量的“LR-HR”配對(duì)數(shù)據(jù)。模型的學(xué)習(xí)目標(biāo)就是學(xué)會(huì)如何從這些人工降質(zhì)的LR圖像中恢復(fù)出原始的HR圖像。這種方法雖然是對(duì)真實(shí)退化過(guò)程的一種簡(jiǎn)化模擬但它奠定了監(jiān)督式超分辨率學(xué)習(xí)的基礎(chǔ)非常有利于我們理解模型是如何學(xué)會(huì)“補(bǔ)全”高頻細(xì)節(jié)的。2.2 主流模型架構(gòu)的取舍打開(kāi)TDSR的源碼你會(huì)發(fā)現(xiàn)它很可能實(shí)現(xiàn)了不止一種網(wǎng)絡(luò)模型。在超分辨率領(lǐng)域有幾個(gè)里程碑式的架構(gòu)是繞不開(kāi)的。首先是SRCNN這算是深度學(xué)習(xí)介入超分辨率的開(kāi)山之作。它的結(jié)構(gòu)非常簡(jiǎn)單就是一個(gè)三層的卷積網(wǎng)絡(luò)分別負(fù)責(zé)特征提取、非線性映射和圖像重建。它的意義在于證明了即使是一個(gè)很淺的網(wǎng)絡(luò)也能通過(guò)學(xué)習(xí)端到端的映射在效果上超越傳統(tǒng)的插值方法。TDSR如果包含SRCNN那更多是出于教學(xué)和對(duì)比的目的讓你理解最基礎(chǔ)的范式。更實(shí)用的可能是像ESPCN或FSRCNN這樣的模型。它們引入了“子像素卷積”或“反卷積”的思想旨在LR圖像的空間域上進(jìn)行計(jì)算最后通過(guò)巧妙的像素重排得到HR輸出。這樣做的好處是計(jì)算效率高因?yàn)榇蟛糠址敝氐木矸e運(yùn)算都在較小的LR特征圖上進(jìn)行。對(duì)于希望部署在資源受限環(huán)境如手機(jī)、嵌入式設(shè)備的應(yīng)用來(lái)說(shuō)這類(lèi)模型是首選。當(dāng)然如果項(xiàng)目追求極致的重建質(zhì)量那么很可能會(huì)包含基于殘差學(xué)習(xí)或密集連接的高級(jí)模型例如EDSR或RDN。這些網(wǎng)絡(luò)通常非常深擁有大量的殘差塊能夠?qū)W習(xí)到更復(fù)雜的映射關(guān)系在公開(kāi)測(cè)試集上能刷出很高的分?jǐn)?shù)如PSNR SSIM。但它們的代價(jià)是參數(shù)量大、計(jì)算慢對(duì)硬件要求高。TDSR實(shí)現(xiàn)這類(lèi)模型是為了展示當(dāng)前SOTA當(dāng)前最優(yōu)的技術(shù)水平。注意模型選擇沒(méi)有絕對(duì)的好壞只有是否適合。如果你是為了學(xué)術(shù)研究、刷榜那么深而復(fù)雜的模型是必經(jīng)之路。但如果你是為了做一個(gè)能實(shí)時(shí)處理視頻的實(shí)用工具那么輕量化和速度才是首要考量。TDSR提供多種實(shí)現(xiàn)的意義就在于讓你能親自體驗(yàn)這種權(quán)衡。2.3 損失函數(shù)的設(shè)計(jì)哲學(xué)模型要學(xué)習(xí)就得有目標(biāo)這個(gè)目標(biāo)由損失函數(shù)來(lái)定義。在TDSR中最基礎(chǔ)的損失函數(shù)一定是像素級(jí)損失比如L1損失或L2損失。它們計(jì)算重建圖像與真實(shí)高清圖像在每個(gè)像素點(diǎn)上的差異。L2損失MSE更強(qiáng)調(diào)懲罰大的誤差但可能導(dǎo)致結(jié)果過(guò)于平滑L1損失對(duì)異常值更魯棒有時(shí)能保留更好的邊緣。很多現(xiàn)代方法會(huì)采用L1損失作為基礎(chǔ)。但光看像素對(duì)齊是不夠的。人眼對(duì)圖像質(zhì)量的感知并非完全取決于像素值的絕對(duì)誤差。因此更高級(jí)的實(shí)現(xiàn)可能會(huì)引入感知損失或?qū)箵p失。感知損失通常利用一個(gè)預(yù)訓(xùn)練好的圖像分類(lèi)網(wǎng)絡(luò)如VGG比較重建圖像和真實(shí)圖像在深層特征空間上的差異鼓勵(lì)模型生成在語(yǔ)義和紋理上更“自然”的圖像。而對(duì)抗損失則引入一個(gè)判別器網(wǎng)絡(luò)讓它和生成器超分模型博弈判別器努力區(qū)分真實(shí)高清圖和生成圖生成器則努力“騙過(guò)”判別器。這能驅(qū)使生成器產(chǎn)生細(xì)節(jié)更豐富、更接近真實(shí)圖像分布的輸出。TDSR的進(jìn)階部分如果包含這些內(nèi)容那它的完整度就相當(dāng)高了。3. 環(huán)境搭建與數(shù)據(jù)準(zhǔn)備實(shí)戰(zhàn)3.1 構(gòu)建可復(fù)現(xiàn)的Python環(huán)境拿到源碼第一步不是急著運(yùn)行而是搭建一個(gè)隔離、純凈的Python環(huán)境。我強(qiáng)烈推薦使用Conda或venv。以Conda為例你可以創(chuàng)建一個(gè)專門(mén)的環(huán)境conda create -n tdsr python3.8 conda activate tdsr接下來(lái)安裝PyTorch。這里坑最多一定要去PyTorch官網(wǎng)根據(jù)你的CUDA版本用nvidia-smi命令查看和操作系統(tǒng)選擇正確的安裝命令。比如對(duì)于CUDA 11.3pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113安裝完P(guān)yTorch后再根據(jù)TDSR項(xiàng)目根目錄下的requirements.txt文件安裝其他依賴pip install -r requirements.txt常見(jiàn)的依賴會(huì)包括opencv-python圖像處理、numpy、scikit-image圖像質(zhì)量評(píng)估如計(jì)算PSNR/SSIM、tensorboard或wandb訓(xùn)練可視化、pillow等。實(shí)操心得很多人會(huì)忽略PyTorch版本與CUDA驅(qū)動(dòng)版本的匹配。如果你的CUDA是11.6卻安裝了支持CUDA 11.3的PyTorch運(yùn)行時(shí)可能會(huì)報(bào)錯(cuò)“CUDA不可用”。最穩(wěn)妥的方法是先在Python交互環(huán)境里執(zhí)行import torch; print(torch.cuda.is_available())確保返回True。3.2 訓(xùn)練數(shù)據(jù)集的準(zhǔn)備與處理TDSR的訓(xùn)練通常需要一個(gè)大容量的高清圖像數(shù)據(jù)集。常用的有DIV2K這是一個(gè)專門(mén)為圖像恢復(fù)任務(wù)設(shè)計(jì)的數(shù)據(jù)集包含800張訓(xùn)練圖、100張驗(yàn)證圖和100張測(cè)試圖分辨率都很高。下載好DIV2K數(shù)據(jù)集后你不能直接把原始圖片扔給模型。需要按照TDSR源碼中數(shù)據(jù)加載腳本的約定進(jìn)行預(yù)處理。典型的步驟包括裁剪將大圖隨機(jī)裁剪成許多個(gè)固定大小的小塊如96x96或128x128。這樣做一是為了增加數(shù)據(jù)量數(shù)據(jù)增強(qiáng)二是為了適配GPU內(nèi)存無(wú)法一次性將整張高清圖送入網(wǎng)絡(luò)。降質(zhì)對(duì)每個(gè)HR圖像塊應(yīng)用“Typical Downscaled”流程。比如先使用雙三次插值下采樣4倍得到LR圖像塊。有時(shí)為了模擬更真實(shí)的退化還會(huì)加上高斯模糊或泊松噪聲。配對(duì)與存儲(chǔ)將處理后的LR-HR圖像對(duì)保存起來(lái)。常見(jiàn)的做法是保存為.npy文件或LMDB數(shù)據(jù)庫(kù)格式。LMDB是一種內(nèi)存映射型數(shù)據(jù)庫(kù)當(dāng)你有幾十萬(wàn)個(gè)小圖像塊時(shí)用它做隨機(jī)讀取比直接從硬盤(pán)讀無(wú)數(shù)個(gè)小文件要快得多能極大緩解訓(xùn)練時(shí)的I/O瓶頸。數(shù)據(jù)準(zhǔn)備的代碼往往枯燥但至關(guān)重要。你需要仔細(xì)檢查數(shù)據(jù)加載器確保它正確地從存儲(chǔ)中讀取了配對(duì)的LR和HR數(shù)據(jù)并且做了必要的預(yù)處理如像素值歸一化到[0,1]或[-1,1]。3.3 關(guān)鍵配置文件解析一個(gè)成熟的源碼項(xiàng)目通常會(huì)有一個(gè)配置文件如config.yml或options.py將所有超參數(shù)和路徑設(shè)置集中管理。理解并正確配置這個(gè)文件是成功運(yùn)行項(xiàng)目的關(guān)鍵。你需要重點(diǎn)關(guān)注以下幾項(xiàng)路徑相關(guān)train_root訓(xùn)練數(shù)據(jù)路徑、val_root驗(yàn)證數(shù)據(jù)路徑、pretrain_model預(yù)訓(xùn)練模型路徑、save_dir模型和日志保存路徑。模型結(jié)構(gòu)model選擇哪種網(wǎng)絡(luò)如srcnn,espcn,edsr、scale超分倍數(shù)如4、num_channels輸入輸出通道數(shù)RGB圖為3、num_features和num_blocks對(duì)于EDSR等定義特征圖數(shù)量和殘差塊個(gè)數(shù)。訓(xùn)練參數(shù)lr初始學(xué)習(xí)率、lr_decay和lr_decay_step學(xué)習(xí)率衰減策略、batch_size、num_epochs、loss_type選擇L1或L2等。數(shù)據(jù)參數(shù)patch_size裁剪的圖像塊大小、num_workers數(shù)據(jù)加載的線程數(shù)通常設(shè)為CPU核心數(shù)。我的習(xí)慣是在第一次運(yùn)行前先復(fù)制一份默認(rèn)配置命名為config_my_exp.yml然后只修改其中必要的路徑和關(guān)鍵參數(shù)如batch_size以適應(yīng)你的GPU顯存。這樣既保留了原始配置又能清晰記錄每次實(shí)驗(yàn)的改動(dòng)。4. 模型訓(xùn)練全流程與核心技巧4.1 訓(xùn)練循環(huán)的代碼級(jí)解讀訓(xùn)練腳本通常是train.py是項(xiàng)目的引擎。其核心是一個(gè)嵌套循環(huán)外層循環(huán)遍歷所有訓(xùn)練輪次內(nèi)層循環(huán)遍歷一個(gè)訓(xùn)練集的所有批次。for epoch in range(start_epoch, num_epochs): model.train() for i, batch in enumerate(train_loader): lr_img, hr_img batch[lr].to(device), batch[hr].to(device) # 前向傳播 sr_img model(lr_img) # 計(jì)算損失 loss criterion(sr_img, hr_img) # 反向傳播與優(yōu)化 optimizer.zero_grad() loss.backward() optimizer.step() # 日志記錄 if i % log_interval 0: print(fEpoch [{epoch}/{num_epochs}], Step [{i}/{len(train_loader)}], Loss: {loss.item():.4f})這段代碼骨架看似簡(jiǎn)單但魔鬼在細(xì)節(jié)里。optimizer.zero_grad()的位置至關(guān)重要。它必須在loss.backward()之前調(diào)用用于清空上一輪計(jì)算得到的梯度。如果放錯(cuò)位置梯度會(huì)不斷累積導(dǎo)致訓(xùn)練失控。另一個(gè)關(guān)鍵是學(xué)習(xí)率調(diào)整策略。在TDSR這類(lèi)圖像恢復(fù)任務(wù)中我們通常不會(huì)使用固定的學(xué)習(xí)率。常見(jiàn)的做法是每訓(xùn)練一定輪次如每20個(gè)epoch將學(xué)習(xí)率乘以一個(gè)衰減因子如0.5。這在PyTorch中可以用torch.optim.lr_scheduler.StepLR輕松實(shí)現(xiàn)。適時(shí)降低學(xué)習(xí)率有助于模型在訓(xùn)練后期更精細(xì)地收斂到最優(yōu)解附近。4.2 驗(yàn)證與模型保存策略訓(xùn)練不能只看訓(xùn)練集上的損失必須用一個(gè)獨(dú)立的驗(yàn)證集來(lái)監(jiān)控模型的真實(shí)泛化能力防止過(guò)擬合。通常在每個(gè)epoch訓(xùn)練結(jié)束后會(huì)跑一次驗(yàn)證循環(huán)model.eval() with torch.no_grad(): total_psnr 0.0 for batch in val_loader: lr_val, hr_val batch[lr].to(device), batch[hr].to(device) sr_val model(lr_val) # 計(jì)算PSNR等指標(biāo) batch_psnr calculate_psnr(sr_val, hr_val) total_psnr batch_psnr avg_val_psnr total_psnr / len(val_loader) print(fValidation PSNR: {avg_val_psnr:.2f} dB)這里有兩個(gè)要點(diǎn)第一一定要用model.eval()和torch.no_grad()上下文管理器。eval()會(huì)將模型中的某些層如BatchNorm和Dropout切換到推理模式no_grad()則告訴PyTorch不要計(jì)算和存儲(chǔ)梯度這樣可以節(jié)省大量?jī)?nèi)存和計(jì)算資源。第二驗(yàn)證指標(biāo)通常選擇PSNR和SSIM它們是超分辨率領(lǐng)域最常用的客觀評(píng)價(jià)指標(biāo)。模型保存策略也很有講究。最簡(jiǎn)單的就是每個(gè)epoch都保存但這會(huì)占用大量磁盤(pán)空間。更好的做法是“只保存更好”的模型。我們可以記錄驗(yàn)證集上的最佳PSNR值只有當(dāng)當(dāng)前模型在驗(yàn)證集上的PSNR超過(guò)歷史最佳時(shí)才保存該模型的狀態(tài)字典。這保證了最終得到的模型是泛化能力最強(qiáng)的。4.3 TensorBoard可視化監(jiān)控訓(xùn)練過(guò)程黑盒進(jìn)行是不可接受的。集成TensorBoard可以讓你實(shí)時(shí)觀察損失下降曲線、驗(yàn)證指標(biāo)變化、甚至可視化輸入-輸出圖像對(duì)比。在訓(xùn)練代碼中添加日志記錄非常簡(jiǎn)單from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(log_dirruns/exp1) # 在訓(xùn)練循環(huán)內(nèi) writer.add_scalar(Loss/train, loss.item(), global_stepepoch*len(train_loader)i) # 在驗(yàn)證循環(huán)后 writer.add_scalar(PSNR/val, avg_val_psnr, global_stepepoch) # 偶爾保存圖像對(duì)比 if epoch % 5 0: writer.add_images(Val/Compare, torch.cat([lr_val[0], sr_val[0], hr_val[0]], dim2), epoch)訓(xùn)練時(shí)在終端啟動(dòng)TensorBoard服務(wù)tensorboard --logdirruns你就可以在瀏覽器中直觀地監(jiān)控整個(gè)訓(xùn)練過(guò)程這對(duì)于調(diào)試超參數(shù)、發(fā)現(xiàn)訓(xùn)練異常如損失爆炸至關(guān)重要。5. 推理測(cè)試與效果優(yōu)化實(shí)戰(zhàn)5.1 編寫(xiě)通用的推理腳本訓(xùn)練好的模型最終要用于處理真實(shí)圖像。一個(gè)健壯的推理腳本inference.py或test.py需要處理各種實(shí)際情況。核心步驟包括加載模型使用torch.load加載保存的.pth文件并通過(guò)model.load_state_dict()將權(quán)重載入到定義好的網(wǎng)絡(luò)結(jié)構(gòu)中。務(wù)必注意加載時(shí)設(shè)置map_locationcpu可以避免因GPU環(huán)境變化導(dǎo)致的錯(cuò)誤。圖像預(yù)處理讀取輸入圖像LR將其從0-255的uint8格式轉(zhuǎn)換為0-1的float32格式并轉(zhuǎn)換為PyTorch張量。通常還需要進(jìn)行歸一化如減去均值除以標(biāo)準(zhǔn)差如果訓(xùn)練時(shí)做了的話。一個(gè)常見(jiàn)的需求是處理任意尺寸的輸入。超分模型的卷積操作可能對(duì)輸入尺寸有要求如需要是縮放因子的整數(shù)倍。因此通常需要先對(duì)輸入LR圖像進(jìn)行填充使其寬高滿足條件。模型推理同樣需要調(diào)用model.eval()和with torch.no_grad()。圖像后處理將模型輸出的張量轉(zhuǎn)換回0-255范圍的圖像數(shù)據(jù)并保存。這里有一個(gè)非常重要的性能技巧如果一次要處理大量圖像或者處理視頻流應(yīng)該將步驟2和4圖像與張量的轉(zhuǎn)換、歸一化盡可能向量化并考慮使用數(shù)據(jù)加載器。對(duì)于單張圖片這些開(kāi)銷(xiāo)不明顯但對(duì)于批處理優(yōu)化后的速度提升是顯著的。5.2 客觀指標(biāo)與主觀效果的權(quán)衡我們用PSNR和SSIM來(lái)定量評(píng)估模型性能但這不代表一切。PSNR高的圖像在人眼看來(lái)不一定就“好看”。有時(shí)為了追求更高的PSNR模型會(huì)傾向于輸出過(guò)于平滑的結(jié)果丟失了生動(dòng)的紋理。而一些感知損失或?qū)箵p失訓(xùn)練出的模型PSNR可能略低但生成的圖像紋理更豐富、更自然。在測(cè)試時(shí)我通常會(huì)做兩件事第一在標(biāo)準(zhǔn)的測(cè)試集如Set5 Set14 Urban100上計(jì)算平均PSNR/SSIM這是為了與學(xué)術(shù)論文中的結(jié)果進(jìn)行橫向?qū)Ρ?。第二也是更重要的找一些我自己的真?shí)低清照片而不是通過(guò)下采樣模擬的讓模型處理然后用肉眼仔細(xì)觀察??纯唇ㄖ锏倪吘壥欠皲J利但無(wú)鋸齒看看人物的頭發(fā)和皮膚紋理是否自然看看有沒(méi)有奇怪的偽影或噪聲主觀評(píng)價(jià)往往能發(fā)現(xiàn)客觀指標(biāo)無(wú)法反映的問(wèn)題。5.3 針對(duì)真實(shí)場(chǎng)景的調(diào)優(yōu)思路TDSR源碼提供的模型是在模擬的“雙三次下采樣”退化數(shù)據(jù)上訓(xùn)練的。但真實(shí)世界的低清圖像其退化過(guò)程要復(fù)雜得多可能是相機(jī)抖動(dòng)導(dǎo)致的運(yùn)動(dòng)模糊、低光照下的噪聲、JPEG壓縮帶來(lái)的塊效應(yīng)等等。直接用標(biāo)準(zhǔn)模型處理這類(lèi)圖像效果往往會(huì)打折扣。如果你想提升模型在特定真實(shí)場(chǎng)景下的效果有幾個(gè)方向數(shù)據(jù)域的適配收集或生成更接近你目標(biāo)場(chǎng)景的退化數(shù)據(jù)。例如如果你的目標(biāo)是修復(fù)老視頻可以嘗試用更復(fù)雜的退化模型如模糊噪聲壓縮來(lái)生成訓(xùn)練數(shù)據(jù)。微調(diào)使用在大型數(shù)據(jù)集如DIV2K上預(yù)訓(xùn)練好的TDSR模型作為起點(diǎn)用你特定場(chǎng)景的一小部分配對(duì)數(shù)據(jù)甚至可以是少量人工標(biāo)注的進(jìn)行微調(diào)。這通常比從頭訓(xùn)練收斂更快效果更好。后處理集成超分模型之后可以串聯(lián)一個(gè)輕量的去噪或去塊效應(yīng)濾波器作為后處理步驟。這屬于工程上的組合創(chuàng)新。6. 常見(jiàn)問(wèn)題排查與深度優(yōu)化指南6.1 訓(xùn)練過(guò)程中的典型問(wèn)題即使按照README一步步操作訓(xùn)練時(shí)也難免會(huì)遇到問(wèn)題。下面是一個(gè)快速排查清單問(wèn)題現(xiàn)象可能原因排查與解決思路Loss值為NaN或突然爆炸學(xué)習(xí)率設(shè)置過(guò)高網(wǎng)絡(luò)中有除零或log(0)操作梯度爆炸。1. 將學(xué)習(xí)率調(diào)低一個(gè)數(shù)量級(jí)再試。2. 檢查數(shù)據(jù)預(yù)處理確保輸入數(shù)據(jù)中沒(méi)有異常值如NaN或inf。3. 使用梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0)。Loss下降很慢或幾乎不降學(xué)習(xí)率過(guò)低模型架構(gòu)或初始化有問(wèn)題數(shù)據(jù)標(biāo)簽有問(wèn)題如LR-HR不對(duì)應(yīng)。1. 適當(dāng)調(diào)高學(xué)習(xí)率。2. 使用更先進(jìn)的權(quán)重初始化方法如Kaiming初始化。3. 可視化幾個(gè)訓(xùn)練批次的數(shù)據(jù)確保LR圖像確實(shí)是HR圖像的正確降質(zhì)版本。GPU內(nèi)存溢出OOMBatch size太大輸入圖像尺寸太大模型參數(shù)量過(guò)大。1. 減小batch_size。2. 減小訓(xùn)練時(shí)裁剪的patch_size。3. 使用梯度累積每N個(gè)小batch才更新一次權(quán)重模擬大batch效果。4. 考慮使用更輕量的模型。驗(yàn)證指標(biāo)PSNR遠(yuǎn)低于預(yù)期嚴(yán)重過(guò)擬合驗(yàn)證集與訓(xùn)練集分布差異大評(píng)估代碼有誤。1. 檢查訓(xùn)練集和驗(yàn)證集的PSNR如果訓(xùn)練集很高而驗(yàn)證集很低是過(guò)擬合??稍黾訑?shù)據(jù)增強(qiáng)如旋轉(zhuǎn)、翻轉(zhuǎn)或使用早停。2. 確保驗(yàn)證集的評(píng)估代碼關(guān)閉了數(shù)據(jù)增強(qiáng)且與訓(xùn)練模式一致。3. 手動(dòng)計(jì)算一張簡(jiǎn)單圖像的PSNR驗(yàn)證評(píng)估函數(shù)是否正確。6.2 推理階段的棘手情況推理時(shí)的問(wèn)題通常與訓(xùn)練環(huán)境不一致有關(guān)。模型加載失敗最常見(jiàn)的錯(cuò)誤是“Missing key(s) in state_dict”或“Unexpected key(s)”。這通常是因?yàn)楸4娴哪P徒Y(jié)構(gòu)比如包含了module.前綴因?yàn)槭怯肈ataParallel包裝后保存的與當(dāng)前加載時(shí)定義的模型結(jié)構(gòu)不匹配。解決方法是打印出保存的state_dict的鍵名然后通過(guò)創(chuàng)建新的字典來(lái)手動(dòng)映射或去除前綴。輸出圖像顏色異常這幾乎總是預(yù)處理或后處理的歸一化/反歸一化步驟與訓(xùn)練時(shí)不匹配造成的。請(qǐng)務(wù)必保證推理時(shí)使用的均值、標(biāo)準(zhǔn)差與訓(xùn)練時(shí)完全相同。一個(gè)笨但有效的方法是將訓(xùn)練數(shù)據(jù)加載器中對(duì)一個(gè)批次數(shù)據(jù)計(jì)算的均值和標(biāo)準(zhǔn)差打印出來(lái)硬編碼到推理腳本中。處理大圖時(shí)內(nèi)存不足即使訓(xùn)練時(shí)用小patch我們也希望推理時(shí)能處理任意大圖。解決方案是分塊推理。將大圖分割成有重疊的小塊分別送入模型超分然后再將結(jié)果拼接起來(lái)。重疊是為了避免在塊邊界產(chǎn)生接縫。拼接時(shí)可以對(duì)重疊區(qū)域進(jìn)行加權(quán)融合如使用余弦窗使過(guò)渡平滑。6.3 性能優(yōu)化進(jìn)階技巧當(dāng)你的模型效果滿意后下一步就是讓它跑得更快、更高效。模型剪枝與量化這是模型部署前的常見(jiàn)操作。剪枝可以移除網(wǎng)絡(luò)中不重要的連接或通道減少參數(shù)量和計(jì)算量。量化則將模型的權(quán)重和激活從32位浮點(diǎn)數(shù)轉(zhuǎn)換為8位整數(shù)能大幅減少模型體積和提升推理速度尤其有利于在移動(dòng)端部署。PyTorch提供了相關(guān)的工具包。使用更快的推理后端將PyTorch模型導(dǎo)出為ONNX格式然后利用ONNX Runtime、TensorRT等高性能推理引擎進(jìn)行部署。這些引擎針對(duì)不同的硬件CPU GPU做了大量?jī)?yōu)化通常能獲得比原生PyTorch推理更快的速度。利用半精度浮點(diǎn)數(shù)現(xiàn)代GPU如Volta架構(gòu)及以后對(duì)半精度浮點(diǎn)數(shù)有很好的硬件支持。在推理時(shí)可以將模型和輸入數(shù)據(jù)轉(zhuǎn)換為torch.float16這不僅能減少顯存占用還能提升計(jì)算吞吐量。在訓(xùn)練時(shí)也可以嘗試使用自動(dòng)混合精度以加速訓(xùn)練過(guò)程。折騰TDSR這類(lèi)完整的源碼項(xiàng)目最大的收獲不是僅僅跑通了一個(gè)程序而是親手搭建、調(diào)試并理解了超分辨率技術(shù)從數(shù)據(jù)到模型再到部署的完整鏈條。每一個(gè)報(bào)錯(cuò)每一次調(diào)參都是對(duì)底層原理的一次加深認(rèn)識(shí)。當(dāng)你最后用自己的模型成功修復(fù)了一張充滿回憶的老照片時(shí)那種成就感遠(yuǎn)非調(diào)用一個(gè)現(xiàn)成API可比。這個(gè)過(guò)程里積累的關(guān)于數(shù)據(jù)管道、模型訓(xùn)練、調(diào)試排查的經(jīng)驗(yàn)是通用的能遷移到任何其他深度學(xué)習(xí)項(xiàng)目中去。