Metrics¶
Every metric is a plain function in cg.metrics, usable without running an experiment.
Information measures are in bits by default. Metrics that need float64, or that have
known problems on MPS, always compute on the CPU. An undefined input raises an error
instead of returning NaN or a silent 0, such as AUROC with one class, or a correlation
with a constant side.
import cognarium as cg
import torch
log_probs = torch.log_softmax(torch.randn(8, 4, generator=torch.Generator().manual_seed(0)), dim=-1)
cg.metrics.entropy(log_probs)
| Family | Functions |
|---|---|
| Information | entropy, conditional_entropy, joint_entropy, mutual_information, ksg_mutual_information, kl_divergence, js_divergence, cross_entropy, surprisal, perplexity, information_bottleneck |
| Classification | accuracy, balanced_accuracy, precision, recall, f1, mcc, auroc, auprc, brier, ece |
| Signal detection | d_prime, criterion, a_prime |
| Geometry | linear_cka, rbf_cka, rsa, procrustes, mse, svcca, pwcca, participation_ratio, intrinsic_dimension, layer_matrix |
| Statistics | cohens_d, hedges_g, bootstrap_ci, permutation_test, fdr |
| Human comparison | item_correlation, split_half_ceiling, effect_comparison |
| Naming | meanings, ib_complexity, ib_accuracy, ib_frontier, efficiency_loss, gnid, co_naming_mse |
On results¶
results.metrics(...) computes named metrics over a run, grouped by the paradigm's
conditions, and results.contrast(...) compares one measure between two levels with a
bootstrap interval and a permutation test.
subject = cg.load("gpt2", device="auto")
results = cg.run(cg.paradigms.ArtificialGrammar(), subject)
results.metrics("accuracy", "entropy")
Signal detection needs both kinds of trial in each group, so by=[] pools the
grammatical and ungrammatical strings:
results.metrics("d_prime", positive="grammatical", by=[])
Geometry¶
The geometry metrics take state matrices with one row per sample. layer_matrix
compares every pair of layers.
x = torch.randn(50, 16, generator=torch.Generator().manual_seed(1))
rotation, _ = torch.linalg.qr(torch.randn(16, 16, generator=torch.Generator().manual_seed(2)))
cg.metrics.linear_cka(x, x @ rotation)
Naming systems¶
A naming system is an items × words table, where each row gives the probability of each
word for an item. ib_frontier traces the optimal systems for a set of meanings by
reverse deterministic annealing, and efficiency_loss gives how far a system falls from
them, with the trade-off value where it comes closest (Zaslavsky et al., 2018). The
frontier for 330 items takes about a minute, so compute it once and reuse it.
points = torch.arange(10, dtype=torch.float64)[:, None]
prior = torch.full((10,), 0.1, dtype=torch.float64)
meanings = cg.metrics.meanings(points, sigma=1.0)
frontier = cg.metrics.ib_frontier(prior, meanings)
halves = torch.tensor([[1.0, 0.0]] * 5 + [[0.0, 1.0]] * 5, dtype=torch.float64)
epsilon, beta = cg.metrics.efficiency_loss(halves, prior, meanings, frontier)
cg.metrics.gnid(halves, frontier.encoder_at(beta), prior)
gnid and co_naming_mse compare two systems whatever their words are called. On
iterated learning results, the same measures score each chain's answers, as the
learning paradigms page shows.
Comparing with people¶
item_correlation correlates a model's item values with people's, with a bootstrap
interval over items. split_half_ceiling estimates how well any model could do, from
the agreement between random halves of the participants, corrected by the
Spearman-Brown formula. effect_comparison standardises the same effect in the model and
in people, since their scales differ, and reports the difference with an interval.
import numpy as np
rng = np.random.default_rng(0)
pattern = rng.normal(size=30)
ratings = pattern + rng.normal(size=(20, 30))
model = pattern + 0.5 * rng.normal(size=30)
ceiling = cg.metrics.split_half_ceiling(ratings)
cg.metrics.item_correlation(model, ratings.mean(axis=0))["correlation"], ceiling["ceiling"]
cg.metrics.effect_comparison(
rng.normal(1.0, 1.0, size=40),
rng.normal(0.0, 1.0, size=40),
rng.normal(0.3, 1.0, size=40),
rng.normal(0.0, 1.0, size=40)
)
results.compare_to_human(human, measure) does the item correlation straight from a run,
as the quickstart shows.