Error-driven dopamine (delta-rule) training mode in KNP: network option, isolated backend
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
39079670c0
commit
64fc5161e0
8 changed files with 267 additions and 32 deletions
|
|
@ -19,7 +19,7 @@ ap.add_argument('--columns', type=int, default=20)
|
|||
ap.add_argument('--seed', type=int, default=42)
|
||||
ap.add_argument('--jitter', type=float, default=20)
|
||||
ap.add_argument('--quant', choices=['default', 'weights'], default='default')
|
||||
ap.add_argument('--backend', choices=['single', 'multi', 'tuned', 'fast'], default='single')
|
||||
ap.add_argument('--backend', choices=['single', 'multi', 'tuned', 'fast', 'delta'], default='single')
|
||||
ap.add_argument('--threads', type=int, default=2)
|
||||
a = ap.parse_args()
|
||||
if a.backend == 'multi':
|
||||
|
|
@ -41,7 +41,8 @@ env['KNP_CPU_THREADS'] = str(a.threads)
|
|||
backends = {'single': '/home/int/knp-build/bin/libknp-cpu-single-threaded-backend.so',
|
||||
'multi': '/home/int/knp-build/bin/libknp-cpu-multi-threaded-backend.so',
|
||||
'tuned': str(root / 'acceleration/libknp-cpu-tuned-backend.so'),
|
||||
'fast': str(root / 'fast-cpu/libknp-cpu-fast-backend.so')}
|
||||
'fast': str(root / 'fast-cpu/libknp-cpu-fast-backend.so'),
|
||||
'delta': '/home/int/run/delta-cpu/libknp-cpu-delta-backend.so'}
|
||||
command = [str(root / 'build/cats_dogs'), '-m', 'altai',
|
||||
'--images', str(a.data_dir / (a.dataset + '.bin')),
|
||||
'--labels', str(a.data_dir / (a.dataset + '.target')),
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@
|
|||
// KNP_COL_GATE=<g1,g2,..> gate->input pulses: weight g_k with delay k (default: single 10000 pulse with delay 1).
|
||||
// KNP_COL_PUNISH=<d> target->input dopamine -d*1000 to every column except the label's one (reward is 0.179376):
|
||||
// neurons of wrong columns that fired recently lose the synapses that made them fire.
|
||||
// KNP_DELTA=<a>,<b> error-driven (delta-rule) training; needs a backend built with KNP_DELTA_RULE support
|
||||
// (augment/build_delta_cpu.py). The label sends dopamine +a to its neurons on every active
|
||||
// step, every input neuron's own spike sends it dopamine -b on the next step, so dopamine =
|
||||
// target - output; no forcing gate, no label inhibition, no Hebbian/stability changes.
|
||||
namespace
|
||||
{
|
||||
float env_float(const char *name, float default_value)
|
||||
|
|
@ -110,6 +114,13 @@ static NetworkPopulations create_populations(NetworkConstructor &constructor)
|
|||
input_neuron.stability_change_parameter_ = stability_change_parameter;
|
||||
input_neuron.resource_drain_coefficient_ = resource_drain_coefficient;
|
||||
input_neuron.synapse_sum_threshold_coefficient_ = synapse_sum_threshold_coefficient;
|
||||
if (env_float_list("KNP_DELTA", {}).size() == 2)
|
||||
{
|
||||
// Only the dopamine (error) rule changes synapses.
|
||||
input_neuron.d_h_ = 0;
|
||||
input_neuron.stability_change_parameter_ = 0;
|
||||
input_neuron.synapse_sum_threshold_coefficient_ = 0;
|
||||
}
|
||||
|
||||
// Create input population with specialized parameters for image processing.
|
||||
const auto &input_pop = constructor.add_population(
|
||||
|
|
@ -179,6 +190,14 @@ static void create_projections(
|
|||
target_to_input_synapse_dopamine.output_type_ = knp::synapse_traits::OutputType::DOPAMINE;
|
||||
target_to_input_synapse_dopamine.weight_ = 0.179376 * 1000;
|
||||
target_to_input_synapse_dopamine.delay_ = 3;
|
||||
const std::vector<float> delta = env_float_list("KNP_DELTA", {});
|
||||
const bool delta_mode = delta.size() == 2;
|
||||
if (delta_mode)
|
||||
{
|
||||
// Label spikes come on every active step, in step with the image spikes.
|
||||
target_to_input_synapse_dopamine.weight_ = delta[0];
|
||||
target_to_input_synapse_dopamine.delay_ = 1;
|
||||
}
|
||||
|
||||
// Create dopamine projection connecting target to input population.
|
||||
auto target_to_input_proj_dopamine = constructor.add_projection(
|
||||
|
|
@ -216,26 +235,32 @@ static void create_projections(
|
|||
target_to_input_synapse_excitatory.weight_ = -30 * 1000;
|
||||
target_to_input_synapse_excitatory.delay_ = 4;
|
||||
|
||||
// Create excitatory projection connecting target population to input population.
|
||||
auto target_to_input_proj_excitatory = constructor.add_projection(
|
||||
target_to_input_synapse_excitatory, knp::framework::projection::creators::all_to_all<DeltaSynapse>,
|
||||
pops.target_pop_, pops.input_pop_, false, false);
|
||||
|
||||
// Record excitatory projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_input_proj_excitatory);
|
||||
// Create excitatory projection connecting target population to input population (not in delta mode).
|
||||
if (!delta_mode)
|
||||
{
|
||||
auto target_to_input_proj_excitatory = constructor.add_projection(
|
||||
target_to_input_synapse_excitatory, knp::framework::projection::creators::all_to_all<DeltaSynapse>,
|
||||
pops.target_pop_, pops.input_pop_, false, false);
|
||||
|
||||
// Record excitatory projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_input_proj_excitatory);
|
||||
}
|
||||
|
||||
// Configure synapse for target to gate projection.
|
||||
DeltaSynapseParams target_to_gate_synapse;
|
||||
target_to_gate_synapse.output_type_ = knp::synapse_traits::OutputType::EXCITATORY;
|
||||
target_to_gate_synapse.weight_ = 10 * 1000;
|
||||
|
||||
// Create projection connecting target population to gate population.
|
||||
auto target_to_gate_proj = constructor.add_projection(
|
||||
target_to_gate_synapse, knp::framework::projection::creators::aligned<DeltaSynapse>, pops.target_pop_,
|
||||
pops.gate_pop_, false, false);
|
||||
|
||||
// Record gate projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_gate_proj);
|
||||
// Create projection connecting target population to gate population (no forcing in delta mode).
|
||||
if (!delta_mode)
|
||||
{
|
||||
auto target_to_gate_proj = constructor.add_projection(
|
||||
target_to_gate_synapse, knp::framework::projection::creators::aligned<DeltaSynapse>, pops.target_pop_,
|
||||
pops.gate_pop_, false, false);
|
||||
|
||||
// Record gate projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_gate_proj);
|
||||
}
|
||||
|
||||
// Configure synapse for input to output projection.
|
||||
DeltaSynapseParams input_to_output_synapse;
|
||||
|
|
@ -276,6 +301,31 @@ static void create_projections(
|
|||
pops.input_pop_, false, false);
|
||||
}
|
||||
|
||||
// Delta mode: a neuron's own spike sends it negative dopamine on the next step (dopamine = target - output).
|
||||
if (delta_mode)
|
||||
{
|
||||
DeltaSynapseParams self_dopamine;
|
||||
self_dopamine.output_type_ = knp::synapse_traits::OutputType::DOPAMINE;
|
||||
self_dopamine.weight_ = -delta[1];
|
||||
self_dopamine.delay_ = 1;
|
||||
auto self_creator = [self_dopamine](
|
||||
const knp::core::UID &pre_uid, const knp::core::UID &post_uid, size_t pre_size,
|
||||
size_t post_size, auto)
|
||||
{
|
||||
return knp::framework::projection::creators::index_based<DeltaSynapse>(
|
||||
pre_uid, post_uid, pre_size, post_size,
|
||||
[self_dopamine](size_t pre, size_t post) -> std::optional<DeltaSynapseParams>
|
||||
{
|
||||
if (pre != post) return std::nullopt;
|
||||
return self_dopamine;
|
||||
});
|
||||
};
|
||||
auto self_proj =
|
||||
constructor.add_projection(self_dopamine, self_creator, pops.input_pop_, pops.input_pop_, false, false);
|
||||
// Training signal only: not part of the inference network.
|
||||
network.data_.inference_internal_projection_.erase(self_proj);
|
||||
}
|
||||
|
||||
// Lateral inhibition inside each column.
|
||||
if (const float lateral = env_float("KNP_COL_LATERAL", 0); lateral > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
*/
|
||||
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <cstdlib>
|
||||
|
||||
#include "global_config.h"
|
||||
#include "network_functions.h"
|
||||
|
||||
|
|
@ -37,7 +39,10 @@ make_training_labels_spikes_generator<knp::neuron_traits::AltAILIF>(const Datase
|
|||
knp::core::messaging::SpikeData message;
|
||||
|
||||
knp::core::Step local_step = step % steps_per_image;
|
||||
if (local_step == 11) message.push_back(dataset.get_data_for_training().first[step / steps_per_image].first);
|
||||
// KNP_DELTA (error-driven training): the label is sent on every active step, in step with the image.
|
||||
static const bool every_step = std::getenv("KNP_DELTA") != nullptr;
|
||||
if (every_step ? local_step < active_steps : local_step == 11)
|
||||
message.push_back(dataset.get_data_for_training().first[step / steps_per_image].first);
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
14
changes-2026-10-15.md
Normal file
14
changes-2026-10-15.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Журнал работы — 15 октября 2026
|
||||
|
||||
## Ночь (продолжение): выход, обучаемый дофамином по ошибке, внутри KNP
|
||||
|
||||
Пользователь: «начинай, связь со мной не нужна». Цель — перенести в KNP правило, проверенное в симуляторе (выход «цель − ответ» × вход).
|
||||
|
||||
### Код
|
||||
- `examples/.../models/altai/construct_network.cpp`: режим `KNP_DELTA=<a>,<b>`. Метка подаёт дофамин +a нейронам своего класса с задержкой 1 на каждом активном шаге; собственный спайк нейрона даёт ему дофамин −b на следующем шаге (проекция input→input, исключена из сети распознавания). Нет торможения по метке (−30000) и принуждения через гейт; у нейронов выключены Хебб (d_h=0), стабильность и порог от суммы весов. Используется с `KNP_COL_SIZE=1` (один нейрон на класс).
|
||||
- `.../models/altai/spike_generators.cpp`: при `KNP_DELTA` метка отправляется на шагах 0–9 (а не на 11-м).
|
||||
- `readout/build_delta_cpu.py` → `/home/int/run/delta-cpu/libknp-cpu-delta-backend.so`: изолированная копия бэкенда; `KNP_DELTA_RULE=<скорость>` — у нейрона с дофамином D ≠ 0 каждый обучаемый синапс, чей входной спайк пришёл с отставанием `KNP_DELTA_LAG` шагов, меняет ресурс на скорость·D (независимо от спайка самого нейрона); `KNP_DELTA_DEBUG` печатает гистограмму отставаний. Оригинальные библиотеки не менялись.
|
||||
- Отладка: при отставании 0 обновлений не было (веса не менялись); гистограмма: отставания 1/2/3 = 406 тыс./252 тыс./120 тыс., 0 — ни одного. Дофамин приходит на шаг позже входа → `KNP_DELTA_LAG=1`.
|
||||
- Пробный прогон (признаки coarse, 3000 обучение, 1000 проверка, 10 нейронов): скорость 0,3 — 48,5%, 1 — 76,8%, 3 — **77,4%** (колонки 200 нейронов на том же объёме: 69,8% без наказания, до 79% с наказанием).
|
||||
- `cats-dogs/source`: те же изменения (`construct_network.cpp`, `spike_generators.cpp`), пересобран `cats_dogs`; `cats-dogs/run.py --backend delta`.
|
||||
- Запущены: `readout/delta_runs.sh` (MNIST coarse, 30 000, 6 вариантов) и кошки/собаки на плотных признаках `features-v3/kmeans_validation` (2048 входов, 18 000 обучение, скорости 0,3/1/3).
|
||||
|
|
@ -41,6 +41,10 @@
|
|||
// KNP_COL_GATE=<g1,g2,..> gate->input pulses: weight g_k with delay k (default: single 10000 pulse with delay 1).
|
||||
// KNP_COL_PUNISH=<d> target->input dopamine -d*1000 to every column except the label's one (reward is 0.179376):
|
||||
// neurons of wrong columns that fired recently lose the synapses that made them fire.
|
||||
// KNP_DELTA=<a>,<b> error-driven (delta-rule) training; needs a backend built with KNP_DELTA_RULE support
|
||||
// (augment/build_delta_cpu.py). The label sends dopamine +a to its neurons on every active
|
||||
// step, every input neuron's own spike sends it dopamine -b on the next step, so dopamine =
|
||||
// target - output; no forcing gate, no label inhibition, no Hebbian/stability changes.
|
||||
namespace
|
||||
{
|
||||
float env_float(const char *name, float default_value)
|
||||
|
|
@ -110,6 +114,13 @@ static NetworkPopulations create_populations(NetworkConstructor &constructor)
|
|||
input_neuron.stability_change_parameter_ = stability_change_parameter;
|
||||
input_neuron.resource_drain_coefficient_ = resource_drain_coefficient;
|
||||
input_neuron.synapse_sum_threshold_coefficient_ = synapse_sum_threshold_coefficient;
|
||||
if (env_float_list("KNP_DELTA", {}).size() == 2)
|
||||
{
|
||||
// Only the dopamine (error) rule changes synapses.
|
||||
input_neuron.d_h_ = 0;
|
||||
input_neuron.stability_change_parameter_ = 0;
|
||||
input_neuron.synapse_sum_threshold_coefficient_ = 0;
|
||||
}
|
||||
|
||||
// Create input population with specialized parameters for image processing.
|
||||
const auto &input_pop = constructor.add_population(
|
||||
|
|
@ -179,6 +190,14 @@ static void create_projections(
|
|||
target_to_input_synapse_dopamine.output_type_ = knp::synapse_traits::OutputType::DOPAMINE;
|
||||
target_to_input_synapse_dopamine.weight_ = 0.179376 * 1000;
|
||||
target_to_input_synapse_dopamine.delay_ = 3;
|
||||
const std::vector<float> delta = env_float_list("KNP_DELTA", {});
|
||||
const bool delta_mode = delta.size() == 2;
|
||||
if (delta_mode)
|
||||
{
|
||||
// Label spikes come on every active step, in step with the image spikes.
|
||||
target_to_input_synapse_dopamine.weight_ = delta[0];
|
||||
target_to_input_synapse_dopamine.delay_ = 1;
|
||||
}
|
||||
|
||||
// Create dopamine projection connecting target to input population.
|
||||
auto target_to_input_proj_dopamine = constructor.add_projection(
|
||||
|
|
@ -216,26 +235,32 @@ static void create_projections(
|
|||
target_to_input_synapse_excitatory.weight_ = -30 * 1000;
|
||||
target_to_input_synapse_excitatory.delay_ = 4;
|
||||
|
||||
// Create excitatory projection connecting target population to input population.
|
||||
auto target_to_input_proj_excitatory = constructor.add_projection(
|
||||
target_to_input_synapse_excitatory, knp::framework::projection::creators::all_to_all<DeltaSynapse>,
|
||||
pops.target_pop_, pops.input_pop_, false, false);
|
||||
|
||||
// Record excitatory projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_input_proj_excitatory);
|
||||
// Create excitatory projection connecting target population to input population (not in delta mode).
|
||||
if (!delta_mode)
|
||||
{
|
||||
auto target_to_input_proj_excitatory = constructor.add_projection(
|
||||
target_to_input_synapse_excitatory, knp::framework::projection::creators::all_to_all<DeltaSynapse>,
|
||||
pops.target_pop_, pops.input_pop_, false, false);
|
||||
|
||||
// Record excitatory projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_input_proj_excitatory);
|
||||
}
|
||||
|
||||
// Configure synapse for target to gate projection.
|
||||
DeltaSynapseParams target_to_gate_synapse;
|
||||
target_to_gate_synapse.output_type_ = knp::synapse_traits::OutputType::EXCITATORY;
|
||||
target_to_gate_synapse.weight_ = 10 * 1000;
|
||||
|
||||
// Create projection connecting target population to gate population.
|
||||
auto target_to_gate_proj = constructor.add_projection(
|
||||
target_to_gate_synapse, knp::framework::projection::creators::aligned<DeltaSynapse>, pops.target_pop_,
|
||||
pops.gate_pop_, false, false);
|
||||
|
||||
// Record gate projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_gate_proj);
|
||||
// Create projection connecting target population to gate population (no forcing in delta mode).
|
||||
if (!delta_mode)
|
||||
{
|
||||
auto target_to_gate_proj = constructor.add_projection(
|
||||
target_to_gate_synapse, knp::framework::projection::creators::aligned<DeltaSynapse>, pops.target_pop_,
|
||||
pops.gate_pop_, false, false);
|
||||
|
||||
// Record gate projection for label processing.
|
||||
network.data_.projections_from_classes_.push_back(target_to_gate_proj);
|
||||
}
|
||||
|
||||
// Configure synapse for input to output projection.
|
||||
DeltaSynapseParams input_to_output_synapse;
|
||||
|
|
@ -276,6 +301,31 @@ static void create_projections(
|
|||
pops.input_pop_, false, false);
|
||||
}
|
||||
|
||||
// Delta mode: a neuron's own spike sends it negative dopamine on the next step (dopamine = target - output).
|
||||
if (delta_mode)
|
||||
{
|
||||
DeltaSynapseParams self_dopamine;
|
||||
self_dopamine.output_type_ = knp::synapse_traits::OutputType::DOPAMINE;
|
||||
self_dopamine.weight_ = -delta[1];
|
||||
self_dopamine.delay_ = 1;
|
||||
auto self_creator = [self_dopamine](
|
||||
const knp::core::UID &pre_uid, const knp::core::UID &post_uid, size_t pre_size,
|
||||
size_t post_size, auto)
|
||||
{
|
||||
return knp::framework::projection::creators::index_based<DeltaSynapse>(
|
||||
pre_uid, post_uid, pre_size, post_size,
|
||||
[self_dopamine](size_t pre, size_t post) -> std::optional<DeltaSynapseParams>
|
||||
{
|
||||
if (pre != post) return std::nullopt;
|
||||
return self_dopamine;
|
||||
});
|
||||
};
|
||||
auto self_proj =
|
||||
constructor.add_projection(self_dopamine, self_creator, pops.input_pop_, pops.input_pop_, false, false);
|
||||
// Training signal only: not part of the inference network.
|
||||
network.data_.inference_internal_projection_.erase(self_proj);
|
||||
}
|
||||
|
||||
// Lateral inhibition inside each column.
|
||||
if (const float lateral = env_float("KNP_COL_LATERAL", 0); lateral > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
*/
|
||||
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <cstdlib>
|
||||
|
||||
#include "global_config.h"
|
||||
#include "network_functions.h"
|
||||
|
||||
|
|
@ -37,7 +39,10 @@ make_training_labels_spikes_generator<knp::neuron_traits::AltAILIF>(const Datase
|
|||
knp::core::messaging::SpikeData message;
|
||||
|
||||
knp::core::Step local_step = step % steps_per_image;
|
||||
if (local_step == 11) message.push_back(dataset.get_data_for_training().first[step / steps_per_image].first);
|
||||
// KNP_DELTA (error-driven training): the label is sent on every active step, in step with the image.
|
||||
static const bool every_step = std::getenv("KNP_DELTA") != nullptr;
|
||||
if (every_step ? local_step < active_steps : local_step == 11)
|
||||
message.push_back(dataset.get_data_for_training().first[step / steps_per_image].first);
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
90
readout/build_delta_cpu.py
Normal file
90
readout/build_delta_cpu.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""Build an isolated CPU single-threaded backend with an error-driven (delta-rule) dopamine plasticity option.
|
||||
|
||||
KNP_DELTA_RULE=<rate> (environment, read once): for every AltAI STDP neuron with non-zero dopamine D on a step,
|
||||
each trainable synapse whose presynaptic spike arrives on that step changes its synaptic resource by rate * D,
|
||||
whether or not the neuron itself spiked; stability is not used. Without the variable the backend behaves like
|
||||
the stock one. Original sources and libraries are not modified.
|
||||
|
||||
usage: python3 build_delta_cpu.py → /home/int/run/delta-cpu/libknp-cpu-delta-backend.so
|
||||
"""
|
||||
from pathlib import Path
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
root = Path('/home/int/run/delta-cpu')
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
source_root = Path('/mnt/c/KNP/examples/knp/backends/cpu')
|
||||
shutil.copytree(source_root / 'cpu-library/include', root / 'include', dirs_exist_ok=True)
|
||||
altai = root / 'include/knp/backends/cpu-library/impl/populations/altai/altai_stdp.h'
|
||||
s = altai.read_text()
|
||||
marker = ''' for (size_t neuron_index = 0; neuron_index < population.size(); ++neuron_index)
|
||||
{
|
||||
auto &neuron = population[neuron_index];
|
||||
// Dopamine processing. Dopamine punishment if forced does nothing.'''
|
||||
assert marker in s
|
||||
s = s.replace(marker, ''' // Experimental delta rule (KNP_DELTA_RULE=<rate>), see build_delta_cpu.py.
|
||||
// Step offset between the dopamine step and the presynaptic arrival step (KNP_DELTA_LAG, default 0).
|
||||
static const int64_t DELTA_LAG = []
|
||||
{
|
||||
const char *value = std::getenv("KNP_DELTA_LAG");
|
||||
return value ? std::stol(value) : 0L;
|
||||
}();
|
||||
static const float delta_rate = []
|
||||
{
|
||||
const char *value = std::getenv("KNP_DELTA_RULE");
|
||||
return value ? std::stof(value) : 0.F;
|
||||
}();
|
||||
for (size_t neuron_index = 0; neuron_index < population.size(); ++neuron_index)
|
||||
{
|
||||
auto &neuron = population[neuron_index];
|
||||
if (delta_rate > 0)
|
||||
{
|
||||
if (neuron.dopamine_value_ == 0.0) continue;
|
||||
std::vector<std::reference_wrapper<SynapseParamType>> delta_synapses =
|
||||
training::stdp::get_all_connected_synapses<SynapseType>(working_projections, neuron_index);
|
||||
static const bool debug = std::getenv("KNP_DELTA_DEBUG") != nullptr;
|
||||
static uint64_t calls = 0, hist[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
for (auto &synapse : delta_synapses)
|
||||
{
|
||||
const int64_t lag = static_cast<int64_t>(step) -
|
||||
static_cast<int64_t>(synapse.get().rule_.last_spike_step_ + synapse.get().delay_ - 1);
|
||||
if (debug && lag >= -3 && lag <= 3) ++hist[lag + 3];
|
||||
// The presynaptic spike reaches the neuron on this step.
|
||||
if (lag == DELTA_LAG)
|
||||
synapse.get().rule_.synaptic_resource_ += delta_rate * neuron.dopamine_value_;
|
||||
}
|
||||
if (debug && ++calls % 500 == 0)
|
||||
std::fprintf(stderr, "KNP_DELTA_DEBUG calls=%lu lag-3..3: %lu %lu %lu %lu %lu %lu %lu\\n",
|
||||
static_cast<unsigned long>(calls), hist[0], hist[1], hist[2], hist[3], hist[4], hist[5], hist[6]);
|
||||
training::stdp::recalculate_synapse_weights(delta_synapses);
|
||||
continue;
|
||||
}
|
||||
// Dopamine processing. Dopamine punishment if forced does nothing.''')
|
||||
if '#include <cstdlib>' not in s:
|
||||
s = s.replace('#include <algorithm>', '#include <algorithm>\n#include <cstdio>\n#include <cstdlib>\n#include <string>', 1)
|
||||
altai.write_text(s)
|
||||
build = Path('/home/int/knp-build/knp/backends/cpu/cpu-single-threaded-backend')
|
||||
folder = build / 'CMakeFiles/knp-cpu-single-threaded-backend.dir'
|
||||
flags = {}
|
||||
for line in (folder / 'flags.make').read_text().splitlines():
|
||||
if ' = ' in line:
|
||||
key, value = line.split(' = ', 1)
|
||||
flags[key] = shlex.split(value)
|
||||
obj = root / 'backend.o'
|
||||
subprocess.run(['/usr/bin/c++', *flags['CXX_DEFINES'], '-I' + str(root / 'include'),
|
||||
*flags['CXX_INCLUDES'], *flags['CXX_FLAGS'], '-c',
|
||||
str(source_root / 'cpu-single-threaded-backend/impl/backend.cpp'), '-o', str(obj)], check=True)
|
||||
link = shlex.split((folder / 'link.txt').read_text())
|
||||
rebuilt = []
|
||||
for item in link:
|
||||
if item.startswith('-Wl,--dependency-file='):
|
||||
continue
|
||||
if item.endswith('/impl/backend.cpp.o'):
|
||||
item = str(obj)
|
||||
elif item.startswith('-Wl,-soname,'):
|
||||
item = '-Wl,-soname,libknp-cpu-delta-backend.so'
|
||||
rebuilt.append(item)
|
||||
rebuilt[rebuilt.index('-o') + 1] = str(root / 'libknp-cpu-delta-backend.so')
|
||||
subprocess.run(rebuilt, cwd=build, check=True)
|
||||
print(root / 'libknp-cpu-delta-backend.so', flush=True)
|
||||
20
readout/delta_runs.sh
Normal file
20
readout/delta_runs.sh
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
# Error-driven (delta-rule) readout in KNP on coarse stroke features, 30k train, validation.
|
||||
# spec: name rate a b jitter
|
||||
cd ~/run/exp
|
||||
export LD_LIBRARY_PATH=$HOME/knp-build/bin:$HOME/deps/lib
|
||||
run() { n=$1; [ -f $n/done ] && return; mkdir -p $n
|
||||
echo | env KNP_COL_SIZE=1 KNP_COL_JITTER=$5 KNP_MNIST_THR=60 KNP_MNIST_ADD_THR_SCALE=0 KNP_MNIST_INFER_INHIB=255 \
|
||||
KNP_DELTA=$3,$4 KNP_DELTA_RULE=$2 KNP_DELTA_LAG=1 KNP_MNIST_DUMP=$HOME/run/exp/$n \
|
||||
$HOME/knp-build/bin/mnist_learn_example -m altai --images ${DATA:-fcoarse_val}30000.bin --labels ${DATA:-fcoarse_val}30000.target \
|
||||
-t 30000 -i 10000 -l error --training_backend $HOME/run/delta-cpu/libknp-cpu-delta-backend.so > $n/log.txt 2>&1
|
||||
touch $n/done; }
|
||||
export -f run
|
||||
cat <<SPECS | xargs -P 6 -L 1 bash -c 'run "$@"' _
|
||||
dl_r1_a1_b1_j20 1 1 1 20
|
||||
dl_r3_a1_b1_j20 3 1 1 20
|
||||
dl_r10_a1_b1_j20 10 1 1 20
|
||||
dl_r3_a1_b0.5_j20 3 1 0.5 20
|
||||
dl_r3_a1_b2_j20 3 1 2 20
|
||||
dl_r3_a1_b1_j0 3 1 1 0
|
||||
SPECS
|
||||
Loading…
Add table
Reference in a new issue