File size: 3,036 Bytes
e2d95ed | 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 | """Class mapping: one vocabulary, one index space, shared by data, models and API."""
from __future__ import annotations
import json
from pathlib import Path
import numpy as np
import config
from backend.preprocessing import include50
def test_class_mapping_is_vocabulary_order(vocabulary):
mapping = include50.class_mapping()
assert list(mapping.keys()) == vocabulary
assert list(mapping.values()) == list(range(len(vocabulary)))
def test_dataset_metadata_class_names_are_uppercase_glosses(vocabulary):
for name in vocabulary:
assert name == name.upper().strip()
assert len(name) <= 32
def test_vocabulary_file_records_provenance():
payload = json.loads((Path(config.METADATA_DIR) / "vocabulary.json").read_text())
assert payload["num_classes"] == 50
assert "INCLUDE" in payload["dataset"].upper()
assert payload["citation"] and payload["doi"], "the dataset must be cited, not just used"
assert len(payload["classes"]) == 50
assert all(c["videos"] > 0 for c in payload["classes"])
def test_processed_classes_are_vocabulary(processed, vocabulary):
assert [str(c) for c in processed["classes"]] == vocabulary
def test_label_mapping_file_matches_vocabulary():
p = Path(config.PROCESSED_DIR) / "label_mapping.json"
if not p.exists():
import pytest
pytest.skip("label_mapping.json not written yet")
payload = json.loads(p.read_text())
assert payload["classes"] == include50.load_vocabulary()
assert payload["num_classes"] == 50
def test_model_class_mapping_matches_vocabulary(vocabulary):
for name in config.AVAILABLE_MODELS:
p = Path(config.MODEL_PATHS[name]) / "class_mapping.json"
if not p.exists():
continue
payload = json.loads(p.read_text())
assert payload["classes"] == vocabulary, f"{name}: class order differs from the vocabulary"
assert payload["num_classes"] == len(vocabulary)
def test_model_output_width_matches_num_classes(all_trained_models):
for name, model in all_trained_models.items():
assert model.output_shape[-1] == config.NUM_CLASSES, name
assert model.input_shape[-1] == config.MODEL_INPUT_DIM, name
def test_preprocessing_config_is_recorded_per_model():
for name in config.AVAILABLE_MODELS:
p = Path(config.MODEL_PATHS[name]) / "preprocessing_config.json"
if not p.exists():
continue
cfg = json.loads(p.read_text())
assert cfg["sequence_length"] == config.SEQUENCE_LENGTH
assert cfg["model_input_dim"] == config.MODEL_INPUT_DIM
assert cfg["split_protocol"] == config.SPLIT_PROTOCOL
def test_label_indices_are_dense(processed):
assert set(np.unique(processed["y_train"]).tolist()) == set(range(config.NUM_CLASSES))
for key in ("y_val", "y_test"):
present = set(np.unique(processed[key]).tolist())
assert present <= set(range(config.NUM_CLASSES))
assert len(present) == config.NUM_CLASSES, f"{key} should be class-stratified"
|