news 2026/9/12 8:42:05

遥感图像语义分割实战:从U-Net原理到PyTorch完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
遥感图像语义分割实战:从U-Net原理到PyTorch完整实现

1. 项目概述:从竞赛题目到实战方案的跨越

看到“遥感图像地块分割与提取”这个题目,很多刚接触计算机视觉和地理信息处理的朋友可能会觉得头大。这不就是2020年MathorCup高校数学建模挑战赛大数据竞赛的B题嘛。当年这道题把不少队伍难住了,因为它完美地卡在了传统图像处理和现代深度学习的交叉点上。简单来说,题目给出一堆卫星或航拍得到的遥感图像,要求我们像“看图说话”一样,把图像里不同性质的地块——比如建筑、道路、植被、水体——自动地、精确地给圈出来,形成一个分割好的掩膜图。这活儿,人眼干起来都费劲,更别说让机器来做了。

但恰恰是这种有挑战性的问题,才是我们练手和积累经验的好机会。这道题的核心,本质上是一个语义分割任务,而且是针对遥感这种特殊图像的语义分割。遥感图像和咱们平时用手机拍的照片有啥不同?首先是“上帝视角”,视角是垂直向下的;其次是通道多,除了红绿蓝,经常还有近红外等波段,信息量巨大;再者是尺度多变,一栋楼在图像里可能就几个像素,一片森林又铺满整张图;最后是目标形态极其不规则,农田的边界弯弯曲曲,河流的走向九曲十八弯。这些特点决定了,直接用为自然图像设计的模型,效果往往打折扣。

所以,这个项目不只是简单地跑通一个模型,它涉及从数据理解、预处理、模型选型与调优、后处理到结果评估的全链条。网上相关的讨论和代码很多,但要么过于理论,要么就是“魔术代码”(跑起来不知所以然)。今天,我就以这道竞赛题为背景,结合这几年在实际项目和研究中趟过的坑,把遥感地块分割这件事,从思路到代码,掰开揉碎了讲清楚。无论你是想复现竞赛方案的学生,还是希望将深度学习应用于国土调查、农业监测、城市规划等领域的工程师,这篇文章都能给你提供一条清晰的、可落地的路径。

2. 核心思路拆解:为什么是U-Net及其变种?

面对遥感图像分割,第一个灵魂拷问就是:用什么模型?卷积神经网络(CNN)无疑是基石,但CNN家族庞大,选择很多。题目相关热词里高频出现的“U-Net”,已经给了我们强烈的提示。这绝非偶然,U-Net在生物医学图像分割领域一战成名后,迅速“出圈”到遥感领域,并成为许多比赛的基线模型和实际项目的首选。我们来深挖一下这背后的逻辑。

2.1 遥感图像分割的独特挑战与模型需求

首先,我们必须明确遥感分割任务给模型提出的几个核心要求:

  1. 处理高分辨率与大尺寸图像:遥感图动不动就是几千x几千像素,无法直接整张输入网络。需要裁剪(Crop)或下采样,但又要保证细节不丢失。
  2. 融合多尺度上下文信息:既要能识别大片的均质区域(如湖泊),也要能分割出细长的线性目标(如道路、田埂)。
  3. 精确的边界定位:地块的边界往往是评估分割质量的关键,模糊的边界会导致面积计算等后续应用产生巨大误差。
  4. 相对较小的训练数据集:标注遥感图像是件极其昂贵和专业的事情,竞赛或特定项目的数据量通常有限,模型不能有太高的数据饥渴度。

基于这些需求,我们来看模型架构的进化。传统的全卷积网络(FCN)是语义分割的开山鼻祖,但它有一个问题:通过多次下采样(池化或跨步卷积)后,特征图的空间分辨率损失严重,即使通过上采样恢复,细节(尤其是边界)也模糊了。这对于需要精确边界的遥感分割来说是致命的。

2.2 U-Net的“编码器-解码器”与“跳跃连接”机制

