Delta-rule KNP: augmented MNIST robustness, object runs; report section
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
917b94035d
commit
6bfdbf69d3
7 changed files with 51 additions and 11 deletions
|
|
@ -42,7 +42,7 @@ Dataset process_dataset(ModelDescription const& model_desc)
|
|||
// Process images and labels into spike representations.
|
||||
dataset.process_labels_and_images(
|
||||
images_stream, labels_stream, model_desc.train_images_amount_ + model_desc.inference_images_amount_,
|
||||
classes_amount, input_size, steps_per_image,
|
||||
classes_amount, get_input_size(), steps_per_image,
|
||||
dataset.make_incrementing_image_to_spikes_converter(active_steps, state_increment_factor));
|
||||
|
||||
// Split dataset into training and inference portions.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -36,7 +38,20 @@ constexpr size_t classes_amount = 2;
|
|||
*
|
||||
* @details MNIST images are 28×28 pixels, resulting in 784 total pixels per image.
|
||||
*/
|
||||
constexpr size_t input_size = 32 * 32 * 2;
|
||||
constexpr size_t default_input_size = 32 * 32 * 2;
|
||||
|
||||
/**
|
||||
* @brief Actual input size: `KNP_MNIST_INPUT_SIZE` environment variable or 2048.
|
||||
*/
|
||||
inline size_t get_input_size()
|
||||
{
|
||||
static const size_t size = []
|
||||
{
|
||||
const char *value = std::getenv("KNP_MNIST_INPUT_SIZE");
|
||||
return value ? static_cast<size_t>(std::stoul(value)) : default_input_size;
|
||||
}();
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Total number of simulation steps per input image.
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ static NetworkPopulations create_populations(NetworkConstructor &constructor)
|
|||
constructor.add_population(default_neuron, classes_amount, PopulationRole::NORMAL, false, "GATE");
|
||||
|
||||
// Create raster population for channelized image processing (28x28 = 784 neurons).
|
||||
const auto &raster_pop = constructor.add_channeled_population(input_size, true);
|
||||
const auto &raster_pop = constructor.add_channeled_population(get_input_size(), true);
|
||||
|
||||
// Create target population for label processing (10 neurons for 10 digit classes).
|
||||
const auto &target_pop = constructor.add_channeled_population(classes_amount, false);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ static NetworkPopulations create_populations(NetworkConstructor &constructor)
|
|||
constructor.add_population(default_neuron, classes_amount, PopulationRole::NORMAL, false, "GATE");
|
||||
|
||||
// Create raster population for channelized image processing (28x28 = 784 neurons).
|
||||
const auto &raster_pop = constructor.add_channeled_population(input_size, true);
|
||||
const auto &raster_pop = constructor.add_channeled_population(get_input_size(), true);
|
||||
|
||||
// Create target population for label processing (10 neurons for 10 digit classes).
|
||||
const auto &target_pop = constructor.add_channeled_population(classes_amount, false);
|
||||
|
|
|
|||
|
|
@ -45,3 +45,9 @@ MNIST, признаки coarse, 30 000 обучение, 10 000 проверка
|
|||
| 3 | 4 | **69,1%** |
|
||||
|
||||
Колонки STDP на этих же плотных признаках молчали (≈0%), на разреженных top-256 — 64–65%; ridge на этих uint8-признаках 74,2%, спайковый нейрон-разность 72,4%. Симулятор `dl_cd_r3_b4`: порог 30–250, торможение 0/255 — 67,6–68,8%.
|
||||
- MNIST, штраф b: 8 — 94,22%; 12 — 92,42% (оптимум b = 4–6). Устойчивость `dl_r3_a1_b6_j20` (симулятор, 2000): как есть 94,5%, сдвиг 2 px 87,5%, толще 90,8%, тоньше 84,0%.
|
||||
- MNIST с аугментацией A (`fcoarseA_val90000`, 90 000, r3 b6): KNP **94,63%**; устойчивость — 94,6 / **91,3** / 91,2 / 80,8%.
|
||||
- Кошки/собаки, ещё b: r3 b6 63,5%, r3 b8 62,2%, r3 b12 60,0%, r1 b4 67,7%, r1 b8 68,4%.
|
||||
- `cats-dogs/source`: размер входа — `get_input_size()` из `KNP_MNIST_INPUT_SIZE` (по умолчанию 2048), пересобран. `objects/make_knp_features.py --model --name`. Признаки онлайн WTA: K=800 (3200 входов) — r3 b4 65,3%, r1 b8 67,2%; K=1600 (6400) — 65,9% / 67,2%.
|
||||
- Три прохода по обучению (обучающая часть ×3 с новым перемешиванием, `*_x3_validation`, 54 000): K=512 — r1 b4 67,3%, r1 b8 65,0%, r3 b4 66,4%; K=1600 r1 b8 63,2%. Не помогает.
|
||||
- Вывод по объектам: в KNP дофамин по ошибке даёт 65–69% (колонки STDP — 64–65% на разреженных, ≈0% на плотных); ridge на тех же признаках — 74%. Вероятная причина разрыва — ограниченный и несимметричный диапазон весов KNP (−253…+92) и насыщение ресурса.
|
||||
|
|
|
|||
|
|
@ -23,11 +23,18 @@ def main():
|
|||
ap.add_argument("--k", type=int, default=512)
|
||||
ap.add_argument("--alpha", type=float, default=0.25)
|
||||
ap.add_argument("--seed", type=int, default=20261014)
|
||||
ap.add_argument("--model", help="use a learned model (npz with mean, zca, d) instead of learning K prototypes")
|
||||
ap.add_argument("--name", default="kmeans", help="output file prefix")
|
||||
a = ap.parse_args()
|
||||
out = Path(a.out)
|
||||
out.mkdir(exist_ok=True)
|
||||
kf.CONTRAST_DIVIDE = False
|
||||
tr, va = np.load(f"{a.data}/train.npz"), np.load(f"{a.data}/val.npz")
|
||||
if a.model:
|
||||
m = np.load(a.model)
|
||||
model = {key: m[key] for key in ("mean", "zca", "d")}
|
||||
a.k = len(model["d"])
|
||||
else:
|
||||
model = kf.learn(tr["rgb"], k=a.k)
|
||||
ft = np.vstack([kf.encode(tr["rgb"], model, alpha=a.alpha), kf.encode(tr["rgb"][:, :, :, ::-1], model, alpha=a.alpha)])
|
||||
yt = np.r_[tr["labels"], tr["labels"]]
|
||||
|
|
@ -37,13 +44,13 @@ def main():
|
|||
order = np.random.default_rng(a.seed).permutation(len(ft))
|
||||
x = np.vstack([q(ft)[order], q(fv)])
|
||||
y = np.r_[yt[order], va["labels"]]
|
||||
assert x.shape[1] == 2048
|
||||
x.tofile(out / "kmeans_validation.bin")
|
||||
(out / "kmeans_validation.target").write_text("\n".join(map(str, y)) + "\n")
|
||||
np.savez(out / "kmeans_model.npz", gain=gain, **model)
|
||||
assert x.shape[1] == 4 * a.k
|
||||
x.tofile(out / f"{a.name}_validation.bin")
|
||||
(out / f"{a.name}_validation.target").write_text("\n".join(map(str, y)) + "\n")
|
||||
np.savez(out / f"{a.name}_model.npz", gain=gain, **model)
|
||||
info = {"k": a.k, "alpha": a.alpha, "train": len(ft), "validation": len(fv), "contrast_divide": False,
|
||||
"mean_value": float(x.mean()), "spikes_per_image": float(x.mean() / 255 * 10 * 2048)}
|
||||
(out / "manifest.json").write_text(json.dumps(info, indent=2) + "\n")
|
||||
"mean_value": float(x.mean()), "spikes_per_image": float(x.mean() / 255 * 10 * x.shape[1])}
|
||||
(out / f"{a.name}_manifest.json").write_text(json.dumps(info, indent=2) + "\n")
|
||||
print(info)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,18 @@
|
|||
- **Нейрон-решатель без подбора порога.** Смещение нейрона сдвинуто так, что «потенциал дошёл до порога» означает «сумма больше нуля». Результат не зависит от порога.
|
||||
- **Больше шагов на картинку** (20 вместо 10) — +1,3 п.п.: 72,9% вместо 71,6%.
|
||||
|
||||
## Обучение по ошибке прямо в KNP (утро 15 октября)
|
||||
|
||||
В KNP добавлен режим `KNP_DELTA`. Метка даёт нейрону своего класса положительный дофамин на каждом шаге, а собственный спайк нейрона даёт ему отрицательный. Дофамин получается равным «цель минус ответ», то есть это правило перцептрона на нейронах. Для него понадобилась отдельная копия бэкенда, `readout/build_delta_cpu.py`: в ней синапс меняется на величину дофамина, если по нему только что пришёл спайк, даже когда сам нейрон молчал. Оригинальные библиотеки не менялись.
|
||||
|
||||
| Задача (проверочная выборка) | Колонки STDP | **Дофамин по ошибке в KNP** | Выход, обученный вне чипа |
|
||||
| --- | --- | --- | --- |
|
||||
| Цифры, признаки штрихов, 30 000 | 83,5% (200 нейронов) | **94,8%** (10 нейронов) | 94,9% |
|
||||
| Цифры, то же + аугментация, 90 000 | — | 94,6%; сдвиг 2 px **91,3%** | 95,1%; сдвиг 89,9% |
|
||||
| Кошки/собаки, выученные признаки | 64–65% (на плотных молчат) | **65–69%** | 74% (без спайков) |
|
||||
|
||||
На цифрах обучение внутри платформы догнало обучение вне чипа и дало самую устойчивую сеть за всё время. На объектах выигрыш у колонок небольшой. Разрыв с 74%, скорее всего, из-за диапазона весов KNP: от −253 до +92, и около краёв вес почти перестаёт меняться.
|
||||
|
||||
## Цифры на странице
|
||||
|
||||
На странице https://claude.ai/artifact/Vc1q1WCZuPY2QAHBSGtrKF появилась панель «4 · Сеть штрихов»: 16 карт штрихов, спайки 10 выходных нейронов и ответ. На тесте MNIST эта сеть даёт 94,7%, колонки — 92,2%. Сеть входит в строку «Итог всех сетей», так что её можно сравнивать на своих рисунках и сдвигах. Расчёт в браузере сверен с Python: на 105 картинках ответы совпали.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue