钻孔岩心裂缝分割(crack segmentation)在地质勘探与工程勘察中几乎是绕不开的任务。真正困难的是:现场大量岩心图像没有像素级标注,只有地质编录报告里的文本描述和粗略区块标记。这类场景非常适合研究“报告派生弱标签(Report-Derived Weak Labels)+ 有监督裂缝分割”的组合路径,目标是让模型在标注成本受限的情况下,仍能自动完成裂缝和破碎带识别。这篇文章围绕这条技术主线,从问题动机、数据流水线、最小复现实验、参数取舍、常见排错到生产落地建议展开,适合正在做岩心图像识别、裂缝自动提取或弱监督分割研究的开发者参考。
1. 先理解弱标签+有监督分割要解决的工程问题
1.1 钻孔岩心分析的难点在哪里
钻孔岩心是地质勘察中最基础的数据来源之一。施工人员把地下数米到数百米的岩芯取出后,按深度顺序放入岩心箱,再由地质人员拍照、编录、描述。传统的人工编录流程依赖经验,效率低,而且不同编录人员对“裂隙发育”“岩芯破碎”的判定并不完全一致。岩心图像进入自动化分析流程后,第一个瓶颈就是数据标注。
如果要做像素级裂缝分割,标注员需要在图像上逐像素描出裂缝轮廓。岩心中真实裂缝非常细,有的只有几个像素宽,有的被岩心盒阴影遮挡,有的沿着岩心柱面螺旋延伸。一块长度约一米的岩心图像,人工精标注可能要花二十分钟到一小时。几十个钻孔的数据量就能让标注成本迅速失控。
另一个难点是深度对齐。岩心图像本身是二维平面照片,但钻孔数据是按深度组织的。如果图像没有深度标尺或控制点,即使模型分割出裂缝,也无法回答“这条裂缝对应地下多少米”这个核心问题。所以,岩心自动化分析不能只看图像,还必须把图像和钻孔深度、报告文本绑在一起。
1.2 报告派生弱标签到底是什么
弱标签(weak label)是相对像素级强标签而言的监督信号。它不要求精确到每个像素,而是只提供一种粗略、有噪声但成本很低的条件信息。
报告派生弱标签的来源是地质编录报告和钻孔台账。常见记录形式是:
- “ZK01 120.30-125.60m 灰岩 裂隙发育 岩芯破碎 RQD=35%”
- “125.60-128.00m 中粒砂岩 节理较发育”
这些文本记录了深度区间、岩性、构造发育程度和RQD等参数。把“裂隙发育”“岩芯破碎”“节理较发育”这类关键词映射到对应深度区间,就可以在岩心图像上生成一个块状mask。这个mask只是在某些深度区间标出“可能有裂缝或破碎”,并没有给出裂缝的精确轮廓,因此是弱标签。
这种弱标签的价值在于:
- 可以全自动批量生成,不需要人工像素级标注。
- 反映了深度区间和裂缝发育程度的对应关系。
- 适合作为预训练信号、正则约束或伪标签筛选依据。
代价是噪声较大。报告说“裂隙发育”,不代表该区间每个像素都是裂缝;报告没有提到裂缝,也不代表图像里绝对没有裂缝。使用这种标签时必须设计专门机制,防止模型被噪声带偏。
1.3 标题方法的核心拆解:弱标签与有监督分割如何配合
从工程实现角度看,“Report-Derived Weak Labels + Supervised Crack Segmentation”可以拆成四层:
- 数据层:岩心图像采集、深度对齐、报告解析、弱标签生成。
- 标签层:少量人工像素级精标注加上大量报告派生弱标签。
- 模型层:训练一个裂缝分割网络,例如U-Net、DeepLabV3+。
- 策略层:设计弱标签参与训练的方式,例如先用弱标签做预训练,再用精标注微调;或者用弱标签做一致性正则、辅助分类、伪标签筛选。
需要注意,这不是“用弱标签替代强标签”,而是“用弱标签降低强标签的依赖”。最终分割模型的训练仍然有监督,只是监督信号从单一的人工精标注,扩展成了“报告弱标签+人工精标注”的混合信号。
这种组合背后有一个工程判断:弱标签虽然不精确,但量大且覆盖完整;人工标注精确,但量少且代价高。两者结合,才能在有限预算内训练出可用的裂缝分割模型。
2. 搭建从岩心图像到裂缝分割的完整数据流水线
2.1 岩心图像采集、深度对齐与预处理
岩心图像进入模型之前,先要回答三个问题:
- 图像中的深度方向是否一致。
- 每张图对应的深度范围是否已知。
- 图像是否包含岩心箱边框、标签纸、色卡等无关区域。
很多现场照片是人工拍摄的,角度、光照、箱体位置都不固定。深度对齐是后续所有工作的前提。推荐在岩心箱旁边放置深度标尺或已知长度的基准物,并且固定拍摄距离。这样可以通过标尺计算每段图像对应的深度。
深度映射比例可以用两个控制点确定。假设图像顶部的深度是top_depth,底部的深度是bottom_depth,图像高度是H,那么:
pixels_per_meter = H / (bottom_depth - top_depth)如果一张图像只包含一个岩心箱,箱深为1米且摆放方向一致,pixels_per_meter也可以直接从标准箱尺寸计算。但实际场景中,岩心盒长度并不总是1米,甚至可能存在缺失段。最稳妥的做法是每张图记录一个深度范围,并单独计算映射参数。
图像预处理至少包括:
- 将输入尺寸缩放到固定大小,例如512x512或1024x1024。
- 去除岩心箱边缘、标签、色卡区域,可以用人工裁剪或检测模型。
- 做亮度、对比度、旋转、翻转、尺度增强,提高对不同光照条件的鲁棒性。
- 如果图像带EXIF旋转信息,需要先统一方向。
注意:深度到像素的映射一旦出错,所有弱标签mask都会系统性错位。正式生成数据集前,先取3到5个已知深度标记点做校验。
2.2 从地质编录报告生成弱标签mask
报告解析是弱标签生成的第一步。规则简单时可以直接用正则表达式提取深度区间和关键词;报告格式不统一时,可以用NER模型或基于词典的抽取工具。
下面是一个常见报告行的解析示例:
ZK01 120.30-125.60m 灰岩 裂隙发育 岩芯破碎 RQD=35%解析后得到结构化数据:
{ "hole_id": "ZK01", "start_depth": 120.30, "end_depth": 125.60, "lithology": "灰岩", "description": "裂隙发育 岩芯破碎", "keywords": ["裂隙发育", "岩芯破碎"], "rqd": 35.0 }关键是把“裂隙发育”“岩芯破碎”“节理发育”“裂缝密集”等词映射为候选裂缝区间。这个词典需要根据项目报告的实际用词维护,通常几十个词就够。
得到深度区间后,需要将其映射到图像行坐标。以下代码是一个最小示例:
import cv2 import numpy as np def report_to_weak_mask(image_path, parsed_report, top_depth=0.0, bottom_depth=10.0, crack_keywords=("裂隙", "裂缝", "破碎", "断口")): image = cv2.imread(image_path) h, w = image.shape[:2] mask = np.zeros((h, w), dtype=np.uint8) text = parsed_report.get("description", "") if not any(k in text for k in crack_keywords): return mask start_depth = parsed_report["start_depth"] end_depth = parsed_report["end_depth"] if end_depth < top_depth or start_depth > bottom_depth: return mask pixels_per_meter = h / (bottom_depth - top_depth) start_row = max(0, int((start_depth - top_depth) * pixels_per_meter)) end_row = min(h - 1, int((end_depth - top_depth) * pixels_per_meter)) mask[start_row:end_row, :] = 1 return mask这段代码只是把整个深度区间标成前景。它的优点是简单,缺点是噪声很大。实际使用中可以做两点改进:
- 对mask加入渐变边界,减少深度映射误差带来的边界突变。
- 将mask作为软标签,而不是硬编码0/1,例如中心区域强度为0.9,边界区域强度为0.5。
2.3 构建有监督裂缝分割数据集
弱标签生成的mask不能直接作为最终训练目标,还需要人工精标注样本。推荐的数据集结构是:
data/ ├── raw/ │ ├── core_images/ │ ├── reports/ │ └── manual_labels/ ├── processed/ │ ├── images/ │ ├── weak_masks/ │ ├── manual_masks/ │ └── splits/每张岩心图像对应一个弱标签mask和一个可选的人工精标注mask。训练集、验证集、测试集建议按钻孔划分,避免同一钻孔的图像同时出现在训练集和验证集中。原因是同一钻孔相邻深度的图像相似度较高,如果随机划分,会导致验证分数虚高。
一张岩心图像通常很大,例如6000x4000像素,直接把整图输入模型既占用显存,又会让细小裂缝在下采样后消失。更常见的做法是切块训练:
- 从图中随机裁剪512x512或1024x1024区域。
- 弱标签mask同步裁剪。
- 人工精标注mask也同步裁剪。
- 每个批次同时包含纯弱标签图像块和精标注图像块。
2.4 弱标签参与训练的三种路径
弱标签不是只能当成带噪声的mask硬训练。根据实际项目条件和标注比例,可以选三种路径:
第一种,弱标签作为预训练数据。先用所有报告弱标签训练一个初始分割模型,忽略噪声,只让模型学到“裂缝和破碎带大致长在什么位置”的统计规律。然后用人工精标注数据微调。这种方式实现简单,适合精标注较少但弱标签覆盖广的项目。
第二种,弱标签作为辅助正则。训练时同时计算弱标签分支和精标注分支的损失。精标注分支负责学习精确边缘,弱标签分支负责约束整体位置。损失函数可以写成:
total_loss = manual_loss + lambda * weak_loss其中lambda表示弱标签损失的权重,通常设为0.3到0.7。弱标签噪声大时降低权重,精标注很少时提高权重。
第三种,弱标签用于伪标签筛选。先用少量人工精标注训练教师模型,然后用教师模型在所有岩心图像上推理,生成高置信度像素预测。报告弱标签作为区域约束,只保留“报告标记为裂缝区间且模型预测置信度高”的像素作为伪标签,再训练学生模型。这种方式适合做迭代式半监督。
从工程角度,推荐先实现第一种,跑通全流程后再尝试第三种。第一种代码改动最小,能最快验证数据流水线是否正确。
3. 最小可复现实验:环境、目录与核心代码
3.1 环境准备与依赖版本
围绕这套流程,不需要特别大的工程体系,常规深度学习环境即可。下面是一组示例依赖:
| 组件 | 建议版本/方案 | 用途 |
|---|---|---|
| Python | 3.8 或 3.10 | 运行环境 |
| PyTorch | 1.13 或 2.x | 模型训练 |
| torchvision | 与PyTorch匹配 | 数据增强与模型网络 |
| OpenCV | 4.x | 图像读写、预处理、形态学后处理 |
| NumPy | 1.24+ | mask与数组操作 |
| pandas | 1.5+ | 报告表格处理 |
| scikit-learn | 1.2+ | 指标计算、数据划分 |
| MMSegmentation(可选) | 1.x | 使用现成分割模型与配置 |
| rasterio/GDAL(可选) | 根据数据源 | 处理带地理坐标的高光谱或扫描图像 |
安装示例:
conda create -n borehole python=3.10 conda activate borehole pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python numpy pandas scikit-learn tqdm如果项目环境不允许使用外网预训练权重,可以把ResNet、EfficientNet等骨干网络换成从零训练的小网络。对于岩心图像这类纹理背景相对固定的场景,小网络也能获得不错效果。
3.2 项目目录结构
推荐按数据、配置、源码、输出分离:
borehole_core_analysis/ ├── data/ │ ├── raw/ │ │ ├── core_images/ │ │ ├── reports/ │ │ └── manual_labels/ │ ├── processed/ │ │ ├── images/ │ │ ├── weak_masks/ │ │ └── manual_masks/ ├── configs/ │ └── train_config.yaml ├── src/ │ ├── report_parser.py │ ├── depth_mapping.py │ ├── weak_label_generator.py │ ├── dataset.py │ ├── model.py │ ├── loss.py │ ├── train.py │ └── evaluate.py ├── outputs/ │ ├── checkpoints/ │ └── predictions/这样组织的好处是:原始数据只读不写,中间产物由脚本生成,实验配置与代码分离,后续换模型或换参数时不用改动核心代码。
3.3 报告解析与弱标签mask生成示例
报告解析最怕格式不规范。可以先针对已知钻孔报告写规则解析器,再逐步扩展。下面是一个规则解析的最小实现:
import re import json def parse_report_line(line): line = line.strip() m = re.search(r"([A-Za-z]{1,10}\d{2,})", line) hole_id = m.group(1) if m else "UNKNOWN" m = re.search(r"(\d+\.?\d*)\s*-\s*(\d+\.?\d*)\s*m", line) if not m: return None start_depth, end_depth = float(m.group(1)), float(m.group(2)) keywords = [] desc_parts = [] for kw in ["裂隙发育", "裂缝发育", "节理发育", "岩芯破碎", "破碎", "断口密集"]: if kw in line: keywords.append(kw) desc_parts.append(kw) return { "hole_id": hole_id, "start_depth": start_depth, "end_depth": end_depth, "keywords": keywords, "description": " ".join(desc_parts) }这段代码只覆盖了最简单的报告行。真实报告中可能会包含“局部裂隙”“底部破碎”“RQD=0”等措辞,需要根据实际语料调整词典和正则规则。
解析完成后,批量生成弱标签mask:
python src/weak_label_generator.py \ --image_dir data/raw/core_images \ --report_dir data/raw/reports \ --output_dir data/processed/weak_masks \ --top_depth 0 --bottom_depth 103.4 有监督裂缝分割训练与评估示例
分割网络的输入是图像块,输出是和输入同尺寸的概率图。下面是一个简化U-Net示例,用于理解结构,不追求完整精度:
import torch import torch.nn as nn class SimpleCrackNet(nn.Module): def __init__(self, in_channels=3, num_classes=1): super().__init__() self.encoder = nn.Sequential( nn.Conv2d(in_channels, 16, 3, padding=1), nn.ReLU(), nn.Conv2d(16, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(), nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(), ) self.decoder = nn.Sequential( nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False), nn.Conv2d(64, 32, 3, padding=1), nn.ReLU(), nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False), nn.Conv2d(32, 16, 3, padding=1), nn.ReLU(), nn.Conv2d(16, num_classes, kernel_size=1), ) def forward(self, x): return self.decoder(self.encoder(x))这个示例没有加skip connection,实际项目建议使用完整U-Net或DeepLabV3+。裂缝分割对边缘连续性要求高,skip connection能保留低层细节,效果通常明显更好。
损失函数推荐组合BCE和Dice:
class CombinedLoss(nn.Module): def __init__(self, dice_weight=0.5, bce_weight=0.5): super().__init__() self.dice_weight = dice_weight self.bce_weight = bce_weight def forward(self, logits, targets): bce = nn.functional.binary_cross_entropy_with_logits(logits, targets) probs = torch.sigmoid(logits) smooth = 1e-6 intersection = (probs * targets).sum() dice = 1 - (2.0 * intersection + smooth) / (probs.sum() + targets.sum() + smooth) return self.bce_weight * bce + self.dice_weight * diceDice损失能缓解裂缝前景占比很小造成的类别不平衡问题。实际训练中,裂缝像素可能只占整张图像的1%到5%,单独使用BCE容易让模型把所有像素预测为背景。
评估模型时,不要只看一个准确率。裂缝分割更关注IoU、Dice、Recall三个指标。下面是评估函数示例:
def compute_metrics(pred_mask, gt_mask): pred = pred_mask > 0.5 gt = gt_mask > 0.5 intersection = (pred & gt).sum() union = (pred | gt).sum() iou = intersection / (union + 1e-6) dice = 2 * intersection / (pred.sum() + gt.sum() + 1e-6) precision = intersection / (pred.sum() + 1e-6) recall = intersection / (gt.sum() + 1e-6) return { "IoU": float(iou), "Dice": float(dice), "Precision": float(precision), "Recall": float(recall) }训练脚本启动示例:
python src/train.py \ --image_dir data/processed/images \ --weak_mask_dir data/processed/weak_masks \ --manual_mask_dir data/processed/manual_masks \ --batch_size 8 \ --epochs 60 \ --lr 1e-4 \ --crop_size 5124. 关键参数与设计取舍
4.1 分割模型参数与损失设计
裂缝分割属于小目标结构分割,参数设计会直接影响结果。下面是最常用到的参数及其选择建议:
| 参数 | 常见取值 | 调小影响 | 调大影响 | 推荐场景 |
|---|---|---|---|---|
| 输入图像尺寸 | 512 / 1024 | 显存占用低,但细裂缝容易断 | 能保留更多裂缝细节,显存占用高 | 裂缝宽2-5像素时优先1024 |
| 下采样倍数 | 4 / 8 / 16 | 边缘保留好,计算量大 | 感受野大,但小裂缝丢失 | 裂缝较细时倍数不超过8 |
| Batch Size | 4-16 | 训练稳定,但耗时长 | 吞吐高,可能显存溢出 | 根据显存调整,8起步 |
| 学习率 | 1e-4到3e-4 | 收敛慢,可能陷入局部最优 | 训练震荡,弱标签噪声被放大 | AdamW场景推荐2e-4 |
| Dice Loss权重 | 0.3-0.7 | 模型偏向大区域 | 对小裂缝敏感,但可能过拟合 | 与BCE组合使用,默认0.5 |
| 弱标签损失权重 | 0.0-1.0 | 弱标签影响小 | 弱标签噪声影响大 | 人工标注少时用0.7,多时用0.3 |
训练时建议先固定随机种子,否则同一份数据多次训练结果不稳定,无法对比实验。
4.2 弱标签阈值与噪声控制
弱标签生成后,如果直接作为训练目标,噪声会传递到模型里。需要设计几道防线:
第一道防线是关键词阈值。报告中出现“局部裂隙”“偶见裂隙”时,不应该和“裂隙发育”“岩芯破碎”同等对待。可以给关键词设置权重:
- 高置信词:“岩芯破碎”“裂隙发育”“裂缝密集”视为强正例。
- 低置信词:“偶见裂隙”“局部裂隙”视为弱正例,或者直接忽略。
- 只提到岩性未提裂隙时,不生成正例,但可以作为背景学习区。
第二道防线是mask边缘软化。深度映射中的误差通常表现为整体偏移,而不是随机噪声。如果mask直接硬编码,边缘附近一个像素的偏移就会造成训练信号错误。可以把mask边缘做3到5像素的渐变过渡。
第三道防线是置信度筛选。如果训练集里同时有弱标签和人工精标注,可以先用人工精标注子集训练一个小模型,再用这个小模型对弱标签区域进行预测。预测置信度低于阈值的像素,在训练时不计入损失。这个做法能显著减少误检。
4.3 学习环境与生产环境的差异
学习环境和生产环境面对的问题完全不同。学习环境只需要跑通流程,生产环境还要考虑深度对齐、数据版本、模型回滚和批量推理。
学习环境建议:
- 使用单张RTX显卡,输入尺寸先设为512。
- 固定少量样本,快速验证代码是否报错。
- 只训练一个模型,不追求SOTA。
- 用交互式工具可视化预测结果。
生产环境建议:
- 保存每个版本的数据集划分和参数配置,保证实验可回溯。
- 推理阶段要记录每张图像的深度范围、输入裁剪位置、模型版本。
- 增加“非岩心区域”这个类别,防止岩心盒边缘被误检为裂缝。
- 对预测mask做后处理:过滤面积过小的连通域,用形态学闭运算连接断裂裂缝。
- 模型输出后自动生成带深度标注的分析表,便于地质人员复核。
5. 常见问题排查:从现象到根因
5.1 常见问题速查表
| 问题现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 弱标签mask整体偏移 | 深度到像素映射参数错误,图像深度范围标注错误 | 在图像上叠加mask,检查已知深度的控制点 | 用两个深度标记点重新计算像素比例,并校正顶部深度 |
| 训练loss不下降 | 学习率过大,弱标签噪声过大,标签大部分为背景 | 打印每个batch的mask分布,检查正样本占比 | 降低学习率,改用Dice/Focal损失,过滤低置信弱标签 |
| 预测结果是一整块高亮 | 报告弱标签是块级标签,模型学到“区间内全是裂缝” | 只使用人工精标注训练并对比 | 增加人工精标注比例,或把弱标签作为辅助分支而非训练目标 |
| 裂缝被预测成碎片 | 裁剪尺寸过小,输入下采样过大,损失对薄结构不敏感 | 查看最小裂缝宽度占几个像素,检查预测mask连通性 | 提高输入分辨率,使用Dice损失,后处理做形态学闭运算 |
| 推理时mask与原始图对不齐 | 推理阶段忘记记录裁剪位置,或图像被缩放后没有同步变换mask | 对比原始图和预测图的分辨率与裁剪坐标 | 推理时保存原始图像尺寸,统一图像变换与mask变换逻辑 |
| 验证集分数高但新孔效果差 | 数据划分按图像随机划分,同一钻孔图像泄漏到多个集合 | 检查划分是否按hole_id进行 | 按钻孔划分训练/验证/测试集,重新生成splits |
5.2 案例一:mask与岩心位置系统性错位
最常见的现象是:弱标签mask看起来位置不对,整个标注区间比岩心实际破碎段靠上或靠下几十像素。
排查顺序:
- 先检查图像顶部深度和底部深度是否记录正确。
- 再检查报告中的深度区间与图像是否属于同一钻孔。
- 接着用一张已知深度标记点的图像计算像素比例,和脚本里的数值对比。
- 如果偏移量固定,修改
top_depth或pixels_per_meter。 - 如果偏移量不定,说明图像来源不统一,需要重新采集或人工校正。
注意:不要只修改代码里的数值来“凑对齐”。应该建立一个深度校验样本集,每张图至少包含两个可确认的深度控制点,每次批量生成后都自动校验误差。
5.3 案例二:弱标签噪声导致模型不收敛
现象是训练损失下降很慢,或者模型倾向于把整图都预测成裂缝。直接原因往往是弱标签太粗糙,“裂隙发育”的深度区间内真正裂缝只占很小一部分,但mask却把整行全部标为1。
解决方案有两种:
- 将弱标签mask从硬标签改成软标签,只有区间中心区域标为0.9,边缘区域标为0.5,背景保持0。
- 在训练损失中降低弱标签样本的权重,例如训练时把弱标签损失乘以0.3,把人工精标注损失保持1.0。
如果弱标签数据量很大,还可以加入标签清洗阶段:统计每个样本的mask前景占比,去掉前景占比异常高或异常低的样本。
5.4 案例三:裂缝细线被分割成离散碎片
裂缝是连续线条结构,但像素级分割网络在损失函数和下采样共同作用下,很容易把细裂缝预测断成一小段一小段。
修复方式有三步:
- 提高输入图像分辨率,保证裂缝宽度至少是3到5个像素。
- 在损失函数中加入Dice损失或拓扑约束,让小目标区域也参与梯度优化。
- 后处理阶段使用形态学闭运算连接近邻碎片:
import cv2 import numpy as np def postprocess(mask, min_area=50): kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, 8) result = np.zeros_like(mask) for i in range(1, num_labels): if stats[i, cv2.CC_STAT_AREA] >= min_area: result[labels == i] = 1 return result后处理能改善视觉效果,但无法替代模型本身的表达能力。如果裂缝普遍密集且细长,优先考虑更合适的模型和更高的输入分辨率。
6. 最佳实践与可复用检查清单
6.1 数据处理阶段的最佳实践
数据处理阶段决定整个实验上限。可以从几个方面把关:
- 每张岩心图像都单独记录深度范围,不依赖统一文件名推断。
- 报告解析后,人工抽检至少50条文本,确认关键词和深度区间抽取正确率。
- 弱标签mask生成后,随机挑选20张图叠加到原图上人工检查。
- 数据集划分严格按钻孔进行,验证集中不能出现训练钻孔的图像。
- 保存深度映射参数,不要每次重新计算,防止版本间不一致。
6.2 模型训练阶段的最佳实践
模型训练阶段要同时控制实验可复现性和模型效果:
- 固定随机种子,并记录在训练配置中。
- 训练前先跑5个batch检查数据形状、mask取值和损失值是否合理。
- 每次实验结束后保存完整配置、指标和预测可视化图。
- 不要只比较最终IoU,还要看Precision和Recall的平衡。裂缝漏检和误检在实际应用中代价不同,需要根据下游用途选择模型。
- 如果人工精标注数量太少,先用弱标签预训练,再用精标注微调。这个策略在大多数场景下比直接用少量精标注训练更稳定。
6.3 发布前可复用检查清单
发布模型前可以按下面清单逐项确认:
[ ] 训练集、验证集、测试集是否按钻孔严格划分 [ ] 报告解析输出的JSON是否有人工抽检记录 [ ] 弱标签mask是否与岩心图像做过叠加可视化检查 [ ] 深度映射参数是否记录在配置文件中 [ ] 训练配置(随机种子、学习率、损失权重、输入尺寸)是否完整保存 [ ] 裂缝预测结果是否有准确率和召回率的综合评估 [ ] 后处理参数是否固定,避免推理时输出不稳定 [ ] 推理推理代码是否能直接输入原始岩心图像并输出带深度信息的结果 [ ] 是否预留“非岩心区域”类别,避免岩心盒边框被误检 [ ] 模型版本、数据集版本、报告解析规则版本是否可回溯6.4 扩展方向
这套方法可以在多个方向继续扩展:
- 从二值裂缝分割扩展到多任务分割,同时识别裂缝、破碎带、矿脉和岩性界面。
- 用报告弱标签做半监督训练时,引入一致性正则或伪标签迭代,进一步降低人工标注成本。
- 结合三维钻孔柱状图,把多个截面的裂缝检测结果连接成岩体裂隙空间分布。
- 将报告解析从规则升级为预训练语言模型NER,适配更多非结构化编录文本。
- 部署时做成批量分析服务,输入岩心图像和报告表格,输出带深度刻度、裂缝面积占比和RQD评估的分析报告。
对于刚开始接触这个方向的开发者,建议先用一个钻孔的数据跑通完整流程,再逐步扩大数据量。先保证报告解析和深度对齐正确,再追求分割模型精度。弱标签加有监督分割的组合,本质上是在成本、噪声和模型效果之间做平衡,真正可用的系统必须把数据流水线、标签策略和模型评估看成一个整体来设计。