Unet模型训练sample_weight维度不匹配致Data cardinality错误排查
解决Unet分割模型样本权重数据基数不匹配问题
问题场景
训练用于冬季卫星图像道路网络识别的Unet模型时,使用compute_sample_weight分配样本权重阶段触发数据基数不匹配错误,训练数据X、Y的样本量为10216,但样本权重数组长度仅为2,无法匹配。
报错信息
Traceback (most recent call last): File "D:/Practise/Scripts/4_Multiclass_unet_sandstone.py", line 84, in <module> shuffle=False) File "C:\Users\User\anaconda3\envs\python_3_6\lib\site-packages\keras\engine\training.py", line 1148, in fit steps_per_execution=self._steps_per_execution) File "C:\Users\User\anaconda3\envs\python_3_6\lib\site-packages\keras\engine\data_adapter.py", line 1383, in get_data_handler return DataHandler(*args, **kwargs) File "C:\Users\User\anaconda3\envs\python_3_6\lib\site-packages\keras\engine\data_adapter.py", line 1150, in __init__ model=model) File "C:\Users\User\anaconda3\envs\python_3_6\lib\site-packages\keras\engine\data_adapter.py", line 241, in __init__ _check_data_cardinality(inputs) File "C:\Users\User\anaconda3\envs\python_3_6\lib\site-packages\keras\engine\data_adapter.py", line 1649, in _check_data_cardinality raise ValueError(msg) ValueError: Data cardinality is ambiguous: x sizes: 10216 y sizes: 10216 sample_weight sizes: 2 Make sure all arrays contain the same number of samples. Process finished with exit code 1
问题根源
compute_sample_weight调用错误:传入np.unique(train_masks_reshaped_encoded)作为第二个参数,导致函数返回的是2个类别的全局权重,而非每个像素对应的权重数组,长度与训练数据不匹配。sample_weight_mode设置错误:使用'temporal'适用于序列任务,而图像分割需要逐像素的权重匹配,应设置为'elementwise'。- 数据泄露风险:基于全量掩码计算权重,而非训练集掩码,违反训练/测试分离原则。
修正方案
1. 修正样本权重计算逻辑
基于训练集掩码生成逐像素的权重数组,确保形状与训练标签匹配:
# 提取训练集掩码并展平,仅基于训练集计算权重避免泄露 y_train_flat = y_train.reshape(-1) # 直接传入训练集展平后的标签,生成每个像素的权重 sample_weights_flat = compute_sample_weight('balanced', y_train_flat) # 将权重恢复为与训练掩码一致的形状,再扩展维度匹配one-hot编码后的标签 sample_weights = sample_weights_flat.reshape(y_train.shape[0], y_train.shape[1], y_train.shape[2]) sample_weights = np.expand_dims(sample_weights, axis=-1)
2. 调整模型编译参数
修改sample_weight_mode为适合分割任务的逐像素模式:
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'], sample_weight_mode='elementwise')
3. 完整修正后的关键代码片段
# 创建测试子集,取10%数据测试,剩余用于训练 X_train, X_test, y_train, y_test = train_test_split(train_images, train_masks_input, test_size=0.10, random_state=0) print('数据集中的类别值: ', np.unique(y_train)) # 0为背景 train_masks_cat = to_categorical(y_train, num_classes=n_classes) y_train_cat = train_masks_cat.reshape((y_train.shape[0], y_train.shape[1], y_train.shape[2], n_classes)) test_masks_cat = to_categorical(y_test, num_classes=n_classes) y_test_cat = test_masks_cat.reshape((y_test.shape[0], y_test.shape[1], y_test.shape[2], n_classes)) # 修正后的样本权重计算 y_train_flat = y_train.reshape(-1) sample_weights_flat = compute_sample_weight('balanced', y_train_flat) sample_weights = sample_weights_flat.reshape(y_train.shape[0], y_train.shape[1], y_train.shape[2]) sample_weights = np.expand_dims(sample_weights, axis=-1) print('权重数组形状:', sample_weights.shape) IMG_HEIGHT = X_train.shape[1] IMG_WIDTH = X_train.shape[2] IMG_CHANNELS = X_train.shape[3] def get_model(): return multiclass_unet_model(n_classes=n_classes, IMG_HEIGHT=IMG_HEIGHT, IMG_WIDTH=IMG_WIDTH, IMG_CHANNELS=IMG_CHANNELS) model = get_model() # 修正sample_weight_mode参数 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'], sample_weight_mode='elementwise') model.summary() history = model.fit(X_train, y_train_cat, batch_size=16, verbose=1, epochs=10, validation_data=(X_test, y_test_cat), sample_weight=sample_weights, shuffle=False) model.save('CNN.hdf5')
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