U-Net的经典结构完美回应了上述挑战。它的形状像一个“U”型,因此得名。

  • 左侧编码器(收缩路径):和普通的CNN分类网络(如VGG)类似,通过卷积和池化层层下采样,提取图像的深层、抽象特征,捕获“这是什么”的语义信息。这个过程会牺牲空间分辨率。
  • 右侧解码器(扩张路径):通过转置卷积或上采样操作,逐步将特征图的空间尺寸放大回去,恢复“这东西在哪”的位置信息。
  • 核心精髓——跳跃连接:这是U-Net的灵魂。它将编码器每一层的高分辨率、富含细节的特征图,直接拼接到解码器对应层的特征图上。这就好比在解码器努力“回忆”细节时,直接把编码器当时“看到”的清晰照片给它看。这种操作极大地缓解了细节丢失问题,让模型能预测出边界清晰的分割图。

对于遥感图像,跳跃连接传递的细节,正是那些田埂、道路边缘、建筑物轮廓的关键信息。同时,U-Net的对称结构使其参数量相对可控,在中等规模的数据集上也能得到良好的训练效果,避免了过拟合。

2.3 超越基础U-Net:针对遥感特性的改进思路

基础U-Net很强,但我们可以让它更强,更适应遥感场景。

  • 更强大的编码器(Backbone):把U-Net的编码器从简单的卷积堆叠,替换为在ImageNet上预训练过的成熟网络,如ResNet、VGG、EfficientNet等。这相当于给模型装上一个“知识渊博”的眼睛,能提取更鲁棒、更具判别力的特征。这是提升模型性能最直接有效的方法之一。
  • 注意力机制:遥感图像中常有无关背景的干扰。引入注意力模块(如SENet中的通道注意力,或CBAM中的空间+通道注意力),让模型学会“聚焦”在重要的地块区域,抑制背景噪声。
  • 多尺度特征融合:在解码器部分,不仅融合对应层的特征,还可以融合来自编码器不同尺度的特征(如使用特征金字塔网络FPN的思想),让模型同时拥有“望远镜”(看全局)和“显微镜”(看细节)的能力。
  • 针对小目标的优化:遥感图像中小目标(车辆、小型建筑)多。可以在浅层特征(分辨率高)上添加辅助分割头,进行深监督,强化模型对小目标的识别能力。

在竞赛或项目初期,我强烈建议从带ResNet34/50编码器的U-Net开始。它在性能、速度和复杂度之间取得了很好的平衡,有大量的开源实现可供参考和修改。

3. 实战全流程解析:从数据到预测

理论说得再多,不如一行代码。接下来,我们进入实战环节。我将以Python为工具,使用PyTorch框架,带你走完一个完整的遥感图像分割Pipeline。这里假设我们的数据是RGB三通道的遥感图像和对应的单通道标签图(每个像素的值为类别ID,如0背景,1建筑,2植被等)。

3.1 数据准备与预处理:磨刀不误砍柴工

数据处理是机器学习项目成功的一半,对于遥感图像更是如此。

1. 数据读取与检查

import os import numpy as np from PIL import Image import matplotlib.pyplot as plt # 假设数据组织方式 # data/train/images/xxx.tif # data/train/masks/xxx.tif # data/val/... 同理 def read_image_mask(img_path, mask_path): # 读取图像,遥感图像可能是.tif格式,PIL或OpenCV均可 image = np.array(Image.open(img_path).convert('RGB')) # 确保为RGB mask = np.array(Image.open(mask_path)) # 单通道标签 return image, mask # 检查一张样本 img, mask = read_image_mask('data/train/images/sample.tif', 'data/train/masks/sample.tif') print(f"Image shape: {img.shape}, dtype: {img.dtype}, value range: [{img.min()}, {img.max()}]") print(f"Mask shape: {mask.shape}, unique values: {np.unique(mask)}") # 可视化 fig, axes = plt.subplots(1, 2, figsize=(10,5)) axes[0].imshow(img) axes[0].set_title('Original Image') axes[0].axis('off') axes[1].imshow(mask, cmap='jet') # 使用色彩映射显示类别 axes[1].set_title('Ground Truth Mask') axes[1].axis('off') plt.show()

