新手起步优先用带resnet34编码器的u-net轻量变体,而非原生deeplabv3;因后者在tensorflow 2.x中官方支持弱,需手动拼接aspp模块易出错,而u-net结构清晰、调试友好、cpu亦可运行,且配套资源完备、开箱即用。

语义分割模型怎么选:U-Net 还是 DeepLabV3?
直接说结论:新手起步优先用 tf.keras.applications.U Net 的轻量变体(比如带 ResNet34 编码器的版本),而不是原生 DeepLabV3。后者在 TensorFlow 2.x 中官方支持弱,tf.keras.applications 下压根没它,得自己拼接 ASPP 模块,容易卡在空洞卷积维度不匹配上。
实际开发中更推荐基于 tensorflow.keras 自定义 U-Net 结构——编码器可用 tf.keras.applications.ResNet50(设 include_top=False),解码器用转置卷积 + 跳连,控制好 strides 和 padding,否则输出尺寸对不上标签图。
- 输入图像必须和 mask 同尺寸,且需做
tf.image.resize对齐,不能只 resize 图像漏掉 mask - mask 必须是整数型(
tf.int32),不能是 float;否则用tf.keras.losses.SparseCategoricalCrossentropy会报InvalidArgumentError: logits and labels must have the same first dimension - batch size 别设太大,GPU 显存容易爆——U-Net 解码路径 feature map 尺寸大,
batch_size=2在 1080Ti 上就常触发ResourceExhaustedError
数据加载怎么写才不崩:tf.data.Dataset 里的坑
语义分割的数据加载最容易栽在路径配对和 shape 对齐上。别用 tf.keras.utils.image_dataset_from_directory,它不支持双路输入(图像 + mask)。
正确做法是构造两个 tf.data.Dataset 分别读图和读 mask,再用 tf.data.Dataset.zip 合并,且必须加 .map 统一预处理逻辑:
def load_and_preprocess(image_path, mask_path):
image = tf.io.read_file(image_path)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.cast(image, tf.float32) / 255.0
<pre class="brush:python;toolbar:false;">mask = tf.io.read_file(mask_path)
mask = tf.image.decode_png(mask, channels=1) # 注意是 png,且 channels=1
mask = tf.cast(mask, tf.int32)
image = tf.image.resize(image, [256, 256])
mask = tf.image.resize(mask, [256, 256], method='nearest') # 插值必须用 nearest!
return image, mask
-
tf.image.decode_png读 mask 时漏掉channels=1→ mask 变成 3 通道,后续SparseCategoricalCrossentropy报错 - mask resize 用
method='bilinear'→ 标签像素被模糊成小数,训练时 loss 突然 nan - 没调
.cache().shuffle().batch()→ 每 epoch 重读硬盘,IO 成瓶颈,GPU 利用率常年低于 30%
损失函数和指标怎么配:别直接套 categorical_crossentropy
如果你的 mask 是单通道整数标签(比如 0=background, 1=car, 2=person),就必须用 SparseCategoricalCrossentropy,而不是 CategoricalCrossentropy。后者要求 label 是 one-hot,而你手里只有 [H,W] 形状的整数数组。
另外,from_logits=True 必须设——U-Net 最后一层通常不接 softmax,直接输出 logits,让 loss 内部算 softmax 更数值稳定:
model.compile(
optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['sparse_categorical_accuracy']
)
- 忘了
from_logits=True→ loss 值异常高(>5),accuracy 停在 0.0 左右不动 - metrics 用
'accuracy'而不是'sparse_categorical_accuracy'→ 计算时自动把 logits 当概率,结果全错 - 类别不平衡严重时(比如 background 占 90%),光看 accuracy 没意义,得加
tf.keras.metrics.IoU,但注意要指定num_classes和target_class_ids
推理时 mask 怎么还原:argmax 后还要做后处理
模型输出是 [B,H,W,num_classes] 的 logits,tf.argmax 只能拿到索引,但真实场景中往往需要过滤小区域、填孔、或做 CRF 优化边界——这些没法靠模型端到端学出来。
最简可行流程是:
pred_logits = model.predict(image_batch) pred_mask = tf.argmax(pred_logits, axis=-1) # shape [B,H,W] pred_mask = pred_mask.numpy().astype(np.uint8)
- 直接
np.argmax而不用tf.argmax→ GPU tensor 没转 CPU,报TypeError: int() argument must be a string... - 输出没做
np.squeeze→ batch size=1 时 shape 是[1,H,W],画图显示全黑(matplotlib 当成 3D 数组) - 想可视化时用
plt.imshow(pred_mask, cmap='tab20'),别用默认 cmap,否则类别多时颜色重复难区分
真正部署时,tf.argmax 只是起点;边界锯齿、小目标漏检、同类粘连,都得靠 OpenCV 的 cv2.morphologyEx 或 skimage.segmentation.clear_border 补救——模型不管这些,得你手动兜底。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











