Простая нейронка без библиотек и многомерных массивов |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2023-09-13 18:10 Год назад у меня впервые зародилось желание написать свою нейросеть и поэкспериментировать с ней, с тех пор я собирал попадающуюся мне информацию, но до дела у меня дошли руки только сейчас. Я твердо решил написать свою нейросеть с блекджеком, обучением с подкреплением и без сторонних библиотек. Собственно это я и сделал, а так как у меня самого опыта в этом еще не было, я подумал, что это может быть полезно и для других людей, которые хотят в этом разобраться. Хочу сказать, что смысл этой статьи не в правильном способе создания нейросетей, таких статей сотни, а в способе понять, что такое нейросети и наконец перейти к практике. Итак, поехали. Сначала немного необходимой теории Вероятно вы уже множество раз прочитали что-нибудь подобное, так что постараюсь покороче. Говоря простым языком: нейронная сеть – несколько слоев, состоящих из искусственных нейронов и синапсов, которые их соединяют.Значение нейрона формируется из активированной суммы дочерних нейронов, умноженных на вес их синапсов. Первый (следующий после нулевого) слой формируется из активированных входных данных, тоже умноженных на веса синапсов. Обычно веса синапсов изначально генерируются случайно, а потом корректируются в зависимости от процесса обучения. «Активированное значение» - значение, которое преобразовано с помощью выбранной функции активации. Почти переходим к практике Дело в том, что когда я "твердо решил написать свою нейросеть", я совершенно не подумал о том, какую задачу эта нейросеть будет решать, так что это я решил на ходу: Задумавшись над задачей для нейронной сети , я решил выбрать что-нибудь подходящее под три критерия: наглядность, чтобы на выходом было какое-то графическое действие, обучение с подкреплением, потому что мне больше всего нравится этот метод, и количество нейронов не более 5—10 млн, ибо мой текущий компьютер с большим не справится. После длительного отбора идей, я вспомнил статью про эксперименты над обучением одноклеточных организмов и пришел к выводу, что правильным решением будет создать примитивную нейросеть, которая будет выполнять роль клетки в чашке Петри. Предварительный анализ задачи показал, что логичней будет ограничить поле зрения: я выбрал поле 5 на 5 вокруг клетки. В итоге я решил сделать нейронную сеть, имеющую входной слой в 25 нейрона, скрытый в 16 и выходной слой в 14. Почему именно столько? В конструировании нейросетей нет четких правил, но для нашей задачи больше одного слоя не требуется, а количество нейронов в скрытом слою, принято делать между количеством во входном и выходном, а дальше корректировать, в зависимости от эмпирических данных, так что спустя несколько попыток, я выбрал именно 16. Систему обучения я выбрал изначально - подкрепление для нашей задачи подходит идеально. Реализовать обучение с подкреплением для нейросети не сложно: для положительного подкрепления необходимо увеличивать веса синапсов активных нейронов, ответственных за правильное решение на n, а для отрицательного уменьшать. Ещё нужна функция активации, чтобы значение нейрона для удобства варьировалось между -1 и 1. Я выбираю стандартный гиперболический тангенс, который на самом деле является модифицированной экспонентой. Пишем код Писать я буду на python, хотя принцип остается тем же и для других языков. Обычно для нейронных сетей используют NumPy с его многомерными массивами, но мне показалось, что для первой нейросети это слишком не наглядно, так что, вдохновившись идеей о создании нейросети методами ООП, я решил реализовать ее через классы. Что я имею ввиду? Я создам класс нейросети и нейрона, а потом уже буду с этим работать. Сначала создаю класс нейрона. У нейрона должны быть 3 переменных: out – выход нейрона, weight – вес синапса, связывающий этот нейрон и родительский, childs – массив дочерних нейронов. Потом класс сети, в ней нужен только массив выходов. (название Mind я использовал в начале, а потом оно приелось, так что я не стал менять): Добавляем функции создания: layers – массив слоев(точнее массив количеств нейронов в слою), не считая выходного p – выходной слой Эта функция – рекурсивная, это означает, что она вызывает сама себя, в этом случае она работает так: Если слой, который необходимо создать, – не предпоследний, то сначала создается нейрон со случайным весом синапса(random.uniform(-1,1) – функция, возвращающая псевдослучайное число от -1 до 1), а потом с помощью этой же функции создаются дочерние нейроны этого нейрона, иначе создается нейрон и сразу дочерние нейроны к нему. Треть уже готова, осталось сделать функцию активации, Смысл создавать отдельную функцию, а не просто использовать math.tanh(), в том, чтобы удобнее было ее заменить, в случае, если я решу, что другая будет эффективней. функции для получения выхода, Эта функция работает следующим образом: Если на нейрон, из которого вызвали эту функцию находится не на предпоследнем слое – его выход вычисляется по формуле иначе - . Эта функция принимает параметр input – массив входных значений. По сути, эта функция возвращает номер самого активного выходного нейрона или случайного из самых активных. Выход дочернего нейрона возвращается функцией Neuron.getout(input). и наконец обучение. На данном этапе мы уже можем запустить нейросеть со случайным входным значением и увидеть, что все работает и нейросеть выдает случайное значение: Для обучения я реализую альфа-систему подкрепления. Надо оговориться, что у меня считаются «активными связями» все нейроны, модуль выхода которых, больше, либо равен 0.4, а вес синапса может быть отрицательным. Итак, представляю вашему вниманию полный код: Функции good и bad меняют веса выбранного нейрона на определенное значение с помощью функции Neuron.chweight(). На практике, как следует из названия, good – положительное подкрепление, а bad – отрицательное. На этом сама нейросеть окончательно закончена, пора приступать к разработке среды обучения. Подробное описание процесса разработки среды не имеет ценности для темы, так что я просто опишу принцип работы: Изначально создается массив, который является картой среды. Массив изначально состоит из 0.1, а потом каждый ход наполняется 1 и -1 случайным образом. Также создается клетка, которая управляется нейросетью, которой на вход подается массив из значений полей в квадрате 5*5, а на выходе число от 1 до 4, обозначающие ход (1- шаг вверх, 2 - вниз, 3 - вправо, 4 – влево). Проверяется по одной клетке вокруг клетки и если находится 1 – то по этому направлению применяется положительное подкрепление, а если -1 – то отрицательное. Чтобы клетка не стояла на месте, если 0.1, то тоже применяется отрицательное подкрепление, но в меньшем количестве, чем при -1. Также я добавил к этому графический интерфейс. Таким образом происходит обучение, что наглядно видно на графике, который строится автоматически. График строится на основе значений положительного и отрицательного подкрепления за ход. Рост графика означает преобладание положительного подкрепления над отрицательным. код среды Итак, первый запуск: Все работает и даже показывается график, который обновляется каждые 200 ходов. Я проделывал еще несколько эксспериментов, но их результат совпал с предсказанным, так что они неинтересны. Гитхаб репозиторий: ссылка Заключение Нейросети - очень интересная тема, с которой я возможно буду еще работать и если сделаю что-нибудь интересное - напишу, если этот мой опыт минимально зайдет. Чуть-чуть обо мне в самом конце: тык во избежание предвзятостиНа самом деле мне 15 и я новичок на Хабре так что, пожалуйста, не сильно ругайтесь на ошибки, это мой первый опыт в написании статей. Если вам понравилось или было полезно, пожалуйста поделитесь этим в комментариях, мне очень важна эта информация. Также если что-то не корректным, прошу обратить мое внимание. Спасибо за прочтение, всего хорошего! Источник: habr.com Комментарии: |
|