Image Classification
Transformers
Safetensors
English
age-estimation
age-prediction
gender-classification
race-classification
ethnicity-classification
face-analysis
demographics
facial-attributes
fairness
bias-evaluation
convnext
Instructions to use TimmaJ/age-gender-race-prediction with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use TimmaJ/age-gender-race-prediction with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-classification", model="TimmaJ/age-gender-race-prediction") pipe("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/parrots.png")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("TimmaJ/age-gender-race-prediction", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 4,108 Bytes
8a7c723 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | """
Correct aggregate group shares for classifier error.
If you classify a corpus and report the share of each group, those shares are
biased by classifier error, and the bias is largest exactly where accuracy is
lowest. With a confusion matrix M where
M[i, j] = P(predicted = i | true = j)
observed and true shares are related by p_obs = M @ p_true, so
p_true ~= pinv(M) @ p_obs
This is the standard quantification / prior-correction estimator. Its bias goes
to zero as M approaches the identity, and it is base-rate invariant, so a
confusion matrix estimated on a stratified validation sample is valid here.
Two cautions:
* Estimate M with the SAME pipeline that produced the counts you are
correcting - same detector, same crop margin, same checkpoints. A confusion
matrix from a different preprocessing is the wrong matrix.
* When a class has very low recall the correction is poorly conditioned and
can return a near-zero or clipped estimate. Report those classes as bounds.
On our data the unweighted correction sent Hispanic to 0.0, while the
inverse-probability-weighted version recovered 2.6%. Prefer the weighted
matrix and say which you used.
Licence: MIT.
"""
from __future__ import annotations
import numpy as np
__all__ = [
"confusion_matrix_from_labels",
"correct_proportions",
"correct_counts",
]
def confusion_matrix_from_labels(y_true, y_pred, labels, weights=None) -> np.ndarray:
"""
Column-stochastic confusion matrix M[i, j] = P(pred = labels[i] | true = labels[j]).
weights : optional per-sample weights. Pass inverse selection probabilities
when the validation sample was stratified on predicted labels,
otherwise M is conditioned on the predictions rather than the
population.
"""
labels = list(labels)
idx = {l: i for i, l in enumerate(labels)}
n = len(labels)
if weights is None:
weights = np.ones(len(y_true), dtype=float)
weights = np.asarray(weights, dtype=float)
M = np.zeros((n, n), dtype=float)
for t, p, w in zip(y_true, y_pred, weights):
if t in idx and p in idx:
M[idx[p], idx[t]] += w
for j in range(n):
col = M[:, j].sum()
if col > 0:
M[:, j] /= col
else:
M[j, j] = 1.0 # unobserved class: assume no confusion
return M
def correct_proportions(p_obs, M, clip_negative: bool = True) -> np.ndarray:
"""
Recover true class proportions from observed ones.
p_obs : observed proportions, same order as the confusion matrix labels
M : column-stochastic confusion matrix
"""
p_obs = np.asarray(p_obs, dtype=float)
q = np.linalg.pinv(M) @ p_obs
if clip_negative:
q = np.clip(q, 0.0, None)
total = q.sum()
return q / total if total > 0 else p_obs
def correct_counts(counts, M) -> np.ndarray:
"""Same correction expressed in counts rather than proportions."""
counts = np.asarray(counts, dtype=float)
total = counts.sum()
if total <= 0:
return counts
return correct_proportions(counts / total, M) * total
if __name__ == "__main__":
# Worked example: race shares of real advertisements, using the published
# real-domain IPW matrix from benchmark/confusion_race_real_ipw.csv
labels = ["white", "black", "asian", "hispanic"]
p_obs = [0.6494, 0.1889, 0.1552, 0.0065]
census = [0.6090, 0.1329, 0.0697, 0.1884]
M = np.array([
[0.9603, 0.1138, 0.2073, 0.1376],
[0.0057, 0.8383, 0.0106, 0.2646],
[0.0327, 0.0448, 0.7804, 0.4092],
[0.0013, 0.0031, 0.0017, 0.1886],
])
p_cor = correct_proportions(p_obs, M)
print(f"{'class':10s} {'observed':>9s} {'corrected':>10s} {'census':>8s} "
f"{'dev obs':>8s} {'dev cor':>8s}")
for l, o, c, r in zip(labels, p_obs, p_cor, census):
print(f"{l:10s} {o*100:8.2f}% {c*100:9.2f}% {r*100:7.2f}% "
f"{(o-r)*100:+7.2f} {(c-r)*100:+7.2f}")
print("\nWhite over-representation: +4.04 pp observed -> +0.67 pp corrected.")
|