Note

Run this notebook from the ARCADE repository root after pip install -e ".[torch,signature]" and, for paper configs, bash scripts/link_paper_data.sh.

Notebook: features and classify stage in depth

This notebook covers feature construction and Stage 2: Classify. You will see how FEATURE_KIND selects the matrix each method receives, how per-classifier log banners look, and how to isolate one method when a zoo run fails halfway.

Pipeline position

Data → [ Features + Classify ] → Hardware → Report

Filter methods share the matched-filter bank. IQ and sequence methods skip that bank and consume iq_trace or raw_trace_seq instead. Mixing those expectations is a common source of cryptic shape errors.

[ ]:
from pathlib import Path
import logging

from arcade._logging import configure_logging
from arcade.classifiers.base import get_classifier, list_classifiers
from arcade.config import load_config
from arcade.stages import DefaultClassifyStage, DefaultDataStage

configure_logging(logging.INFO)

CONFIG = Path("configs/example.yaml")
if not CONFIG.is_file():
    CONFIG = Path("configs/paper_all_methods_benchmark.yaml")

cfg = load_config(CONFIG)

# Shrink the run for interactive debugging.
cfg.classifiers.run[:] = ["threshold", "lda"]  # mutate list in place
print("methods =", cfg.classifiers.run)
print("filter_types =", cfg.classifiers.filter_types)
print("registered sample =", list_classifiers()[:8])

Inspect FEATURE_KIND before fitting

threshold  FEATURE_KIND=filter_features
lda        FEATURE_KIND=filter_features
fnn        FEATURE_KIND=iq_trace
transformer FEATURE_KIND=raw_trace_seq

If fit receives the wrong rank or width, check this attribute first.

[ ]:
for name in cfg.classifiers.run:
    cls = get_classifier(name)
    print(
        f"{name:16s} kind={getattr(cls, 'FEATURE_KIND', '?')} "
        f"category={getattr(cls, 'CATEGORY', '?')}"
    )

[ ]:
data_out = DefaultDataStage().run(cfg)
classify_out = DefaultClassifyStage().run(cfg, data_out)

# Typical structure: per-method metrics under classify_out["classifiers"]
clfs = classify_out.get("classifiers", classify_out)
if isinstance(clfs, dict):
    for name, payload in clfs.items():
        metrics = payload.get("metrics") if isinstance(payload, dict) else None
        print(name, "→", metrics)

Expected log pattern

[INFO] arcade.stages.classify: === Stage 2: Classify ===
[INFO] arcade.stages.classify: --- Classifier: threshold ---
[INFO] arcade.stages.classify:   threshold → joint_acc=... f5q=...
[INFO] arcade.stages.classify: --- Classifier: lda ---
[INFO] arcade.stages.classify:   lda → joint_acc=... f5q=...

Progress bars from tqdm may appear during neural training. A method that prints (no metrics) usually failed to evaluate or returned an empty metrics dict; scroll upward for the first WARNING or traceback for that name.

Debugging checklist for Stage 2

Symptom

Likely cause

What to try

Shape error inside fit

Wrong FEATURE_KIND or filter bank

arcade describe name; confirm filter_types

Only one method fails in a zoo

Method-specific config_file / extra missing

Run with classifiers.run: [that_name] alone

Neural import errors

Missing torch

pip install -e ".[torch]"

Path signature import errors

Missing iisignature

pip install -e ".[signature]"

Metrics look fine per-qubit but joint is random

Bit order or label packing from Stage 1

Fix data-stage label settings; do not retune the model yet

Isolate one classifier from YAML

classifiers:
  run: [fnn]
  fnn:
    config_file: configs/nn_lienhard_fnn.yaml

Then:

arcade run path/to/debug.yaml

Next

Continue with Hardware and report, or jump to Debugging the pipeline if you are chasing a failure across stages.