注意:务必检查mask的像素值。有的数据集标签从0开始(0=背景),有的从1开始。需要统一并确认类别数量。同时,遥感图像的像素值范围可能不是标准的0-255,可能是16位数据,需要进行归一化。

2. 数据增强(Data Augmentation)数据量小?增强来凑。遥感图像的增强要符合其物理意义。

  • 几何变换:随机水平/垂直翻转、随机旋转(90,180,270度)、随机裁剪。这些变换不会改变地物的语义。
  • 颜色变换:轻微调整亮度、对比度、饱和度。模拟不同光照、天气条件下的成像效果。
  • 高级增强:MixUp, CutMix等,在遥感领域需谨慎使用,因为可能破坏地物的空间连续性。

我推荐使用albumentations库,它专门为图像分割任务设计,能同步处理图像和掩膜。

import albumentations as A # 定义训练和验证阶段的增强策略 train_transform = A.Compose([ A.RandomRotate90(p=0.5), A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), A.RandomBrightnessContrast(brightness_limit=0.1, contrast_limit=0.1, p=0.3), A.OneOf([ # 随机选择一种弹性或网格形变 A.GridDistortion(distort_limit=0.1, p=0.5), A.ElasticTransform(alpha=1, sigma=50, alpha_affine=50, p=0.5), ], p=0.3), # 最重要的:随机裁剪到网络输入尺寸 A.RandomCrop(height=256, width=256, p=1.0), A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), # ImageNet统计量,适用性强 ]) val_transform = A.Compose([ A.CenterCrop(height=256, width=256, p=1.0), # 验证集采用中心裁剪,保证确定性 A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ])

3. 自定义Dataset类这是PyTorch数据加载的核心。

from torch.utils.data import Dataset, DataLoader class RemoteSensingDataset(Dataset): def __init__(self, image_dir, mask_dir, transform=None): self.image_dir = image_dir self.mask_dir = mask_dir self.transform = transform self.images = sorted(os.listdir(image_dir)) self.masks = sorted(os.listdir(mask_dir)) # 简单检查文件名是否对应 assert len(self.images) == len(self.masks), "图像和掩膜数量不匹配!" for img, msk in zip(self.images, self.masks): assert os.path.splitext(img)[0] == os.path.splitext(msk)[0], f"文件名不匹配: {img} vs {msk}" def __len__(self): return len(self.images) def __getitem__(self, idx): img_path = os.path.join(self.image_dir, self.images[idx]) mask_path = os.path.join(self.mask_dir, self.masks[idx]) image = np.array(Image.open(img_path).convert('RGB')) mask = np.array(Image.open(mask_path)) if self.transform: augmented = self.transform(image=image, mask=mask) image = augmented['image'] mask = augmented['mask'] # 转换维度:numpy (H, W, C) -> torch (C, H, W) image = image.transpose(2, 0, 1).astype(np.float32) mask = mask.astype(np.int64) # 分类任务,标签需要是Long类型 return torch.tensor(image), torch.tensor(mask) # 创建数据加载器 train_dataset = RemoteSensingDataset('data/train/images', 'data/train/masks', transform=train_transform) val_dataset = RemoteSensingDataset('data/val/images', 'data/val/masks', transform=val_transform) train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True, num_workers=4, pin_memory=True) val_loader = DataLoader(val_dataset, batch_size=4, shuffle=False, num_workers=4, pin_memory=True)

3.2 模型构建:搭建一个加强版U-Net

我们不从零造轮子,利用segmentation_models_pytorch这个优秀的库,它可以快速搭建各种分割模型。

pip install segmentation-models-pytorch
import torch import torch.nn as nn import segmentation_models_pytorch as smp # 定义模型 model = smp.Unet( encoder_name="resnet34", # 编码器 backbone,可选 'resnet50', 'efficientnet-b3' 等 encoder_weights="imagenet", # 使用在ImageNet上预训练的权重,加速收敛 in_channels=3, # 输入通道数,RGB图为3 classes=5, # 分割类别数(包括背景) activation=None, # 输出层不设激活,后面接CrossEntropyLoss ) # 将模型移动到GPU device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = model.to(device) print(model)

