You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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, sklearn utilities, 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

  1. One-Hot Encoding: Your model uses categorical_crossentropy, which requires labels to be in one-hot format. The to_categorical function handles this conversion.
  2. 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.
  3. Multi-Class ROC: Since you're doing face recognition (a multi-class task), we use label_binarize to convert labels into a binary format for each class, then compute a micro-average ROC to summarize overall performance.
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:53:11