Всем привет, это моя первая статья на Хабре, и я решил посвятить ее своему недавнему мини‑проекту, сутью которого является обучение небольшого перцептрона 2-5-1 с помощью Python без сторонних библиотек (типа NumPy), и его последующий инференс на непрограммируемом инженерном калькуляторе Casio‑Fx-82-Es Plus (2nd edition).
В качестве задачи для перцептрона я выбрал определение того, находится ли точка в пределах графика следующей лемнискаты Бернулли: (x² + y²)² — 2a²(x² — y²) = 0 (с a = sqrt(0.5), то есть вообще без коэффициента 2a²), с минимально приемлемой вероятностью (70–85%) Читать далее
Всем привет, это моя первая статья на Хабре и я решил посвятить ее своему недавнему мини‑проекту, сутью которого является обучение небольшого перцептрона 2-5-1 с помощью Python без сторонних библиотек (типа NumPy), и его последующий инференс на непрограммируемом инженерном калькуляторе Casio‑Fx-82-Es Plus (2nd edition).
В качестве задачи для перцептрона я выбрал определение того, находится ли точка в пределах графика следующей лемнискаты Бернулли: (x² + y²)² — 2a²(x² — y²) = 0 (с a = sqrt(0.5), то есть вообще без коэффициента 2a²), с минимально приемлемой вероятностью (70–85%)

Лемниската Бернулли
Я всегда интересовался инференсом различных ИИ моделей на предельно слабом оборудовании (по большей части LLM, но об этом в другой статье) и оборудовании с ограничениями по мощности и архитектуре. И в определенный момент я понял, что теоретически для запуска не очень большого перцептрона совершенно не обязательно использовать циклы и напрямую условные операторы, поэтому и решил попробовать. Я думаю что подобные небольшие проекты позволяют задуматься, что мы еще далеки от идеала в вопросах оптимизации софта, в частности в ИИ моделях.
По моему мнению задача будет выполнена, если в конечном итоге я смогу записать значения в 2 переменных, выполнить 1–2 выражения и получить ответ. Важный момент: выражения должны влезть в буфер последних выполненных выражений (должно остаться место под запись переменных) и должна остаться возможность повторно их использовать.
Калькулятор принимает только математические выражения. Построчное программирование, циклы и условные операторы отсутствуют. Для записи пользовательских значений и использования в выражениях доступно 9 переменных. Память для одного выражения всего 99 байт, всего под выражения можно использовать около ~128-150 байт, чтобы хватило места под запись входных данных во входные переменные, без потери выражений.
Я не являюсь специалистом в области машинного обучения и не считаю себя хорошим программистом. Я скорее энтузиаст. Обучение перцептрона я представляю относительно поверхностно и обладаю лишь базовыми знаниями в матанализе, в частности имею лишь общее представление о градиентах и градиентном спуске. Поэтому для написания кода для обучения модели я использовал LLM (DeepSeek), а затем во время попыток обучения модели, я занимался лишь тем, что мне интересно и что я могу нормально сделать, а именно редактировал гипер‑параметры и параметры для генерации датасета, адаптировал выражения, вручную квантовал и оптимизировал их.
По моему мнению лемниската Бернулли одновременно имеет достаточно интересную и сложную границу, но при этом является достаточно наглядной и поддается отоносительно простой логике, доступной для сети всего с 5 скрытыми нейронами.
— 2 входа для координат X и Y
— Скрытый слой на 5 нейронов (были эксперименты на 3 нейрона, но сеть не достаточно хорошо справлялась с задачей)
— 1 выход (вероятность принадлежности точки к лемнискате)
— Функция активации — логистическая сигмоида (1/(1+e‑x))
Архитектура выбиралась по принципу «Чем больше — тем лучше», но запихнуть в скрытый слой еще больше нейронов или добавить еще один слой было бы проблематично, так как памяти и так хватило в упор. Логистическая сигмоида была выбрана, так как неплохо подходит к такой архитектуре, не требует большого количества знаков для написания и не нуждается в прямом использовании условных переходов.
Является набором случайных точек в квадрате [-1.5, 1.5] x [-1.5, 1.5]. Метка точки вычисляется по уравнению лемнискаты:
val = (x**2 + y**2)**2 - 1.0 * (x**2 - y**2)
label = 1 if val <= 0 else 0Я выбрал количество обучающих примеров n=5000 и 500 для тестовых:
train_data = generate_dataset(n=5000)
test_data = generate_dataset(n=500, bias_right=0.5)Чистый Python без библиотек, бинарная кросс‑энтропия, обратное распространение ошибки.
train(train_prepared, w, b, v, b_out, lr=0.01, epochs=10000)Конечная точность неквантованной модели 96% на обучающих данных и 96.6 на тестовых.
Конечные выражения выглядят так:

