Keras训练CNN表情识别模型报Shapes(None,12)(None,11)不兼容错误
报错原因
核心错误是模型输出维度和验证集标签维度不匹配:验证集标签是12分类的独热编码,形状为(None, 12),但加载的模型最后一层输出仅11维,形状为(None, 11),计算交叉熵损失时维度无法对齐直接触发报错。具体触发问题点如下:
- 本地残留了之前训练的旧模型文件
cnn_model_keras.h5,旧模型训练时数据集只有11个类别,最后全连接层输出节点为11,和当前12类的标签维度完全不匹配。 - 代码同时混用了两套图像数据格式配置:开头设置
K.set_image_data_format('channels_first'),构建卷积层时又硬编码data_format='channels_last',配置冲突会导致维度判断异常。 - 加载训练完的模型后多余添加了
model.add(BatchNormalization(),name='new'),训练完成做评估时不需要往已有模型里加新层,这个操作会直接破坏模型原有输出结构。 ModelCheckpoint回调监控的指标写的是val_acc,新版Keras中验证集准确率的字段名为val_accuracy,监控字段错误会导致回调无法正常保存当前12分类训练的最优权重,默认加载的就是目录里残留的旧模型。- SGD优化器初始化用了已废弃的
lr参数,新版Keras需要用learning_rate传参,这个问题会触发优化器状态加载失败的警告。
修复步骤
- 先删除代码运行目录下残留的旧
cnn_model_keras.h5文件,避免加载历史11分类训练的权重。 - 删除开头的
K.set_image_data_format('channels_first')配置,和卷积层设置的channels_last格式保持统一。 - 删除加载模型后多余的
model.add(BatchNormalization(),name='new')代码行。 - 把
ModelCheckpoint的监控参数从val_acc改为val_accuracy,确保当前训练的12分类模型权重能被正常保存。 - 把SGD优化器初始化参数从
lr=1e-2改为learning_rate=1e-2,消除废弃参数警告。
修正后的核心代码片段如下:
import numpy as np import pickle import cv2, os from keras import optimizers from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.utils import np_utils from keras.callbacks import ModelCheckpoint from tensorflow.keras.layers import BatchNormalization from tensorflow.keras import optimizers from keras import backend as K from keras.callbacks import TensorBoard from keras.models import load_model from time import time os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' def get_image_size(): img = cv2.imread('dataset/0/1.jpg', 0) return img.shape def get_num_of_classes(): return len(os.listdir('dataset/')) image_x, image_y = get_image_size() def cnn_model(): num_of_classes = get_num_of_classes() model = Sequential() model.add(Conv2D(32, (5,5), input_shape=(image_x, image_y, 1), activation='relu', data_format='channels_last')) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size=(10, 10), strides=(10, 10), padding='same')) model.add(Flatten()) model.add(Dense(1024, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.6)) model.add(Dense(num_of_classes, activation='softmax')) sgd = optimizers.SGD(learning_rate=1e-2) model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) filepath="cnn_model_keras.h5" checkpoint1 = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max') callbacks_list = [checkpoint1] from keras.utils import plot_model plot_model(model, to_file='model.png', show_shapes=True) return model, callbacks_list def train(): with open("train_images", "rb") as f: train_images = np.array(pickle.load(f)) with open("train_labels", "rb") as f: train_labels = np.array(pickle.load(f), dtype=np.uint8) with open("test_images", "rb") as f: test_images = np.array(pickle.load(f)) with open("test_labels", "rb") as f: test_labels = np.array(pickle.load(f), dtype=np.uint8) with open("val_images", "rb") as f: val_images = np.array(pickle.load(f)) with open("val_labels", "rb") as f: val_labels = np.array(pickle.load(f), dtype=np.uint8) train_images = np.reshape(train_images, (train_images.shape[0], image_x, image_y, 1)) test_images = np.reshape(test_images, (test_images.shape[0], image_x, image_y, 1)) val_images = np.reshape(val_images, (val_images.shape[0], image_x, image_y, 1)) train_labels = np_utils.to_categorical(train_labels) test_labels = np_utils.to_categorical(test_labels) val_labels = np_utils.to_categorical(val_labels) model, callbacks_list = cnn_model() tensorboard = TensorBoard(log_dir="./logs/{}".format(time())) callbacks_list.append(tensorboard) model.fit(train_images, train_labels, validation_data=(test_images, test_labels), epochs=10, batch_size=100, callbacks=callbacks_list) model = load_model('cnn_model_keras.h5') model.summary() scores = model.evaluate(val_images, val_labels, verbose=1) print("CNN Error: %.2f%%" % (100-scores[1]*100)) train()
注意:重新运行代码前必须确认旧的h5模型文件已经删除,否则还是会加载到不匹配的旧权重。
内容的提问来源于stack exchange,提问作者ash_coder
相关产品推荐
相关产品推荐

