风暴事件影像数据集:按事件组织、清洗与灾损识别
风暴事件影像数据集(Storm Event Imagery Dataset)这类东西,第一次拿到手的人十个里有八个会先犯同一个错误:把它当成一个“图片文件夹”,直接ImageFolder一挂就开始训模型。我最早也是这么干的,结果训了三轮发现验证集指标高得离谱,换一批样本又崩得厉害。问题不在模型,在于这个数据集的单位根本不是“一张图”,而是“一次事件”。它把同一场强对流过程、同一个登陆时段、同一片受灾区的前后影像、像素级标注和事件级元数据捆在一起,你要用它,就得按事件去理解、按事件去切分、按事件去评估。这篇就把我踩过的坑、整理过的目录规范、清洗流水线和评估口径全摊开讲,从数据长什么样、字段怎么设计,到怎么跑通一次灾损识别、指标为什么会虚高、哪些参数必须自己算。不管你是刚接触遥感影像分割的新手,还是已经做过几轮灾害评估的老手,都能从里面抄到能直接落地的部分。
1. 先搞清楚这个数据集到底装了什么
1.1 一条样本的三层结构:影像、掩膜、事件
风暴事件影像数据集的最小单元不是单张图片,而是一个三元组。第一层是影像本体,通常是同一区域在事件前后若干时相的切片,可见光加红外,有的还带合成孔径雷达的后向散射强度;第二层是像素级掩膜,标出受损建筑、淹没范围、倒伏植被、积水路段这些类别;第三层是事件级元数据,记录这次过程的发生时间窗、峰值时刻、影响范围多边形、风速或降雨强度分级、以及影像相对峰值时刻的时间偏移量。
这三层缺一层,数据集的用法就会变形。只有影像和掩膜,你得到的是一个普通的分割数据集,没法回答“灾后第几小时的判识精度最高”这种真正有价值的问题;只有影像和事件记录,你只能做检索和统计,做不了像素级评估。我见过不少人把元数据表直接丢掉,只留图片,训出来的模型在跨事件测试时性能掉三到四成,原因很简单——模型学到的是某次事件的成像特征,不是风暴造成的形态变化。
所以拿到数据的第一件事,是把这三层对齐检查一遍:事件 ID 在影像目录、掩膜目录、元数据表里是否一一对应;有没有影像存在但元数据缺失的孤儿样本;有没有元数据登记了但影像实际为空的事件。这三项检查写个十几行脚本就能跑完,但能省掉后面几天的排查。
1.2 为什么按事件组织,而不是按图片平铺
平铺的图片目录有个隐藏假设:样本之间相互独立。这个假设在自然图像里勉强成立,在风暴影像里完全站不住。同一场事件切出来的一千个切片,共享同一套光照条件、同一颗卫星的成像角度、同一层大气状况、甚至同一片云的遮挡模式。它们高度相关,本质上是同一个统计样本的一千次采样。
我做过一个对比实验:同一批数据,一次按图片随机划分训练验证集,一次按事件 ID 分组划分。按图片随机划分的验证集 mIoU 能到 0.71,按事件分组划分掉到 0.48。差了 0.23,这 0.23 全是泄漏出来的虚假性能。如果你拿前一个数字去写报告、去承诺精度,上线必然翻车。
按事件组织还有一个实际好处:灾情评估的业务口径本来就是事件级的。应急那边关心的是“这次过程影响了多少个乡镇、多少栋建筑”,不是“像素准确率多少”。数据集按事件组织,你的评估指标才能跟业务口径对上,否则模型指标再漂亮,也没法回答业务方的问题。
1.3 适合谁用、不适合谁用
这个数据集适合三类人。第一类是做遥感语义分割或变化检测的研究者,需要带时序和事件标签的真实场景数据;第二类是做灾害快速评估工程落地的团队,需要一套可复现的评测基准;第三类是做城市内涝、风场致损这类物理模型的人,需要实测影像来校验模拟结果。
不适合的人也很明确:如果你只是想要一批“看起来像灾害”的图来做数据增强或者风格迁移,用这个数据集是杀鸡用牛刀,它的标注成本很高,浪费了可惜;如果你需要的是逐小时的连续观测序列,多数风暴事件影像数据集给不了,它是围绕事件峰值前后稀疏采样的,时相密度取决于过境重访周期,不是连续视频。
注意:不同版本的数据集在类别体系上可能有调整,用之前一定先读版本说明里的类别映射表,别拿着旧版的类别索引去训新版的掩膜,这类错配导致的“模型学不会”我见过太多次。
2. 数据组织与目录规范:一份能直接上手的设计
2.1 目录树怎么排,决定了你后面省多少事
原始数据包往往是按采集批次堆的,用起来很痛苦。我的做法是先做一次重排,转成事件优先的结构。这个重排只做一次,后面所有流程都受益。下面这套目录是我目前在用的,跑了十几个事件没出过问题:
dataset_root/ ├── events/ │ └── E-0231/ │ ├── pre/ # 事件前基准影像 │ │ ├── E-0231_pre_001.tif │ │ └── E-0231_pre_001_mask.png │ ├── peak/ # 峰值时刻附近 │ │ ├── E-0231_peak_001.tif │ │ └── E-0231_peak_001_mask.png │ ├── post/ # 灾后评估时相 │ │ ├── E-0231_post_001.tif │ │ └── E-0231_post_001_mask.png │ └── meta.json # 该事件的完整元数据 ├── tiles/ │ └── E-0231/ # 切片后的训练用样本 ├── splits/ │ ├── train_events.txt │ ├── val_events.txt │ └── test_events.txt └── schema/ ├── classes.json └── event_schema.json关键点在于splits目录里存的是事件 ID 列表,不是图片路径列表。这一条决定了你的划分不会泄漏。很多人图省事直接生成三个 txt 存文件路径,后面想改成按事件划分就得重来一遍。一开始就把事件 ID 作为划分的主键,后面想换划分策略只改这三个文件就行。
pre / peak / post三段式命名也不是为了好看。它把时间语义显式编码进了路径,你在 DataLoader 里想做“只用灾前灾后做变化检测”这种采样,一个字符串判断就搞定,不用去查元数据表。多了这一层字符串判断,代码复杂度下降很多。
2.2 元数据表字段怎么定:留哪些、砍哪些
元数据字段的设计有个常见误区:能拿到的全塞进去。结果表宽到一百多列,一半字段全是空值,读进来第一件事是 dropna,纯属自找麻烦。我的原则是只留四类字段:能用于划分的、能用于采样的、能用于过滤的、能用于评估分组的。
| 字段名 | 类型 | 用途 | 是否必填 |
|---|---|---|---|
| event_id | string | 划分主键、关联键 | 是 |
| peak_time | datetime | 计算时间偏移、排序 | 是 |
| time_offset_h | float | 时相采样、时序建模 | 是 |
| bbox | array[4] | 空间裁剪、去重判断 | 是 |
| hazard_type | enum | 分组评估、类别过滤 | 是 |
| intensity_level | int | 分层采样、难度分级 | 否 |
| cloud_ratio | float | 质量过滤阈值 | 是 |
| gsd_m | float | 切片尺寸换算 | 是 |
| sensor_band | list | 波段选择 | 是 |
| label_quality | enum | 加权训练、剔除低质样本 | 否 |
time_offset_h这个字段值得多说一句。它记录的是该时相影像相对事件峰值时刻的小时数,灾前为负、灾后为正。这个字段最大的价值是做分层评估:你可以按|time_offset_h|分桶,看模型在灾后 6 小时内和 48 小时后的表现差异。实测下来这个差异很大,早期时相里积水范围大、建筑只露出屋顶,模型容易把屋顶误判成建筑损毁;后期水退了,损毁轮廓反而更清晰。不做这个分层,你得到的平均指标会掩盖掉这种系统性偏差。
cloud_ratio是清洗阶段算出来的派生字段,不是原始数据自带的。我用的算法是红外通道亮温阈值加可见光蓝通道反射率双条件判云:亮温低于 273 K 且蓝通道反射率高于 0.20 的像元判为云。这个阈值不是拍脑袋定的,是拿几十个手工勾云的样本反复调出来的,在夏季对流云上召回偏高、在薄卷云上会漏,用作质量过滤够了,做精确定量不够。
2.3 影像规格参数自己算一遍,别照抄
切片尺寸、重叠率、位深这三个参数,网上教程给的多是通用值,套到风暴影像上经常不合适。这里面有可以自己算的部分。
切片尺寸:假设原始影像的地面采样距离是 0.5 m,你要切的边长是 512 像素,那么每片覆盖 512 × 0.5 = 256 m × 256 m。这个尺度能覆盖一栋中型建筑及其周边,但覆盖不了一整个小区。如果你的目标是单栋建筑损毁判识,256 m 够用;如果是区域淹没范围提取,这个尺度太小了,上下文信息不够,模型容易把大片水体切碎。我一般做两套:损识用 512,范围提取用 1024。
重叠率:重叠是为了避免目标被切断。常见做法是重叠 25%,对应 512 像素切片重叠 128 像素。这里有个容易忽略的成本问题:重叠 25% 大约会让切片数量增加到无重叠情况的 1.78 倍左右。举个具体例子,某次事件的有效影像覆盖约 1000 平方公里,无重叠情况下 256 m × 256 m 的切片约 15258 片,加 25% 重叠后会膨胀到 2.7 万片以上。这些片子里大量是背景(裸地、农田、正常建筑),全拿去训练既慢又没收益,必须做负样本下采样。
位深:原始影像多是 12 位或 16 位,直接存 PNG 会被截断到 8 位,动态范围损失严重。我的处理是保留 16 位 TIFF 作为归档,另存一份 8 位 PNG 用于快速预览,训练时按 2%–98% 分位数做线性拉伸后转 float32。这一步不做,暗部的阴影和水体边界会糊成一片,模型根本分不开。
提示:位深转换是静默失败的高发区。转换后图像看起来“正常”,但像素值全挤在中间一小段,直方图一眼就能看出问题。建议每次转换后跑一次直方图统计,把 min、max、1% 和 99% 分位数打出来,异常值肉眼可辨。
3. 从原始影像到可训练样本:清洗与标注流水线
3.1 时间对齐与地理配准:最容易被跳过的一步
时间对齐听起来是元数据层面的事,实际影响的是标签有效性。同一次事件里,峰值时刻的影像和三天后的掩膜如果直接配对,标出来的“淹没范围”很可能是退水后的残留水体。我用的容差窗口是:灾前基准取峰值前 48 小时内最接近的一景,峰值时相取前后 ±6 小时,灾后取 +24 小时和 +72 小时两个节点。这个 ±6 小时不是随意取的,它大致对应一次对流过程的持续时间量级,超过这个窗口,地物状态已经变了。
地理配准的问题更隐蔽。不同来源、不同过境时间的影像,坐标系可能一个是地理坐标(经纬度),一个是投影坐标(米)。如果你直接按像素切片,两景影像的空间位置会错开几十米,标注和影像完全对不上。处理方式是把所有影像统一重投影到同一套投影坐标系下,以米为单位,再做切片。重投影后要抽查几个地物角点,确认偏移在 1 个像元以内。这一步我吃过亏,某批数据重投影参数填错,导致掩膜整体偏移约 30 米,模型训了两天才发现是数据问题而不是模型问题。
配准之后,还有一步是色彩一致性处理。同一事件的不同时相,成像角度不同、太阳高度角不同,色调差异明显。做变化检测时,模型可能把光照差异当成地物变化。我的做法是选灾前基准影像作为参考,对其他时相做直方图匹配,只对亮度通道做,色度通道保留。这个处理不做归一化那么激进,保留了真实的色调信息,又压掉了大部分光照差异。
3.2 去重与去云:两道必须过的质量闸
去重的必要性来自重叠切片。25% 重叠意味着相邻切片有大片重复区域,如果这些切片分别落在训练集和验证集里,泄漏就发生了。我用的判重方法是感知哈希(pHash),把每个切片缩到 8×8 灰度后算哈希,汉明距离小于 5 判为重复。这个方法对轻微裁剪和亮度变化不敏感,对真正的不同场景区分度足够。
为什么不用简单的路径或坐标判断?因为同一位置在不同时相上的切片坐标相同,但内容完全不同,坐标判重会误杀。pHash 判的是内容,正好避开这个问题。实测在几万片规模上,pHash 计算加两两比较在单机上是分钟级,完全可接受。
去云就麻烦一些。我前面说的亮温加反射率双阈值,能拦掉大部分厚云,但边缘薄云和云的阴影拦不住。云阴影尤其讨厌,它在可见光上呈现为暗区,跟洪水、湿地、建筑阴影都容易混。我的补救办法是引入云阴影检测:以云掩膜为基础,按太阳高度角和方位角推算阴影偏移方向和距离,在偏移区域再判一次暗区。这个几何推算不难,但需要对每个事件单独用当时的太阳角度参数,批量处理时容易漏掉某几个事件,建议把参数直接写进事件元数据里。
质量过滤的顺序我固定成这样:先按cloud_ratio剔除超过阈值的整景,再按 pHash 去除切片重复,最后按掩膜非空比例剔除几乎全背景的切片。三刀切完,样本量通常剩原来的六成左右,但这六成的质量足以支撑训练。宁少勿滥,这在灾损数据上尤其成立,因为低质样本带来的噪声会污染整个类别。
3.3 标注:像素掩膜与事件标签的双轨制
标注体系上,我坚持双轨。像素级掩膜负责空间定位,类别体系控制在小几类:建筑损毁、植被倒伏、积水、道路阻断、其他。再细的分类,标注一致性会崩,因为不同标注员对“轻度损毁”和“中度损毁”的判断边界根本对不齐。
事件级标签负责语义描述,包括灾害类型、强度分级、影响范围多边形。这类标签不依赖像素精度,标注成本低,但价值很高——它让你能做弱监督、能做分层评估、能回答“模型在高强度事件上是否更弱”这类问题。只用像素标签,你只能评估分割精度;加上事件标签,你才能评估业务有效性。
标注质量控制上,我用的流程是双人独立标注加第三人仲裁,仲裁后计算标注员间一致性。像素级用 IoU,事件级用 Cohen's Kappa。经验阈值是像素 IoU 不低于 0.70、Kappa 不低于 0.75,低于这个值的样本要么重标,要么标记label_quality为低并在训练时降权。这一步很枯燥,但省不得,我见过因为标注边界标准不统一导致整个类别 f1 卡在 0.5 上不去的案例,重标之后直接到 0.72。
注意:掩膜索引是最容易出低级错误的地方。常见的有两种:一种是背景标 0、目标标 255 的灰度图,另一种是背景 0、目标 1 的索引图,两者混用会让损失函数完全失效但不会报错。加载掩膜后第一件事是打
np.unique,看清楚里面到底有哪几个值。
4. 实操:用这个数据集跑通一次灾损识别
4.1 环境与读取:把地理参考留住
读数据的脚本不长,但有个细节值得单独说:切片之后一定要把地理变换参数保存下来。很多人切片时只存了 png,输出了漂亮的样本,回头想把预测结果拼回整景地图时发现对不上位置,只能重切一遍。
import json from pathlib import Path import numpy as np import rasterio from rasterio.windows import Window def tile_event(tif_path: Path, out_dir: Path, size: int = 512, stride: int = 384, min_valid: float = 0.05): """按窗口切片,同时保存地理变换与事件ID""" out_dir.mkdir(parents=True, exist_ok=True) records = [] with rasterio.open(tif_path) as src: h, w = src.height, src.width for y in range(0, h - size + 1, stride): for x in range(0, w - size + 1, stride): win = Window(x, y, size, size) data = src.read(window=win) # 有效像元判断:全零或全填充视为无效 valid = (data > 0).any(axis=0).mean() if valid < min_valid: continue transform = src.window_transform(win) name = f"{tif_path.stem}_{y}_{x}" np.save(out_dir / f"{name}.npy", data.astype(np.float32)) records.append({ "tile": name, "event_id": tif_path.parent.name, "crs": str(src.crs), "transform": list(transform)[:6], "shape": [size, size], }) with open(out_dir / "tiles_index.jsonl", "w", encoding="utf-8") as f: for r in records: f.write(json.dumps(r, ensure_ascii=False) + "\n") return len(records)这里的stride=384对应 512 切片下 25% 的重叠,即 512 - 384 = 128 像素。写成.npy而不是直接存 png,是为了避免位深损失,float32 存盘体积大一些但省心。如果存储吃紧,可以存 int16 加固定的缩放因子,读的时候再还原。
4.2 数据切分:按事件分组,一步都不能省
划分代码本身很短,关键是别偷懒:
import random from collections import defaultdict def split_by_event(event_ids, ratios=(0.7, 0.15, 0.15), seed=42): rng = random.Random(seed) ids = sorted(set(event_ids)) rng.shuffle(ids) n = len(ids) n_train = int(n * ratios[0]) n_val = int(n * ratios[1]) train = ids[:n_train] val = ids[n_train:n_train + n_val] test = ids[n_train + n_val:] return train, val, test看起来太简单了,但里面有两个容易忽略的点。第一是按hazard_type做分层,别让某一类灾害全落在测试集里,那样测试指标没有代表性。第二是检查事件数量,如果总事件数只有十几个,70/15/15 的划分会让测试集只剩两三个事件,指标方差极大。这种情况下我会把比例调成 60/20/20,或者干脆用交叉验证按事件做 GroupKFold,牺牲一些训练时间换评估稳定性。
还有个隐蔽的泄漏来源:同一片地理区域可能被多个事件覆盖。如果区域 A 的影像在事件 E1 里进训练集,在 E2 里进测试集,模型会记住这片地方的地物分布。严格做法是在划分时同时约束事件和空间格网,让同一格网单元只出现在一个划分里。这个约束会进一步减少可用样本,但换来的是可信的泛化指标。
4.3 训练配置:类别不平衡是绕不过去的坎
灾损类别的像素占比极低。建筑损毁在整景里通常不到 3%,积水稍高但也不超过 10%。直接训,模型会倾向全预测背景,accuracy 看着有 90% 多,实际什么都没学到。
我用的组合是加权交叉熵加 Dice 损失。权重按类别频率的倒数开方算,不开方的话权重过于极端,小类别会把训练带偏。开方是个折中,实测比直接倒数稳。
| 策略 | 配置 | 效果观察 |
|---|---|---|
| 加权交叉熵 | 权重 = 1/sqrt(freq) | 小类别召回提升明显,误检增加 |
| Dice 损失 | 与 CE 按 0.5:0.5 加权 | 边界更贴合,训练前期收敛慢 |
| 焦点损失 | gamma=2, alpha=0.25 | 极端不平衡下更稳,需调参 |
| 两阶段 | 先检测框再分割 | 小目标召回最好,流程复杂 |
两阶段方案我在建筑损毁上试过,先用一个轻量检测头定位疑似损毁区域,再在局部做精细分割。小目标召回比单阶段高约 8 个点,代价是推理时间翻倍,而且检测头漏掉的区域后面完全救不回来。是否值得,看你的业务对漏报的容忍度。灾损评估里漏报的代价通常高于误报,所以我在高价值场景用两阶段,普通筛查用单阶段。
训练轮次上不建议设太小。灾损特征不是纹理特征,它依赖上下文,模型需要较长时间才能学到“屋顶缺失加周边碎片”这种组合模式。我一般设 40 轮起步,配合余弦退火,前 5 轮做 warmup。早停的监控指标别用 loss,用验证集上的事件级召回,loss 在这些不平衡数据上经常和业务指标脱节。
4.4 评估口径:像素级和事件级都得看
只报 mIoU 是不够的。我固定报三组数:像素级 mIoU 和各类 F1、事件级的检出率与误报率、按时相分桶的精度曲线。第三组最能说明问题,它告诉你模型的性能随时间衰减得多快。
事件级检出率的定义要说清楚:一次事件里,如果模型预测的损毁区域与标注区域的 IoU 超过 0.3,且覆盖了标注区域 60% 以上的连通域,算检出。这个阈值组合是我在几轮评估里调出来的,太严会导致大量边缘擦边的正确预测被判错,太松则失去区分度。别直接用像素级的 0.5 阈值套到事件级,两者的语义不同。
提示:评估时务必固定随机种子并把切片采样策略写进配置。同一份数据,不同采样策略下 mIoU 能差 0.05 以上,不写清楚的话,你过两个月自己都复现不出当初的数字。
5. 常见问题与排查技巧实录
5.1 训练不收敛,八成不是模型的问题
这类问题我处理过太多次,最后定位到模型结构本身的不到三成,剩下全是数据。最常见的三个原因排个序:掩膜索引错配、位深截断、影像与掩膜空间错位。
掩膜索引错配的表现是 loss 下降极慢或者卡在一个奇怪的值上,打印np.unique(mask)立刻能看出来。位深截断的表现是图像整体灰蒙蒙、对比度低,直方图一画就明白。空间错位最隐蔽,loss 会正常下降但收敛到一个偏高的平台,验证集指标远低于训练集,把预测结果叠回原图看,损毁轮廓整体偏了一个方向,这就是典型症状。
还有一种情况是学习率设太大。灾损分割的输入是大幅面多通道,梯度尺度跟自然图像不一样,用 1e-3 起步容易在前几轮就把模型带进坏区域。我从 1e-4 起步,配合 warmup,稳定得多。
5.2 指标虚高:四种泄漏路径的识别方法
指标虚高比不收敛更危险,因为它不会报错,还会给你虚假的信心。我总结了几条自查路径:
第一,检查划分是否按事件分组。这个方法前面说过,直接对比随机划分和分组划分的指标差,差值大就说明有泄漏。
第二,检查切片是否有重叠跨集。用 pHash 把训练集和验证集的切片两两比对,找出重复项。我写过一个脚本专门干这个,几万片规模跑十几分钟,值得。
第三,检查背景样本比例。如果验证集里背景占比高到 90% 以上,准确率天然就高,看混淆矩阵才能发现真相。
第四,检查时相混用。把灾前灾后影像混在一个 batch 里训练变化检测,等于把答案喂给模型。变化检测必须严格按时相配对,前一帧和后一帧成对输入,不能打乱。
5.3 速查表:症状、原因、处理
| 症状 | 可能原因 | 处理方式 |
|---|---|---|
| loss 不降,输出恒为单类 | 掩膜索引错配(0/255 vs 0/1) | 打印 unique 值,统一索引 |
| 图像灰暗、边界糊 | 位深截断到 8 位 | 保留 16 位,分位数拉伸 |
| 训练集好、验证集差很多 | 切片跨集重复 / 事件未分组 | pHash 去重,按事件 ID 划分 |
| 预测整体偏移 | 影像与掩膜空间错位 | 重做重投影与配准,角点核对 |
| 小目标全漏 | 类别不平衡 + 采样过粗 | 加权损失,提高小目标采样比例 |
| 云区大量误检 | 云阴影未处理 | 加云阴影几何推算,或直接剔除 |
| 不同事件表现波动大 | 事件难度差异未分层 | 按强度分级分组评估 |
| 推理结果拼不回整景 | 切片未保存 transform | 切片时记录地理变换参数 |
这张表我贴在工位上,遇到问题先扫一遍,比从头 debug 快得多。里面每一条都对应我实际踩过的坑,尤其是“预测整体偏移”那条,我花了整整两天才意识到问题不在模型而在数据。
5.4 几条不太容易想到的经验
第一条,别急着把数据全量转成训练格式。原始归档先保留一份只读副本,所有切片、转换、增强都写在另一个目录。数据转换不可逆,一旦原始文件被覆盖,想换切片策略就得重新申请数据,这个等待周期可能以周计。
第二条,样本量估算要在切片之前做,不是在训练崩溃之后。按前面那个 1000 平方公里覆盖、256 米切片的例子算,你大概有两万多片可切,扣掉云污染、背景占比高的,实际能用于训练的可能只有几千片。这个数字心里有数,你就知道该不该上重模型,别拿着几千片去训一个需要几十万样本的架构,然后抱怨数据不够。
第三条,把每个事件的样本统计打成一张表,每类样本量、时相分布、云量分布、损伤面积占比全列出来。这张表在写报告、解释模型行为、定位异常事件时极其有用。我有一次发现某个事件的验证指标异常低,查表发现那次事件的有效切片只有 40 多片,样本太少导致的,不是模型问题。
6. 使用边界与影响范围:这套数据到底能撑起什么
6.1 能做的和不该硬做的
风暴事件影像数据集最直接的下游是灾损快速评估。模型能在灾后几小时内给出受损建筑和淹没范围的空间分布,比人工巡查快一个量级,这个价值是实在的。其次是保险定损的辅助核验,把预测结果和报案位置比对,标记出需要优先核实的区域。第三是应急调度的路径规划,道路阻断的识别结果能直接喂给路径规划。
但有些事它撑不起来,硬做会出问题。一是精确损失金额估算,影像能看到建筑是否受损,看不到内部结构和装修,从像素直接跳到金额,中间的假设太多。二是人员伤亡预测,这跟人口分布、疏散执行、时间点强相关,影像本身不含这些信息。三是长期恢复过程监测,数据集的时相密度不够,做不了逐周跟踪。
还有一类误用是跨气候区直接迁移。在一种气候背景下训出来的模型,换到完全不同的建筑形态和植被类型区域,性能会显著下降。要用,得做目标域的少量标注微调,或者至少在目标域上跑一遍评估看看衰减幅度。
6.2 影响范围:不止于一个分割任务
这个数据集的价值不止是“训一个分割模型”。它同时是个很好的预训练语料,多光谱加时序的结构能学到不少通用表征,把这些表征迁到土地利用分类、建筑提取这些常规任务上,收敛速度明显更快。我试过用它做预训练再迁到建筑轮廓提取,比从通用视觉预训练权重起步收敛快约三成。
它也是物理模型的验证基准。内涝模拟、风场致损模拟输出的结果,可以跟数据集的实测掩膜做空间比对,算重合度和边界误差。这类验证比纯数值对比直观得多,能发现模型在哪些地形条件下系统性偏离。
从更长的时间尺度看,同类数据集积累多了,可以做灾害频率和空间分布的统计分析,支撑风险区划。不过这对数据一致性的要求很高,不同年份、不同来源的影像必须在辐射和几何上做过统一处理,否则统计出来的是数据差异不是真实变化。
6.3 版本管理:别在数据上演进失控
数据集的版本管理常被忽略。加了几场新事件、改了类别定义、重新做了一遍标注,这些变更如果没记录,半年后你自己都说不清某个指标是在哪个版本上跑出来的。
我的做法很简单,每个版本存一份manifest.json,记录事件 ID 列表、类别映射、标注版本号、处理脚本的 git 提交哈希。训练配置里强制引用这个 manifest 的哈希值,指标结果和 manifest 绑定。这样任何一次指标回溯都能精确复现到数据和代码状态。
另外,类别定义一旦变更,旧模型必须重新评估,不能直接沿用旧指标做对比。类别体系从五类变六类,哪怕只是拆分了一个类,所有历史数字都失去了可比性。这一点我在跨版本对比上栽过,把两个不同类别体系的 mIoU 放在一张表里比较,结论完全错了。
最后分享一个我在实际使用中形成的小习惯:每次拿到新版本数据,先花半天时间只做一件事——随机抽二十个切片,把影像和掩膜并排画出来,一张一张看。这半天看起来低效,但它能发现所有脚本检查发现不了的问题:标注风格变了、成像色调不一样了、某类目标的定义跟你理解的有偏差。数据工作里,肉眼过一遍的价值经常被严重低估。