среда, 15 июля 2026 г.

Обратное распространение ошибки и градиентный спуск

 Продолжим изучение темы нейронных сетей. На прошлом уроке мы рассмотрели простейший двухслойный персептрон с двумя входами и двумя выходами состоящий из весовых коэффициентов и не имеющий коэффициентов смещения, с сигмоидой в качестве функции активации для всех нейронов. В том уроке мы рассмотрели прямой проход т.е. алгоритм использования нейронной сети но он также имеется в составе алгоритма её обучения. Обучать нейронную сеть можно разными путями. Например можно случайным образом немного менять весовые коэффициенты, смотреть что получаем а выходе, сохранять наиболее лучшие результаты а также комбирировать между собой и так повторять до тех пор пока результат не станет удовлетворительным. Это называется "генетический" алгоритм. Очень интересный способ, однако он практически не применяется т.к. требует большого объема памяти и очень медленно работает. Помимо "генетического" алгоритма существует также алгоритм обучения на основе градиентного спуска. У этого алгоритма есть множество современных эффективных разновидностей. Но мы, для начала для простоты, рассмотрим классический градиентный спуск. Идея заключается в том чтобы во время обратного прохода, от выходов ко входам, вычислять ошибки создаваемые нейронами и корректировать веса таким образом чтобы немного минимизировать эти ошибки с каким то небольшим шагом за один проход путем изменения весовых коэффициентов в сторону противоположную градиентам ошибок.

Проще всего будет показать на примере как это делается. Возьмем нашу двухслойный персептрон с двумя входами и двумя выходами. Допустим мы уже сделали прямой проход и получили результат на выходе. Теперь у нас есть числа которые мы хотим иметь на выходе.  Чтобы сделать до конца первую итерацию обучения персептрона, нам нужно выполнить обратный проход. На первом этапе мы вычислим ошибки каждого нейрона. Начиная с выходного слоя и заканчивая входным. Чтобы вычислить ошибку нейрона выходного слоя нам нужно из полученного на выходе значения этого нейрона вычесть требуемое значение которое мы хотим чтобы было на выходе этого нейрона. Результат этого вычитания умножить на производную функции активации (в данном случае сигмоида) в точке взвешенной суммы. Т.е. производная сигмоиды просто выражается через саму сигмоиду а выходы нам известны то можно подставить выход в формулу производной сигмоиды и умножить это на разницу т.е. отклонение от выхода.  Далее проделать так для всех остальных нейронов выходного слоя. Теперь нужно рассчитать ошибки нейронов слоев предшествующих выходному. Сделать это уже сложнее но к счастью метод всё таки есть. На данном этапе ошибка как бы распространяется назад. Поэтому метод и называется обратным распространением ошибки. Ошибка распространяется назад и перемножается с весовыми коэффициентами а взвешенная сумма умножается на производную функции активации в точке взвешенной суммы. Таким образом. Можно рассчитать ошибки нейронов скрытых слоев. Возможно принцип работы данного метода, на первый взгляд, не очевиден но главное что он работает если просто примнеять формулы.  После того как ошибки найдены можно приступать к корректировке весов. Чтобы скорректировать вес методом градиентного спуска, из этого веса нужно вычесть произведение этого веса на градиент умноженный на шаг обучения который обычно является небольшим числом например 0.01 или что то вроде того. Выбор шага это большая отдельная тема, пока остановимся на том что это просто небольшое число. Градиент рассчитывается как произведение входа нейрона на ошибку. Можно было бы выделить расчет градиентов в отдельный этап но для реализации на языке программирования лучше объединить этап расчета градиентов с этапом корректировки весов чтобы не занимать лишнюю память т.к. на весовые коэффициенты её и так много приходиться + другие модификации градиентного спуска требуют ещё больше память поэтому очень важно стараться её экономить. Итак мы скорректировали веса. Теперь мы переходим в начало цикла обучения, выполняем прямой поход. Получаем новые значения выходов, можем оценить ошибку на данном этапе. После повторяем обратный проход и так до тех пор пока сеть не обучиться или не застрянет если например её структура такова что сеть не может быть обучена до требуемого уровня теми методами с теми данными и стартовыми условиями которые мы имеем.

Наглядно весь процесс обучения можно увидеть на картинке:

Теперь попробуем это реализовать на языке javascript. Немного изменим код предыдущей программы. Добавим кнопку для запуска обучения а также область вывода результатов. Размеры нейросети и функция активации остаются прежними. Входной вектор обучающей выборки остается прежним + добавляется выходной вектор обучающей выборки. Добавляем шаг обучения. Правильный выбор этого шага очень важен и желательно его делать небольшим но в целях изучения и на такой простой сети с такой просто обучающей выборкой, целесообразно его сделать побольше чтобы результат получился быстрее и нагляднее. Массивы весовых коэффициентов, выходов, ошибок объявляем и инициализируем. Добавим обработчик нажатия кнопки а также обернем итерацию обучения в цикл т.к. одна итерация меняет результат незначительно и для наглядности лучше сделать некоторое количество шагов обучения чтобы заметить изменение на выходе и при этом не пришлось бы слишком много кликать по кнопке. Далее делаем прямой проход и выводим результат работы нейросети. Далее делаем обратный проход по формулам. Сначала рассчитываем ошибки выходного слоя, перемножая разницу выхода требуемого и фактического с производной функции активации в точке взвешенной суммы. Потом ошибки скрытого слоя путем вычисления произведения взвешенной суммы ошибок выходного слоя с производной функции активации. После рассчитываем градиенты и корректируем веса. Полный код приведен в текстовом поле:

Или же можно поиграться с этой нейросетью непосредственно на данной странице

обучающая выборка
x0=,x1=,
out0=,out1=
шаг обучения h =

можно заметить что каждые 50 шагов приближают результат всё ближе и ближе к истине и т.о. нейронная сеть обучается всё точнее и точнее. Чем ближе к результату тем медленнее обучается сеть но это просто особенность класического градиентного спуска. Чтобы ускорить обучение можно использовать другие оптимизаторы например моментум который также помогает преодолевать локальные минимум. Также в данной простой сети нет коэффициентов смешения для того чтобы можно было принимать больше вариантов входных данных, например данные с нулями. И обучающая выборка состоит всего из двух векторов, входного и выходного, но на практике их обычно гораздо больше. Ещё можно пробовать менять функции активации. Например использовать Relu на скрытых слоях что гораздо лучше для глубокого обучения или гиперболический тангенс чтобы использовать область отрицательных значений. В общем сеть ещё можно улучшать но это уже отдельные темы.

На Ютубе можно посмотреть можно на видео данного урока:

Номер биткоин кошелька для поддержки блога - bc1qlhrmmkh77x2lzhqe4lt9qwkglswj64tsqt2l5g



воскресенье, 7 июня 2026 г.

w801 wifi http softAP

 На момент написания данной статьи, существует одна интересная альтернатива популярным ESP32 т.е. недорогой производительный микроконтроллер со встроенным wifi модулем w801. Интересен он тем что имеет встроенную оперативную память что существенно упрощает разводку платы для такого микроконтроллера. Несмотря на то что существуют версии ESP32 со встроенной оперативной памятью, W801 всё таки может представлять интерес. Этот микроконтроллер не смог стать настолько же популярным в рунете и обзавестись таким же большим колличеством туториалов для простоты его использования но тем не менее. Помочь с его программированием всё таки довольно неплохо могут нейросети. Особенно хорошо что т.о. получилось создать рабочий код http wifi точки доступа и управлять светодиодом на плате через смартфон, сэкономив при этом большое количество времени. Даже если сгенерированный код не рабочий то делать его не с нуля всё равно получается проще. В общем главное что w801 вполне реально использовать наряду с ESP32 как wifi модуль. О том как скомпилировать и загрузить в микроконтроллер программу (это на самом деле не трудно и даже удобно) есть первые три части серии уроков по w801 поэтому сейчас предлагаю рассмотреть исходный код рабочего примера простого http сервера wifi точки доступа для управления светодиодом на плате get запросами.

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

В начале кода имеются заголовочные файлы:

Ниже указан номер порта 80. Если указать такой номер порта то его не обязательно будет вводить в адресную строку браузера, после айпи адреса, для того чтобы попасть в наш веб интерфейс управления светодиодом.


После, задается сама html страница, в массиве символов HTTP_RESPONSE[], на языке разметки html. В ней имеется приветствие и пара кнопок для отправки get запросов включения и выключения светодиода. 

Ещё ниже есть две функции взятые из примера для создания точки доступа. Одна собственно инициализирует точку доступа а другая периодически вызывается в таймере для мониторинга, насколько я понял.


Функция создания точки доступа принимает 5 параметров. Это идентификатор точки доступа, пароль для подключения к ней, номер канала, тип шифрования и формат данных.

В теле функции есть комментарий с подсказками того какие можно выбрать типы шифрования, форматы данных. Также там задаются ip адрес и маска подсети. 

Ниже нейросеть прокомментировала прием двух аргументов функцией создания точки доступа. Возможно есть какая то другая версия SDK где эта функция перегружена и может принимать один параметр но с данным SDK то вызовет ошибку поэтому нужно передавать две структуры. Одну для настройки точки доступа и вторую с настройками ip адреса, маски подсети и dns.

Ещё есть сгенерированнная нейросетью функция для обработки http трафика. В ней создается сокет для прослушивания очереди клиентов.