这个简单的几行代码,我们就得到了一个编码器为ResNet34、带有预训练权重的U-Net。segmentation_models_pytorch库内部已经实现了跳跃连接等复杂结构,让我们可以专注于调参和训练。

3.3 训练策略与损失函数选择

训练语义分割网络,损失函数的选择至关重要。

1. 损失函数(Loss Function)

  • 交叉熵损失(CrossEntropyLoss):最基础、最常用的选择。但它有一个潜在问题:当类别极度不均衡时(遥感中背景像素往往占大多数),模型会倾向于预测主导类别,导致小类别(如道路)难以学习。
  • Dice Loss / Focal Loss / Tversky Loss:这些是解决类别不平衡的利器。
    • Dice Loss:直接优化Dice系数,对前景像素(非背景)的预测错误更敏感,非常适合分割任务。
    • Focal Loss:通过降低易分类样本的权重,让模型更关注难分的样本(如边界、小物体)。
    • 组合损失:我个人的经验是,CrossEntropyLoss + Dice Loss的组合在很多遥感数据集上表现稳健。前者保证分类概率分布合理,后者直接优化分割重叠度。
# 定义组合损失 class CombinedLoss(nn.Module): def __init__(self, alpha=0.5): super().__init__() self.alpha = alpha self.ce_loss = nn.CrossEntropyLoss() self.dice_loss = smp.losses.DiceLoss(mode='multiclass') # 使用smp中的DiceLoss def forward(self, pred, target): ce = self.ce_loss(pred, target) dice = self.dice_loss(pred, target) return self.alpha * ce + (1 - self.alpha) * dice criterion = CombinedLoss(alpha=0.5).to(device)

2. 评估指标(Metrics)不能只看Loss,必须看客观指标。

  • 交并比(IoU, Intersection over Union):每个类别的预测区域与真实区域交集与并集的比值。这是分割任务的核心指标。
  • 平均IoU(mIoU):所有类别IoU的平均值,是衡量模型整体性能的黄金标准。
  • 像素精度(Pixel Accuracy):整体分类正确的像素比例,但在类别不均衡时参考价值有限。
# 使用smp.utils.metrics计算 from segmentation_models_pytorch.utils.metrics import IoU iou_metric = IoU(threshold=0.5, ignore_channels=[0]) # 可以忽略背景类

3. 优化器与学习率调度

import torch.optim as optim from torch.optim import lr_scheduler optimizer = optim.AdamW(model.parameters(), lr=1e-4, weight_decay=1e-4) # AdamW通常比Adam更稳定 # 使用余弦退火学习率调度,配合热启动(Warmup)效果更好 scheduler = lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=10, T_mult=2, eta_min=1e-6)

3.4 训练循环与模型验证

这是将一切串联起来的核心代码块。

def train_one_epoch(model, dataloader, criterion, optimizer, device, epoch): model.train() running_loss = 0.0 for images, masks in dataloader: images, masks = images.to(device), masks.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, masks) loss.backward() optimizer.step() running_loss += loss.item() * images.size(0) epoch_loss = running_loss / len(dataloader.dataset) print(f'Epoch [{epoch+1}], Train Loss: {epoch_loss:.4f}') return epoch_loss def validate(model, dataloader, criterion, device, metric): model.eval() running_loss = 0.0 metric.reset() with torch.no_grad(): for images, masks in dataloader: images, masks = images.to(device), masks.to(device) outputs = model(images) loss = criterion(outputs, masks) running_loss += loss.item() * images.size(0) # 计算指标,需要将输出转换为预测类别 preds = torch.argmax(outputs, dim=1) metric.update(preds, masks) epoch_loss = running_loss / len(dataloader.dataset) epoch_iou = metric.evaluate() print(f'Validation Loss: {epoch_loss:.4f}, IoU: {epoch_iou:.4f}') return epoch_loss, epoch_iou # 主训练循环 num_epochs = 50 best_iou = 0.0 for epoch in range(num_epochs): train_loss = train_one_epoch(model, train_loader, criterion, optimizer, device, epoch) val_loss, val_iou = validate(model, val_loader, criterion, device, iou_metric) scheduler.step() # 更新学习率 # 保存最佳模型 if val_iou > best_iou: best_iou = val_iou torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), 'best_iou': best_iou, }, 'best_model.pth') print(f'>>> Best model saved with IoU: {best_iou:.4f}')

