← All courses ← Course home

Lesson 07 of 08

Evaluate the clothing classifier

Accuracy is only the start. First look at the mistakes. Then compare Mac scores to Core AI, and decide whether the top label is good enough.

Agent brief (llms.md)

Why this check matters

A Fashion-MNIST accuracy number can look fine. But Shirt and T-shirt/top can still swap. A picked photo can be inverted. Or Core AI can disagree with the Mac weights. Before you call the SwiftUI label done, read the confusion matrix (which pairs get mixed up). Open-code the photos that fail: write short notes in your own words, then group those notes into a few problem types. Also check that the Mac and the device give the same top label.

Lesson 06 already measured load, specialization, and inference. This lesson does not repeat Instruments. It asks whether the label is right.

Look at the wrong labels first. Then write a simple yes/no check: is the top label acceptable? The intro this lesson follows is Hamel Husain and Shreya Shankar, Evals for AI systems. Cite that talk once in this course.

One step at a time

Held-outAccuracy and matrix
Held-outAccuracy and matrix
Open codeMisclassified photos
Held-outAccuracy and matrix
Open codeMisclassified photos
ParityMac vs Core AI JSONL
Held-outAccuracy and matrix
Open codeMisclassified photos
ParityMac vs Core AI JSONL
AutomateTop label acceptable

Environment setup

Use the same uv project as training. Apple Silicon MPS when available, otherwise CPU. Do not add CUDA.

cd clothing-coreai
uv add torch torchvision
uv run python -c "import torch, torchvision; print(torch.__version__, torchvision.__version__); print('MPS:', torch.backends.mps.is_available())"
mkdir -p evals/traces evals/open-codes
uv run python evaluate_classifier.py

Held-out accuracy and confusion matrix

Reload ClothingCNN and clothing.pt. Run the official Fashion-MNIST test split with ToTensor() only. Print accuracy and a 10-by-10 confusion matrix. Shirt versus T-shirt/top is the pair that often gets mixed up. If that cell is large, a higher overall accuracy will not fix the app.

import torch
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

from train import ClothingCNN

CLASSES = [
    "T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
    "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot",
]

if torch.backends.mps.is_available():
    device = torch.device("mps")
else:
    device = torch.device("cpu")

model = ClothingCNN()
model.load_state_dict(torch.load("clothing.pt", map_location="cpu", weights_only=True))
model.to(device).eval()

test = datasets.FashionMNIST("data", train=False, download=True, transform=transforms.ToTensor())
loader = DataLoader(test, batch_size=256)
matrix = torch.zeros(10, 10, dtype=torch.int64)

with torch.no_grad():
    for images, labels in loader:
        pred = model(images.to(device)).argmax(1).cpu()
        for y, y_hat in zip(labels, pred):
            matrix[y, y_hat] += 1

correct = int(matrix.diag().sum())
total = int(matrix.sum())
print(f"accuracy={correct / total:.3f} on {device}")
print(CLASSES)
print(matrix)

Open-code the misclassified photos

Accuracy does not tell you why a picked photo failed. Export the worst cells and a few real camera shots. For each one, write a short note in your own words. Then group those notes into a few problem types, such as inverted grayscale, a cropped torso, Shirt versus T-shirt mix-ups, a preprocess mismatch, or a class the camera should not have asked for.

{
  "id": "photo-coat-12",
  "source": "device",
  "true_or_expected": "Coat",
  "mac_top": "Coat",
  "coreai_top": "Pullover",
  "open_codes": [
    "sleeves fill the 28x28 frame",
    "Swift resize looks darker than ToTensor"
  ]
}

Mac versus Core AI parity

Parity here means the Mac and the device give the same top label. Run the same bundled sample and a few test tensors through PyTorch on the Mac and through the Core AI app. Write both top labels (and the ten logits if you can export them) to JSONL. A name or shape bug in conversion often shows up as the same swap every time, not as random noise.

import json

def parity_row(sample_id, mac_logits, coreai_logits, classes=CLASSES):
    mac_top = classes[int(mac_logits.argmax())]
    coreai_top = classes[int(coreai_logits.argmax())]
    return {
        "id": sample_id,
        "mac_top": mac_top,
        "coreai_top": coreai_top,
        "label_match": mac_top == coreai_top,
        "max_abs_logit_delta": float((mac_logits - coreai_logits).abs().max()),
    }

print(json.dumps(parity_row("fashion-sample", mac, coreai)))

If the labels match and the logits are close, conversion worked. If labels differ, stop judging "model quality" and reopen lesson 03 and the Swift image prep. Do not retrain this small classifier to hide a tensor contract bug.

Binary: top label acceptable

For the SwiftUI path, the release question is a simple yes or no. Is the displayed top label acceptable for this image? Shirt versus T-shirt/top may be acceptable in a demo if you write that down. Coat versus Sandal is not. Write that rule down. A 1-5 confidence score is extra. The real check is whether a person would accept the label.

Instruments stays in lesson 06

Gauge colors, specialization, and later inference stay in Profile the clothing inference path. Do not mix milliseconds into the confusion matrix. A fast wrong label is still a fail.

When this goes wrong

Done when

Keep learning

The same look-then-score path on voice is Evaluate the writing style. On generations it is Evaluate generations.

Key concepts

  • Print held-out Fashion-MNIST accuracy and a 10x10 confusion matrix with ToTensor() only.
  • Shirt versus T-shirt/top is the confusion cell that often breaks real photos.
  • Open-code misclassified images, then group them into a few problem types.
  • Compare Mac and Core AI top labels on the same sample. The release check is yes or no, not a 1-5 score.

Takeaways

  • High test accuracy does not mean the camera path is done.
  • If Mac and Core AI top labels differ, fix conversion or Swift prep before you retrain.
  • Keep Instruments in lesson 06. Do not mix timing into the confusion matrix.