基于CNN的人脸微笑检测模型训练报错:数组真值判断歧义
解决Keras训练CNN时的ValueError: 数组真值不明确问题
问题根源
错误出在class_weight参数的格式上:代码中计算的classWeight是numpy数组,但Keras的model.fit()要求class_weight为字典类型(键为类别索引,值为对应权重)。传入数组时,Keras内部尝试判断其真值,触发了"数组真值不明确"的报错。此外代码还存在拼写错误、导入缺失和缩进问题,也需要同步修正。
修正步骤
1. 补全缺失导入并修正拼写错误
添加必要库的导入,同时修正rom imutils import paths的拼写错误:
import numpy as np import os import imutils from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, Activation, MaxPooling2D, Flatten, Dense from tensorflow.keras.utils import np_utils
2. 转换class_weight为字典格式
将原数组格式的权重转换为Keras要求的字典结构:
classTotals = labels.sum(axis=0) # 生成{类别索引: 权重值}的字典 classWeight = {i: classTotals.max() / classTotals[i] for i in range(len(classTotals))}
3. 修正LeNet类的缩进问题
原代码中build方法内的层添加代码缩进错误,导致方法返回空模型。修正后加上@staticmethod装饰器,确保无需实例化即可调用:
class LeNet: @staticmethod def build(width, height, depth, classes): model = Sequential() inputShape = (height, width, depth) # 第一层CONV=>RELU=>POOL model.add(Conv2D(20, (5, 5), padding="same", input_shape=inputShape)) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) # 第二层CONV=>RELU=>POOL model.add(Conv2D(50, (5, 5), padding="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) # 全连接层与扁平化 model.add(Flatten()) model.add(Dense(500)) model.add(Activation("relu")) model.add(Dense(classes)) model.add(Activation("softmax")) return model
完整修正后的代码
from google.colab import drive drive.mount('/content/drive') # 补全缺失导入 import numpy as np import os import imutils from imutils import paths import cv2 from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, Activation, MaxPooling2D, Flatten, Dense from tensorflow.keras.utils import img_to_array, np_utils data = [] labels = [] imagePaths = list(paths.list_images("/content/drive/MyDrive/dataset/SMILEs")) for imagePath in sorted(imagePaths): # 图像预处理 image = cv2.imread(imagePath) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = imutils.resize(image, width=28) image = img_to_array(image) data.append(image) # 提取标签 label = imagePath.split(os.path.sep)[-3] label = "smiling" if label == "positives" else "not_smiling" labels.append(label) # 数据标准化与标签编码 data = np.array(data, dtype="float") / 255.0 labels = np.array(labels) le = LabelEncoder().fit(labels) labels = np_utils.to_categorical(le.transform(labels), 2) # 计算类别权重并转换为字典格式 classTotals = labels.sum(axis=0) classWeight = {i: classTotals.max() / classTotals[i] for i in range(len(classTotals))} # 划分训练测试集 (trainX, testX, trainY, testY) = train_test_split(data,labels, test_size=0.20, stratify=labels, random_state=42) # 定义LeNet模型 class LeNet: @staticmethod def build(width, height, depth, classes): model = Sequential() inputShape = (height, width, depth) model.add(Conv2D(20, (5, 5), padding="same", input_shape=inputShape)) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Conv2D(50, (5, 5), padding="same")) model.add(Activation("relu")) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Flatten()) model.add(Dense(500)) model.add(Activation("relu")) model.add(Dense(classes)) model.add(Activation("softmax")) return model # 构建并训练模型 model = LeNet.build(28, 28, 1, 2) print("[INFO] compiling model...") model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=['accuracy']) print("[INFO] training network...") H = model.fit(trainX, trainY, validation_data=(testX, testY), class_weight=classWeight, batch_size=64, epochs=15, verbose=1)
内容的提问来源于stack exchange,提问作者Ibrahim Oussama benhabi
相关产品推荐
相关产品推荐