3.5 预测与后处理

训练好模型后,如何对新的全尺寸大图进行预测?由于显存限制,我们需要采用滑动窗口预测的策略。

def predict_large_image(model, large_img, window_size=256, stride=128, device='cuda'): """ 使用滑动窗口预测大图 Args: model: 训练好的模型 large_img: 大尺寸numpy图像,形状 (H, W, C) window_size: 窗口大小 stride: 滑动步长,小于window_size以实现重叠 device: 计算设备 Returns: full_mask: 预测的全图掩膜,形状 (H, W) """ model.eval() h, w, _ = large_img.shape # 初始化全图预测概率图和计数图 full_probs = np.zeros((h, w, num_classes), dtype=np.float32) count_map = np.zeros((h, w), dtype=np.float32) # 预处理归一化(与训练时一致) norm = A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) large_img_norm = norm(image=large_img)['image'].transpose(2, 0, 1) # (C, H, W) with torch.no_grad(): for y in range(0, h, stride): for x in range(0, w, stride): # 提取窗口 y_end = min(y + window_size, h) x_end = min(x + window_size, w) window = large_img_norm[:, y:y_end, x:x_end] # 如果窗口小于指定尺寸,进行填充 if window.shape[1] < window_size or window.shape[2] < window_size: pad_h = window_size - window.shape[1] pad_w = window_size - window.shape[2] window = np.pad(window, ((0,0), (0,pad_h), (0,pad_w)), mode='constant') window_tensor = torch.from_numpy(window).unsqueeze(0).float().to(device) output = model(window_tensor) # (1, C, H, W) probs = torch.softmax(output, dim=1).squeeze(0).cpu().numpy() # (C, H, W) probs = probs.transpose(1, 2, 0) # (H, W, C) # 将窗口预测结果累加到全图上 actual_h, actual_w = y_end - y, x_end - x full_probs[y:y_end, x:x_end, :] += probs[:actual_h, :actual_w, :] count_map[y:y_end, x:x_end] += 1 # 平均重叠区域的预测 count_map[count_map == 0] = 1 # 避免除零 full_probs /= count_map[..., np.newaxis] # 取概率最大的类别作为最终预测 full_mask = np.argmax(full_probs, axis=2).astype(np.uint8) return full_mask

实操心得:滑动窗口的stride通常设为window_size的一半或三分之二,重叠预测可以平滑边界,减少窗口边缘的割裂感。后处理还可以加入条件随机场(CRF)来优化边界,但会增加计算量,需权衡。

4. 性能优化与高级技巧

当你的基础模型跑通后,下一步就是思考如何让它更快、更准、更稳。

4.1 针对遥感图像的特定优化策略

  1. 多尺度训练与测试(TTA)

    • 训练时:除了固定尺寸裁剪,可以尝试多尺度随机裁剪(如256, 384, 512),让模型学会适应不同尺度的目标。
    • 测试时增强(TTA):对同一张预测图像,进行水平翻转、垂直翻转、旋转等操作,分别预测,然后将结果平均或投票。这是一个几乎无成本的提分技巧,通常能稳定提升mIoU 0.5-2个百分点。
  2. 类别权重与样本权重

    • 如果某些类别(如“道路”)的像素数量远少于其他类别,可以在损失函数中为其赋予更高的权重。在CrossEntropyLoss中,可以通过weight参数实现。
    • 更精细的做法是计算每个样本的难度(如预测损失),动态调整其在训练中的权重(如在线难例挖掘OHEM的思想)。
  3. 利用多波段信息:如果数据包含近红外等额外波段,不要浪费。将这些通道一并输入网络(调整in_channels参数),能显著提升对植被、水体等地物的区分能力。

