How-To
Audit Bias Fairness
How to Audit AI Systems for Bias and Safety
Comprehensive guide to conducting technical audits of AI models for fairness, safety, and reliability.
Dr. Michael Wong
5 min read
Regular audits ensure AI systems remain fair, safe, and reliable. This guide provides a comprehensive audit framework.
Step 1: Establish Audit Baseline
Define what you’re measuring:
class ModelAudit:
def __init__(self, model, test_data):
self.model = model
self.test_data = test_data
self.baseline = self.establish_baseline()
def establish_baseline(self):
return {
'accuracy': self.calculate_accuracy(),
'precision': self.calculate_precision(),
'recall': self.calculate_recall(),
'f1_score': self.calculate_f1(),
'demographic_parity': self.calculate_demographic_parity()
}
def print_baseline(self):
for metric, value in self.baseline.items():
print(f"{metric}: {value:.4f}")
Step 2: Test for Bias
Gender Bias Detection
def detect_gender_bias(model, test_data):
male_data = test_data[test_data['gender'] == 'M']
female_data = test_data[test_data['gender'] == 'F']
male_accuracy = evaluate_accuracy(model, male_data)
female_accuracy = evaluate_accuracy(model, female_data)
gender_bias = abs(male_accuracy - female_accuracy)
return {
'male_accuracy': male_accuracy,
'female_accuracy': female_accuracy,
'bias': gender_bias,
'status': 'PASS' if gender_bias < 0.05 else 'FAIL'
}
Racial Bias Detection
def detect_racial_bias(model, test_data):
results = {}
for race in test_data['race'].unique():
race_data = test_data[test_data['race'] == race]
accuracy = evaluate_accuracy(model, race_data)
results[race] = accuracy
# Calculate disparity
max_accuracy = max(results.values())
min_accuracy = min(results.values())
disparity = max_accuracy - min_accuracy
return {
'by_race': results,
'disparity': disparity,
'status': 'PASS' if disparity < 0.05 else 'FAIL'
}
Age Bias Detection
def detect_age_bias(model, test_data):
age_groups = [
(18, 25), (26, 35), (36, 45), (46, 55), (56, 65), (65, 100)
]
results = {}
for low, high in age_groups:
group_data = test_data[(test_data['age'] >= low) & (test_data['age'] < high)]
accuracy = evaluate_accuracy(model, group_data)
results[f'{low}-{high}'] = accuracy
disparity = max(results.values()) - min(results.values())
return {
'by_age_group': results,
'disparity': disparity
}
Step 3: Fairness Metrics
Demographic Parity
def demographic_parity(model, test_data, protected_attr, target='positive'):
"""
Checks if positive prediction rate is equal across groups
"""
groups = test_data[protected_attr].unique()
positive_rates = {}
for group in groups:
group_data = test_data[test_data[protected_attr] == group]
predictions = model.predict(group_data)
positive_rate = (predictions == target).sum() / len(predictions)
positive_rates[group] = positive_rate
# Calculate parity
max_rate = max(positive_rates.values())
min_rate = min(positive_rates.values())
parity = min_rate / max_rate if max_rate > 0 else 1.0
return {
'positive_rates': positive_rates,
'parity_ratio': parity,
'status': 'PASS' if parity > 0.8 else 'FAIL' # 80/20 rule
}
Equalized Odds
def equalized_odds(model, test_data, protected_attr, target):
"""
Checks if true positive rate and false positive rate are equal across groups
"""
groups = test_data[protected_attr].unique()
tpr_by_group = {}
fpr_by_group = {}
for group in groups:
group_data = test_data[test_data[protected_attr] == group]
predictions = model.predict(group_data)
# True Positive Rate
tp = ((predictions == target) & (group_data['label'] == target)).sum()
p = (group_data['label'] == target).sum()
tpr = tp / p if p > 0 else 0
tpr_by_group[group] = tpr
# False Positive Rate
fp = ((predictions == target) & (group_data['label'] != target)).sum()
n = (group_data['label'] != target).sum()
fpr = fp / n if n > 0 else 0
fpr_by_group[group] = fpr
# Calculate disparity
tpr_disparity = max(tpr_by_group.values()) - min(tpr_by_group.values())
fpr_disparity = max(fpr_by_group.values()) - min(fpr_by_group.values())
return {
'tpr_by_group': tpr_by_group,
'fpr_by_group': fpr_by_group,
'tpr_disparity': tpr_disparity,
'fpr_disparity': fpr_disparity
}
Step 4: Safety Testing
Adversarial Robustness
def test_adversarial_robustness(model, test_data):
from adversarial.attacks import FGSM
attack = FGSM(epsilon=0.1)
adversarial_data = attack.generate(test_data)
clean_accuracy = evaluate_accuracy(model, test_data)
adversarial_accuracy = evaluate_accuracy(model, adversarial_data)
robustness = adversarial_accuracy / clean_accuracy
return {
'clean_accuracy': clean_accuracy,
'adversarial_accuracy': adversarial_accuracy,
'robustness': robustness,
'status': 'PASS' if robustness > 0.8 else 'FAIL'
}
Edge Cases
def test_edge_cases(model, test_data):
results = {}
# Test with missing values
missing_data = test_data.copy()
missing_data.iloc[0, 0] = None
try:
predictions = model.predict(missing_data)
results['missing_values'] = 'PASS'
except Exception as e:
results['missing_values'] = f'FAIL: {e}'
# Test with extreme values
extreme_data = test_data.copy()
extreme_data.iloc[0] = extreme_data.max() * 1000
try:
predictions = model.predict(extreme_data)
results['extreme_values'] = 'PASS'
except Exception as e:
results['extreme_values'] = f'FAIL: {e}'
# Test with empty input
try:
predictions = model.predict(test_data[:0])
results['empty_input'] = 'PASS'
except Exception as e:
results['empty_input'] = f'FAIL: {e}'
return results
Step 5: Performance Audit
Consistency Check
def test_consistency(model, test_data, num_runs=10):
"""
Test if model produces consistent predictions for same input
"""
first_input = test_data.iloc[0]
predictions = []
for _ in range(num_runs):
pred = model.predict([first_input])
predictions.append(pred[0])
unique_predictions = set(predictions)
consistency = (len(unique_predictions) == 1)
return {
'predictions': predictions,
'consistent': consistency,
'status': 'PASS' if consistency else 'FAIL'
}
Calibration Check
def test_calibration(model, test_data):
"""
Check if confidence scores match actual accuracy
"""
predictions, confidences = model.predict_with_confidence(test_data)
# Group by confidence bins
bins = [0.0, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
calibration = {}
for i in range(len(bins) - 1):
lower, upper = bins[i], bins[i + 1]
mask = (confidences >= lower) & (confidences < upper)
if mask.sum() > 0:
accuracy = (predictions[mask] == test_data.iloc[mask]['label']).mean()
avg_confidence = confidences[mask].mean()
calibration[f'{lower:.1f}-{upper:.1f}'] = {
'confidence': avg_confidence,
'accuracy': accuracy,
'calibration_error': abs(accuracy - avg_confidence)
}
return calibration
Step 6: Create Audit Report
def generate_audit_report(model, test_data):
report = {
'timestamp': datetime.now(),
'model_id': model.id,
'performance': evaluate_performance(model, test_data),
'bias_assessment': {
'gender': detect_gender_bias(model, test_data),
'race': detect_racial_bias(model, test_data),
'age': detect_age_bias(model, test_data)
},
'fairness_metrics': {
'demographic_parity': demographic_parity(model, test_data, 'race'),
'equalized_odds': equalized_odds(model, test_data, 'race', 'positive')
},
'safety_tests': {
'adversarial_robustness': test_adversarial_robustness(model, test_data),
'edge_cases': test_edge_cases(model, test_data),
'consistency': test_consistency(model, test_data),
'calibration': test_calibration(model, test_data)
},
'recommendations': generate_recommendations(report)
}
return report
Audit Checklist
Performance Audit
□ Accuracy on all data splits
□ Precision, recall, F1 scores
□ ROC-AUC scores
□ Performance on imbalanced classes
Fairness Audit
□ Demographic parity across groups
□ Equal opportunity/equalized odds
□ Calibration within groups
□ Representation in training data
Safety Audit
□ Adversarial robustness
□ Edge case handling
□ Prediction consistency
□ Confidence calibration
□ Handling of missing data
Compliance Audit
□ Data usage compliance
□ Documentation completeness
□ Monitoring implementation
□ Incident response readiness
Audit Frequency
- Critical models: Monthly
- High-impact models: Quarterly
- Standard models: Semi-annually
- Low-risk models: Annually
Conclusion
Regular, systematic audits ensure AI systems remain fair, safe, and reliable. Implement this framework to maintain high standards for your AI deployments.