Online WTA feature learning; configurable active steps in spiking pipeline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
899e0e3601
commit
ec913f51c1
3 changed files with 28 additions and 0 deletions
|
|
@ -317,3 +317,7 @@ KNP, validation: `fc_v_plain` 81,0%, `fc_v_augB` 79,5%. Симулятор (2000
|
|||
| A: K=800 с делением на контраст, ridge (без спайков) | 78,4% | 77,2% |
|
||||
|
||||
95% интервал при n=600 около ±3,7 п.п. **Свежий тест теперь просмотрен**; все test-картинки кошек и собак CIFAR (0–999) использованы, для новой независимой оценки нужен другой источник.
|
||||
|
||||
### 01:00 – : слой признаков нейронным правилом; число шагов
|
||||
- `kmeans_features.learn_online`: обучение «победитель забирает всё» по одному кусочку за проход (как WTA-слой с Хеббом/STDP): победивший нейрон сдвигает нормированные веса к кусочку, скорость lr0/(1 + t/20000), 200 000 кусочков, то же выбеливание. Validation, K=400, без деления на контраст, +зеркало, ridge 300: пакетные k-средние 74,9%, **онлайн WTA 75,9%** — правило на нейронах даёт признаки не хуже.
|
||||
- `spiking_pipeline.py --active N`: число активных шагов входа (по умолчанию 10). Запущены 20 и 30 шагов (порог слоя 1 тот же 108,08).
|
||||
|
|
|
|||
|
|
@ -69,3 +69,24 @@ def encode(images, model, alpha=0.25, grid=2, batch=250):
|
|||
for gy in range(grid) for gx in range(grid)]
|
||||
out.append(np.concatenate(pooled, axis=1))
|
||||
return np.concatenate(out)
|
||||
|
||||
|
||||
def learn_online(images, k=400, n_patches=200000, lr0=0.05, seed=0, base=None):
|
||||
"""Online winner-take-all learning, one patch at a time (what a spiking WTA layer with Hebbian/STDP does):
|
||||
the most responsive neuron moves its normalised weights towards the patch, the others stay. Uses the same
|
||||
whitening as `learn` (from `base` if given). Single pass, learning rate decays as lr0 / (1 + t / 20000)."""
|
||||
rng = np.random.default_rng(seed)
|
||||
if base is None:
|
||||
base = learn(images, k=k, n_patches=min(n_patches, 50000), iters=0, seed=seed)
|
||||
x = images.astype(np.float32) / 255
|
||||
idx = rng.integers(0, len(x), n_patches)
|
||||
ys, xs = rng.integers(0, 32 - PATCH + 1, n_patches), rng.integers(0, 32 - PATCH + 1, n_patches)
|
||||
p = np.stack([x[i, :, y:y + PATCH, xx:xx + PATCH].reshape(-1) for i, y, xx in zip(idx, ys, xs)])
|
||||
pw = (normalise(p) - base["mean"]) @ base["zca"]
|
||||
d = pw[rng.choice(len(pw), k, replace=False)].copy()
|
||||
d /= np.linalg.norm(d, axis=1, keepdims=True)
|
||||
for t, v in enumerate(pw):
|
||||
win = int(np.argmax(d @ v))
|
||||
d[win] += lr0 / (1 + t / 20000) * v
|
||||
d[win] /= np.linalg.norm(d[win])
|
||||
return {"mean": base["mean"], "zca": base["zca"], "d": d.astype(np.float32)}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,10 @@ def main():
|
|||
ap.add_argument("--thr1", type=float, default=0, help="layer-1 threshold in quantised units (0: auto)")
|
||||
ap.add_argument("--train-limit", type=int, default=0)
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--active", type=int, default=ACTIVE, help="active (spiking) input steps; 5 silent steps follow")
|
||||
a = ap.parse_args()
|
||||
global ACTIVE, STEPS
|
||||
ACTIVE, STEPS = a.active, a.active + 5
|
||||
model = dict(np.load(a.model))
|
||||
w, b = fold(model, a.alpha)
|
||||
wq, bq, s = quant_layer1(w, b)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue