File size: 2,174 Bytes
f2aa0f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Benchmark SpikeCascade against an offline baseline and emit the
calibration contract required by the paper.

Usage:
    python benchmark.py --data path/to/recording.npy \
                        --baseline path/to/kilosort_output.npz

The output is a single JSON object with the four calibration fields:
    activity_fraction, stage3_fraction, latency_ms, correlation
plus a 'speedup_vs_full' field computed by the theorem
    S = (1 + alpha) / (1/k + alpha),  alpha = (1 - T_s/T) / (T_s/T).
"""

import argparse
import json
import time

import numpy as np

from modeling_spikecascade import SpikeCascadeForSorting


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--data", required=True, help="(n_channels, n_samples) .npy")
    parser.add_argument("--baseline", required=True, help=".npz with 'unit_ids' and 'spike_times_ms'")
    parser.add_argument("--model", default="your-org/SpikeCascade")
    args = parser.parse_args()

    voltage = np.load(args.data).astype(np.float32)
    baseline = np.load(args.baseline)
    baseline_counts = {}
    for uid in baseline["unit_ids"]:
        baseline_counts[int(uid)] = baseline_counts.get(int(uid), 0) + 1

    model = SpikeCascadeForSorting.from_pretrained(args.model)

    # Warm up.
    _ = model.infer(voltage[:, :3000])

    t0 = time.perf_counter()
    report = model.infer(voltage, baseline_spike_counts=baseline_counts)
    wall_ms = (time.perf_counter() - t0) * 1000

    # The theorem: S = (1 + alpha) / (1/k + alpha), with
    # alpha = (1 - f) / f and f = stage3_fraction.
    f = report.stage3_fraction
    alpha = (1.0 - f) / f if f > 0 else float("inf")
    k = 20.0  # conservative cost ratio (full clustering / template match)
    speedup = (1.0 + alpha) / (1.0 / k + alpha) if f > 0 else 1.0

    out = {
        "activity_fraction": report.activity_fraction,
        "stage3_fraction": report.stage3_fraction,
        "latency_ms": report.latency_ms,
        "wall_ms": wall_ms,
        "correlation": report.correlation,
        "speedup_vs_full": speedup,
        "warning": report.warning,
    }
    print(json.dumps(out, indent=2))


if __name__ == "__main__":
    main()