fit_generator中class_weight数组可用字典报错?UNet二值图像训练疑问
解决UNet分割任务中
class_weight报错的问题 首先得明确报错的核心原因:class_weight这个参数是为图像分类任务设计的——这类任务的目标是1D数组,每个元素对应单张图片的类别标签(比如[0,1,1,0])。但你用UNet做的是语义分割任务,目标是和输入图像同尺寸的2D/3D掩码(形状为(batch_size, height, width, 1)),每个像素都对应一个类别,属于逐像素的分类场景。Keras检测到你的目标是3+维度的张量时,无法理解如何将类别权重应用到每个像素上,因此抛出了ValueError。
两种格式的差异
你提到用numpy数组形式时代码能正常运行,大概率是这两种场景的目标形态或参数使用逻辑不同:
- 用生成器时,输出的目标是完整的分割掩码(多维度张量),同时你传入了
class_weight参数,触发了Keras对目标维度的检查,直接触发报错。 - 用numpy数组直接训练时,要么你没传入
class_weight参数,要么你可能误将目标处理成了1D类别索引(这其实不符合分割任务的需求),或者你手动实现了加权损失逻辑,绕过了class_weight的限制。
正确处理分割任务类别不平衡的方法
既然class_weight不适合分割场景,咱们可以把类别权重融入到损失函数中,自定义一个加权损失。比如针对二值分割的加权交叉熵:
import tensorflow.keras.backend as K def weighted_binary_crossentropy(y_true, y_pred): # 你的类别权重 weight_0 = 5.76901408 weight_1 = 0.54744721 # 加入epsilon避免log(0)的计算错误 bce_loss = (weight_0 * y_true * K.log(y_pred + K.epsilon()) + weight_1 * (1 - y_true) * K.log(1 - y_pred + K.epsilon())) return -K.mean(bce_loss)
之后在编译模型时使用这个自定义损失:
model.compile(optimizer='sgd', loss=weighted_binary_crossentropy, metrics=['accuracy'])
这样就能让模型在训练时自动给少数类(类别0)的像素损失赋予更高权重,解决类别不平衡问题,同时不会触发维度相关的报错。
内容的提问来源于stack exchange,提问作者Sarvagya Gupta
相关产品推荐
相关产品推荐

