fix(SNNBot): fix reservoir threshold, remove decay, stop re-forward in EVALUATE
- Threshold 4→1: neurons now fire (~50% rate) instead of never firing - Remove aggressive decay that erased learning signal immediately - Remove EVALUATE re-forward that corrupted reservoir state before learn()
This commit is contained in:
@@ -460,9 +460,12 @@ method run*(bot: SNNBot) =
|
||||
let absBearing = directionTo(myX, myY, futureX, futureY)
|
||||
let targetRel = normalizeRelativeAngle(absBearing - bot.lastDecideGunDir)
|
||||
when USE_RESERVOIR:
|
||||
let winBin = bot.res.forward(toBitVec80(encodeInputFull(
|
||||
normalizeRelativeAngle(bot.enemyBearing - bot.lastDecideGunDir),
|
||||
bot.velDirDeg, bot.velSpeed, bot.hasLastPos)))
|
||||
# state/scores already set by DECIDE's forward(); re-forwarding would corrupt them
|
||||
let winBin = block:
|
||||
var best = 0; var bestS = -1
|
||||
for k in 0 ..< N_BINS:
|
||||
if bot.res.scores[k] > bestS: bestS = bot.res.scores[k]; best = k
|
||||
best
|
||||
let aimAngle = bot.res.interpolatedAngle(winBin)
|
||||
bot.res.learn(targetRel)
|
||||
echo "RES tick=" & $bot.tick & " bin=" & $winBin &
|
||||
|
||||
@@ -47,12 +47,6 @@ proc sparseBits(r: var Reservoir, density: float): uint64 =
|
||||
if r.nextRand() < thresh:
|
||||
result = result or (1'u64 shl bit)
|
||||
|
||||
proc randomDecayMask(r: var Reservoir): uint64 =
|
||||
## ~1% bits set: AND 6 random words (1/2^6 = 1/64 ≈ 1.5% density).
|
||||
result = r.nextRand()
|
||||
for _ in 0 ..< 5:
|
||||
result = result and r.nextRand()
|
||||
|
||||
# ── Init ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
proc initReservoir*(seed: int): Reservoir =
|
||||
@@ -67,13 +61,8 @@ proc initReservoir*(seed: int): Reservoir =
|
||||
for w in 0 ..< 16:
|
||||
result.wRec[i][w] = sparseBits(result, SPARSITY_REC)
|
||||
|
||||
let inPop = popcount(result.wIn[i][0]) + popcount(result.wIn[i][1])
|
||||
let recPop = block:
|
||||
var s = 0
|
||||
for w in 0 ..< 16: s += popcount(result.wRec[i][w])
|
||||
s
|
||||
# Threshold: ~50% of expected input votes + ~30% of expected recurrent votes
|
||||
result.threshold[i] = max(1, int(float(inPop) * 0.5 + float(recPop) * 0.3))
|
||||
# ponytail: threshold=1 gives ~50% firing; raise if reservoir saturates (all neurons fire every tick)
|
||||
result.threshold[i] = 1
|
||||
|
||||
# readout and state are zero-initialized by default
|
||||
|
||||
@@ -158,7 +147,4 @@ proc learn*(r: var Reservoir, correctAngle: float) =
|
||||
for w in 0 ..< 16:
|
||||
r.readout[worstBin][w] = r.readout[worstBin][w] and (not r.state[w])
|
||||
|
||||
# Decay: clear ~1.5% of bits per bin to prevent saturation
|
||||
for k in 0 ..< N_BINS:
|
||||
for w in 0 ..< 16:
|
||||
r.readout[k][w] = r.readout[k][w] and (not randomDecayMask(r))
|
||||
# ponytail: decay removed; add back if readout weights saturate (all scores converge to same value)
|
||||
|
||||
Reference in New Issue
Block a user