- BrainTools - https://www.braintools.ru -

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio

Всем привет, это моя первая статья на Хабре и я решил посвятить ее своему недавнему мини‑проекту, сутью которого является обучение [1] небольшого перцептрона 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 переменных. Память [2] для одного выражения всего 99 байт, всего под выражения можно использовать около ~128-150 байт, чтобы хватило места под запись входных данных во входные переменные, без потери выражений.

Важное признание

Я не являюсь специалистом в области машинного обучения и не считаю себя хорошим программистом. Я скорее энтузиаст. Обучение перцептрона я представляю относительно поверхностно и обладаю лишь базовыми знаниями в матанализе, в частности имею лишь общее представление о градиентах и градиентном спуске. Поэтому для написания кода для обучения модели я использовал LLM (DeepSeek), а затем во время попыток обучения модели, я занимался лишь тем, что мне интересно и что я могу нормально сделать, а именно редактировал гипер‑параметры и параметры для генерации датасета, адаптировал выражения, вручную квантовал и оптимизировал их.

Коротко о задаче и архитектуре

Почему именно лемниската Бернулли?

По моему мнению лемниската Бернулли одновременно имеет достаточно интересную и сложную границу, но при этом является достаточно наглядной и поддается отоносительно простой логике [3], доступной для сети всего с 5 скрытыми нейронами.

Ограничения архитектуры

— 2 входа для координат X и Y
— Скрытый слой на 5 нейронов (были эксперименты на 3 нейрона [4], но сеть не достаточно хорошо справлялась с задачей)
— 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 без библиотек, бинарная кросс‑энтропия, обратное распространение ошибки [5].

train(train_prepared, w, b, v, b_out, lr=0.01, epochs=10000)

Конечная точность неквантованной модели 96% на обучающих данных и 96.6 на тестовых.
Конечные выражения выглядят так:

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 2

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

 График перцептрона и лемнискаты. Ссылка на график: https://www.desmos.com/3d/lifmbtkz06

График перцептрона и лемнискаты. Ссылка на график: https://www.desmos.com/3d/lifmbtkz06 [6]

Считаю, что точность не плохая для такой небольшой модели.

Адаптация к калькулятору

Проблема

Напомню, что размер одного выражения всего 99 байт, а задача была в том, чтобы все поместилось в памяти и запускалось с одной‑двух кнопок, не заставляя пользователя думать в каком порядке что нужно запустить и в какую переменную что нужно записать. А у нас на данный момент 6 выражений, в каждом из которых числа с достаточно большим количеством знаков после запятой.

Упрощение выражений и удаление лишних знаков / битва за байты

Для начала я перенес все выражения в Desmos3D, чтобы во время упрощений не совершить ошибку. Так же в будущем это будет полезно чтобы примерно оценивать влияние квантования конкретных коэффициентов на общую точность.

Начальные выражения

Начальные выражения

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 5

Округление значений, уменьшение количества знаков / впихивание невпихуемого

Заметим смещения или значения с коэффициентами близкими к нулю:

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 6
Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 7
Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 8

Попробуем удалить их:

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 9

Ничего страшного не произошло.

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

Получаем следующее:

 Ссылка на конечный график: https://www.desmos.com/3d/81uiflhf10

Ссылка на конечный график: https://www.desmos.com/3d/81uiflhf10 [7]

Запуск на калькуляторе (насилие)

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 11

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

Для теста возьму несколько точек.

1) (1;1):

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 12

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 13

2) (0.5;0):

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 14

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 15

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 16

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

Как я запустил перцептрон на обычном непрограммируемом калькуляторе Casio - 17

Заключение

У меня получилась вполне рабочая нейросеть запущенная на инженерном непрограммируемом калькуляторе. Пусть и с ограничениями, но действительно выполняющая свои задачи.

Здесь еще есть что доработать и улучшить. Думаю, что при желании расчёт скрытого слоя и выходного нейрона можно попробовать уместить в одно выражение, можно заняться файнтюнингом модели и дообучить ее, улучшив определения точки по краям и в центре лемнискаты. Возможно получится уместить в выражение дополнительные нейроны [9], заменить функцию активации или как‑то по другому улучшить архитектуру модели, но я доволен текущем результатом, который показывает, что модель в принципе работает. Надеюсь, кто‑то захочет это повторить или улучшить. Github с полезными файлами [10].

Автор: NoName12332112

Источник [11]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/32615

URLs in this post:

[1] обучение: http://www.braintools.ru/article/5125

[2] Память: http://www.braintools.ru/article/4140

[3] логике: http://www.braintools.ru/article/7640

[4] нейрона: http://www.braintools.ru/article/6020

[5] ошибки: http://www.braintools.ru/article/4192

[6] https://www.desmos.com/3d/lifmbtkz06: https://www.desmos.com/3d/lifmbtkz06

[7] https://www.desmos.com/3d/81uiflhf10: https://www.desmos.com/3d/81uiflhf10

[8] внимание: http://www.braintools.ru/article/7595

[9] нейроны: http://www.braintools.ru/article/9161

[10] Github с полезными файлами: https://github.com/No%E2%80%91Name618/Calc%E2%80%91Perceptron

[11] Источник: https://habr.com/ru/articles/1055284/?utm_campaign=1055284&utm_source=habrahabr&utm_medium=rss

www.BrainTools.ru

Rambler's Top100