训练EfficientNetB3遇维度不匹配ValueError,求排查代码问题
1. GLCM特征与图像拼接的维度不匹配错误
在compute_glcm_transformed_image函数中,img_resized是2维数组(300,300),而glcm_features是greycomatrix输出ravel后的1维数组(65536,)。你直接用np.concatenate((img_resized, glcm_features), axis=-1)拼接时,2维数组的axis=-1是列维度(长度300),1维数组的axis=-1是自身长度(65536),两者维度无法对齐,导致返回的transformed_image形状混乱,最终data_list中元素维度不一致,触发报错。
修正方案:
如果要将GLCM特征与图像结合,需把GLCM特征转换为和图像同维度的特征图,再进行通道拼接:
def compute_glcm_transformed_image(image_path, target_size=(300, 300)): img = io.imread(image_path) img_gray = color.rgb2gray(img) img_resized = resize(img_gray, target_size) # 把2维灰度图扩展为单通道:(300,300) → (300,300,1) img_resized = np.expand_dims(img_resized, axis=-1) glcm = feature.greycomatrix((img_resized * 255).astype(np.uint8)[...,0], [5], [0], 256, symmetric=True, normed=True) glcm_features = np.ravel(glcm) # 将GLCM特征转为同尺寸单通道特征图(示例用均值填充,也可按需设计) glcm_feature_map = np.full((target_size[0], target_size[1], 1), glcm_features.mean()) # 拼接为(300,300,2)的多通道输入 return np.concatenate((img_resized, glcm_feature_map), axis=-1)
2. 未定义变量提前使用的逻辑错误
遍历图像的循环中,你提前使用了img_height、img_width、channels、len(glcm_features)这些变量,但这些变量都是在循环结束、X生成之后才定义的,会直接触发NameError;即使你手动提前定义过,也会因形状不匹配导致后续数据维度混乱。
修正方案:
提前定义固定参数,直接使用处理后图像的形状:
# 提前定义目标尺寸 img_height, img_width = 300, 300 data_list = [] labels_list = [] for class_folder in os.listdir(main_directory): class_path = os.path.join(main_directory, class_folder) if os.path.isdir(class_path): for filename in os.listdir(class_path): if filename.endswith(".jpg") or filename.endswith(".png"): image_path = os.path.join(class_path, filename) transformed_image = compute_glcm_transformed_image(image_path) # 直接添加处理后的图像,无需额外reshape data_list.append(transformed_image) labels_list.append(class_folder)
3. 输入形状与EfficientNetB3不兼容的错误
EfficientNetB3要求输入为(height, width, channels)格式的多通道图像,而你当前拼接后的输入是(300, 300 + 65536)的2维数组,完全不符合CNN模型的输入规范,会导致模型输入层与数据不匹配。
推荐修正方案:使用多输入模型
分别传入灰度图像和GLCM特征,让模型同时学习视觉特征和纹理特征:
# 1. 图像输入分支(适配EfficientNetB3的3通道要求) image_input = Input(shape=(img_height, img_width, 1), name='image_input') # 将单通道转为3通道 image_input_3ch = tf.keras.layers.Conv2D(3, (1,1))(image_input) base_model = EfficientNetB3(weights='imagenet', include_top=False, input_tensor=image_input_3ch) x_image = base_model.output x_image = GlobalAveragePooling2D()(x_image) # 2. GLCM特征输入分支 glcm_input = Input(shape=(65536,), name='glcm_input') x_glcm = Dense(256, activation='relu')(glcm_input) x_glcm = Dropout(0.2)(x_glcm) # 3. 拼接两个分支输出 x = tf.keras.layers.concatenate([x_image, x_glcm]) x = Dense(1024, activation='relu')(x) x = Dense(512, activation='relu')(x) # 替换为实际类别数量 num_classes = len([f for f in os.listdir(main_directory) if os.path.isdir(os.path.join(main_directory, f))]) preds = Dense(num_classes, activation='softmax')(x) model = Model(inputs=[image_input, glcm_input], outputs=preds)
4. 其他潜在问题
- 标签处理:
labels_list是字符串类名,建议转换为整数编码,避免sparse_categorical_crossentropy的潜在问题:
from sklearn.preprocessing import LabelEncoder le = LabelEncoder() y = le.fit_transform(labels_list)
- EfficientNetB3默认输入尺寸为224x224,若使用300x300需确保所有输入图像形状一致。
内容的提问来源于stack exchange,提问作者Arjun

