catalyst-n1 / sdk /benchmarks /xor_classification.py
mrwabbit's picture
Initial upload: Catalyst N1 open source neuromorphic processor RTL
e4cdd5f verified
"""XOR Classification Benchmark
================================
Demonstrates basic STDP learning on the classic XOR problem.
Uses two input populations (encoding the two XOR bits) and one output neuron.
Correlated/anti-correlated spike patterns train the output via STDP.
Features demonstrated: Network building, STDP learning, spike trains, raster plot.
"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
import neurocore as nc
def main():
print("=" * 60)
print(" XOR Classification Benchmark")
print("=" * 60)
net = nc.Network()
# Input populations (2 bits, 8 neurons each for rate coding)
inp_a = net.population(8, params={"threshold": 100, "leak": 0, "refrac": 2}, label="input_A")
inp_b = net.population(8, params={"threshold": 100, "leak": 0, "refrac": 2}, label="input_B")
# Hidden layer
hidden = net.population(16, params={"threshold": 400, "leak": 5, "refrac": 3}, label="hidden")
# Output neuron
output = net.population(1, params={"threshold": 600, "leak": 3, "refrac": 5}, label="output")
# Connections with moderate weights
net.connect(inp_a, hidden, topology="all_to_all", weight=150)
net.connect(inp_b, hidden, topology="all_to_all", weight=150)
net.connect(hidden, output, topology="all_to_all", weight=200)
# Inhibitory recurrence in hidden layer
net.connect(hidden, hidden, topology="random_sparse", p=0.3, weight=-100, seed=42)
sim = nc.Simulator()
sim.deploy(net)
sim.set_learning(learn=True)
# XOR truth table: (0,0)->0, (0,1)->1, (1,0)->1, (1,1)->0
xor_patterns = [
(False, False, False), # 0 XOR 0 = 0
(False, True, True), # 0 XOR 1 = 1
(True, False, True), # 1 XOR 0 = 1
(True, True, False), # 1 XOR 1 = 0
]
print("\nTraining phase (20 epochs)...")
for epoch in range(20):
total_spikes = 0
for a_active, b_active, expected in xor_patterns:
# Encode inputs as spike rates
if a_active:
sim.inject(inp_a, current=300)
if b_active:
sim.inject(inp_b, current=300)
result = sim.run(10)
total_spikes += result.total_spikes
if (epoch + 1) % 5 == 0:
print(f" Epoch {epoch + 1}: {total_spikes} total spikes")
# Test phase
print("\nTest phase:")
for a_active, b_active, expected in xor_patterns:
if a_active:
sim.inject(inp_a, current=300)
if b_active:
sim.inject(inp_b, current=300)
result = sim.run(10)
out_gid = result.placement.neuron_map[(output.id, 0)]
out_gid_flat = out_gid[0] * 1024 + out_gid[1]
out_spikes = len(result.spike_trains.get(out_gid_flat, []))
label = "1" if expected else "0"
print(f" A={int(a_active)}, B={int(b_active)} -> "
f"Output spikes: {out_spikes} (expected: {label})")
print(f"\nCompiled: {sim._compiled.placement.num_cores_used} cores, "
f"{sim._compiled.placement.total_neurons} neurons")
print("Done!")
if __name__ == "__main__":
main()