| | """Custom Learning Rule Benchmark
|
| | ==================================
|
| | Demonstrates P19 microcode learning engine with custom learning rules.
|
| |
|
| | Compares default STDP, anti-STDP, and a custom reward-modulated rule
|
| | assembled from microcode text mnemonics.
|
| |
|
| | Features demonstrated: P19 microcode ISA, assembler, LearningRule, custom rules.
|
| | """
|
| |
|
| | import sys, os
|
| | sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
| |
|
| | import neurocore as nc
|
| | from neurocore.microcode import LearningRule
|
| |
|
| |
|
| | def build_network():
|
| | """Create a simple pre->post network for learning experiments."""
|
| | net = nc.Network()
|
| | pre = net.population(1, params={"threshold": 100, "leak": 0, "refrac": 0}, label="pre")
|
| | post = net.population(1, params={"threshold": 100, "leak": 0, "refrac": 0}, label="post")
|
| | net.connect(pre, post, topology="all_to_all", weight=500)
|
| | return net, pre, post
|
| |
|
| |
|
| | def get_final_weight(sim):
|
| | """Extract the weight from the simulator's adjacency table."""
|
| | for targets in sim._adjacency.values():
|
| | for entry in targets:
|
| | return entry[1]
|
| | return None
|
| |
|
| |
|
| | def run_stdp(rule, rule_name, three_factor=False):
|
| | """Run a learning trial with the given rule."""
|
| | net, pre, post = build_network()
|
| | net.set_learning_rule(rule)
|
| |
|
| | sim = nc.Simulator()
|
| | sim.deploy(net)
|
| | sim.set_learning(learn=True, three_factor=three_factor)
|
| |
|
| |
|
| | for _ in range(5):
|
| | sim.inject(pre, current=200)
|
| | sim.run(1)
|
| | sim.run(1)
|
| |
|
| | if three_factor:
|
| | sim.reward(500)
|
| | sim.run(1)
|
| |
|
| | final_w = get_final_weight(sim)
|
| | print(f" {rule_name}: initial=500, final={final_w}")
|
| | return final_w
|
| |
|
| |
|
| | def main():
|
| | print("=" * 60)
|
| | print(" Custom Learning Rule Benchmark (P19 Microcode)")
|
| | print("=" * 60)
|
| |
|
| |
|
| | print("\n1. Default STDP (pre-before-post = LTP):")
|
| | rule_stdp = LearningRule.stdp()
|
| | w_stdp = run_stdp(rule_stdp, "Default STDP")
|
| | assert w_stdp > 500, "STDP LTP should increase weight"
|
| |
|
| |
|
| | print("\n2. Anti-STDP (inverted correlation):")
|
| | rule_anti = LearningRule()
|
| | rule_anti.assemble_ltd("""
|
| | SHR R5, R0, 3 ; delta = trace >> 3
|
| | SKIP_Z R5 ; skip if zero
|
| | ADD R2, R2, R5 ; weight += delta (anti-LTD = potentiate)
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | rule_anti.assemble_ltp("""
|
| | SHR R5, R0, 3 ; delta = trace >> 3
|
| | SKIP_Z R5 ; skip if zero
|
| | SUB R2, R2, R5 ; weight -= delta (anti-LTP = depress)
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | w_anti = run_stdp(rule_anti, "Anti-STDP")
|
| | assert w_anti < 500, "Anti-STDP should decrease weight for pre-before-post"
|
| |
|
| |
|
| | print("\n3. Scaled STDP (2x learning rate):")
|
| | rule_fast = LearningRule()
|
| | rule_fast.assemble_ltd("""
|
| | SHR R5, R0, 3 ; delta = trace >> 3
|
| | SHL R5, R5, 1 ; delta *= 2 (double rate)
|
| | SKIP_Z R5
|
| | SUB R2, R2, R5
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | rule_fast.assemble_ltp("""
|
| | SHR R5, R0, 3 ; delta = trace >> 3
|
| | SHL R5, R5, 1 ; delta *= 2
|
| | SKIP_Z R5
|
| | ADD R2, R2, R5
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | w_fast = run_stdp(rule_fast, "2x STDP")
|
| | assert w_fast > w_stdp, f"2x STDP ({w_fast}) should be > default ({w_stdp})"
|
| |
|
| |
|
| | print("\n4. 3-factor eligibility + reward:")
|
| | rule_3f = LearningRule.three_factor()
|
| | w_3f = run_stdp(rule_3f, "3-factor STDP", three_factor=True)
|
| | print(f" (Reward applied: weight change reflects eligibility * reward)")
|
| |
|
| |
|
| | print("\n5. Capped STDP (weight bounded [400, 600]):")
|
| | rule_capped = LearningRule()
|
| | rule_capped.assemble_ltp("""
|
| | SHR R5, R0, 3 ; delta = trace >> 3
|
| | SKIP_Z R5
|
| | ADD R2, R2, R5 ; weight += delta
|
| | LOADI R4, 600 ; max weight
|
| | MIN R2, R2, R4 ; clamp to max
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | rule_capped.assemble_ltd("""
|
| | SHR R5, R0, 3
|
| | SKIP_Z R5
|
| | SUB R2, R2, R5 ; weight -= delta
|
| | LOADI R4, 400 ; min weight
|
| | MAX R2, R2, R4 ; clamp to min
|
| | STORE_W R2
|
| | HALT
|
| | """)
|
| | w_capped = run_stdp(rule_capped, "Capped STDP")
|
| | assert 400 <= w_capped <= 600, f"Capped weight should be in [400,600], got {w_capped}"
|
| |
|
| |
|
| | print("\n--- Summary ---")
|
| | print(f"Default STDP: {w_stdp:>6d} (LTP: weight increased)")
|
| | print(f"Anti-STDP: {w_anti:>6d} (inverted: weight decreased)")
|
| | print(f"2x STDP: {w_fast:>6d} (double learning rate)")
|
| | print(f"3-Factor: {w_3f:>6d} (eligibility + reward)")
|
| | print(f"Capped [400,600]: {w_capped:>4d} (bounded)")
|
| | print("\nAll custom learning rules verified!")
|
| | print("Done!")
|
| |
|
| |
|
| | if __name__ == "__main__":
|
| | main()
|
| |
|