4.2 模型集成与知识蒸馏

如果追求极致的竞赛成绩,模型集成是必经之路。

  • 简单集成:训练多个不同架构的模型(如U-Net with ResNet34, DeepLabV3+, PSPNet),或者同一架构不同初始化的模型,在预测时对它们的输出概率进行平均。
  • 知识蒸馏:用一个庞大复杂的“教师模型”去指导一个轻量级的“学生模型”训练,让学生模型在保持较小体积的同时,逼近教师模型的性能。这对于后续模型部署到边缘设备非常有用。

4.3 工程化与部署考量

从实验到应用,还有最后一公里。

  • 模型量化:使用PyTorch的量化工具,将FP32的模型转换为INT8,可以大幅减少模型体积、提升推理速度,对精度影响通常很小。
  • 使用TensorRT或ONNX Runtime加速:对于生产环境,可以将PyTorch模型导出为ONNX格式,然后利用NVIDIA的TensorRT或ONNX Runtime进行优化和加速,获得数倍的推理性能提升。
  • 构建推理服务:使用FastAPI或Flask等框架,将模型封装成RESTful API服务,方便与其他系统(如GIS平台)集成。

5. 避坑指南与常见问题排查

这条路我踩过不少坑,希望你能绕过去。

5.1 训练阶段常见问题

问题1:Loss不下降或震荡剧烈。

  • 检查数据:首先可视化几个批次的数据和标签,确保数据加载和增强是正确的,图像和掩膜是对齐的。
  • 检查学习率:学习率太大是主要原因。尝试使用更小的学习率(如1e-5),并配合学习率监控。使用torch.optim.lr_scheduler.ReduceLROnPlateau在指标停滞时自动降低学习率是个好习惯。
  • 检查损失函数:如果使用自定义损失,确保其实现正确,没有数值不稳定(如Dice Loss分母加平滑项epsilon)。
  • 检查标签范围:确保你的掩膜标签值在[0, num_classes-1]的连续整数范围内。一个常见的错误是背景标签为255,这会导致CrossEntropyLoss出错。

问题2:模型过拟合,训练集IoU很高,验证集很低。

  • 增强数据:加强数据增强的力度,特别是随机裁剪、颜色抖动和几何形变。
  • 正则化:增加weight_decay(L2正则化),使用Dropout(可以在U-Net的解码器部分添加)。
  • 简化模型:如果数据量真的很少,考虑使用更轻量的编码器(如ResNet18)或减少网络通道数。
  • 早停:监控验证集指标,当其在连续多个epoch不再提升时,果断停止训练。

问题3:某些类别(如“道路”)永远学不好。

  • 类别不平衡:这是最可能的原因。采用Dice Loss、Focal Loss或为小类别设置更高的损失权重。
  • 数据问题:检查训练数据中是否包含足够多的、有代表性的该类别样本。可能需要人工补充标注。
  • 模型容量:小目标需要更精细的特征。尝试使用更高分辨率的输入,或者在浅层特征上添加辅助损失进行深监督。

5.2 预测阶段常见问题

问题1:预测结果有明显的网格状伪影。

  • 原因:这是滑动窗口预测时,窗口间重叠不足或后处理平均不当造成的。
  • 解决:减小滑动步长stride,增加重叠区域。使用高斯加权而不是简单平均来融合重叠区域的预测(窗口中心区域权重高,边缘权重低)。

问题2:对大图预测时显存溢出(OOM)。

  • 解决:减小window_size。如果已经很小了,可以尝试在预测时将图像预先下采样到一个中等尺寸,预测出掩膜后再上采样回原尺寸。虽然会损失细节,但可以处理极大尺寸的图片。