Если отразить полученную модель на трехмерном графике, используя входы X и Y в качестве соответствующих осей, а выход в качестве оси Z, то получится следующее:

График перцептрона и лемнискаты. Ссылка на график: https://www.desmos.com/3d/lifmbtkz06
Считаю, что точность не плохая для такой небольшой модели.
Напомню, что размер одного выражения всего 99 байт, а задача была в том, чтобы все поместилось в памяти и запускалось с одной‑двух кнопок, не заставляя пользователя думать в каком порядке что нужно запустить и в какую переменную что нужно записать. А у нас на данный момент 6 выражений, в каждом из которых числа с достаточно большим количеством знаков после запятой.
Для начала я перенес все выражения в Desmos3D, чтобы во время упрощений не совершить ошибку. Так же в будущем это будет полезно чтобы примерно оценивать влияние квантования конкретных коэффициентов на общую точность.

Начальные выражения
Для начала перемножаем все минусы, переносим все слагаемые так, чтобы у нас не возникало лишних минусов (то есть ‑a+b → b‑a), удаляем знаки умножения и лишние скобки:

Заметим смещения или значения с коэффициентами близкими к нулю:
Попробуем удалить их:

Ничего страшного не произошло.
Далее в каждом коэффициенте по‑очереди стараемся уменьшить число знаков до минимума, стараясь терять минимум точности, пробуем округлять в большую или в меньшую сторону. Если что‑то не влияет на точность или влияет минимально — пытаемся удалить. Небольшие двузначные значения(например ~12.87) пробуем заменить на 9, чтобы сэкономить дополнительный знак. Все оставшиеся значения более чем с 1 знаком записываем в свободные переменные, и используем в выражении их.
Получаем следующее:

Ссылка на конечный график: https://www.desmos.com/3d/81uiflhf10
1) По очереди задаем значения всем переменным A‑E: [Значение] [SHIFT] [RCL(STO)] [Клавиша с буквой переменной]; 2) Затем вводим само выражение после «a=» и нажимаем «=». Не обращаем внимание на вывод калькулятора, вне зависимости от того какой он; 3) Далее вводим второе выражение после «z=» заменяя переменную «a» на Ans и снова нажимем «=»

Готово! Для использования перцептрона необходимо задать значения X и Y тем же методом, что и первые переменные, а затем, последовательно выполнить первое и второе выражение, возвращаясь к ним стрелками вверх и вниз, как в терминале.
Для теста возьму несколько точек.
1) (1;1):

Видим что по мнению перцептрона вероятность нахождения точки в пределах лемнискаты близка к 0, что правда:

2) (0.5;0):

Значение почти совпадает с 1, значит вероятность попадания точки в лемнискату почти 100%. Результат верный:

Ну и возьмем точку (0.6;0.25):

Значение ~= 0.8. На точках близких к границе точность определения падает, но все же определено верно:

У меня получилась вполне рабочая нейросеть запущенная на инженерном непрограммируемом калькуляторе. Пусть и с ограничениями, но действительно выполняющая свои задачи.
Здесь еще есть что доработать и улучшить. Думаю, что при желании расчёт скрытого слоя и выходного нейрона можно попробовать уместить в одно выражение, можно заняться файнтюнингом модели и дообучить ее, улучшив определения точки по краям и в центре лемнискаты. Возможно получится уместить в выражение дополнительные нейроны, заменить функцию активации или как‑то по другому улучшить архитектуру модели, но я доволен текущем результатом, который показывает, что модель в принципе работает. Надеюсь, кто‑то захочет это повторить или улучшить. Github с полезными файлами.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Flappy Bird: делаем игру сложнее и добавляем автопилот на чистой математике | 0 | 5 | 30-06-2026 |
| 2 | Ну и пригодились тебе твои синусы? | 0 | 5 | 20-06-2026 |
| 3 | USB без магии: устройство протокола | 0 | 7 | 23-06-2026 |
| 4 | Taskbar с живыми превью работающих приложений (олдскул на NET11) | 0 | 6 | 04-07-2026 |
| 5 | Компактные и интеллектуальные (роботизированные) DIY-тренажёры для дома? Вполне себе реальность… | 5 | 7 | 25-06-2026 |
| 6 | Японский «Хаябуса-2» выполнил высокоскоростной пролёт мимо астероида Торифунэ Вы когда-нибудь ... | 5 | 7 | 06-07-2026 |
| 7 | ИИ‑анализатор для космических миссий, предназначенный для создания фотонного зеркала из ... | 5 | 7 | 06-07-2026 |
| 8 | Мама, я программист: 7 лучших нейросетей для вайбкодинга | 3 | 7 | 22-06-2026 |
| 9 | Raspberry Pi — как много в этом слове для уха гикова слилось | 7 | 8 | 07-08-2013 |
| 10 | Apple может разрабатывать своё первое умное кольцо — iRing | 0 | 3 | 25-06-2026 |