Очередь прослушивается в бесконечном цикле. И в ответ на get запрос выдается html страница.

Функция UserMain является стартовой. В ней вызывается функция инициализации точки доступа. Также назначаются идентификатор, пароль, номер канала, шифрование, формат данных и в функцию создания задач передается ранее созданная задача обработки http трафика. Если конечно точка доступа была успешно создана. Тут можно заметить сходство функции tls_os_task_create() с рассмотренной ранее при изучении FreeRTOS функцией xTaskCreate().

Для управления светодиодом можно добавить проверку запроса на наличие параметров перед отправкой HTTP заголовка с HTML страницей. И если например есть параметр с командой включения светодиода то включить светодиод. Если есть параметр с командой выключения светодиода то выключить. Далее, в любом случае, клиенту выдается html страница. Которую также можно немного изменить.

Также можем заметить константу задающую номер пина к которому подключен встроенный светодиод которым мы хотим управлять. 



В функции UserMain добавлена настройка нужного пина на выход. 

Откомпилировать код можно командой sudo make из корня проекта и загрузить специальной командой

sudo tools/w800/wm_tool -c ttyUSB0 -rs rts -dl bin/w800/w800.fls

а после попробовать подключиться к появившейся точке доступа по wifi с телефона или ноутбука. 

Введя нужный пароль (который мы указали в функции UserMain). То далее мы сможем зайти в браузер по дефолтному адресу и получить веб страницу от микрокнотроллера w801 а также управлять светодиодом на плате по wifi, нажимая кнопки в web интерфейсе. Успешное тестирование кода и платы можно посмотреть на видео

Я думаю, это есть успешное создание wifi http сервера на w801. Данный код можно взять за основу и использовать для создания более сложных проектов. Можно развивать идею дальше и освоить например post запросы, ajax, другие протоколы помимо http, например mqtt который лучше подходит для умного дома и интернета вещей, udp который лучше подходит для передачи видео или https который как http только зашищенный шифрованием.

Адрес биткоин кошелька для поддержки блога - bc1qlhrmmkh77x2lzhqe4lt9qwkglswj64tsqt2l5g

четверг, 21 мая 2026 г.

Симулятор переходных процессов в электрических цепях

В данном симуляторе можно собрать схему с пассивными элементами (резисторами, катушками, конденсаторами) а также источниками ЭДС, тока и ключами (переключателями) меняющими свое состояние в момент начала расчета схемы и служащими для задания начальных условий. После нажатия кнопки "решить" составляются уравнения модифицированным методом узловых потенциалов и решаются численным методом с заданным шагом и количеством шагов. Данный симулятор можно использовать например для исследования переходных процессов в электрических схемах или их реакций на периодические сигналы т.к. источникам ЭДС или тока, можно задать различные формы сигналов из наиболее распространенных либо задать форму рядом Фурье. Прежде чем провести расчет, симулятор попытается валидировать схему и дать визуальные подсказки в случае ошибок. При создании схемы следует придерживаться правил для схем замещения. Учитывать что элементы идеальные (хотя это не всегда верно и в некоторых случаях вводиться искусственная неидеальность для возможности проведения расчетов) или близки к идеальным. Например не следует "запирать" узел источниками тока т.к. это нарушает первый закон Кирхгофа. Делать контуры из источников ЭДС и катушек, либо контуры из одних конденсаторов. Следует учитывать что сопротивление идеальных источников ЭДС равно нулю и их следует дополнять последовательно соединенными резисторами. Сопротивление идеального источника тока равно бесконечности, поэтому параллельно ему следует ставить резистор. Также бесконечно высоким сопротивлением обладают идеальные конденсаторы а бесконечно малым идеальные катушки индуктивности. Также не следует задавать слишком большое или слишком малое количества шагов рассчета. Если схема составлена корректно, по ней правильно составились уравнения и были произведены расчеты то в результате будут выведены графики потенциалов узлов, относительно нулевого (который можно задать (по умолчанию это потенциал с индексом ноль)) и токов источников ЭДС (результаты расчета методов ММУП) а также будет таблица значений на каждом шаге. Если необходимо узнать напряжение на конкретном элементе то можно посчитать разность потенциалов на нем или, перед началом расчета, поставить землю на одном из его узлов.
шагов рассчета время шага(с)
Элемент не выбран Клик: выбрать/поставить | Drag: переместить | R: вращать выбранный | Ctrl+Z: отмена
Здесь появятся данные ...
Если данный САПР, калькулятор, проектирования схем оказался полезным то есть возможность поддержать автора и способстовать т.о. появлению подобного рода контента. Адрес биткоин кошелька для поддержки блога - bc1qlhrmmkh77x2lzhqe4lt9qwkglswj64tsqt2l5g