File size: 2,617 Bytes
032a961
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env python3
"""Quick hyperparameter probe for the three-factor rule (40k ticks each)."""
import sys
import time

import numpy as np

sys.path.insert(0, "/home/z/my-project/download/spira")
from spira import SPIRA, SPIRAConfig
from spira.hashing import fnv1a64
from spira.spiking import SpikingCore

data = open("/home/z/my-project/data/train.bin", "rb").read()
cfg = SPIRAConfig(snn_tokens=40_000, am_tokens=1000, epochs=1)
model = SPIRA.build(data, cfg, log=lambda m: None)
ids = model._ids_train
N = 40_000

neurons = SPIRA.input_neurons_stream(ids[:N], cfg.d_in, cfg.k_in)
cols = model.cols_of(ids[: N + 1])
inv_mask = (cols[1:] != cfg.vocab_size)[: N - 1]
print(f"coverage: {inv_mask.mean():.3f}")

variants = [
    ("eta_r=0.010 d-full", 0.010, -1.0),
    ("eta_r=0.001 d-full", 0.001, -1.0),
    ("eta_r=0.010 d>=-0.25", 0.010, -0.25),
    ("eta_r=0.000 pure-inst", 0.000, 0.0),
]
for name, eta_r, d_floor in variants:
    core = SpikingCore(n_out=cfg.vocab_size + 1, seed=cfg.seed, eta_r=eta_r)
    # monkeypatch learn with d floor
    orig_learn = core.learn
    def learn(pred, target, x, core=core, floor=d_floor, orig=orig_learn):
        # replicate learn() but with d floor on the chosen-column update
        correct = 1 if pred == target else 0
        reward = float(correct)
        core.baseline = core.baseline_momentum * core.baseline + (1 - core.baseline_momentum) * reward
        d = reward - core.baseline
        W_out = core.W_out
        if target != core.n_out - 1:
            W_out[:, target] += np.float32(core.eta_pos) * x
        d_eff = d if d > 0 else max(d, floor)
        W_out[:, pred] += np.float32(core.eta_r * d_eff) * x
        np.clip(W_out[:, target], -core.w_clip, core.w_clip, out=W_out[:, target])
        np.clip(W_out[:, pred], -core.w_clip, core.w_clip, out=W_out[:, pred])
        if core.s.any():
            spiked = np.nonzero(core.s)[0]
            W_rec = core.W_rec
            delta = np.float32(core.eta_stdp * d)
            W_rec[:, spiked] += delta * core.x_prev[:, None]
            np.clip(W_rec[:, spiked], core._rec_lo[:, None], core._rec_hi[:, None],
                    out=W_rec[:, spiked])
        return correct, reward, d
    core.learn = learn
    t0 = time.perf_counter()
    res = core.train_pass(neurons[: N - 1], cols[1:N], log_every=10_000, log_fn=lambda d: None)
    # in-vocab accuracy measured inline: recompute via final pass? use overall + coverage
    overall = res["accuracy"]
    print(f"{name:24s} overall={overall:.4f} in-vocab~={overall/max(inv_mask.mean(),1e-9):.4f} "
          f"({res['ticks_per_sec']:.0f} t/s)")