问题3:模型推理速度太慢。

  • 分析瓶颈:使用PyTorch的torch.utils.bottleneckprofiler工具分析代码,看时间是耗在数据加载、模型前向传播还是后处理上。
  • 优化:数据加载使用多进程和pin_memory;模型推理时使用torch.no_grad()model.eval();考虑使用半精度(torch.cuda.amp)进行推理;最终部署时采用前面提到的量化、TensorRT等方法。

5.3 一个实用的调试清单

当你遇到奇怪的问题时,可以按此清单逐一排查:

  1. [ ]数据层面:随机可视化几个训练样本,图像和标签是否对应?像素值范围是否正常?增强效果是否符合预期?
  2. [ ]输入层面:输入网络的Tensor形状是否正确?(B, C, H, W)。数值是否经过归一化?
  3. [ ]输出层面:模型输出的形状是否正确?(B, Num_Classes, H, W)。对于分割任务,通常不需要在输出层加激活函数(如Softmax),因为CrossEntropyLoss内部包含了LogSoftmax。
  4. [ ]损失计算:手动计算一个批次数据的损失,看是否合理。尝试用一个非常简单的样本(如全0的预测和标签)验证损失函数。
  5. [ ]梯度检查:在训练初期,检查模型参数的梯度是否不为None且不是全零。可以使用torch.autograd.grad或简单的loss.backward()后打印某层权重的grad属性。
  6. [ ]学习率:使用学习率查找器(如torch-lr-finder)或简单的线性扫描,找到一个合适的初始学习率。

遥感图像地块分割是一个充满乐趣和挑战的领域,它连接了人工智能与地理空间信息。从理解U-Net为何有效,到亲手处理数据、搭建模型、调参优化,再到最后看到模型准确地勾勒出大地上的每一块脉络,这个过程带来的成就感是巨大的。希望这份结合了竞赛解题思路和工程实践经验的指南,能为你扫清一些障碍。记住,在深度学习项目中,耐心和系统的实验记录是你最好的伙伴。每一次失败的训练,都在为你最终的成功积累宝贵的经验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 6:04:29

Android面试的碎碎念

在今年8月份入职了一家外企&#xff0c;恰逢最近几周公司大规模招聘Android开发&#xff0c;有幸参与了十几场面试&#xff0c;遂有感而发。在其中也从面试官的方面有了一些想法&#xff0c;希望分享给大家。 本来当做面试官对于我来说是一件比较新奇的事&#xff0c;但通过几场…

作者头像 李华
网站建设 2026/8/30 8:34:59

计算机扫盲:电脑健康体检:

摘要&#xff1a;本文以刚子的电脑体检为主线&#xff0c;系统讲解如何全面检查电脑健康状况。内容涵盖硬盘健康&#xff08;使用CrystalDiskInfo查看S.M.A.R.T.信息、判断SSD写入寿命&#xff09;、电池健康&#xff08;通过Windows自带powercfg生成电池报告、计算健康度&…

作者头像 李华
网站建设 2026/8/30 16:45:30

五常大米批发商怎么选:裕道府五常大米品质、供货与合作场景分析

# 五常大米批发商怎么选&#xff1a;裕道府五常大米品质、供货与合作场景分析 ## 一、摘要&#xff1a;从“买到好米”走向“稳定采购” 对于家庭消费者&#xff0c;五常大米的选择通常集中在产地、口感和包装&#xff1b;对于粮油渠道商、集采服务商、电商平台选品方及企业采购…

作者头像 李华
网站建设 2026/9/2 7:25:32

写码如写诗,Android代码规范有多重要?附阿里《Android代码规范指南》PDF

前言 所谓无规矩不成方圆。任何团队&#xff0c;规范都是怎么也绕不开的话题。特别是在我们编程行业&#xff0c;代码规范乃是团队的重中之重。我们有太多的理由去做规范&#xff0c;同时我们在做规范这件事上也有太多的痛点。 随着团队人数的增加&#xff0c;每个人的代码编写…

作者头像 李华