Нейросети на python: Простая нейронная сеть в 9 строк кода на Python
Простая нейронная сеть в 9 строк кода на Python
Из статьи вы узнаете, как написать свою простую нейросеть на python с нуля, не используя никаких библиотек для нейросетей. Если у вас еще нет своей нейронной сети, вот всего лишь 9 строчек кода:
Перед вами перевод поста How to build a simple neural network in 9 lines of Python code, автор — Мило Спенсер-Харпер. Ссылка на оригинал — в подвале статьи.
В статье мы разберем, как это получилось, и вы сможете создать свою собственную нейронную сеть на python. Также будут показаны более длинные и красивые версии кода.
Диаграмма 1
Но для начала, что же такое нейронная сеть? Человеческий мозг состоит из 100 миллиарда клеток, называемых нейронами, соединенных синапсами. Если достаточное количество синаптичеких входов возбуждены, то и нейрон тоже становится возбужденным. Этот процесс также называется “мышление”.
Мы можем смоделировать этот процесс, создав нейронную сеть на компьютере. Не обязательно моделировать всю сложную модель человеческого мозга на молекулярном уровне, достаточно только высших правил мышления. Мы используем математические техники называемые матрицами, то есть просто сетки с числами. Чтобы сделать все максимально просто, построим модель из трех входных сигналов и одного выходного.
Мы будем тренировать нейрон на решение задачи, представленной ниже.
Первые четыре примера назовем тренировочной выборкой. Вы сможете выделить закономерность? Что должно стоять на месте “?”
Диаграмма 2. Input — входный сигнал, Output — выходной сигнал.
Вероятно вы заметили, что выходной сигнал всегда равен самой левой входной колонке. Таким образом ответ будет 1.
Процесс обучения нейронной сети
Как же должно происходить обучение нашего нейрона, чтобы он смог ответить правильно? Мы добавим каждому входу вес, который может быть положительным или отрицательным числом. Вход с большим положительным или большим отрицательным весом сильно повлияет на выход нейрона. Прежде чем мы начнем, установим каждый вес случайным числом. Затем начнем обучение:
- Берем входные данные из примера обучающего набора, корректируем их по весам и передаем по специальной формуле для расчета выхода нейрона.
- Вычисляем ошибку, которая является разницей между выходом нейрона и желаемым выходом в примере обучающего набора.
- В зависимости от направления ошибки слегка отрегулируем вес.
- Повторите этот процесс 10 000 раз.
Диаграмма 3
В конце концов вес нейрона достигнет оптимального значения для тренировочного набора. Если мы позволим нейрону «подумать» в новой ситуации, которая сходна с той, что была в обучении, он должен сделать хороший прогноз.
Формула для расчета выхода нейрона
Вам может быть интересно, какова специальная формула для расчета выхода нейрона? Сначала мы берем взвешенную сумму входов нейрона, которая:
Затем мы нормализуем это, поэтому результат будет между 0 и 1. Для этого мы используем математически удобную функцию, называемую функцией Sigmoid:
Если график нанесен на график, функция Sigmoid рисует S-образную кривую.
Подставляя первое уравнение во второе, получим окончательную формулу для выхода нейрона:
Возможно, вы заметили, что мы не используем пороговый потенциал для простоты.
Формула для корректировки веса
Во время тренировочного цикла (Диаграмма 3) мы корректируем веса. Но насколько мы корректируем вес? Мы можем использовать формулу «Взвешенная по ошибке» формула
Почему эта формула? Во-первых, мы хотим сделать корректировку пропорционально величине ошибки. Во-вторых, мы умножаем на входное значение, которое равно 0 или 1. Если входное значение равно 0, вес не корректируется. Наконец, мы умножаем на градиент сигмовидной кривой (диаграмма 4). Чтобы понять последнее, примите во внимание, что:
- Мы использовали сигмовидную кривую для расчета выхода нейрона.
- Если выходной сигнал представляет собой большое положительное или отрицательное число, это означает, что нейрон так или иначе был достаточно уверен.
- Из Диаграммы 4 мы можем видеть, что при больших числах кривая Сигмоида имеет небольшой градиент.
- Если нейрон уверен, что существующий вес правильный, он не хочет сильно его корректировать. Умножение на градиент сигмовидной кривой делает именно это.
Градиент Сигмоды получается, если посчитать взятием производной:
Вычитая второе уравнение из первого получаем итоговую формулу:
Существуют также другие формулы, которые позволяют нейрону учиться быстрее, но приведенная имеет значительное преимущество: она простая.
Написание Python кода
Хоть мы и не будем использовать библиотеки с нейронными сетями, мы импортируем 4 метода из математической библиотеки numpy. А именно:
- exp — экспоненцирование
- array — создание матрицы
- dot — перемножения матриц
- random — генерация случайных чисел
Например, мы можем использовать array() для представления обучающего множества, показанного ранее.
“.T” — функция транспонирования матриц. Итак, теперь мы готовы для более красивой версии исходного кода. Заметьте, что на каждой итерации мы обрабатываем всю тренировочную выборку одновременно.
Код также доступен на гитхабе. Если вы используете Python3 нужно заменить xrange на range.
Заключительные мысли
Попробуйте запустить нейросеть, используя команду терминала:
python main.py
Итоговый должен быть похож на это:
У нас получилось! Мы написали простую нейронную сеть на Python!
Сначала нейронная сеть присваивала себе случайные веса, а затем обучалась с использованием тренировочного набора. Затем нейросеть рассмотрела новую ситуацию [1, 0, 0] и предсказала 0.99993704. Правильный ответ был 1. Так очень близко!
Традиционные компьютерные программы обычно не могут учиться. Что удивительного в нейронных сетях, так это то, что они могут учиться, адаптироваться и реагировать на новые ситуации. Так же, как человеческий разум.
Конечно, это был только 1 нейрон, выполняющий очень простую задачу. А если бы мы соединили миллионы этих нейронов вместе?
Как создать собственную нейронную сеть с нуля на языке Python
Джеймс Лой, Технологический университет штата Джорджия. Руководство для новичков, после которого вы сможете создать собственную нейронную сеть на Python.
Мотивация: ориентируясь на личный опыт в изучении глубокого обучения, я решил создать нейронную сеть с нуля без сложной учебной библиотеки, такой как, например, TensorFlow. Я считаю, что для начинающего Data Scientist-а важно понимание внутренней структуры нейронной сети.
Эта статья содержит то, что я усвоил, и, надеюсь, она будет полезна и для вас! Другие полезные статьи по теме:
Что такое нейронная сеть?
Большинство статей по нейронным сетям при их описании проводят параллели с мозгом. Мне проще описать нейронные сети как математическую функцию, которая отображает заданный вход в желаемый результат, не вникая в подробности.
Нейронные сети состоят из следующих компонентов:
- входной слой, x
- произвольное количество скрытых слоев
- выходной слой, ŷ
- набор весов и смещений между каждым слоем W и b
- выбор функции активации для каждого скрытого слоя σ; в этой работе мы будем использовать функцию активации Sigmoid
На приведенной ниже диаграмме показана архитектура двухслойной нейронной сети (обратите внимание, что входной уровень обычно исключается при подсчете количества слоев в нейронной сети).
Создание класса Neural Network на Python выглядит просто:
Обучение нейронной сети
Выход ŷ простой двухслойной нейронной сети:
В приведенном выше уравнении, веса W и смещения b являются единственными переменными, которые влияют на выход ŷ.
Естественно, правильные значения для весов и смещений определяют точность предсказаний. Процесс тонкой настройки весов и смещений из входных данных известен как обучение нейронной сети.
Каждая итерация обучающего процесса состоит из следующих шагов
- вычисление прогнозируемого выхода ŷ, называемого прямым распространением
- обновление весов и смещений, называемых обратным распространением
Последовательный график ниже иллюстрирует процесс:
Прямое распространение
Как мы видели на графике выше, прямое распространение — это просто несложное вычисление, а для базовой 2-слойной нейронной сети вывод нейронной сети дается формулой:
Давайте добавим функцию прямого распространения в наш код на Python-е, чтобы сделать это. Заметим, что для простоты, мы предположили, что смещения равны 0.
Однако нужен способ оценить «добротность» наших прогнозов, то есть насколько далеки наши прогнозы). Функция потери как раз позволяет нам сделать это.
Функция потери
Есть много доступных функций потерь, и характер нашей проблемы должен диктовать нам выбор функции потери. В этой работе мы будем использовать сумму квадратов ошибок в качестве функции потери.
Сумма квадратов ошибок — это среднее значение разницы между каждым прогнозируемым и фактическим значением.
Цель обучения — найти набор весов и смещений, который минимизирует функцию потери.
Обратное распространение
Теперь, когда мы измерили ошибку нашего прогноза (потери), нам нужно найти способ распространения ошибки обратно и обновить наши веса и смещения.
Чтобы узнать подходящую сумму для корректировки весов и смещений, нам нужно знать производную функции потери по отношению к весам и смещениям.
Напомним из анализа, что производная функции — это тангенс угла наклона функции.
Если у нас есть производная, то мы можем просто обновить веса и смещения, увеличив/уменьшив их (см. диаграмму выше). Это называется градиентным спуском.
Однако мы не можем непосредственно вычислить производную функции потерь по отношению к весам и смещениям, так как уравнение функции потерь не содержит весов и смещений. Поэтому нам нужно правило цепи для помощи в вычислении.
Фух! Это было громоздко, но позволило получить то, что нам нужно — производную (наклон) функции потерь по отношению к весам. Теперь мы можем соответствующим образом регулировать веса.
Добавим функцию backpropagation (обратного распространения) в наш код на Python-е:
Проверка работы нейросети
Теперь, когда у нас есть наш полный код на Python-е для выполнения прямого и обратного распространения, давайте рассмотрим нашу нейронную сеть на примере и посмотрим, как это работает.
Идеальный набор весов
Наша нейронная сеть должна изучить идеальный набор весов для представления этой функции.
Давайте тренируем нейронную сеть на 1500 итераций и посмотрим, что произойдет. Рассматривая график потерь на итерации ниже, мы можем ясно видеть, что потеря монотонно уменьшается до минимума. Это согласуется с алгоритмом спуска градиента, о котором мы говорили ранее.
Посмотрим на окончательное предсказание (вывод) из нейронной сети после 1500 итераций.
Мы сделали это! Наш алгоритм прямого и обратного распространения показал успешную работу нейронной сети, а предсказания сходятся на истинных значениях.
Заметим, что есть небольшая разница между предсказаниями и фактическими значениями. Это желательно, поскольку предотвращает переобучение и позволяет нейронной сети лучше обобщать невидимые данные.
Финальные размышления
Я многому научился в процессе написания с нуля своей собственной нейронной сети. Хотя библиотеки глубинного обучения, такие как TensorFlow и Keras, допускают создание глубоких сетей без полного понимания внутренней работы нейронной сети, я нахожу, что начинающим Data Scientist-ам полезно получить более глубокое их понимание.
Я инвестировал много своего личного времени в данную работу, и я надеюсь, что она будет полезной для вас!
PyBrain работаем с нейронными сетями на Python / Хабр
В рамках одного проекта столкнулся необходимостью работать с нейронными сетями, рассмотрел несколько вариантов, больше всего понравилась PyBrain. Надеюсь её описание будет многим интересно почитать.
PyBrain — одна из лучших Python библиотек для изучения и реализации большого количества разнообразных алгоритмов связанных с нейронными сетями. Являет собой удачный пример совмещения компактного синтаксиса Python с хорошей реализацией большого набора различных алгоритмов из области машинного интеллекта.
Предназначен для:
- Исследователей — предоставляет единообразную среду для реализации различных алгоритмов, избавляя от потребности в использовании десятков различных библиотек. Позволяет сосредоточится на самом алгоритме а не особенностях его реализации.
- Студентов — с использованием PyBrain удобно реализовать домашнее задание, курсовой проект или вычисления в дипломной работе. Гибкость архитектуры позволяет удобно реализовывать разнообразные сложные методы, структуры и топологии.
- Лекторов — обучение методам Machine Learning было одной из основных целей при создании библиотеки. Авторы будут рады, если результаты их труда помогут в подготовке грамотных студентов и специалистов.
- Разработчиков — проект Open Source, поэтому новым разработчикам всегда рады.
О библиотеке
PyBrian представляет собой модульную библиотеку предназначенную для реализации различных алгоритмов машинного обучения на языке Python. Основной его целью является предоставление исследователю гибких, простых в использовании, но в то же время мощных инструментов для реализации задач из области машинного обучения, тестирования и сравнения эффективности различных алгоритмов.
Название PyBrain является аббревиатурой от английского: Python-Based Reinforcement Learning, Artificial Intelligence and Neural Network Library.
Как сказано на одном сайте: PyBrain — swiss army knife for neural networking ( PyBrain — это швейцарский армейский нож в области нейро-сетевых вычислений).
Библиотека построена по модульному принципу, что позволяет использовать её как студентам для обучения основам, так и исследователям, нуждающимся в реализации более сложных алгоритмов. Общая структура процедуры её использования приведена на следующей схеме:
Сама библиотека является продуктом с открытым исходным кодом и бесплатна для использования в любом проекте с единственно оговоркой, при её использовании для научных исследований, они просят добавлять в список цитируемых информационных источников (что народ и делает) следующую книгу:
Tom Schaul, Justin Bayer, Daan Wierstra, Sun Yi, Martin Felder, Frank Sehnke, Thomas Rückstieß, Jürgen Schmidhuber. PyBrain. To appear in: Journal of Machine Learning Research, 2010.
Основные возможности
Основными возможностями библиотеки (для версии 0.3 ) являются:
Сети
PyBrain оперирует сетевыми структурами, которые могут быть использованы для построения практически всех поддерживаемых библиотекой сложных алгоритмов. В качестве примера можно привести:
Инструменты
Дополнительно присутствуют программные инструменты, позволяющие реализовывать сопутствующие задачи:
- Построение / Визуализация графиков
- Поддержка netCDF
- Запись/чтение XML
Установка библиотеки
Перед установкой Pybrain, создатели рекомендуют установить следующие библиотеки:
Setuptools — пакетный менеджер для Python, который значительно упрощает установку новых библиотек. Для его установки рекомендуется скачать и выполнить (python ez_setup.py) этот скрипт.
После установки у Вас появиться возможность использовать команду
easy_install
для установки новых библиотек.
Сразу воспользуемся ими и установим два необходимых пакета:
$ easy_install scipy
$ easy_install matplotlib
Далее устанавливается сама PyBrain
- Либо используем репозиторий с github
git clone git://github.com/pybrain/pybrain.git
- Либо качаем последнюю на текущий момент стабильную версию тут. И устанавливаем стандартным способом:
$ python setup.py install
Основы работы с библиотекой
Создание нейронной сети
Создание нейронной сети с двумя входами, тремя скрытыми слоями и одним выходом:
>>> from pybrain.tools.shortcuts import buildNetwork
>>> net = buildNetwork(2, 3, 1)
В результате, в объекте net находится созданная нейронная цепь, инициализированная случайными значениями весов.
Функция активации
Функция активации задаётся следующим образом:
net.activate([2, 1])
Количество элементов передаваемых в сеть должно быть равно количеству входов. Метод возвращает ответ в виде единственного числа, если текущая цепь имеет один выход, и массив, в случае большего количества выходов.
Получение данных о сети
Для того, чтобы получить информацию о текущей структуре сети, каждый её элемент имеет имя. Данное имя может быть дано автоматически, либо по иным критериям при создании сети.
К примеру, для сети net имена даны автоматически:
>>> net['in']
<LinearLayer 'in'>
>>> net['hidden0']
<SigmoidLayer 'hidden0'>
>>> net['out']
<LinearLayer 'out'>
Скрытые слои поименованы с номером слоя добавленным к имени.
Возможности при создании сети
Конечно в большинстве случаев, созданная нейронная сеть должна иметь другие характеристики, нежели заданные по умолчанию. Для этого существуют разнообразные возможности. К примеру, по умолчанию скрытый слой создаётся с использованием сигмоидной функции активации, для задания другого её типа возможно использовать следующие константы:
- BiasUnit
- GaussianLayer
- LinearLayer
- LSTMLayer
- MDLSTMLayer
- SigmoidLayer
- SoftmaxLayer
- StateDependentLayer
- TanhLayer
>>> from pybrain.structure import TanhLayer
>>> net = buildNetwork(2, 3, 1, hiddenclass=<b>TanhLayer</b>)
>>> net['hidden0']
<TanhLayer 'hidden0'>
Также возможно задать и тип выходного слоя:
>>> from pybrain.structure import SoftmaxLayer
>>> net = buildNetwork(2, 3, 2, hiddenclass=TanhLayer, outclass=SoftmaxLayer)
>>> net.activate((2, 3))
array([ 0.6656323, 0.3343677])
Дополнительно возможно использование смещения (bias)
>>> net = buildNetwork(2, 3, 1, bias=True)
>>> net['bias']
<BiasUnit 'bias'>
Оперирование данными (Building a DataSet)
Созданная сеть должна обрабатывать данные, работе с которыми и посвящён этот раздел. Типичным набором данных является набор входных и выходных значений. Для работы с ними PyBrain использует модуль pybrain.dataset, также далее используется класс SupervisedDataSet.
Настройка данных
Класс SupervisedDataSet используется для типичного обучения с учителем. Он поддерживает массивы выходных и выходных данных. Их размеры задаются при создании экземпляра класса:
Запись вида:
>>> from pybrain.datasets import SupervisedDataSet
>>> ds = SupervisedDataSet(2, 1)
означает, что создаётся структура данных для хранения двухмерных входных данных и одномерных выходных.
Добавление образцов
Классической задачей при обучении нейронной сети является обучение функции XOR, далее показан набор данных используемый для создания такой сети.
>>> ds.addSample((0, 0), (0,))
>>> ds.addSample((0, 1), (1,))
>>> ds.addSample((1, 0), (1,))
>>> ds.addSample((1, 1), (0,))
Исследование структуры образца
Для получения массивов данных в текущем их наборе возможно использовать стандартные функции Python для работы с массивами.
>>> len(ds)
выведет 4, так-как это количество элементов.
Итерация по множеству также может быть организована обычным для массивов способом:
>>> for inpt, target in ds:
print inpt, target
...
[ 0. 0.] [ 0.]
[ 0. 1.] [ 1.]
[ 1. 0.] [ 1.]
[ 1. 1.] [ 0.]
Также к каждому набору полей можно получить прямой доступ с использованием его имени:
>>> ds['input']
array([[ 0., 0.],
[ 0., 1.],
[ 1., 0.],
[ 1., 1.]])
>>> ds['target']
array([[ 0.],
[ 1.],
[ 1.],
[ 0.]])
Также можно вручную освободить занимаемую образцом память полностью его удалив:
>>> ds.clear()
>>> ds['input']
array([], shape=(0, 2), dtype=float64)
>>> ds['target']
array([], shape=(0, 1), dtype=float64)
Тренировка сети на образцах
В PyBrain использована концепция тренеров (trainers) для обучения сетей с учителем. Тренер получает экземпляр сети и экземпляр набора образцов и затем обучает сеть по полученному набору.
Классический пример это обратное распространение ошибки (backpropagation). Для упрощения реализации этого подход в PyBrain существует класс BackpropTrainer.
>>> from pybrain.supervised.trainers import BackpropTrainer
Обучающий набор образцов (ds) и целевая сеть (net) уже созданы в примерах выше, теперь они будут объединены.
>>> net = buildNetwork(2, 3, 1, bias=True, hiddenclass=TanhLayer)
>>> trainer = BackpropTrainer(net, ds)
Тренер получил ссылку на структуру сети и может её тренировать.
>>> trainer.train()
0.31516384514375834
Вызов метода train() производит одну итерацию (эпоху) обучения и возвращает значение квадратичной ошибки (double proportional to the error).
Если организовывать цикл по каждой эпохи нет надобности, то существует метод обучающий сеть до сходимости:
>>> trainer.trainUntilConvergence()
Данный метод возвратит массив ошибок для каждой эпохи.
Ещё примеры реализации разных сетей
В статье
Tom Schaul, Martin Felder, et.al. PyBrain, Journal of Machine Learning Research 11 (2010) 743-746.
приведён пример создания сети с загрузкой данных из .mat файла.
# Load Data Set.
ds = SequentialDataSet.loadFromFile(’parity.mat’)
# Build a recurrent Network.
net = buildNetwork(1, 2, 1, bias=True,
hiddenclass=TanhLayer,
outclass=TanhLayer,
recurrent=True)
recCon = FullConnection(net[’out’], net[’hidden0’])
net.addRecurrentConnection(recCon)
net.sortModules()
# Create a trainer for backprop and train the net.
trainer = BackpropTrainer(net, ds, learningrate=0.05)
trainer.trainEpochs(1000)
Немного ссылок:
Заключение
В заключении хочу сказать, что эта библиотека производит очень хорошее впечатление, работать с ней удобно, описания алгоритмов получаются компактные, но не теряют понятности в дебрях кода.
P.S. Если есть поправки по названиям некоторых терминов, то я готов выслушать, не уверен в 100% точности пары переводов, возможно уже есть устоявшиеся названия.
Как построить свою собственную нейронную сеть с нуля в Python — Python 3 | Data Science | Нейронные сети | AI
Содержание страницы
Руководство для начинающих, чтобы понять внутреннюю работу глубокого обучения
Beginner’s Guide of Deep Learning
Мотивация: как часть моего личного пути, чтобы получить лучшее понимание глубокого обучения, я решил построить нейронную сеть с нуля без библиотеки глубокого обучения, такой как TensorFlow. Я считаю, что понимание внутренней работы нейронной сети важно для любого начинающего специалиста по данным.
Эта статья содержит то, что я узнал, и, надеюсь, это будет полезно и для вас!
В большинстве вводных текстов по нейронным сетям приводятся аналогии с мозгом при их описании. Не углубляясь в аналогии с мозгом, я считаю, что проще описать нейронные сети как математическую функцию, которая отображает заданный вход в желаемый результат.
Нейронные сети состоят из следующих компонентов
- Входной слой , х
- Произвольное количество скрытых слоев
- Выходной слой , сечение ■
- Набор весов и смещений между каждым слоем, W и B
- Выбор функции активации для каждого скрытого слоя, σ . В этом уроке мы будем использовать функцию активации Sigmoid.
На диаграмме ниже показана архитектура двухслойной нейронной сети ( обратите внимание, что входной слой обычно исключается при подсчете количества слоев в нейронной сети )
Архитектура двухслойной нейронной сети
Создать класс нейросети в Python просто.
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(y.shape)
Обучение нейронной сети
Выход ŷ простой двухслойной нейронной сети:
Вы можете заметить, что в приведенном выше уравнении весовые коэффициенты W и смещения b являются единственными переменными, которые влияют на результат ŷ.
Естественно, правильные значения весов и смещений определяют силу прогнозов. Процесс тонкой настройки весов и смещений из входных данных известен как обучение нейронной сети.
Каждая итерация учебного процесса состоит из следующих шагов:
- Расчет прогнозируемого выхода known , известный как прямая связь
- Обновление весов и уклонов, известных как обратное распространение
Последовательный график ниже иллюстрирует процесс.
прогнозирование
Как мы видели на приведенном выше последовательном графике, прямая связь — это просто простое исчисление, и для базовой двухслойной нейронной сети результат работы нейронной сети:
Давайте добавим функцию обратной связи в наш код Python, чтобы сделать именно это. Обратите внимание, что для простоты мы приняли смещения равными 0.
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(self.y.shape) def feedforward(self): self.layer1 = sigmoid(np.dot(self.input, self.weights1)) self.output = sigmoid(np.dot(self.layer1, self.weights2))
Однако нам все еще нужен способ оценить «доброту» наших прогнозов (т. Е. Насколько далеки наши прогнозы)? Функция потерь позволяет нам делать именно это.
Функция потери
Есть много доступных функций потерь, и природа нашей проблемы должна диктовать наш выбор функции потерь. В этом уроке мы будем использовать простую ошибку суммы квадратов в качестве нашей функции потерь.
То есть ошибка суммы квадратов — это просто сумма разности между каждым прогнозируемым значением и фактическим значением. Разница возводится в квадрат, поэтому мы измеряем абсолютное значение разницы.
Наша цель в обучении — найти лучший набор весов и смещений, который минимизирует функцию потерь.
обратное распространение
Теперь, когда мы измерили ошибку нашего прогноза (потери), нам нужно найти способ распространить ошибку назад и обновить наши веса и отклонения.
Чтобы узнать соответствующую сумму, с помощью которой можно корректировать веса и смещения, нам необходимо знать производную функции потерь по весам и смещениям .
Напомним из исчисления, что производная функции — это просто наклон функции.
Алгоритм градиентного спуска
Если у нас есть производная, мы можем просто обновить веса и смещения, увеличивая / уменьшая ее (см. Диаграмму выше). Это известно как градиентный спуск .
Однако мы не можем напрямую рассчитать производную функции потерь по весам и смещениям, потому что уравнение функции потерь не содержит весов и смещений. Поэтому нам нужно цепное правило, чтобы помочь нам его вычислить.
Цепное правило для вычисления производной функции потерь по весам. Обратите внимание, что для простоты мы отобразили только частную производную в предположении, что это 1-слойная нейронная сеть.
Уф! Это было некрасиво, но оно позволяет нам получить то, что нам нужно — производную (наклон) функции потерь по отношению к весам, чтобы мы могли соответствующим образом корректировать веса.
Теперь, когда у нас это есть, давайте добавим функцию обратного распространения в наш код Python.
class NeuralNetwork: def __init__(self, x, y): self.input = x self.weights1 = np.random.rand(self.input.shape[1],4) self.weights2 = np.random.rand(4,1) self.y = y self.output = np.zeros(self.y.shape) def feedforward(self): self.layer1 = sigmoid(np.dot(self.input, self.weights1)) self.output = sigmoid(np.dot(self.layer1, self.weights2)) def backprop(self): # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1 d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output))) d_weights1 = np.dot(self.input.T, (np.dot(2*(self.y - self.output) * sigmoid_derivative(self.output), self.weights2.T) * sigmoid_derivative(self.layer1))) # update the weights with the derivative (slope) of the loss function self.weights1 += d_weights1 self.weights2 += d_weights2
Для более глубокого понимания применения исчисления и правила цепочки в обратном распространении я настоятельно рекомендую этот урок от 3Blue1Brown.
Теперь, когда у нас есть полный код Python для выполнения обратной связи и обратного распространения, давайте применим нашу нейронную сеть на примере и посмотрим, насколько хорошо она работает.
Наша нейронная сеть должна изучить идеальный набор весов для представления этой функции. Обратите внимание, что для нас не совсем просто вычислить вес только одним осмотром.
Давайте обучим нейронную сеть для 1500 итераций и посмотрим, что произойдет. Глядя на график потерь на итерацию ниже, мы ясно видим, что потери монотонно уменьшаются до минимума. Это согласуется с алгоритмом градиентного спуска, который мы обсуждали ранее.
Давайте посмотрим на окончательный прогноз (выход) из нейронной сети после 1500 итераций.
Прогнозы после 1500 тренировочных итераций
Мы сделали это! Наш алгоритм обратной связи и обратного распространения успешно обучил нейронную сеть, и прогнозы сошлись на истинных значениях.
Обратите внимание, что существует небольшая разница между прогнозами и фактическими значениями. Это желательно, поскольку это предотвращает переоснащение и позволяет нейронной сети лучше обобщать невидимые данные.
К счастью для нас, наше путешествие не закончено. Еще многое предстоит узнать о нейронных сетях и глубоком обучении. Например:
- Какую другую функцию активации мы можем использовать, кроме функции Sigmoid?
- Использование скорости обучения при обучении нейронной сети
- Использование сверток для задач классификации изображений
Я скоро напишу больше на эти темы, так что следите за мной на Medium и следите за ними!
Я, конечно, многому научился писать свою собственную нейронную сеть с нуля.
Хотя библиотеки глубокого обучения, такие как TensorFlow и Keras, позволяют легко создавать глубокие сети без полного понимания внутренней работы нейронной сети, я считаю, что для начинающего ученого-исследователя полезно получить более глубокое понимание нейронных сетей.
Распознавание текста. Нейронные сети.Python | LinuxBlog.РФ
В этой статье мы напишем простую нейронную сеть(персептрон) для распознавания рукописного текса. Это скорей практикум по реализации конкретной сети, мы совсем поверхностно коснемся теории. План работы:
- Немного теории.
- Пишем сеть.
- Обучение сети, обратное распространение ошибки, машинное обучение.
- Итог.
Теория.
Совсем без теории конечно не обойтись и начнем мы с нейрона.
Все нейронные сети состоят из нейронов. А если конкретней из математической модели работы настоящего нейрона. Суть этой модели в том что есть много входов ( X ) по которым поступают какие то данные ( на примет 1 или 0 ). У каждого сигнала\входа есть вес (сила сигнала W) . Все эти данные обрабатываются внутри нейрона, так называемая функция активации нейрона f(x) . И нейрон падает обработанные данные на выход.
Из этих кубиков собираются слои : входной, скрытый , выходной. Собственно на входной слой подаються сигналы, далее они передаться на скрытый слой ( их может быть и несколько) . В скрытом слое происходит сама работа всей сети. Ну и по аналоги со скрытого слоя данные поступают на выходной. На этих выходных данных и строиться результат работы. Классификация объектов , распознавание или вероятность чего то. Важно помнить, не одна нейронная сеть не дает 100% точности так же как и мозг человека.
Пишем код.
Мы будем писать Персептрон, простая модель в который сигналы передаются с лева на право (от входного к выходному слою) и все нейроны соединены друг с другом. То есть каждый нейрон входного слоя соединен выходами со всеми нейронами скрытого слоя и т.д.
Первым делом нам надо задать число нейронов в входном,выходном и скрытом слое . Еще нужно задать коэффициент обучения (с какой скоростью будет обучаться сеть от 0 до 1) нам он потребуется позже.
def init_net(): input_nodes = 784 print('Введите число скрытых нейронов: ') hidden_nodes = int(input()) out_nodes = 10 print('Введите скорость обучения(0.5): ') lern_node = float(input()) return input_nodes, hidden_nodes, out_nodes, lern_node
Теперь создадим саму сеть. Мы создадим все связи между слоями, если точнее — силу этих связей. Для этого мы будем использовать матрицы ( двухмерные массивы) которые будут хранить эти связи. Вы же помните что каждый нейрон связен с каждым нейроном следующего слоя ( например если в скрытом слое 100 нейронов, то для каждого нейрона входного слоя будет иметься 1х100 связей и т.д.)
import numpy def creat_net(input_nodes, hidden_nodes, out_nodes,): # сознание массивов. -0.5 вычитаем что бы получить диапазон -0.5 +0.5 для весов input_hidden_w = (numpy.random.rand(hidden_nodes, input_nodes) - 0.5) hidden_out_w = (numpy.random.rand(out_nodes, hidden_nodes) - 0.5) return input_hidden_w, hidden_out_w
Numpy — это библиотека языка Python, добавляющее поддержку больших многомерных массивов и матриц, вместе с большой библиотекой высокоуровневых математических функций для операций с этими массивами.
numpy.random.rand() — создает массив заданной формы и заполняет его случайными значениями от 0 до 1.
Нейроны входного слоя просто передаю информацию поступившую на них( для них не используется функция активации) нейронам следующего слоя по связям. Если очень просто то это как устройство ввода или матрица в фотоаппарате. Далее мы эти данные умножаем на вес связи и они поступают в нейрон следующего слоя. Нейрон используя функцию активации обрабатывает эти данные. Мы будем использовать Сигмоиду. И передает дальше.
Сигмооида — это гладкая монотонная возрастающая нелинейная функция, имеющая форму буквы «S», которая часто применяется для «сглаживания» значений некоторой величины. Формула : f(x) = 1 / (1+e ** -x )
В нейронных сетях применяют не только эту функцию, а например : Гиперболический тангенс , Ступенчатая функция , Гауссова функция.
import scipy.special # библиотека scipy.special содержит сигмоиду expit() def fun_active(x): return scipy.special.expit(x)
Теперь нам нужна функция которая принимает входные данные, все это считает и выдает выходные данные сети. В ней мы будем использовать умножение матриц. Это отличный вариант дял подсчета суммы сигналов для нейронов.
Тут очень важный момент, почему матрицы ? На этой картинке простоя модель
А теперь представим эти данные в виде матрицы :
def query(input_hidden_w, hidden_out_w, inputs_list): # преобразовать список входных значений # в двухмерный массив inputs_sig = numpy.array(inputs_list, ndmin=2).T hidden_inputs = numpy.dot(input_hidden_w, inputs_sig)# умножение матриц hidden_out = fun_active(hidden_inputs) # вычисляем выходной сигнал скрытого слоя # умножение матриц выходи в веса для выходного слоя final_inputs = numpy.dot(hidden_out_w, hidden_out) final_out = fun_active(final_inputs) return final_out
T — означает транспонированная матрица, не буду вдаваться в математику. Вы можете посмотреть что это значит в интернете.
Машинное обучение.
У нас есть каркас. Но наша сеть глупа как только что родившийся ребенок. И теперь нам надо ее обучить распознавать рукописный текст. Первым делам для этого нужны входные данные( много ) а так же проверочные выходные данные с которыми мы будем сверяться в ходе обучения.
Мы возьмем готовую базу MNIST (сокращение от «Modified National Institute of Standards and Technology») — объёмная база данных образцов рукописного написания цифр. База данных является стандартом, предложенным Национальным институтом стандартов и технологий США с целью калибрации и сопоставления методов распознавания изображений с помощью машинного обучения в первую очередь на основе нейронных сетей. Качаем с нашего сайта.
Смысл обучения нейронной сети сводиться к коррекции W весов связей( силы сигнала) между нейронами. Первым делом мы вычисляем ошибку выходных данных : e1 = t1 — o1 где t1 проверочное значение для нейрона выходного слоя, o1 — фактическое значение. Что бы посчитать ошибку для нейронов скрытого слоя мы воспользуемся методом обратного распространения ошибки . Суть проста : Ошибка1 (первого нейрона скрытого слоя) = e1(выходной) * w1.1 + e2(второй выходной нейрона) * w1.2(вес связи от него)
Формула для матриц
def treyn(targget_list,input_list, input_hidden_w, hidden_out_w, lern_node): #Прогоняем данные через сеть targgets = numpy.array(targget_list, ndmin=2).T inputs_sig = numpy.array(input_list, ndmin=2).T hidden_inputs = numpy.dot(input_hidden_w, inputs_sig) hidden_out = fun_active(hidden_inputs) final_inputs = numpy.dot(hidden_out_w, hidden_out) final_out = fun_active(final_inputs) #Рассчитываем ошибку выходного слоя out_errors = targgets - final_out #Рассчитываем ошибку скрытого слоя hidden_errors = numpy.dot(hidden_out_w.T, out_errors)
Ошибки нейронов мы посчитали, а на сколько же и как нам менять веса связей ? Не вдаваясь в подробности, будем использовать метод Градиентного спуска. То есть коррекция = lern_nodes * e выходного слой * сигмоида выходного слоя * (1 — сигмоида выходного слоя) * сигмоида скрытого слоя
# Обновление весов связей hidden_out_w += lern_node * numpy.dot((out_errors * final_out*(1 - final_out)), numpy.transpose(hidden_out)) input_hidden_w += lern_node * numpy.dot((hidden_errors * hidden_out*(1-hidden_out)), numpy.transpose(inputs_sig))
Обучающие данные.
Нас с вами интересует два файл :
- mnist_train.csv
- mnist_test.csv
Данные предоставлены в удобной текстовой форме, разделенные запятой. Тренировочный набор содержит около 60.000 промаркированных образцов, тестовый поменьше — около 10.000 .
- Первое значение это маркер от 0-9 , какая цифра изображена.
- Далее следует пиксельный массив 28х28 . Всего 784 значения от 0 до 255.
Прежде чем использовать эти данные для обучения и проверки нейронной сети, нам нужно подготовить их для работы с функцией активации. Что бы данные оставались в оптимальном диапазоне для нее. Для нас будет оптимально значение от 0,01 до 1.00 . Почему не 0 ? Нулевое значение может помешать нам обновлять весовые коэффициенты .
data_file = open('mnist_train.csv','r') trening_list = data_file.readlines() data_file.close() for record in trening_list: получить список значений, используя символы запятой (1,1) в качестве разделителей all_values = record.split(',') #масштабировать и сместить входные значения # numpy.asfarray(a,dtype=float64'>>) Возвращает массив,преобразованный в тип float. inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # Создаем массив из 10 элементов и в нужном элемент (считанный из первого знака базы данных) записываем проверочное значение. targets = numpy.zeros(10) + 0.01 targets[int(all_values[0])] =0.99
Наша нейросеть будет классифицировать изображения по 10 признакам , цифра от 0 до 9 . Выходные значения опять же будут в рамках нашей функции активации, фактически сигмоида не может достичь 1 , по этому мы записываем 0.99 .
Немного все сумбурно получилось. Используя эту базу данных мы будем подавать на каждый входной нейрон одно значение пикселя картинки. То есть входной слой будет у нас матрица 28х28 (784 нейрона) . А выходной слой будет содержать 10 нейронов- классификаторов. Самый интерес вопрос : сколько нейронов должно быть в скрытом слое ? Если их будет мало, сеть будет не способна распознать цифры. Если очень много сеть просто запомнит обучающие данные(зазубрит) что скажется на точности распознания. Попробуем остановиться на 100 скрытых нейронах.
input_nodes, hidden_nodes, out_nodes, lern_node = init_net() input_hidden_w, hidden_out_w = creat_net(input_nodes, hidden_nodes, out_nodes) data_file = open('mnist_train.csv','r') trening_list = data_file.readlines() data_file.close() for record in trening_list: all_values = record.split(',') #масштабировать и сместить входные значения # numpy.asfarray(a,dtype=float64'>>) Возвращает массив,преобразованный в тип float. inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # Создаем массив из 10 элементов и в нужном элемент (считанный из первого знака базы данных) записываем проверочное значение. targets = numpy.zeros(10) + 0.01 targets[int(all_values[0])] = 0.99 hidden_out_w, input_hidden_w = treyn(targets, inputs, input_hidden_w, hidden_out_w, lern_node) data_file = open('mnist_test.csv','r') test_list = data_file.readlines() data_file.close() test = [] for record in test_list: all_values = record.split(',') inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 out_session = query(input_hidden_w, hidden_out_w, inputs) if int(all_values[0]) == numpy.argmax(out_session): #Если ответ верный записывает 1 в список test.append(1) else: test.append(0) test = numpy.asarray(test) # Сумму делим на размер массива и вычисляем эффективность сети print('Эффективность сети % =', (test.sum()/test.size)*100)
Все, дальше вы можете поиграться с числом нейронов скрытого слоя, с коэффициентом обучения, попробовать несколько раз обучать сеть на тех же данных, добавить еще один скрытый слой и т.д. В общем успехов.
Код полностью.
import numpy import scipy.special # pip install scipy def init_net(): input_nodes = 784 print('Введите число скрытых нейронов: ') hidden_nodes = int(input()) out_nodes = 10 print('Введите скорость обучения(0.5): ') lern_node = float(input()) return input_nodes, hidden_nodes, out_nodes, lern_node def creat_net(input_nodes, hidden_nodes, out_nodes,): # сознание массивов. -0.5 вычитаем что бы получить диапазон -0.5 +0.5 для весов input_hidden_w = (numpy.random.rand(hidden_nodes, input_nodes) - 0.5) hidden_out_w = (numpy.random.rand(out_nodes, hidden_nodes) - 0.5) return input_hidden_w, hidden_out_w def fun_active(x): return scipy.special.expit(x) def query(input_hidden_w, hidden_out_w, inputs_list): # преобразовать список входных значений # в двухмерный массив inputs_sig = numpy.array(inputs_list, ndmin=2).T hidden_inputs = numpy.dot(input_hidden_w, inputs_sig) # умножение матриц hidden_out = fun_active(hidden_inputs) # вычисляем выходной сигнал скрытого слоя # умножение матриц выходи в веса для выходного слоя final_inputs = numpy.dot(hidden_out_w, hidden_out) final_out = fun_active(final_inputs) return final_out def treyn(targget_list,input_list, input_hidden_w, hidden_out_w, lern_node): #Прогоняем данные через сеть targgets = numpy.array(targget_list, ndmin=2).T inputs_sig = numpy.array(input_list, ndmin=2).T hidden_inputs = numpy.dot(input_hidden_w, inputs_sig) hidden_out = fun_active(hidden_inputs) final_inputs = numpy.dot(hidden_out_w, hidden_out) final_out = fun_active(final_inputs) #Рассчитываем ошибку выходного слоя out_errors = targgets - final_out #Рассчитываем ошибку скрытого слоя hidden_errors = numpy.dot(hidden_out_w.T, out_errors) # Обновление весов связей hidden_out_w += lern_node * numpy.dot((out_errors * final_out * (1 - final_out)), numpy.transpose(hidden_out)) input_hidden_w += lern_node * numpy.dot((hidden_errors * hidden_out * (1 - hidden_out)),numpy.transpose(inputs_sig)) return hidden_out_w, input_hidden_w def test_set(hidden_out_w, input_hidden_w): data_file = open('mnist_train.csv', 'r') trening_list = data_file.readlines() data_file.close() for record in trening_list: all_values = record.split(',') # масштабировать и сместить входные значения # numpy.asfarray(a,dtype=float64'>>) Возвращает массив,преобразованный в тип float. inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # Создаем массив из 10 элементов и в нужном элемент (считанный из первого знака базы данных) записываем проверочное значение. targets = numpy.zeros(10) + 0.01 targets[int(all_values[0])] = 0.99 hidden_out_w, input_hidden_w = treyn(targets, inputs, input_hidden_w, hidden_out_w, lern_node) data_file = open('mnist_test.csv', 'r') test_list = data_file.readlines() data_file.close() test = [] for record in test_list: all_values = record.split(',') inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 out_session = query(input_hidden_w, hidden_out_w, inputs) if int(all_values[0]) == numpy.argmax(out_session): test.append(1) else: test.append(0) print(len(test)) test = numpy.asarray(test) print('Эфективность сети % =', (test.sum() / test.size) * 100) return hidden_out_w, input_hidden_w input_nodes, hidden_nodes, out_nodes, lern_node = init_net() input_hidden_w, hidden_out_w = creat_net(input_nodes, hidden_nodes, out_nodes) for i in range (5): print('Test #', i+1) hidden_out_w, input_hidden_w = test_set(hidden_out_w, input_hidden_w)
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Искусственная нейронная сеть с нуля на Python c библиотекой NumPy
В туториале показано, как с нуля построить искусственную нейронную сеть на Python с помощью библиотеки NumPy. Сеть будет классифицировать изображения из датасета Fruit360.
Материалы туториала, за исключением цветных изображений из сета Fruit360, взяты из книги «Practical Computer Vision Applications Using Deep Learning with CNNs» автора Ahmed Fawzy Gad.
Исходных код сети доступен странице автора на GitHub.
В туториале рассмотрен пример классификации изображений из датасета Fruit360 с помощью искусственной нейронной сети (Artificial Neural Network, ANN) — выбор признаков и реализация сети с нуля с помощью NumPy.
Объекты в наборе Fruit360 разбиты на 60 классов: яблоко, гуава, банан, финик, киви и другие категории фруктов. Мы будем работать с четырьмя классами: яблоко Braeburn, лимон Meyer, манго, малина. Каждый класс имеет порядка 491 изображений для обучения и 162 изображения для тестирования. Размер изображений 100х100 пикселей.
Извлечение признаков
Начнем с выбора подходящего набора признаков, чтобы достичь наибольшей точности классификации.
На рисунке ниже у объектов из 4 классов разные цвета. Поэтому цвет является подходящим признаком для данной задачи.
Пространство цветов RGB не изолирует информацию о цвете от другой информации, например, освещения. Если использовать RGB для представления изображения, в расчетах нужно учитывать все 3 канала. Поэтому намного удобнее работать с цветовым пространством HSV, которое изолирует информацию о цвете в единый канал. В таком случае за цвет отвечает канал hue (H), оттенок. Следующие изображения показывают, как будет выглядеть канал hue для примера фруктов, представленного выше. Значение оттенка отличается для каждого из изображений.
Канал hue также имеет размер 100×100 пикселей. Если в ANN использовать канал целиком, тогда входной слой должен иметь 10000 нейронов. Это большая сеть. Чтобы уменьшить количество используемых данных, можно использовать гистограмму для представления канала оттенка. Такая гистограмма будет иметь 360 ячеек (bin), что отражает количество возможных значений для канала hue.
Ниже представлена гистограмма для 4 выбранных фруктов. Каждому фрукту соответствует заполнение конкретной ячейки гистограммы. Теперь классы в данных меньше пересекаются друг с другом по выбранному признаку, чего нельзя сказать о цветовом пространстве RGB. Например, для яблока заполняются ячейки в диапазоне от 0 до 10, для манго — от 90 до 110. Поскольку в пространстве HSV между классами наблюдается такое различие в представлении, задача классификации упрощается, так как уменьшается неоднозначность, а качество предсказания увеличивается.
С помощью этого кода можно можно вывести диаграмму канала hue для 4 изображений.
import numpy import skimage.io, skimage.color import matplotlib.pyplot raspberry = skimage.io.imread(fname="raspberry.jpg", as_grey=False) apple = skimage.io.imread(fname="apple.jpg", as_grey=False) mango = skimage.io.imread(fname="mango.jpg", as_grey=False) lemon = skimage.io.imread(fname="lemon.jpg", as_grey=False) apple_hsv = skimage.color.rgb2hsv(rgb=apple) mango_hsv = skimage.color.rgb2hsv(rgb=mango) raspberry_hsv = skimage.color.rgb2hsv(rgb=raspberry) lemon_hsv = skimage.color.rgb2hsv(rgb=lemon) fruits = ["apple", "raspberry", "mango", "lemon"] hsv_fruits_data = [apple_hsv, raspberry_hsv, mango_hsv, lemon_hsv] idx = 0 for hsv_fruit_data in hsv_fruits_data: fruit = fruits[idx] hist = numpy.histogram(a=hsv_fruit_data[:, :, 0], bins=360) matplotlib.pyplot.bar(left=numpy.arange(360), height=hist[0]) matplotlib.pyplot.savefig(fruit+"-hue-histogram.jpg", bbox_inches="tight") matplotlib.pyplot.close("all") idx = idx + 1
Проходя в цикле через все изображения четырех классов, можно извлечь признаки со всех изображений. Следующий код проделывает это. В соответствии с числом изображений в 4 классах (1962) и длиной вектора признаков, извлеченных из каждого изображения (360), создаем массив NumPy из нулей и сохраняем его в переменной dataset_features.
Чтобы хранить метки классов для каждого изображения, создаем еще один NumPy массив и сохраняем его в переменной outputs. Яблоку соответствует метка 0, лимону — 1, манго — 2, малине — 3. Код запускается из корневой директории, в которой находятся 4 папки с именами, соответствующими названиям фруктов, записанным в списке fruits.
В коде проходится цикл по всем изображениям во всех папках:
- с каждого изображения извлекается диаграмма канала hue;
- каждому изображению приписывается метка класса;
- извлеченные признаки и метки классов сохраняются с помощью библиотеки pickle.
Можно также использовать NumPy для сохранения результирующих массивов.
import numpy import skimage.io, skimage.color, skimage.feature import os import pickle fruits = ["apple", "raspberry", "mango", "lemon"] #492+490+490+490=1,962 dataset_features = numpy.zeros(shape=(1962, 360)) outputs = numpy.zeros(shape=(1962)) idx = 0 class_label = 0 for fruit_dir in fruits: curr_dir = os.path.join(os.path.sep, fruit_dir) all_imgs = os.listdir(os.getcwd()+curr_dir) for img_file in all_imgs: fruit_data = skimage.io.imread(fname=os.getcwd()+curr_dir+img_file, as_grey=False) fruit_data_hsv = skimage.color.rgb2hsv(rgb=fruit_data) hist = numpy.histogram(a=fruit_data_hsv[:, :, 0], bins=360) dataset_features[idx, :] = hist[0] outputs[idx] = class_label idx = idx + 1 class_label = class_label + 1 with open("dataset_features.pkl", "wb") as f: pickle.dump("dataset_features.pkl", f) with open("outputs.pkl", "wb") as f: pickle.dump(outputs, f)
Теперь каждое изображение представлено вектором признаков, состоящим из 360 элементов. Вектор фильтруется таким образом, чтобы сохранять наиболее релевантные элементы для разделения 4 классов. Новый укороченный вектор признаков имеет длину 102 вместо 360. Использование меньшего количества элементов помогает ускорить работу алгоритма. Переменная dataset_features будет иметь размер 1962х102.
Данные для тренировки (признаки и метки классов) готовы. Следующий шаг — реализация ANN с помощью NumPy.
Реализация нейронной сети
На рисунке представлена структура нейронной сети. Входной слой имеет 102 входных нейрона, два скрытых слоя состоят из 150 и 60 нейронов, соответственно, выходной слой имеет 4 выхода (по одному на каждый класс).
Входной вектор в любом слое умножается на матрицу весов; такая операция производит вектор локального выхода. Этот вектор выхода далее снова умножается на матрицу весов в следующем слое. Процесс продолжается до тех пор, пока не достигнут выходной слой. Лучше понять эту цепочку матричных перемножений помогает картинка:
Входной вектор размера 1х102 умножается на матрицу весов первого скрытого слоя размером 102х150. Под умножением подразумевается матричное умножение. После этой операции на выходе получается массив 1х150. Такой массив далее используется в качестве входа, подаваемого на второй скрытый слой, где он умножается на матрицу весов размера 150х60. Результатом станет массив 1х60.
Затем этот массив умножается на весовую матрицу между вторым скрытым и выходным слоем, имеющую размер 60х4. Результатом таких операций станет вектор 1х4. Каждый элемент результирующем векторе соответствует определенному классу. Подаваемому на вход объекту приписывается метка, имеющая наибольшее значение в результирующем векторе.
Код, реализующий умножение, представлен ниже.
import numpy import pickle def sigmoid(inpt): return 1.0 / (1 + numpy.exp(-1 * inpt)) f = open("dataset_features.pkl", "rb") data_inputs2 = pickle.load(f) f.close() features_STDs = numpy.std(a=data_inputs2, axis=0) data_inputs = data_inputs2[:, features_STDs > 50] f = open("outputs.pkl", "rb") data_outputs = pickle.load(f) f.close() HL1_neurons = 150 input_HL1_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(data_inputs.shape[1], HL1_neurons)) HL2_neurons = 60 HL1_HL2_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(HL1_neurons, HL2_neurons)) output_neurons = 4 HL2_output_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(HL2_neurons, output_neurons)) h2_outputs = numpy.matmul(a=data_inputs[0, :], b=input_HL1_weights) h2_outputs = sigmoid(h2_outputs) h3_outputs = numpy.matmul(a=h2_outputs, b=HL1_HL2_weights) h3_outputs = sigmoid(h3_outputs) out_otuputs = numpy.matmul(a=h3_outputs, b=HL2_output_weights) predicted_label = numpy.where(out_otuputs == numpy.max(out_otuputs))[0][0] print("Predicted class : ", predicted_label)
После считывания ранее сохраненных признаков и меток, фильтрации признаков определяются весовые матрицы в каждом слое. Им случайным образом приписываются значения в диапазоне от -0.1 до 0.1. Например, переменная input_HL1_weights хранит матрицу весов при переходе от входного к первому скрытому слою. Размер этой матрицы определяется в соответствии с количеством элементов в векторе признаков и числом нейронов в скрытом слое.
После создания матриц весов следующим шагом является матричное умножение. Переменная h2_outputs хранит выходы от перемножения вектора признаков выбранного объекта и матрицей весов между входным и первым скрытым слоями.
Обычно, чтобы выявить нелинейные зависимости между входами и выходами, функция активации применяется к выходам каждого скрытого слоя. Результаты матричного умножения проходят через сигмоидную функцию активации.
После генерации выходов на финальном слое делается предсказание. Предсказываемая метка класса сохраняется в переменной predicted_label. Все перечисленные выше шаги повторяются для каждого входного объекта. Полный код, проделывающий эту процедуру, представлен ниже.
import numpy import pickle def sigmoid(inpt): return 1.0 / (1 + numpy.exp(-1 * inpt)) def relu(inpt): result = inpt result[inpt < 0] = 0 return result def update_weights(weights, learning_rate): new_weights = weights - learning_rate * weights return new_weights def train_network(num_iterations, weights, data_inputs, data_outputs, learning_rate, activation="relu"): for iteration in range(num_iterations): print("Itreation ", iteration) for sample_idx in range(data_inputs.shape[0]): r1 = data_inputs[sample_idx, :] for idx in range(len(weights) - 1): curr_weights = weights[idx] r1 = numpy.matmul(a=r1, b=curr_weights) if activation == "relu": r1 = relu(r1) elif activation == "sigmoid": r1 = sigmoid(r1) curr_weights = weights[-1] r1 = numpy.matmul(a=r1, b=curr_weights) predicted_label = numpy.where(r1 == numpy.max(r1))[0][0] desired_label = data_outputs[sample_idx] if predicted_label != desired_label: weights = update_weights(weights, learning_rate=0.001) return weights def predict_outputs(weights, data_inputs, activation="relu"): predictions = numpy.zeros(shape=(data_inputs.shape[0])) for sample_idx in range(data_inputs.shape[0]): r1 = data_inputs[sample_idx, :] for curr_weights in weights: r1 = numpy.matmul(a=r1, b=curr_weights) if activation == "relu": r1 = relu(r1) elif activation == "sigmoid": r1 = sigmoid(r1) predicted_label = numpy.where(r1 == numpy.max(r1))[0][0] predictions[sample_idx] = predicted_label return predictions f = open("dataset_features.pkl", "rb") data_inputs2 = pickle.load(f) f.close() features_STDs = numpy.std(a=data_inputs2, axis=0) data_inputs = data_inputs2[:, features_STDs > 50] f = open("outputs.pkl", "rb") data_outputs = pickle.load(f) f.close() HL1_neurons = 150 input_HL1_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(data_inputs.shape[1], HL1_neurons)) HL2_neurons = 60 HL1_HL2_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(HL1_neurons, HL2_neurons)) output_neurons = 4 HL2_output_weights = numpy.random.uniform(low=-0.1, high=0.1, size=(HL2_neurons, output_neurons)) weights = numpy.array([input_HL1_weights, HL1_HL2_weights, HL2_output_weights]) weights = train_network(num_iterations=10, weights=weights, data_inputs=data_inputs, data_outputs=data_outputs, learning_rate=0.01, activation="relu") predictions = predict_outputs(weights, data_inputs) num_flase = numpy.where(predictions != data_outputs)[0] print("num_flase ", num_flase.size)
Переменная weights хранит все веса нейросети. На основе размера каждой весовой матрицы структура сети может меняться динамически. Если размер переменной input_HL1_weights равен 102х80, то первый скрытый слой имеет 80 нейронов.
Главной функцией в нашем коде является train_network, так как в ней происходит обучение сети через прохождение в цикле по всем объектам датасета. Для каждого объекта выполняются рассмотренные выше шаги. Количество итераций, признаки, метки классов, веса, скорость обучения и функция активации остаются постоянными. В качестве функции активации берется ReLU или сигмоида. ReLU — функция с порогом значения, она возвращает входное значение, когда оно больше нуля. В противном случае ReLU возвращает 0.
Если сеть делает ошибочное предсказание для определенного объекта, веса обновляются с помощью функции update_weights. Для обновления весов не используется алгоритм оптимизации. Веса просто обновляются в соответствии с параметром learning rate (скорость обучения). Точность не превышает 45%. Для достижения лучшей точности уже используется алгоритм оптимизации. Например, в реализации ANN в библиотеке scikit-learn используется градиентный спуск.
Сверточная нейронная сеть на Python и Keras.
Наконец то мы продолжим писать нейронные сети на Питоне. Сегодня мы познакомимся с сверточными сетями. Будем опять распознавать рукописные цифры из базы MNIST. В сверточные сети так же входит полносвязная сеть, например персептрон. По этому читаем первую статью.
Немного теории.
Свёрточная нейронная сеть (англ.convolutional neural network, CNN) — специальная архитектура искусственных нейронных сетей, предложенная Яном Лекуном в 1988 году и нацеленная на эффективное распознавание образов, Использует некоторые особенности зрительной коры, в которой были открыты так называемые простые клетки, реагирующие на прямые линии под разными углами, и сложные клетки, реакция которых связана с активацией определённого набора простых клеток.
ВикипедиЯ
Свёрточными сети называются так из за операции свертки, которая является основой всей сети. В этих сетях нету привычных связей и весовых коэффициентов. Вместо этого используется ядро свертки размером от 3х3 до 7х7. Операция свертки выделяет какой то признак в картинке, например переход от светлого пикселя к темному. Признаки зависят от ядра. Например в базе MNIST наши рукописные цифры это черно-белая картинка размером 28х28 (каждый пиксель имеет значения яркости от 0 до 255). По этой матрице мы проходим ядром и производим операцию свертки. После этого мы получаем слой свертки ( обычно такового размера , но бывает что большего или меньшего) или карту признака.
Автор: Michael Plotke
Следующая операция Пулинг . Это как бы сжатие картинки или слоя свёртки по максимум или среднему значению, при этом группа пикселей (обычно размера 2×2) уплотняется до одного пикселя. По факту мы увеличиваем область которую захватывает ядро свертки в два раза. Переходя от маленьких деталей изображения к более крупным. Так же пулингом мы объединяем карты признаков (полученные сверткой) в более абстрактные признаки, уже не пиксела , а черточки и т.д.
Автор: Aphex34
Keras. Создаем сеть.
Keras — открытая нейросетевая библиотека, написанная на языке Python. Она представляет собой надстройку над фреймворками TensorFlow, упрощая работу с последним.
TensorFlow — открытая программная библиотека для машинного обучения, разработанная компанией Google для решения задач построения и тренировки нейронной сети с целью автоматического нахождения и классификации образов, достигая качества человеческого восприятия.
Первым делом ставим TensorFlow 2.0.0 , потом Keras. Далее нам надо будет понизить ваш numpy до 1.16.4. Все это дело работает на Python 3.6.8.
pip install tensorflow==2.0.0
pip install keras
pip uninstall numpy
pip install numpy==1.16.4
База MNIST уже есть в данных нашей библиотеки, загружаем базу:
# Подключаем датасет.
from keras.datasets import mnist
#Загружаем данные x_train и x_test содержат двухмерный массив с изображение цифр
# x_test, y_test массив с проверочными данными сети.
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# Трансформируем из двухмерного массива в трех мерный(28х28х1 канал)
x_train = x_train.reshape(60000,28,28,1)
x_test = x_test.reshape(10000,28,28,1)
Функция reshape() изменяет форму массива без изменения его данных.
Numpy
Тестовые данные нам тоже надо преобразовать.
from keras.utils import to_categorical
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
keras.utils.to_categorical(y, num_classes=None, dtype=’float32′) . Преобразует вектор класса (целые числа) в двоичную матрицу классов.
Построение модели сети.
Теперь у нас все готово к построению нашей нейро-сети.
from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
# создание модели
model = Sequential()
# Добавляем слой
model.add(Conv2D(64, kernel_size=3, activation='relu', input_shape=(28,28,1)))
Первый слой будет сверточный двухмерный (Conv2D
) . Эти сверточные слои будут работать с входными изображениями, которые рассматриваются как двумерные матрицы. kernel_size
=3
— размер ядра 3х3. Функция активации 'relu'
( Rectified Linear Activation ) , 64
это число ядер свертки( сколько признаком будем искать)
# Второй сверточный слой
model.add(Conv2D(32, kernel_size=3, activation='relu'))
# Создаем вектор для полносвязной сети.
model.add(Flatten())
Flatten() – слой, преобразующий 2D-данные в 1D-данные.
Keras
# Создадим однослойный перцептрон
model.add(Dense(10, activation='softmax'))
Dense()
— полносвязный слов, число выходов — 10
, функция активации 'softmax'
.
Далее, нам нужно скомпилировать нашу модель. Компиляция модели использует три параметра: оптимизатор, потери и метрики.
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
Оптимизатор весов optimizer='adam'
(Адам: метод стохастической оптимизации). Функция потерь : loss='categorical_crossentropy'
категориальная перекрестная энтропия (categorical crossentropy CCE). Последний параметр я не очень понял что такое :
metrics: List of metrics to be evaluated by the model during training and testing. Typically you will use metrics=['accuracy']
. To specify different metrics for different outputs of a multi-output model, you could also pass a dictionary, such as metrics={'output_a': 'accuracy'}
.
Теперь запускаем обучение сети :
hist = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=1)
print(hist.history)
epochs=1
число эпох , validation_data=(x_test, y_test)
— проверочные данные
Визуализация, эксперименты, сохранение.
Давайте построим графики обучения для наглядности. Благо метод fit()
возвращает историю обучения.
import matplotlib.pyplot as plt
history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=5)
# Plot training & validation accuracy values
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
#
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
Добавим слой Пулинг по Максимуму, и запустим на 10 эпох. Так же поменяем функцию ошибки и оптимизации.
from keras.layers import Dense, Conv2D, Flatten, MaxPooling2D
model.add(Conv2D(64, kernel_size=3, activation='relu', input_shape=(28, 28, 1)))
model.add(MaxPooling2D())
model.add(Conv2D(128, kernel_size=3, activation='relu'))
model.add(Flatten())
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='sgd', loss='mean_squared_error', metrics=['accuracy'])
history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
'val_acc': [0.8221, 0.9609, 0.9733, 0.9756, 0.9797, 0.9809, 0.9821, 0.9828, 0.9836, 0.9841]
Сохранение / загрузка целых моделей (архитектура + веса + состояние оптимизатора)
Вы можете использовать model.save(filepath)
для сохранения модели Keras в один файл HDF5, который будет содержать:
- архитектура модели, позволяющая воссоздать модель
- весовые коэффициенты модели
- конфигурация обучения (потеря, оптимизатор)
- состояние оптимизатора, позволяющее возобновить тренировку именно там, где вы остановились.
from keras.models import load_model
model.save('my_model.h5') # Создание HDF5 файла 'my_model.h5'
del model # Удаление модели.
# Загрузка модели обратно
model = load_model('my_model.h5')
Использование GPU.
Если вы работаете на TensorFlow или CNTK backends, ваш код автоматически запускается на GPU, если обнаружен какой-либо доступный GPU.
tensorflow
—Latest stable release for CPU-onlytensorflow-gpu
—Latest stable release with GPU support (Ubuntu and Windows)
Я думаю у вас еще много вопросов, но к сожаления разобраться со всем в одной статье очень трудно. Изучайте в месте со мной официальную документацию и экспериментируйте ))
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Нейронная сеть в 11 строках Python (Часть 1)
Описание: Я лучше всего учусь с игрушечным кодом, с которым я могу играть. В этом руководстве показано обратное распространение с помощью очень простого игрушечного примера — короткой реализации на Python.
Edit: Некоторые люди спрашивали о следующей статье, и я планирую написать ее. Я напишу об этом в Твиттере, когда он будет готов, на @iamtrask. Не стесняйтесь подписываться, если вам интересно его прочитать, и спасибо за все отзывы!
Просто дайте мне код:
X = np.массив ([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) y = np.array ([[0,1,1,0]]). T syn0 = 2 * np.random.random ((3,4)) - 1 syn1 = 2 * np.random.random ((4,1)) - 1 для j в xrange (60000): l1 = 1 / (1 + np.exp (- (np.dot (X, syn0)))) l2 = 1 / (1 + np.exp (- (np.dot (l1, syn1)))) l2_delta = (y - l2) * (l2 * (1-l2)) l1_delta = l2_delta.dot (syn1.T) * (l1 * (1-l1)) syn1 + = l1.T.dot (l2_delta) syn0 + = X.T.dot (l1_delta)
Другие языки: D, C ++ CUDA
Однако это немного лаконично….давайте разберем его на несколько простых частей.
Часть 1: Сеть крошечных игрушек
Нейронная сеть, обученная методом обратного распространения ошибки, пытается использовать ввод для прогнозирования вывода.
Входы | Выход | ||
---|---|---|---|
0 | 0 | 1 | 0 |
1 | 1 | 1 | 1 |
1 | 0 | 1 | 1 |
0 | 1 | 1 | 0 |
Попробуйте предсказать выходной столбец по трем входным столбцам.Мы могли бы решить эту проблему, просто измерив статистики между входными и выходными значениями. Если бы мы сделали это, то увидели бы, что крайний левый входной столбец идеально коррелирует с на выходе. Обратное распространение в своей простейшей форме измеряет подобную статистику, чтобы создать модель. Давайте сразу же воспользуемся им для этого.
2-х слойная нейронная сеть:
импортировать numpy как np # сигмовидная функция def nonlin (x, производное = False): если (производное == Истина): вернуть x * (1-x) возврат 1 / (1 + np.ехр (-x)) # входной набор данных X = np.array ([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) # выходной набор данных y = np.array ([[0,0,1,1]]). T # начальные случайные числа для расчета # детерминированный (просто хорошая практика) np.random.seed (1) # инициализировать веса случайным образом со средним значением 0 syn0 = 2 * np.random.random ((3,1)) - 1 для iter в xrange (10000): # прямое распространение l0 = X l1 = nonlin (np.dot (l0, syn0)) # сколько мы пропустили? l1_error = y - l1 # умножьте количество пропущенных # наклон сигмоида при значениях в l1 l1_delta = l1_error * nonlin (l1, Истина) # обновить веса syn0 + = np.точка (l0.T, l1_delta) print "Вывод после обучения:" печать l1
Выход после тренировки: [[0.00966449] [0,00786506] [0.99358898] [0,99211957]]
Переменная | Определение |
---|---|
х | Матрица входного набора данных, где каждая строка является обучающим примером |
y | Матрица выходного набора данных, где каждая строка является обучающим примером |
l0 | Первый уровень сети, заданный входными данными |
л 1 | Второй уровень сети, иначе известный как скрытый уровень |
син0 | Первый слой весов, Synapse 0, соединяющий l0 с l1. |
* | Поэлементное умножение, поэтому два вектора равного размера умножают соответствующие значения 1 к 1 для создания конечного вектора одинакового размера. |
– | Поэлементное вычитание, поэтому два вектора равного размера вычитают соответствующие значения 1 к 1 для создания конечного вектора одинакового размера. |
x.dot (y) | Если x и y — векторы, это скалярное произведение.Если оба являются матрицами, это умножение матрицы на матрицу. Если только одна матрица, то это умножение векторной матрицы. |
Как видно в «Выводе после обучения», работает !!! Прежде чем описывать процессы, я рекомендую поиграть с кодом, чтобы интуитивно понять, как он работает. Вы должны иметь возможность запускать его «как есть» в блокноте ipython (или в сценарии, если необходимо, но я НАСТОЯТЕЛЬНО рекомендую ноутбук). Вот несколько хороших мест для поиска кода:
• Сравните l1 после первой итерации и после последней итерации.
• Проверьте функцию «nonlin». Это то, что дает нам вероятность на выходе.
• Проверьте, как изменяется l1_error при повторении.
• Разобрать строку 36. Большая часть секретного соуса здесь.
• Проверьте строку 39. Все в сети готовится к этой операции.
Давайте пройдемся по коду построчно.
Рекомендация: откройте этот блог на двух экранах, чтобы вы могли видеть код во время его чтения. Это вроде того, что я делал, пока писал это.:)
Строка 01:
Это импортирует numpy, библиотеку линейной алгебры. Это наша единственная зависимость.
Строка 04:
Это наша «нелинейность». Хотя это может быть несколько видов функций, эта нелинейность отображает функцию, называемую «сигмоидой». Сигмоидальная функция сопоставляет любое значение со значением от 0 до 1. Мы используем его для преобразования чисел в вероятности. Он также имеет несколько других желательных свойств для обучения нейронных сетей.
Строка 05:
Обратите внимание, что эта функция также может генерировать производную сигмоида (когда производная = True).Одним из желательных свойств сигмоидной функции является то, что ее выходные данные могут использоваться для создания ее производной. Если выход сигмоиды — это переменная «out», тогда производная просто out * (1-out). Это очень эффективно.
Если вы не знакомы с производными, просто подумайте об этом как о наклоне сигмовидной функции в данной точке (как вы можете видеть выше, разные точки имеют разные наклоны). Чтобы узнать больше о производных, ознакомьтесь с этим учебником по производным от Khan Academy.
Строка 10:
Это инициализирует наш входной набор данных как матрицу numpy.Каждая строка представляет собой отдельный «обучающий пример». Каждый столбец соответствует одному из наших входных узлов. Таким образом, у нас есть 3 входных узла в сеть и 4 обучающих примера.
Строка 16:
Это инициализирует наш выходной набор данных. В этом случае я сгенерировал набор данных по горизонтали (с одной строкой и 4 столбцами) для пространства. «.T» — это функция транспонирования. После транспонирования эта матрица y имеет 4 строки с одним столбцом. Как и наши входные данные, каждая строка является обучающим примером, а каждый столбец (только один) является выходным узлом.Итак, наша сеть имеет 3 входа и 1 выход.
Строка 20:
Хорошая практика — засеивать случайные числа. Ваши числа по-прежнему будут распределяться случайным образом, но они будут случайным образом распределяться в точно так же, как каждый раз, когда вы тренируетесь. Это позволяет легче увидеть, как ваши изменения влияют на сеть.
Строка 23:
Это наша матрица весов для этой нейронной сети. Это называется «syn0», что означает «нулевой синапс». Поскольку у нас всего 2 слоя (входной и выходной), нам нужна только одна матрица весов для их соединения.Его размерность (3,1), потому что у нас есть 3 входа и 1 выход. С другой стороны, l0 имеет размер 3, а l1 имеет размер 1. Таким образом, мы хотим соединить каждый узел в l0 с каждым узлом в l1, для чего требуется матрица размерности (3,1). 🙂
Также обратите внимание, что он инициализируется случайным образом с нулевым средним значением. Есть довольно много теории, касающейся инициализации веса. На данный момент просто примите как лучшую практику, что при инициализации веса рекомендуется иметь нулевое среднее значение.
Еще одно замечание: «нейронная сеть» на самом деле является именно этой матрицей. У нас есть «слои» l0 и l1, но они являются временными значениями, основанными на наборе данных. Мы их не спасаем. Все обучение хранится в матрице syn0.
Строка 25:
С этого начинается наш код обучения сети. Этот цикл for несколько раз повторяет обучающий код, чтобы оптимизировать нашу сеть для набора данных.
Строка 28:
Поскольку наш первый слой l0 — это просто наши данные.Здесь мы явно описываем это как таковое. Помните, что X содержит 4 обучающих примера (строки). В этой реализации мы собираемся обрабатывать их все одновременно. Это известно как «полное пакетное обучение». Таким образом, у нас есть 4 разных 10 строк, но вы можете рассматривать их как один обучающий пример, если хотите. На данный момент это не имеет значения. (Мы могли бы загрузить 1000 или 10 000, если захотим, не меняя код).
Строка 29:
Это шаг нашего предсказания.По сути, мы сначала позволяем сети «попытаться» предсказать результат при вводе. Затем мы изучим, как он работает, чтобы мы могли настроить его, чтобы он работал немного лучше для каждой итерации.
Эта строка содержит 2 шага. Первая матрица умножает l0 на syn0. Второй передает наш вывод через сигмовидную функцию. Примите во внимание размеры каждого:
(4 x 3) точка (3 x 1) = (4 x 1)
Матричное умножение упорядочено, поэтому размеры в середине уравнения должны быть одинаковыми.Таким образом, окончательная сгенерированная матрица представляет собой количество строк первой матрицы и количество столбцов второй матрицы.
Поскольку мы загрузили 4 обучающих примера, мы получили 4 предположения для правильного ответа, матрицу (4 x 1). Каждый выход соответствует предположению сети для данного входа. Возможно, станет интуитивно понятно, почему мы могли «загрузить» произвольное количество обучающих примеров. Умножение матриц все равно сработает. 🙂
Строка 32:
Итак, учитывая, что l1 имел «предположение» для каждого входа.Теперь мы можем сравнить, насколько хорошо он справился, вычитая истинный ответ (y) из предположения (l1). l1_error — это просто вектор положительных и отрицательных чисел, отражающий, сколько сеть пропустила.
Строка 36:
Теперь мы переходим к хорошему! Это секретный соус! В этой строке много чего происходит, поэтому давайте разделим ее на две части.
Часть первая: производная
nonlin (l1, Истина)
Если l1 представляет эти три точки, приведенный выше код генерирует наклон линий ниже.Обратите внимание, что очень высокие значения, такие как x = 2,0 (зеленая точка), и очень низкие значения, такие как x = -1,0 (фиолетовая точка), имеют довольно пологие наклоны. Максимальный уклон, который вы можете иметь, находится при x = 0 (синяя точка). Это играет важную роль. Также обратите внимание, что все производные находятся в диапазоне от 0 до 1.
Полный текст: производная, взвешенная по ошибкам
l1_delta = l1_error * nonlin (l1, Истина)
Есть более «математически точные» способы, чем «производная, взвешенная по ошибкам», но я думаю, что это улавливает интуицию.l1_error — это матрица (4,1). nonlin (l1, True) возвращает матрицу (4,1). Мы просто умножаем их «поэлементно». Это возвращает матрицу (4,1) l1_delta с умноженными значениями.
Когда мы умножаем «наклоны» на ошибку, мы получаем , уменьшая ошибку предсказаний с высокой степенью достоверности . Посмотрите еще раз на сигмовидную картинку! Если наклон был действительно мелким (близким к 0), то в сети было либо ve
.
Простая нейронная сеть с Python и Keras
Получите мгновенный доступ к коду этого руководства и всех других 400+ руководств по PyImageSearch.
Внутри вы найдете …
- Доступ к централизованным репозиториям кода для все 400 руководств в блоге PyImageSearch
- Предварительно настроенные блокноты Jupyter в Google Colab для всех новых руководств
- Углубленные видеоуроки для всех новых сообщений в блогах — эти видео включают дополнительные комментарии, методы и советы, которые я не включаю в текстовые версии моих руководств
Введите адрес электронной почты ниже, чтобы получить доступ:
Я использовал часть одного из ваших руководств для решения возникшей у меня проблемы с Python и OpenCV.Боролся с этим две недели, но от других экспертов не ответили. Прочтите вашу статью я нашел …. Исправил за два часа. И это тоже было критически важно. Ваши вещи качественные!
Исмаил Томас-Бенге Старший консультант по обеспечению качества и архитектор
PyImageSearch Plus — получите мгновенный доступ к коду для этого руководства и всех других 400 руководств по PyImageSearch!
Выберите свой тарифный план ниже …
$ 4.95 / мес
49,50 $ / год (экономия 15%)
- Доступ к централизованным репозиториям кода для все 400 руководств на PyImageSearch
- Простой код доступа для все новых учебников , которые публикуются каждый понедельник
- Простая загрузка в один клик для кода, моделей, наборов данных и т. Д.
$ 14.95 / мес
149,50 $ / год (экономия 15%)
- Предварительно настроенные блокноты Jupyter в Google Colab для всех новых учебников
- Запускайте все примеры кода в своем веб-браузере. — работает в Windows, macOS и Linux.
- Доступ к централизованным репозиториям кода для все 400 руководств на PyImageSearch
- Простой код доступа для все новых учебников , которые публикуются каждый понедельник
- Простая загрузка в один клик для кода, моделей, наборов данных и т. Д.
$ 74.95 / мес
749,50 $ / год (экономия 15%)
- Видеоуроки для всех новых сообщений в блоге
- Предварительно настроенные блокноты Jupyter в Google Colab для всех новых учебников
- Запускайте все примеры кода в своем веб-браузере. — работает в Windows, macOS и Linux.
- Доступ к централизованным репозиториям кода для все 400 руководств на PyImageSearch
- Простой код доступа для все новых учебников , которые публикуются каждый понедельник
- Простая загрузка в один клик для кода, моделей, наборов данных и т. Д.
- Доступ к централизованным репозиториям кода для все 400+ руководств в блоге PyImageSearch
- Простой код доступа для Все новые учебные пособия , которые публикуются каждый понедельник в 10:00 EST
- Простая загрузка в один клик для исходного кода, наборов данных, предварительно обученных моделей и т. Д.
- Отменить в любое время
- Легкий доступ к коду, наборам данных и предварительно обученным моделям для всех 400+ руководств в блоге PyImageSearch
- Изучите использование Jupyter Notebooks в Google Colab для всех новых руководств по , опубликованных на PyImageSearch
- Используйте предварительно настроенные среды разработки в Google Colab — больше никаких головных болей и траты времени на настройку среды разработки
- Подробные видеоуроки и пошаговые инструкции для всех новых руководств и руководств
- Доступ к эксклюзивных сделок по моим книгам и курсам
Я использовал часть одного из ваших руководств для решения возникшей у меня проблемы с Python и OpenCV.Боролся с этим две недели, но от других экспертов не ответили. Прочтите вашу статью я нашел …. Исправил за два часа. И это тоже было критически важно. Ваши вещи качественные!
Исмаил Томас-Бенге Старший консультант по обеспечению качества и архитектор
.