ΠΠ΅ΠΉΡΠΎΠΌΠΎΡΡΠ½ΡΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ ΠΈΠΌΠΈΡΠΈΡΡΡΡ ΡΠ°Π±ΠΎΡΡ ΠΌΠΎΠ·Π³Π° β Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΡΠΏΠ°ΠΉΠΊΠΎΠ² (ΠΈΠΌΠΏΡΠ»ΡΡΠΎΠ²) Π²ΠΌΠ΅ΡΡΠΎ ΡΠΈΡΠ΅Π». ΠΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ΅ΡΡ ΠΈΠ· 8 Π½Π΅ΠΉΡΠΎΠ½ΠΎΠ², ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½Π½ΡΡ ΡΠ΅ΡΠ΅Π· ΡΠΈΠ½Π°ΠΏΡΡ Ρ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌ Π²Π΅ΡΠΎΠΌ.
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΏΠ°ΠΉΠΊΠΎΠ²ΠΎΠΉ Π½Π΅ΠΉΡΠΎΠ½Π½ΠΎΠΉ ΡΠ΅ΡΠΈ:
cpp
#include <avr/io.h>
#include <avr/interrupt.h>
#define NEURON_COUNT 8
#define SYNAPSE_DELAY 5 // ΠΠ°Π΄Π΅ΡΠΆΠΊΠ° ΡΠ°ΡΠΏΡΠΎΡΡΡΠ°Π½Π΅Π½ΠΈΡ ΡΠΏΠ°ΠΉΠΊΠ°
// ΠΠ΅ΠΉΡΠΎΠ½
struct Neuron {
int16_t potential; // ΠΠ΅ΠΌΠ±ΡΠ°Π½Π½ΡΠΉ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»
uint8_t threshold; // ΠΠΎΡΠΎΠ³ Π²ΠΎΠ·Π±ΡΠΆΠ΄Π΅Π½ΠΈΡ (ΠΎΠ±ΡΡΠ½ΠΎ 100)
uint8_t refractory; // Π Π΅ΡΡΠ°ΠΊΡΠ΅ΡΠ½ΡΠΉ ΠΏΠ΅ΡΠΈΠΎΠ΄ (ΡΡΠ΅ΡΡΠΈΠΊ)
uint8_t fired; // Π€Π»Π°Π³ ΡΡΠ°Π±Π°ΡΡΠ²Π°Π½ΠΈΡ
};
// Π‘ΠΈΠ½Π°ΠΏΡ
struct Synapse {
uint8_t source; // ΠΠ΅ΠΉΡΠΎΠ½-ΠΈΡΡΠΎΡΠ½ΠΈΠΊ
uint8_t target; // ΠΠ΅ΠΉΡΠΎΠ½-ΡΠ΅Π»Ρ
int8_t weight; // ΠΠ΅Ρ (-128..127)
};
Neuron neurons[NEURON_COUNT];
Synapse synapses[NEURON_COUNT * NEURON_COUNT];
uint8_t synapseCount = 0;
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π΅ΠΉΡΠΎΠ½Π½ΠΎΠΉ ΡΠ΅ΡΠΈ
void initNetwork() {
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
neurons[i].potential = 0;
neurons[i].threshold = 100;
neurons[i].refractory = 0;
neurons[i].fired = 0;
}
}
// ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠΈΠ½Π°ΠΏΡΠ°
void addSynapse(uint8_t source, uint8_t target, int8_t weight) {
synapses[synapseCount].source = source;
synapses[synapseCount].target = target;
synapses[synapseCount].weight = weight;
synapseCount++;
}
// Π‘ΠΏΠ°ΠΉΠΊ-Π·Π°Π²ΠΈΡΠΈΠΌΠ°Ρ ΠΏΠ»Π°ΡΡΠΈΡΠ½ΠΎΡΡΡ (STDP)
void stdpLearning(uint8_t source, uint8_t target, uint32_t timeDiff) {
// ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠΈΠ½Π°ΠΏΡ
for (uint8_t i = 0; i < synapseCount; i++) {
if (synapses[i].source == source && synapses[i].target == target) {
// ΠΡΠ»ΠΈ ΡΠΏΠ°ΠΉΠΊ ΠΏΡΠΈΡΠ΅Π» Π΄ΠΎ Π²ΠΎΠ·Π±ΡΠΆΠ΄Π΅Π½ΠΈΡ - ΡΡΠΈΠ»ΠΈΠ²Π°Π΅ΠΌ
if (timeDiff < 1000) {
if (synapses[i].weight < 127) synapses[i].weight++;
} else {
// ΠΡΠ»ΠΈ ΠΏΠΎΡΠ»Π΅ - ΠΎΡΠ»Π°Π±Π»ΡΠ΅ΠΌ
if (synapses[i].weight > -128) synapses[i].weight--;
}
break;
}
}
}
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠΏΠ°ΠΉΠΊΠ°
void processSpike(uint8_t neuronIdx, uint32_t currentTime) {
// ΠΡΠΏΡΠ°Π²Π»ΡΠ΅ΠΌ ΡΠΏΠ°ΠΉΠΊ Π²ΡΠ΅ΠΌ ΡΠ²ΡΠ·Π°Π½Π½ΡΠΌ Π½Π΅ΠΉΡΠΎΠ½Π°ΠΌ
for (uint8_t i = 0; i < synapseCount; i++) {
if (synapses[i].source == neuronIdx) {
uint8_t target = synapses[i].target;
// ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ ΠΊ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»Ρ ΡΠ΅Π»Π΅Π²ΠΎΠ³ΠΎ Π½Π΅ΠΉΡΠΎΠ½Π° (Ρ ΡΡΠ΅ΡΠΎΠΌ Π²Π΅ΡΠ°)
neurons[target].potential += synapses[i].weight;
// STDP ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ (Π΅ΡΠ»ΠΈ Π½Π΅ΠΉΡΠΎΠ½ ΡΡΠ°Π±ΠΎΡΠ°Π»)
if (neurons[target].fired) {
stdpLearning(neuronIdx, target, currentTime - lastSpikeTime[target]);
}
}
}
}
// ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΡΠΈΠΊΠ» ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ (Π²ΡΠ·ΡΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΆΠ΄ΡΠ΅ 1 ΠΌΡ)
uint32_t time = 0;
uint32_t lastSpikeTime[NEURON_COUNT];
void processNetwork() {
time++;
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
// ΠΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ ΡΠ΅ΡΡΠ°ΠΊΡΠ΅ΡΠ½ΠΎΡΡΡ
if (neurons[i].refractory > 0) {
neurons[i].refractory--;
continue;
}
// ΠΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ ΠΏΠΎΡΠΎΠ³
if (neurons[i].potential >= neurons[i].threshold) {
// Π‘ΠΏΠ°ΠΉΠΊ!
neurons[i].fired = 1;
neurons[i].potential = 0;
neurons[i].refractory = 5; // 5 ΠΌΡ ΡΠ΅ΡΡΠ°ΠΊΡΠ΅ΡΠ½ΠΎΡΡΠΈ
lastSpikeTime[i] = time;
processSpike(i, time);
} else {
neurons[i].fired = 0;
// ΠΠΎΡΡΠ΅ΠΏΠ΅Π½Π½ΠΎΠ΅ ΡΠ³Π°ΡΠ°Π½ΠΈΠ΅ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»Π°
neurons[i].potential = (neurons[i].potential * 15) / 16;
}
}
}
// ΠΡ
ΠΎΠ΄Π½ΠΎΠΉ ΡΡΠΈΠΌΡΠ» (ΠΎΡ Π΄Π°ΡΡΠΈΠΊΠΎΠ²)
void stimulateNetwork(uint8_t* input) {
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
if (input[i]) {
neurons[i].potential += 20; // ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ ΡΡΠΈΠΌΡΠ»
}
}
}
// Π§ΡΠ΅Π½ΠΈΠ΅ Π²ΡΡ
ΠΎΠ΄Π° (ΡΡΠ°Π±ΠΎΡΠ°Π²ΡΠΈΠ΅ Π½Π΅ΠΉΡΠΎΠ½Ρ)
void readOutput(uint8_t* output) {
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
output[i] = neurons[i].fired;
}
}
// ΠΡΠΈΠΌΠ΅Ρ: ΡΠ°ΡΠΏΠΎΠ·Π½Π°Π²Π°Π½ΠΈΠ΅ ΠΏΠ°ΡΡΠ΅ΡΠ½ΠΎΠ²
void setup() {
Serial.begin(115200);
initNetwork();
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠ»ΡΡΠ°ΠΉΠ½ΡΠ΅ ΡΠ²ΡΠ·ΠΈ (50% Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡΡ)
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
for (uint8_t j = 0; j < NEURON_COUNT; j++) {
if (i != j && (rand() % 2)) {
addSynapse(i, j, rand() % 20 - 10);
}
}
}
// ΠΠ±ΡΡΠ°Π΅ΠΌ ΡΠ΅ΡΡ Π½Π° ΠΏΠ°ΡΡΠ΅ΡΠ½Π΅ (00110011)
uint8_t pattern[] = {0, 0, 1, 1, 0, 0, 1, 1};
for (uint8_t epoch = 0; epoch < 100; epoch++) {
stimulateNetwork(pattern);
for (uint8_t i = 0; i < 100; i++) {
processNetwork();
}
}
}
void loop() {
// Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌ ΡΠ΅ΡΡ
uint8_t testInput[] = {0, 1, 1, 0, 0, 0, 1, 1};
uint8_t output[NEURON_COUNT];
stimulateNetwork(testInput);
for (uint8_t i = 0; i < 100; i++) {
processNetwork();
}
readOutput(output);
Serial.print("Π Π°ΡΠΏΠΎΠ·Π½Π°Π½Π½ΡΠΉ ΠΏΠ°ΡΡΠ΅ΡΠ½: ");
for (uint8_t i = 0; i < NEURON_COUNT; i++) {
Serial.print(output[i]);
}
Serial.println();
delay(1000);
}