CNN训练报错:预期dense_1形状(13,)但实际为(40,)求解决
这个错误ValueError: Error when checking target: expected dense_1 to have shape (13,) but got array with shape (40,)的核心问题是模型最后一层的输出维度(类别数)和你的训练/测试标签的one-hot编码维度不匹配。下面一步步分析并解决:
1. 修复get_num_of_classes函数的语法错误
你的get_num_of_classes函数存在明显的语法问题:
def get_num_of_classes(): return len(os.listdir('gestures/')) //13classes
这里的//13classes是无效代码——//是Python的整除运算符,后面需要跟数字,而13classes不是合法的数值。看起来你是想添加注释,应该用#而不是//。
更重要的是,这个函数的作用是返回你手势数据集的实际类别数:
- 如果你的
gestures文件夹下有40个类别子文件夹(对应标签0~39),那么应该直接返回文件夹数量:
def get_num_of_classes(): # 返回gestures目录下的子文件夹数量(即类别数) return len(os.listdir('gestures/'))
- 如果你确定是13个类别,那直接写死数值更稳妥:
def get_num_of_classes(): return 13 # 明确指定类别数
2. 确认标签的实际类别数
你需要验证训练标签的真实类别范围,在train()函数里添加几行代码查看:
def train(): with open("train_labels", "rb") as f: train_labels = np.array(pickle.load(f), dtype=np.int32) # 查看标签的最大值和最小值,确认类别范围 print(f"训练标签最小值: {np.min(train_labels)}, 最大值: {np.max(train_labels)}") print(f"实际类别数: {np.max(train_labels) + 1}") # 因为标签从0开始计数 # ... 其余代码保持不变
如果输出显示最大值是39,那实际类别数是40,这时候你的模型最后一层Dense(num_of_classes, ...)必须输出40维,而不是13维——这就是报错的核心原因。
3. 附带修复get_image_size函数的错误
你的get_image_size函数同样有语法问题:
def get_image_size(): img = cv2.imread('gestures/0/100.jpg', 0) return img.shape // 50*50
img.shape是一个元组(比如(高度, 宽度)),不能直接和整数做//运算。如果你想固定图像尺寸为50x50,直接返回即可:
def get_image_size(): # 固定输入图像尺寸为50x50 return (50, 50)
如果想读取样本图像的真实尺寸,应该返回元组的前两个元素:
def get_image_size(): img = cv2.imread('gestures/0/100.jpg', 0) # 返回图像的高度和宽度 return img.shape[:2]
4. 重新验证模型与标签的匹配度
修改完上述代码后,你可以在cnn_model()函数里打印类别数,确认模型输出维度:
def cnn_model(): num_of_classes = get_num_of_classes() print(f"模型输出类别数: {num_of_classes}") # ... 其余代码保持不变
同时,在train()函数里查看标签经过to_categorical后的形状:
train_labels = np_utils.to_categorical(train_labels) print(f"训练标签形状: {train_labels.shape}") # 应该是(样本数, num_of_classes)
确保两者的维度一致,就能解决这个匹配错误了。
内容的提问来源于stack exchange,提问作者epssy_sy

