feat(SNNBot): 1° bin resolution (360 bins) + neighbor reinforcement
5° bins caused visible jumping. 360 bins at 1° costs 5.7KB. Reinforce ±2 neighbors per learn call for faster coverage. Punish only bins >2° away from correct target.
This commit is contained in:
@@ -4,15 +4,15 @@ import std/[bitops, math]
|
||||
|
||||
const
|
||||
INPUT_BITS* = 80
|
||||
N_BINS* = 72
|
||||
BIN_WIDTH* = 5.0
|
||||
N_BINS* = 360
|
||||
BIN_WIDTH* = 1.0
|
||||
WORDS_IN* = 2 # 80 bits → 2 × uint64 (128 bits, only 80 used)
|
||||
|
||||
type
|
||||
BitVec80* = array[WORDS_IN, uint64]
|
||||
|
||||
BinaryAimer* = object
|
||||
readout*: array[N_BINS, BitVec80] # 72 bins × 80-bit weight vectors
|
||||
readout*: array[N_BINS, BitVec80] # 360 bins × 80-bit weight vectors
|
||||
scores*: array[N_BINS, int]
|
||||
|
||||
proc initAimer*(): BinaryAimer =
|
||||
@@ -59,22 +59,24 @@ proc interpolatedAngle*(a: BinaryAimer, winnerBin: int): float =
|
||||
result = radToDeg(arctan2(sinAvg, cosAvg))
|
||||
|
||||
proc learn*(a: var BinaryAimer, input: BitVec80, correctAngle: float) =
|
||||
## WTA Hebbian: reinforce correct bin, punish worst wrong bin
|
||||
## WTA Hebbian: reinforce correct bin + ±2 neighbors, punish worst wrong bin (>2° away)
|
||||
let correctBin = angleToBin(correctAngle)
|
||||
|
||||
# Reinforce: OR input into correct bin
|
||||
for w in 0 ..< WORDS_IN:
|
||||
a.readout[correctBin][w] = a.readout[correctBin][w] or input[w]
|
||||
# Reinforce correct bin + 2 neighbors on each side
|
||||
for offset in -2 .. 2:
|
||||
let bin = (correctBin + offset + N_BINS) mod N_BINS
|
||||
for w in 0 ..< WORDS_IN:
|
||||
a.readout[bin][w] = a.readout[bin][w] or input[w]
|
||||
|
||||
# Find highest-scoring WRONG bin
|
||||
# Punish highest-scoring wrong bin (must be >2 bins away from correct)
|
||||
var worstBin = -1
|
||||
var worstScore = -1
|
||||
for k in 0 ..< N_BINS:
|
||||
if k != correctBin and a.scores[k] > worstScore:
|
||||
let dist = min(abs(k - correctBin), N_BINS - abs(k - correctBin)) # circular distance
|
||||
if dist > 2 and a.scores[k] > worstScore:
|
||||
worstScore = a.scores[k]
|
||||
worstBin = k
|
||||
|
||||
# Punish: AND NOT input from worst wrong bin
|
||||
if worstBin >= 0:
|
||||
for w in 0 ..< WORDS_IN:
|
||||
a.readout[worstBin][w] = a.readout[worstBin][w] and (not input[w])
|
||||
|
||||
Reference in New Issue
Block a user