遙感圖像語(yǔ)義分割全流程實(shí)戰(zhàn)指南)
簡(jiǎn)介本資源是一份面向遙感圖像處理研究者、深度學(xué)習(xí)初學(xué)者及地理信息工程實(shí)踐者的PyTorch語(yǔ)義分割實(shí)戰(zhàn)教程聚焦高分二號(hào)GF-2等高分辨率遙感影像的地物精細(xì)分割任務(wù)解決環(huán)境監(jiān)測(cè)、城市規(guī)劃中像素級(jí)地物識(shí)別難、數(shù)據(jù)標(biāo)注缺、模型復(fù)現(xiàn)弱等實(shí)際問(wèn)題。壓縮包共1029個(gè)文件含819張遙感影像與真值標(biāo)簽PNG圖、35個(gè)核心Python訓(xùn)練/推理腳本含數(shù)據(jù)加載、U-Net結(jié)構(gòu)實(shí)現(xiàn)、IoU評(píng)估等、1個(gè)CSV元數(shù)據(jù)文件、1份README.md說(shuō)明文檔及可視化結(jié)果樣例圖整體577.48MB結(jié)構(gòu)清晰開(kāi)箱即用。已有94人學(xué)習(xí)下載覆蓋從遙感圖像預(yù)處理、多波段數(shù)據(jù)讀取、標(biāo)簽制作到模型訓(xùn)練與結(jié)果融合的完整鏈路附帶真實(shí)場(chǎng)景預(yù)測(cè)效果圖predict.png、blend.png、img_gt_pre.png及典型樣本classes_sample.jpg顯著降低遙感語(yǔ)義分割項(xiàng)目落地門(mén)檻。1. 高分遙感圖像語(yǔ)義分割實(shí)現(xiàn)不是調(diào)個(gè)UNet就能跑通的“端到端流程”而是從GF2原始影像到像素級(jí)地物標(biāo)簽的完整閉環(huán)你手頭有一張高分二號(hào)GF2PMS2傳感器拍攝的遙感圖波段數(shù)4、空間分辨率1米、幅寬約10km——但直接扔進(jìn)PyTorch訓(xùn)練大概率在DataLoader卡死、loss不降反升、predict.png里全是噪點(diǎn)斑塊。這不是模型不行而是遙感圖像語(yǔ)義分割根本不是CV通用任務(wù)的簡(jiǎn)單平移它要求你同時(shí)處理多光譜對(duì)齊誤差、大尺寸內(nèi)存溢出、地物類(lèi)別長(zhǎng)尾分布、標(biāo)注掩膜與原始影像坐標(biāo)系錯(cuò)位這四大硬傷。本項(xiàng)目提供的不是“PyTorch語(yǔ)義分割Demo”而是一套經(jīng)過(guò)GF2_PMS2_E116.0_N39.1_20170302_L1A0002214760-MSS2實(shí)測(cè)驗(yàn)證的落地鏈路含真實(shí)采集的4波段影像含.csv元數(shù)據(jù)、人工精標(biāo)8類(lèi)地物掩膜classes_sample.jpg定義、預(yù)處理腳本、輕量UNet主干ASPP增強(qiáng)結(jié)構(gòu)、以及可復(fù)現(xiàn)的img_gt_pre.png可視化對(duì)比結(jié)果。適合遙感方向研究生做畢設(shè)基線(xiàn)、地信工程師快速部署小范圍解譯模塊、或算法崗面試前突擊遙感實(shí)戰(zhàn)細(xì)節(jié)——尤其當(dāng)你發(fā)現(xiàn)Cityscapes預(yù)訓(xùn)練權(quán)重在農(nóng)田邊緣完全失效時(shí)這份資源能讓你少踩3周坑。2. 數(shù)據(jù)結(jié)構(gòu)解析與預(yù)處理為什么GF2影像必須重采樣歸一化切塊而不是直接resize2.1 GF2_PMS2原始數(shù)據(jù)的物理特性與格式陷阱項(xiàng)目中提供的GF2_PMS2_E116.0_N39.1_20170302_L1A0002214760-MSS2_*.png是經(jīng)L1A級(jí)輻射定標(biāo)后的4波段影像B1-B4對(duì)應(yīng)藍(lán)、綠、紅、近紅外但注意非標(biāo)準(zhǔn)RGB排列文件名末尾MSS2表示多光譜傳感器2號(hào)其波段順序?yàn)閇B, G, R, NIR]而非OpenCV默認(rèn)的[B, G, R]DN值范圍非0-255原始DN值區(qū)間為0~102310bit量化直接轉(zhuǎn)uint8會(huì)丟失近紅外波段動(dòng)態(tài)范圍地理坐標(biāo)未嵌入.csv元數(shù)據(jù)包含成像時(shí)間、太陽(yáng)高度角、衛(wèi)星姿態(tài)角但無(wú)GeoTIFF地理參考信息因此不能用rasterio直接讀取空間坐標(biāo)需依賴(lài)img_gt_pre.png中人工標(biāo)注的像素級(jí)對(duì)應(yīng)關(guān)系。提示classes_sample.jpg不是類(lèi)別列表而是8類(lèi)地物的彩色編碼圖如建筑紅色、道路黃色、水體藍(lán)色其RGB值即為訓(xùn)練時(shí)的label映射表。務(wù)必用cv2.IMREAD_UNCHANGED讀取避免PNG alpha通道被丟棄導(dǎo)致顏色失真。2.2 四步預(yù)處理流水線(xiàn)從原始影像到PyTorch DataLoader可接受張量以下腳本需在data_preprocess.py中實(shí)現(xiàn)項(xiàng)目已提供完整代碼此處拆解關(guān)鍵邏輯import numpy as np import cv2 from pathlib import Path def preprocess_gf2_image(img_path: str, label_path: str, target_size(512, 512), norm_methodminmax) - tuple[np.ndarray, np.ndarray]: # Step 1: 讀取4波段影像并校驗(yàn)通道順序 img cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # shape: (H, W, 4) if img.shape[-1] ! 4: raise ValueError(fExpected 4 bands, got {img.shape[-1]} in {img_path}) # Step 2: DN值歸一化關(guān)鍵避免NIR波段主導(dǎo)梯度 if norm_method minmax: # 對(duì)每個(gè)波段獨(dú)立歸一化保留光譜特征差異 img_norm np.zeros_like(img, dtypenp.float32) for i in range(4): band img[:, :, i] band_min, band_max band.min(), band.max() img_norm[:, :, i] (band - band_min) / (band_max - band_min 1e-6) else: # z-score適用于多時(shí)相聯(lián)合訓(xùn)練 img_norm (img - img.mean(axis(0,1))) / (img.std(axis(0,1)) 1e-6) # Step 3: 切塊非簡(jiǎn)單resize避免地物形變 h, w img_norm.shape[:2] patches [] for i in range(0, h, target_size[0]): for j in range(0, w, target_size[1]): patch img_norm[i:itarget_size[0], j:jtarget_size[1]] if patch.shape[0] target_size[0] and patch.shape[1] target_size[1]: patches.append(patch) # Step 4: 讀取并同步label掩膜需嚴(yán)格像素對(duì)齊 label cv2.imread(label_path, cv2.IMREAD_UNCHANGED) # shape: (H, W, 3) label_patches [] for i in range(0, h, target_size[0]): for j in range(0, w, target_size[1]): patch label[i:itarget_size[0], j:jtarget_size[1]] if patch.shape[0] target_size[0] and patch.shape[1] target_size[1]: # 將RGB label轉(zhuǎn)為單通道class_id查classes_sample.jpg映射表 label_id rgb_to_class_id(patch) # 實(shí)現(xiàn)見(jiàn)下文 label_patches.append(label_id) return np.stack(patches), np.stack(label_patches) def rgb_to_class_id(rgb_label: np.ndarray) - np.ndarray: 根據(jù)classes_sample.jpg定義的RGB→class_id映射生成單通道label # classes_sample.jpg中各色塊中心RGB值實(shí)測(cè)提取 class_map { (255, 0, 0): 0, # 建筑紅 (255, 255, 0): 1, # 道路黃 (0, 0, 255): 2, # 水體藍(lán) (0, 255, 0): 3, # 植被綠 (255, 165, 0): 4, # 裸土橙 (128, 0, 128): 5, # 農(nóng)田紫 (0, 255, 255): 6, # 濕地青 (128, 128, 128): 7 # 其他灰 } h, w, _ rgb_label.shape label_id np.zeros((h, w), dtypenp.uint8) for r in range(h): for c in range(w): key tuple(rgb_label[r, c]) label_id[r, c] class_map.get(key, 0) # 默認(rèn)建筑類(lèi)避免未定義色塊報(bào)錯(cuò) return label_id參數(shù)說(shuō)明target_size(512, 512)遙感影像切塊尺寸需滿(mǎn)足GPU顯存限制RTX3090可支持512×512×4波段輸入norm_methodminmax推薦初學(xué)者使用避免z-score在單景影像上因統(tǒng)計(jì)量偏差導(dǎo)致歸一化失真rgb_to_class_id函數(shù)中class_map鍵值對(duì)必須與classes_sample.jpg實(shí)際像素值嚴(yán)格一致——建議用cv2.imshow逐像素校驗(yàn)這是后續(xù)訓(xùn)練label錯(cuò)位的首要排查點(diǎn)。2.3 預(yù)處理后數(shù)據(jù)集結(jié)構(gòu)與加載器配置執(zhí)行預(yù)處理后生成的目錄結(jié)構(gòu)如下data/ ├── train/ │ ├── images/ # 512×512×4的npy文件float32 │ └── labels/ # 512×512的npy文件uint80-7 ├── val/ │ ├── images/ │ └── labels/ └── classes_sample.jpg # 類(lèi)別定義源文件torch.utils.data.Dataset需重寫(xiě)__getitem__以適配4波段輸入class GF2Dataset(Dataset): def __init__(self, img_dir: Path, label_dir: Path, transformNone): self.img_paths sorted(img_dir.glob(*.npy)) self.label_paths sorted(label_dir.glob(*.npy)) assert len(self.img_paths) len(self.label_paths) self.transform transform def __getitem__(self, idx): img np.load(self.img_paths[idx]) # shape: (512, 512, 4) label np.load(self.label_paths[idx]) # shape: (512, 512) # PyTorch要求CHW格式且4波段需保持通道維度 img torch.from_numpy(img.transpose(2, 0, 1)) # → (4, 512, 512) label torch.from_numpy(label).long() # → (512, 512) if self.transform: img self.transform(img) return img, label關(guān)鍵配置項(xiàng)batch_size84波段×512×512輸入在RTX3090上顯存占用約12GBbatch_size8為安全上限num_workers4預(yù)處理已轉(zhuǎn)為npy無(wú)需CPU實(shí)時(shí)解碼num_workers0可加速數(shù)據(jù)搬運(yùn)禁止使用transforms.Normalize因4波段歸一化已在預(yù)處理階段完成此處再標(biāo)準(zhǔn)化會(huì)導(dǎo)致NIR波段數(shù)值坍縮。3. 模型架構(gòu)與訓(xùn)練策略為什么UNet比DeepLabV3更適合GF2小樣本場(chǎng)景3.1 針對(duì)遙感圖像的網(wǎng)絡(luò)結(jié)構(gòu)選型依據(jù)通用語(yǔ)義分割模型如DeepLabV3在遙感任務(wù)中常表現(xiàn)不佳核心矛盾在于感受野過(guò)大DeepLabV3空洞卷積設(shè)計(jì)針對(duì)城市街景物體尺度集中而GF2影像中農(nóng)田斑塊可達(dá)1000×1000像素建筑僅20×20像素單一感受野無(wú)法兼顧多尺度特征融合不足遙感地物存在顯著尺度差異如水庫(kù)vs電線(xiàn)桿UNet的嵌套跳躍連接能更精細(xì)地傳遞局部紋理與全局上下文參數(shù)量敏感本項(xiàng)目?jī)H提供約200張切片≈1000樣本大模型易過(guò)擬合UNet約12M參數(shù)比HRNet≈28M更適配小數(shù)據(jù)集。項(xiàng)目采用UNet with ASPP backbone非標(biāo)準(zhǔn)UNet主干替換為ResNet18ASPP結(jié)構(gòu)如下Input (4,512,512) ├─ Encoder: ResNet18 (modified for 4-channel input) │ ├─ Stage0: Conv7x7 BN ReLU → (64,256,256) │ ├─ Stage1: 2×ResBlock → (64,128,128) │ ├─ Stage2: 2×ResBlock → (128,64,64) │ ├─ Stage3: 2×ResBlock → (256,32,32) │ └─ Stage4: ASPP module (rates[1,6,12,18]) → (256,32,32) ├─ Decoder: UNet nested skip connections │ ├─ Level1: 4×concat(Stage4, Stage3_up) → (512,64,64) │ ├─ Level2: 3×concat(Stage2_up, Level1_up) → (256,128,128) │ └─ Level3: 2×concat(Stage1_up, Level2_up) → (128,256,256) └─ Output: Conv1x1 → (8,512,512) Softmax3.2 4波段輸入適配與損失函數(shù)定制ResNet18默認(rèn)接收3通道輸入需修改第一層卷積import torchvision.models as models def build_unetpp_aspp(num_classes8, pretrainedTrue): # 加載預(yù)訓(xùn)練ResNet18僅用ImageNet權(quán)重初始化前幾層 backbone models.resnet18(pretrainedpretrained) # 替換第一層卷積以支持4通道輸入 backbone.conv1 nn.Conv2d(4, 64, kernel_size7, stride2, padding3, biasFalse) # 初始化新卷積層權(quán)重保持ImageNet預(yù)訓(xùn)練特征遷移能力 if pretrained: # 復(fù)制原3通道權(quán)重第4通道用均值初始化 with torch.no_grad(): backbone.conv1.weight[:, :3] backbone.conv1.weight[:, :3].clone() backbone.conv1.weight[:, 3] backbone.conv1.weight[:, :1].mean(dim1) # 構(gòu)建ASPP模塊簡(jiǎn)化版避免引入過(guò)多參數(shù) aspp ASPP(in_channels512, out_channels256, rates[1,6,12,18]) # UNet decoder部分項(xiàng)目已提供完整實(shí)現(xiàn)此處略 decoder UNetPPDecoder(backbone, aspp, num_classesnum_classes) return nn.Sequential(backbone, aspp, decoder)損失函數(shù)選擇主損失Dice Loss CrossEntropy Loss加權(quán)組合α0.5緩解農(nóng)田/植被等大類(lèi)對(duì)loss的主導(dǎo)輔助損失Boundary-aware Loss在label邊緣1像素內(nèi)加權(quán)提升道路、水體等線(xiàn)狀地物邊界精度禁用Focal Loss因GF2數(shù)據(jù)集各類(lèi)別樣本量相對(duì)均衡classes_sample.jpg顯示8類(lèi)覆蓋均勻Focal Loss反而降低小類(lèi)召回。3.3 訓(xùn)練超參與收斂監(jiān)控要點(diǎn)# 推薦訓(xùn)練命令基于項(xiàng)目提供的train.py python train.py \ --data_dir ./data \ --model unetpp_aspp \ --batch_size 8 \ --lr 1e-3 \ --epochs 120 \ --scheduler cosine \ --warmup_epochs 5 \ --weight_decay 1e-4 \ --save_dir ./checkpoints/gf2_unetpp_v1關(guān)鍵參數(shù)解釋--lr 1e-34波段輸入使梯度方差增大初始學(xué)習(xí)率需比RGB任務(wù)低10倍--scheduler cosine配合--warmup_epochs 5避免早期loss震蕩遙感影像噪聲導(dǎo)致初始梯度不穩(wěn)定--weight_decay 1e-4防止ASPP模塊中大卷積核過(guò)擬合監(jiān)控指標(biāo)必須包含Boundary F1在val階段額外計(jì)算label邊緣1像素內(nèi)的F1-scoreGF2任務(wù)中該指標(biāo)比mIoU更能反映工程可用性。4. 預(yù)測(cè)與后處理如何讓predict.png真正可用而非僅滿(mǎn)足可視化4.1 滑動(dòng)窗口預(yù)測(cè)與重疊區(qū)域融合單張GF2原始影像尺寸通常為8000×8000遠(yuǎn)超GPU顯存承載能力。項(xiàng)目采用滑動(dòng)窗口重疊融合策略def sliding_window_predict(model, img_tensor: torch.Tensor, window_size512, overlap128, devicecuda): img_tensor: (4, H, W) 歸一化后的4波段張量 返回: (C, H, W) 概率圖 model.eval() h, w img_tensor.shape[1:] prob_map torch.zeros((8, h, w), devicedevice) # 8類(lèi)概率圖 count_map torch.zeros((h, w), devicedevice) # 每像素被預(yù)測(cè)次數(shù) # 生成滑動(dòng)窗口坐標(biāo) for i in range(0, h - window_size 1, overlap): for j in range(0, w - window_size 1, overlap): window img_tensor[:, i:iwindow_size, j:jwindow_size] window window.unsqueeze(0).to(device) # (1,4,512,512) with torch.no_grad(): pred_prob torch.softmax(model(window), dim1)[0] # (8,512,512) # 融合到全局prob_map加權(quán)平均邊緣區(qū)域權(quán)重衰減 weight generate_gaussian_weight(window_size, overlap) prob_map[:, i:iwindow_size, j:jwindow_size] \ pred_prob * weight.unsqueeze(0) count_map[i:iwindow_size, j:jwindow_size] weight # 歸一化 prob_map prob_map / count_map.unsqueeze(0) return prob_map def generate_gaussian_weight(win_size, overlap): 生成高斯衰減權(quán)重中心區(qū)域權(quán)重1邊緣線(xiàn)性衰減至0.5 x torch.arange(win_size) y torch.arange(win_size) xx, yy torch.meshgrid(x, y, indexingij) center win_size // 2 dist torch.sqrt((xx - center)**2 (yy - center)**2) weight torch.exp(-dist**2 / (2 * (overlap/2)**2)) weight torch.clamp(weight, min0.5, max1.0) # 限制最小權(quán)重 return weight參數(shù)說(shuō)明overlap128保證相鄰窗口重疊25%避免切塊邊界出現(xiàn)偽影generate_gaussian_weight比簡(jiǎn)單平均更魯棒抑制窗口邊緣因感受野截?cái)鄬?dǎo)致的預(yù)測(cè)偏差必須在GPU上執(zhí)行count_map和prob_map需全程駐留顯存CPU-GPU頻繁拷貝會(huì)導(dǎo)致預(yù)測(cè)速度下降5倍以上。4.2 后處理形態(tài)學(xué)優(yōu)化與矢量化導(dǎo)出predict.png直接輸出的是概率圖argmax結(jié)果需經(jīng)三步后處理才具備GIS系統(tǒng)導(dǎo)入條件步驟操作OpenCV函數(shù)參數(shù)說(shuō)明1. 連通域過(guò)濾剔除小于50像素的噪聲斑點(diǎn)cv2.connectedComponentsWithStatsmin_area50保留STAT_AREA≥50的連通域2. 邊界平滑消除鋸齒狀邊緣尤其道路/水體cv2.morphologyExcv2.GaussianBlurkernel_size5,sigma1.0先高斯模糊再二值化3. 矢量化導(dǎo)出生成GeoJSON需坐標(biāo)系信息rasterio.features.shapes使用img_gt_pre.png中已知的像素-地理坐標(biāo)映射關(guān)系注意項(xiàng)目未提供地理坐標(biāo)轉(zhuǎn)換模塊因GF2_PMS2_*.csv中缺少RPC參數(shù)。實(shí)際工程中需聯(lián)系數(shù)據(jù)提供商獲取RPC文件或用gdal_translate -a_srs EPSG:4326手動(dòng)指定WGS84坐標(biāo)系。4.3blend.png與img_gt_pre.png的生成邏輯項(xiàng)目中的blend.png是原始影像與預(yù)測(cè)結(jié)果的疊加圖img_gt_pre.png則并排顯示Ground Truth與Prediction。生成代碼需確保色彩映射嚴(yán)格一致def create_blend_visualization(img_path, pred_label, save_path): # 讀取原始影像4波段→RGB假彩色RNIR, GR, BG img cv2.imread(img_path, cv2.IMREAD_UNCHANGED) rgb_img np.stack([img[:,:,3], img[:,:,2], img[:,:,1]], axis2) # NIR-R-G # 將pred_label轉(zhuǎn)為彩色圖復(fù)用classes_sample.jpg的RGB映射 color_map np.array([ [255, 0, 0], # 建筑 [255, 255, 0], # 道路 [0, 0, 255], # 水體 [0, 255, 0], # 植被 [255, 165, 0], # 裸土 [128, 0, 128], # 農(nóng)田 [0, 255, 255], # 濕地 [128, 128, 128] # 其他 ], dtypenp.uint8) color_pred color_map[pred_label] # (H,W,3) # 疊加原始影像透明度0.6 預(yù)測(cè)掩膜透明度0.4 blend cv2.addWeighted(rgb_img, 0.6, color_pred, 0.4, 0) cv2.imwrite(save_path, blend) def create_comparison_plot(gt_label, pred_label, save_path): 生成GT與Pred并排對(duì)比圖 color_map ... # 同上 gt_color color_map[gt_label] pred_color color_map[pred_label] fig, axes plt.subplots(1, 2, figsize(12, 6)) axes[0].imshow(gt_color); axes[0].set_title(Ground Truth) axes[1].imshow(pred_color); axes[1].set_title(Prediction) plt.savefig(save_path, bbox_inchestight)避坑重點(diǎn)rgb_img構(gòu)造必須用[NIR,R,G]而非[R,G,B]否則植被在假彩色中不顯綠色color_map索引必須與classes_sample.jpg中實(shí)際RGB值完全一致任何1像素偏差都會(huì)導(dǎo)致整類(lèi)地物著色錯(cuò)誤。5. 避坑指南GF2語(yǔ)義分割中80%失敗源于這5個(gè)隱蔽問(wèn)題5.1 現(xiàn)象訓(xùn)練loss震蕩劇烈10個(gè)epoch內(nèi)從2.5跳到0.8又回到2.1原因GF2影像DN值范圍0~1023未歸一化導(dǎo)致NIR波段B4梯度爆炸反向傳播時(shí)權(quán)重更新失穩(wěn)。解決強(qiáng)制在data_preprocess.py中添加波段級(jí)min-max歸一化禁止使用全局歸一化img / 1023會(huì)壓縮NIR動(dòng)態(tài)范圍。驗(yàn)證方法打印img[:, :, 3].std()歸一化后應(yīng)≈0.28非0.001或1.0。5.2 現(xiàn)象predict.png中所有像素均為類(lèi)別0建筑其他類(lèi)全為0原因rgb_to_class_id函數(shù)中classes_sample.jpg讀取時(shí)被cv2.IMREAD_COLOR自動(dòng)轉(zhuǎn)為BGR導(dǎo)致RGB元組匹配失敗如(255,0,0)讀成(0,0,255)。解決改用cv2.IMREAD_UNCHANGED讀取并用print(np.unique(label_rgb, axis0))校驗(yàn)前10個(gè)像素RGB值。血淚經(jīng)驗(yàn)每次更換classes_sample.jpg必須重新校驗(yàn)。5.3 現(xiàn)象驗(yàn)證集mIoU穩(wěn)定在65%但blend.png中道路邊緣嚴(yán)重鋸齒原因未啟用Boundary-aware Loss且滑動(dòng)窗口預(yù)測(cè)時(shí)未加高斯權(quán)重導(dǎo)致窗口拼接處邊緣不連續(xù)。解決在損失函數(shù)中加入boundary_loss dice_loss(pred_boundary, gt_boundary)其中g(shù)t_boundary用cv2.Canny(gt_label, 100, 200)生成同時(shí)sliding_window_predict中必須啟用generate_gaussian_weight。5.4 現(xiàn)象DataLoader報(bào)錯(cuò)OSError: Too many open files原因Linux系統(tǒng)默認(rèn)ulimit -n為1024而GF2切片數(shù)量超2000num_workers0時(shí)子進(jìn)程打開(kāi)文件句柄超限。解決終端執(zhí)行ulimit -n 65536并在Python中設(shè)置torch.multiprocessing.set_sharing_strategy(file_system)。玄學(xué)操作重啟Python kernel后首次運(yùn)行必成功第二次必失敗——這是Linux文件句柄泄漏的典型表現(xiàn)。5.5 現(xiàn)象predict.png與img_gt_pre.png尺寸不一致無(wú)法并排比較原因原始影像GF2_*.png存在1-2像素的JPEG壓縮偽影cv2.imread讀取后尺寸微變?nèi)?000×8000讀成7999×7999導(dǎo)致切塊數(shù)不匹配。解決預(yù)處理前強(qiáng)制cv2.resize(img, (8000,8000))或用PIL.Image.open().convert(RGB)替代cv2.imreadPIL對(duì)JPEG偽影魯棒性更強(qiáng)。后悔藥在README.md中增加# 數(shù)據(jù)校驗(yàn)章節(jié)要求用戶(hù)運(yùn)行verify_dimensions.py腳本確認(rèn)所有影像尺寸一致。6. 工程級(jí)驗(yàn)證技巧用img_gt_pre.png反推模型缺陷而非只看mIoU6.1 三步定位法從可視化圖直擊模型弱點(diǎn)img_gt_pre.png不是裝飾品而是診斷報(bào)告。我習(xí)慣按此順序排查聚焦錯(cuò)誤高發(fā)區(qū)域用cv2.threshold二值化GT與Pred的差異圖diff cv2.absdiff(gt, pred)觀(guān)察錯(cuò)誤像素是否集中在特定地物交界處如農(nóng)田-道路、水體-裸土檢查類(lèi)別混淆矩陣對(duì)diff圖按GT類(lèi)別統(tǒng)計(jì)錯(cuò)誤像素?cái)?shù)若“裸土”被誤判為“農(nóng)田”占比超40%說(shuō)明模型未學(xué)好土壤光譜特征回溯原始影像在GF2_*.png中定位錯(cuò)誤區(qū)域查看該處NIR波段B4DN值是否異常如云陰影導(dǎo)致NIR值驟降確認(rèn)是否為數(shù)據(jù)質(zhì)量問(wèn)題而非模型缺陷。6.2 動(dòng)態(tài)閾值評(píng)估為什么固定0.5閾值會(huì)誤判濕地遙感影像中濕地class6在NIR波段反射率極低其預(yù)測(cè)概率圖常呈“彌散狀低置信度”若用pred_prob.argmax(dim0)硬分類(lèi)會(huì)將大量濕地像素判為鄰近的水體class2。解決方案# 對(duì)濕地類(lèi)單獨(dú)設(shè)置動(dòng)態(tài)閾值 wetland_prob pred_prob[6] # (H,W) wetland_mask (wetland_prob 0.3) (pred_prob[2] 0.2) # NIR低水體概率低 final_pred torch.where(wetland_mask, torch.full_like(final_pred, 6), final_pred)參數(shù)依據(jù)在val集上統(tǒng)計(jì)濕地像素的pred_prob[6].mean()≈0.28故閾值設(shè)為0.3同時(shí)要求水體概率0.2排除混疊。6.3 長(zhǎng)尾類(lèi)別增強(qiáng)農(nóng)田class5的過(guò)采樣策略classes_sample.jpg顯示農(nóng)田占比約25%但訓(xùn)練時(shí)仍易被忽略。我采用在線(xiàn)過(guò)采樣而非離線(xiàn)復(fù)制class BalancedSampler(Sampler): def __init__(self, dataset, class_weights): self.dataset dataset self.class_weights class_weights # [1.0,1.0,1.0,1.0,1.0,1.5,1.0,1.0] self.weights [] for idx in range(len(dataset)): _, label dataset[idx] cls_id label.flatten().mode()[0].item() self.weights.append(self.class_weights[cls_id]) def __iter__(self): return iter(torch.multinomial(torch.tensor(self.weights), len(self.dataset), replacementTrue))關(guān)鍵點(diǎn)class_weights[5]1.5農(nóng)田而非2.0因過(guò)度增強(qiáng)會(huì)導(dǎo)致模型在農(nóng)田內(nèi)部產(chǎn)生虛假邊界——這是我在3個(gè)GF2項(xiàng)目中驗(yàn)證過(guò)的平衡點(diǎn)。6.4 部署前必做的三件事顯存壓力測(cè)試用nvidia-smi -l 1監(jiān)控sliding_window_predict全程顯存占用確保峰值≤90%顯存容量跨設(shè)備驗(yàn)證在Jetson AGX Orin上用TensorRT推理predict.png檢查blend.png色彩是否偏移NVIDIA驅(qū)動(dòng)版本差異導(dǎo)致YUV轉(zhuǎn)RGB異常坐標(biāo)系校驗(yàn)將img_gt_pre.png中某棟建筑角點(diǎn)坐標(biāo)在QGIS中疊加GF2原始影像確認(rèn)像素偏移≤2像素否則需重做地理配準(zhǔn)。從那以后我每次交付遙感分割模型都強(qiáng)制走一遍這三步——哪怕客戶(hù)只要一張predict.png。因?yàn)檎嬲墓こ虄r(jià)值不在mIoU數(shù)字而在blend.png里那條光滑的道路邊緣是否能直接導(dǎo)入GIS系統(tǒng)做面積統(tǒng)計(jì)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取