如何在Keras CNN人脸识别模型中绘制ROC、FAR、FRR?求协助
Fixing ROC, FAR, and FRR Calculation for Your Keras CNN Face Recognition Model
Hey Sara, awesome work getting your CNN model trained on Faces94 with a solid 90.97% accuracy! Let's tackle those issues with calculating and plotting ROC curves, FAR, and FRR—these are key metrics for evaluating face recognition systems, so it's great you're focusing on them.
First, let's address a few small gaps in your original code that might have caused issues:
- Missing imports for critical libraries (like
numpy,sklearnutilities, and Keras model layers) - No one-hot encoding for labels (required for
categorical_crossentropy) - Hardcoded output layer size (72) instead of using dynamic class count from your dataset
- No logic to extract predicted probabilities (needed for ROC/FAR/FRR, since these metrics depend on thresholding probabilities, not just predicted classes)
Below is the full, corrected code with step-by-step additions for calculating and visualizing your desired metrics:
Full Corrected Code
import keras from keras import backend as K from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout from keras.layers.advanced_activations import LeakyReLU from keras.utils import to_categorical import os import numpy as np import joblib import tensorflow as tf from sklearn.model_selection import train_test_split from sklearn.metrics import roc_curve, auc from sklearn.preprocessing import label_binarize import matplotlib.pyplot as plt from importlib import reload # Set Keras backend to TensorFlow def set_keras_backend(backend): if K.backend() != backend: os.environ['KERAS_BACKEND'] = backend reload(K) assert K.backend() == backend set_keras_backend("tensorflow") # Load your dataset DATA = joblib.load(open('Data.sav', 'rb')) LABEL = joblib.load(open('Lable.sav', 'rb')) # Note: kept your filename typo "Lable"—adjust if needed print(f"Data shape: {DATA.shape}") print(f"Label shape: {LABEL.shape}") print(f"TensorFlow version: {tf.__version__}") # Split data into train/test sets X_train, X_test, y_train, y_test = train_test_split(DATA, LABEL, test_size=0.30, random_state=45) # Reshape and normalize image data X_train = np.reshape(X_train, (X_train.shape[0], 200, 180, 1)).astype('float32') / 255.0 X_test = np.reshape(X_test, (X_test.shape[0], 200, 180, 1)).astype('float32') / 255.0 # One-hot encode labels (required for categorical crossentropy) num_classes = len(np.unique(LABEL)) Y_train = to_categorical(y_train, num_classes=num_classes) Y_test = to_categorical(y_test, num_classes=num_classes) # Build your CNN model (adjusted for dynamic class count) model = Sequential() model.add(Conv2D(32, kernel_size=(5,5), strides=(1,1), activation='relu', input_shape=(200, 180, 1))) model.add(LeakyReLU(alpha=0.1)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(64, (5,5), activation='relu')) model.add(LeakyReLU(alpha=0.1)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(128, (5,5), activation='relu')) model.add(LeakyReLU(alpha=0.1)) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.30)) model.add(Flatten()) model.add(Dense(1000, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) # Dynamic output size based on dataset # Compile and train the model model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adam(), metrics=['accuracy']) hist = model.fit(X_train, Y_train, batch_size=32, epochs=12, verbose=1, validation_data=(X_test, Y_test)) # Evaluate model accuracy score = model.evaluate(X_test, Y_test, verbose=0) print(f"Accuracy: {score[1]*100:.2f}%") # ---------------------- ROC Curve Calculation (Multi-Class) ---------------------- # Binarize test labels for multi-class ROC analysis y_test_binarized = label_binarize(y_test, classes=np.arange(num_classes)) # Get predicted probabilities from the model y_pred_proba = model.predict(X_test) # Compute ROC and AUC for each class fpr = dict() tpr = dict() roc_auc = dict() for i in range(num_classes): fpr[i], tpr[i], _ = roc_curve(y_test_binarized[:, i], y_pred_proba[:, i]) roc_auc[i] = auc(fpr[i], tpr[i]) # Compute micro-average ROC (aggregates all class predictions) fpr["micro"], tpr["micro"], _ = roc_curve(y_test_binarized.ravel(), y_pred_proba.ravel()) roc_auc["micro"] = auc(fpr["micro"], tpr["micro"]) # Plot micro-average ROC curve plt.figure(figsize=(8, 6)) plt.plot(fpr["micro"], tpr["micro"], label=f'Micro-average ROC Curve (AUC = {roc_auc["micro"]:.2f})') plt.plot([0, 1], [0, 1], 'k--', label='Random Guess') plt.xlabel('False Positive Rate (FAR)') plt.ylabel('True Positive Rate (1 - FRR)') plt.title('Multi-Class ROC Curve (Micro-Average)') plt.legend(loc="lower right") plt.show() # ---------------------- FAR, FRR, and EER Calculation ---------------------- # Get predicted probabilities for the true class of each test sample true_class_probs = y_pred_proba[np.arange(len(y_test)), y_test] # Test a range of probability thresholds thresholds = np.linspace(0, 1, 1000) far_values = [] frr_values = [] for thresh in thresholds: # Calculate FAR: % of incorrect predictions where model confidence exceeded threshold pred_classes = np.argmax(y_pred_proba, axis=1) false_accepts = np.sum((pred_classes != y_test) & (np.max(y_pred_proba, axis=1) > thresh)) total_incorrect = np.sum(pred_classes != y_test) current_far = false_accepts / total_incorrect if total_incorrect > 0 else 0 # Calculate FRR: % of correct samples where model confidence in true class was below threshold false_rejects = np.sum(true_class_probs < thresh) current_frr = false_rejects / len(y_test) far_values.append(current_far) frr_values.append(current_frr) # Convert to numpy arrays for easier processing far_values = np.array(far_values) frr_values = np.array(frr_values) # Find Equal Error Rate (EER) where FAR ≈ FRR eer_idx = np.argmin(np.abs(far_values - frr_values)) eer_threshold = thresholds[eer_idx] eer_value = (far_values[eer_idx] + frr_values[eer_idx]) / 2 # Plot FAR and FRR against thresholds plt.figure(figsize=(8, 6)) plt.plot(thresholds, far_values, label='False Accept Rate (FAR)') plt.plot(thresholds, frr_values, label='False Reject Rate (FRR)') plt.scatter(eer_threshold, eer_value, color='red', marker='o', label=f'EER = {eer_value:.2f} (Threshold = {eer_threshold:.2f})') plt.xlabel('Probability Threshold') plt.ylabel('Rate') plt.title('FAR and FRR vs. Confidence Threshold') plt.legend(loc="upper right") plt.grid(True) plt.show() # Print EER results print(f"Equal Error Rate (EER): {eer_value*100:.2f}%") print(f"Optimal Threshold at EER: {eer_threshold:.2f}")
Key Explanations
- One-Hot Encoding: Your model uses
categorical_crossentropy, which requires labels to be in one-hot format. Theto_categoricalfunction handles this conversion. - Predicted Probabilities: Instead of just getting predicted classes, we use
model.predict(X_test)to get the full probability distribution over all classes—this is essential for threshold-based metrics like ROC, FAR, and FRR. - Multi-Class ROC: Since you're doing face recognition (a multi-class task), we use
label_binarizeto convert labels into a binary format for each class, then compute a micro-average ROC to summarize overall performance. - FAR & FRR:
- FAR: Measures how often the model incorrectly accepts an imposter (wrong class with high confidence).
- FRR: Measures how often the model incorrectly rejects a genuine user (correct class with low confidence).
- EER: The threshold where FAR and FRR are equal—this is a standard benchmark for face recognition systems.
Let me know if you run into any issues with this code, or if you want to dive deeper into any of these metrics!
内容的提问来源于stack exchange,提问作者sara2020
相关产品推荐
相关产品推荐

