Статья «Cultivation Begins» познакомит вас с глубоким обучением

алгоритм

Ставьте лайк и смотрите снова, выработайте привычку, найдите [JackCui-AI] в общедоступной учетной записи WeChat и подпишитесь на этого программиста, который любит создавать технические галантереи. Эта статьяGitHubGitHub.com/Джек-Чери — это…Включено, и есть полные тестовые площадки, материалы и мой цикл статей для интервью с производителями первой линии.

Введение

Обещанная серия руководств по иллюстративным алгоритмам ИИ уже здесь!

В последнее время я написал много интересных туториалов по алгоритмам ИИ, и на данный момент я написал 14, среди которых есть учебники с хорошим откликом:

Читатели прекрасно провели время и интересовались алгоритмами ИИ и глубоким обучением.

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

Теперь, когда вам интересно, почему бы не ковать железо, пока горячо, получить больше базовых знаний и стремиться как можно скорее вступить в ряды «Героев-наставников».

Давайте все вместе займемся алхимией и попрактикуемся.

Учебники серии графических алгоритмов ИИ включают не только базовые знания глубокого обучения, но и обучения с подкреплением, обучения переносу и т. д., а также, кроме того, такие как разборка алгоритмов обнаружения целей, состязательных нейронных сетей (GAN) и т. д.

Если вам понравилась эта серия туториалов по алгоритму ИИ, обязательно дайте мне знать, пересылка — это поддержка, а больше текстов — больше мотивации!

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

2. Глубокое обучение

глубокое обучение(Глубокое обучение) — это область исследований, которая быстро развивается в последние годы.искусственный интеллектМногие подполя . С самого начала глубокое обучение является ответвлением машинного обучения.

Глубокое обучение происходит отограниченная выборкаОбщие правила суммируются с помощью алгоритмов и могут быть применены к новымНеизвестные данныеначальство.

Например, мы можем подытожить какой-нибудь сборник исторических случаевсимптомиболезньмежду правилами. Таким образом, когда есть новый пациент, мы можем использовать суммированное правило, чтобы определить, какое заболевание у пациента.

Какие базовые знания вам нужно освоить, если вы хотите научиться глубокому обучению?прямо над:

Организовал карту разума давно,Рекомендуемая коллекция!

Глубокое обучение в основном состоит из нескольких частей, как показано на рисунке выше.Если вы хотите изучить принцип алгоритма глубокого обучения, это зависит от того, какая у него структура сети, как вычисляются потери и как выполняются предварительная и постобработка. Выполнено.

Существует так много стратегий инициализации веса и настройки скорости обучения, алгоритмов оптимизации и сред глубокого обучения, и не все из них нужно освоить.Например, среды глубокого обучения, Pytorch может обрабатывать большинство сценариев.

Сначала имейте общее познание, а затем следуйте этой карте ума, изучайте точки знания одну за другой и, наконец, объединяйте их вместе, вы обнаружите, что:Вы также можете реализовать свои собственные алгоритмы для различных функций..

Основная цель глубокого обучения состоит в том, чтобы автоматически учиться на данных, чтобы эффективноПредставление функций, как это работает? Начать нужно с нейронов.

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

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

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

Синапсы между разными нейронами бывают сильными или слабыми, и их сила может непрерывно изменяться в процессе обучения (тренировки) с определенной степенью пластичности, и разные связи образуют разные отпечатки памяти.

Нейронная сеть глубокого обучения — это вычислительная модель, вдохновленная нейронной сетью человеческого мозга, которая имитирует нейронную сеть человеческого мозга с точки зрения структуры, механизма реализации и функции.

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

Как работает нейронная сеть? Как работает сетевая иерархия, функция потерь, алгоритм оптимизации, инициализация веса, настройка скорости обучения?

Обратное распространение дает вам ответ. фронт,Предупреждение о высокой энергии!

3. Обратное распространение

Чтобы понять принципы глубокого обучения, вы должныобратное распространениеи правило вывода цепи.

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

Первый слойвходной слой, содержащий два нейрона i1, i2 и точку пересечения b1 (смещение);

Второй слойскрытый слой, содержащий два нейрона h1, h2 и точку пересечения b2;

Третий слойвыходной слойo1 и o2, wi, отмеченный в каждой строке, представляет собой вес связи между слоями, а функция активации по умолчанию является сигмовидной функцией.

Перед обучением этой сети эти веса wi должны быть инициализированы, чтоИнициализация веса, способов инициализации тут много, выбираем самый простой,случайная инициализация.

Результат случайной инициализации, как показано на следующем рисунке:

Среди них исходные данные: i1=0,05, i2=0,10;

Выходные данные (желаемый результат): o1=0,01, o2=0,99;

Начальные веса: w1=0,15, w2=0,20, w3=0,25, w4=0,30, w5=0,40, w6=0,45, w7=0,50, w8=0,55.

Цель: Имея входные данные i1, i2 (0,05 и 0,10), сделайте вывод как можно ближе к исходному выводу o1, o2 (0,01 и 0,99).

Рабочий процесс нейронной сети делится на два этапа:прямое распространениеиобратное распространение.

1. Прямое распространение

Прямое распространение заключается в вычислении входных данных для выходного слоя в соответствии с весами.

1) Входной слой -> скрытый слой

Вычислите взвешенную сумму входов в нейрон h1:

сетьh1=w1*i1+w2*i2+b1*1сетьh1=0.15*0.05+0.2*0.1+0.35*1=0.3775\begin{array}{l} \text { net }_{h 1}=w_{1} * i_{1}+w_{2} * i_{2}+b_{1} * 1 \\ \text { net }_{h 1}=0.15 * 0.05+0.2 * 0.1+0.35 * 1=0.3775 \end{array}

После нейрона следуйтеслой активации, тем самым вводя нелинейные факторы, которые подобны человеческим нейронам, позволяя клеткам находиться ввзволнованныйилиторможениестатус.

Форма математического моделирования черезфункция активации, если он больше порога, он будет активирован, иначе будет заблокирован.

Часто используемые функции активации, такие каккарта разумаКак показано, в качестве примера приведена очень простая сигмовидная функция активации, форма ее функции выглядит следующим образом:

Математическая формула:

f(x)=11+exf(x) = \frac{1}{1+e^{-x}}

Используя сигмовидную функцию активации, продолжим расчет, вывод нейрона h1 o_h1:

внеh1=11+eneth1=11+e0.3775=0.593269992\text { out }_{h 1}=\frac{1}{1+e^{-n e t_{h 1}}}=\frac{1}{1+e^{-0.3775}}=0.593269992

Точно так же можно рассчитать выход o_h2 нейрона h2:

внеh2=0.596884378\text { out }_{h 2}=0.596884378

2) Скрытый слой -> выходной слой

Рассчитаем значения нейронов выходного слоя o1 и o2:

сетьo1=w5*внеh1+w6*внеh2+b2*1сетьo1=0.4*0.593269992+0.45*0.596884378+0.6*1=1.105905967внеo1=11+eneto1=11+e1.105905967=0.75136507\begin{array}{l} \text { net }_{o 1}=w_{5} * \text { out }_{h 1}+w_{6} * \text { out }_{h 2}+b_{2} * 1 \\ \text { net }_{o 1}=0.4 * 0.593269992+0.45 * 0.596884378+0.6 * 1=1.105905967 \\ \text { out }_{o 1}=\frac{1}{1+e^{-n e t_{o 1}}}=\frac{1}{1+e^{-1.105905967}}=0.75136507 \end{array}

Таким образом, процесс прямого распространения завершен.По входному значению и весу мы получаем выходное значение [0,75136079, 0,772928465], которое далеко от фактического значения (целевого) [0,01, 0,99].Теперь делаем обратное Распространение ошибки, обновление весов, пересчет вывода.

2. Обратное распространение

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

Так называемое обучение глубокому обучению (алхимия) изучает эти веса, и мы ожидаем отрегулировать эти веса так, чтобы выходные результаты соответствовали нашим ожиданиям.

Способ обновления весов основан на обратном распространении.

1) Рассчитать общую ошибку

После прямого распространения возникает разрыв между выходным значением (прогнозируемое значение) и целевым значением (значение метки), поэтому необходимо измерить, насколько велик этот разрыв.

Метод измерения заключается в использованиикарта разумафункция потерь в .

Функций потерь тоже много, мы все равно выбираем самую простую, среднеквадратичную ошибку (MSE loss).

Формула функции среднеквадратичной ошибки:

MSE=1ni=1n(y^iyi)2M S E=\frac{1}{n} \sum_{i=1}^{n}\left(\hat{y}_{i}-y_{i}\right)^{2}

По формуле непосредственно рассчитайте общую ошибку между прогнозируемым значением и значением метки:

Etotal=12(targetoutput)2E_{\text {total}}=\sum \frac{1}{2}(\text {target}-\text {output})^{2}

Есть два выхода, поэтому ошибки для o1 и o2 рассчитываются отдельно, а общая ошибка представляет собой сумму двух:

Eo1=12(targeto1outo1)2=12(0.010.75136507)2=0.274811083Eo2=0.023560026Etotal=Eo1+Eo2=0.274811083+0.023560026=0.298371109\begin{array}{l} E_{o 1}=\frac{1}{2}\left(\text {target}_{o 1}-\text {out}_{o 1}\right)^{2}=\frac{1}{2}(0.01-0.75136507)^{2}=0.274811083 \\ E_{o 2}=0.023560026 \\ E_{\text {total}}=E_{o 1}+E_{o 2}=0.274811083+0.023560026=0.298371109 \end{array}

2) Скрытый слой -> обновление веса выходного слоя

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

Это цепное правило, которое является правилом вывода составных функций в исчислении, и вот оно:

По цепному правилу легко получить:

Etotalw5=Etotalouto1*outo1neto1*neto1w5\frac{\partial E_{\text {total}}}{\partial w_{5}}=\frac{\partial E_{\text {total}}}{\partial \text {out}_{o 1}} * \frac{\partial \text {out}_{o 1}}{\partial \text {net}_{o 1}} * \frac{\partial \text {net}_{o 1}}{\partial w_{5}}

Следующий рисунок может быть более интуитивным, чтобы увидеть, как ошибка распространяется обратно:

Теперь посчитаем значение каждой формулы отдельно:

рассчитатьEtotalouto1\frac{\partial E_{\text {total}}}{\partial \text {out}_{o 1}}:

Etotal=12(targeto1outo1)2+12(targeto2outo2)2Etotalout01=2*12(targeto1outo1)21*1+0Etotalouto1=(targeto1outo1)=(0.010.75136507)=0.74136507\begin{array}{l} E_{\text {total}}=\frac{1}{2}\left(\operatorname{target}_{o 1}-\text {out}_{o 1}\right)^{2}+\frac{1}{2}\left(\operatorname{target}_{o 2}-\text {out}_{o 2}\right)^{2} \\ \frac{\partial E_{\text {total}}}{\partial o u t_{01}}=2 * \frac{1}{2}\left(\text {target}_{o 1}-\text {out}_{o 1}\right)^{2-1} *-1+0 \\ \frac{\partial E_{\text {total}}}{\partial \text {out}_{o 1}}=-\left(\text {target}_{o 1}-\text {out}_{o 1}\right)=-(0.01-0.75136507)=0.74136507 \end{array}

рассчитатьouto1neto1\frac{\partial o u t_{o 1}}{\partial n e t_{o 1}}:

outo1=11+eneto1outo1neto1=outo1(1outo1)=0.75136507(10.75136507)=0.186815602\begin{array}{l} \text {out}_{o 1}=\frac{1}{1+e^{-n e t_{o 1}}} \\ \frac{\partial o u t_{o 1}}{\partial n e t_{o 1}}=o u t_{o 1}\left(1-o u t_{o 1}\right)=0.75136507(1-0.75136507)=0.186815602 \end{array}

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

рассчитатьneto1w5\frac{\partial n e t_{o 1}}{\partial w_{5}}:

сетьo1=w5*внеh1+w6*внеh2+b2*1neto1w5=1*внеh1*w5(11)+0+0=внеh1=0.593269992\begin{array}{l} \text { net }_{o 1}=w_{5} * \text { out }_{h 1}+w_{6} * \text { out }_{h 2}+b_{2} * 1 \\ \frac{\partial n e t_{o 1}}{\partial w_{5}}=1 * \text { out }_{h 1} * w_{5}^{(1-1)}+0+0=\text { out }_{h 1}=0.593269992 \end{array}

Умножьте последние три:

Etotalw5=Etotalouto1*outo1neto1*neto1w5\frac{\partial E_{\text {total}}}{\partial w_{5}}=\frac{\partial E_{\text {total}}}{\partial o u t_{o 1}} * \frac{\partial \text {out}_{o 1}}{\partial n e t_{o 1}} * \frac{\partial n e t_{o 1}}{\partial w_{5}}
Ettalw5=0.74136507*0.186815602*0.593269992=0.082167041\frac{\partial E_{t t a l}}{\partial w_{5}}=0.74136507 * 0.186815602 * 0.593269992=0.082167041

Таким образом, мы вычисляем частную производную общей ошибки E(total) по w5.

Возвращаясь к приведенной выше формуле, мы находим:

Etotalw5=(targeto1outo1)*внеo1(1внеo1)*внеh1\frac{\partial E_{t o t a l}}{\partial w_{5}}=-\left(\operatorname{target}_{o 1}-o u t_{o 1}\right) * \text { out }_{o 1}\left(1-\text { out }_{o 1}\right) * \text { out }_{h 1}

Для удобства выражения используйтедельтаo1\delta_{o 1}для представления ошибки выходного слоя:

дельтаo1=Etotalouto1*outo1neto1=Etotalneto1дельтаo1=(targeto1outo1)*внеo1(1outo1)\begin{array}{l} \delta_{o 1}=\frac{\partial E_{t o t a l}}{\partial o u t_{o 1}} * \frac{\partial o u t_{o 1}}{\partial n e t_{o 1}}=\frac{\partial E_{t o t a l}}{\partial n e t_{o 1}} \\ \delta_{o 1}=-\left(\operatorname{target}_{o 1}-o u t_{o 1}\right) * \text { out }_{o 1}\left(1-o u t_{o 1}\right) \end{array}

Следовательно, формула частной производной общей ошибки E(total) для w5 может быть записана как:

Etotalw5=дельтаo1внеh1\frac{\partial E_{\text {total}}}{\partial w_{5}}=\delta_{o 1} \text { out }_{h 1}

Если ошибка выходного слоя считается отрицательной, ее также можно записать как:

Etotalw5=дельтаo1внеh1\frac{\partial E_{t o t a l}}{\partial w_{5}}=-\delta_{o 1} \text { out }_{h 1}

Наконец, мы обновляем значение w5: входной слой

w5+=w5н*Etotalw5=0.40.5*0.082167041=0.35891648w_{5}^{+}=w_{5}-\eta * \frac{\partial E_{t o t a l}}{\partial w_{5}}=0.4-0.5 * 0.082167041=0.35891648

Стратегия обновления весовкарта разумасерединаоптимизация,н\etaскорость обучения, здесь мы берем 0,5.

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

Точно так же можно обновить w6,w7,w8:

w6+=0.408666186w7+=0.511301270w8+=0.561370121\begin{array}{l} w_{6}^{+}=0.408666186 \\ w_{7}^{+}=0.511301270 \\ w_{8}^{+}=0.561370121 \end{array}

3) Скрытый слой -> обновление веса скрытого слоя

Метод на самом деле похож на описанный выше, но есть одно место, которое необходимо изменить.При расчете частной производной полной ошибки для w5 выше, это из out(o1)->net(o1)->w5, но в скрытом слое. Когда веса между ними обновляются, это out(h1)->net(h1)->w1, а out(h1) примет ошибку от E(o1) и E(o2), так что это место Оба должны быть рассчитаны.

рассчитатьEtotalouth1\frac{\partial E_{\text {total}}}{\partial \text {out}_{h 1}}:

Etotalouth1=Eo1outh1+Eo2outh1\frac{\partial E_{\text {total}}}{\partial o u t_{h 1}}=\frac{\partial E_{o 1}}{\partial o u t_{h 1}}+\frac{\partial E_{o 2}}{\partial o u t_{h 1}}

Рассчитать сначалаEo1outh1\frac{\partial E_{o 1}}{\partial o u t_{h 1}}:

Eo1outh1=Eo1neto1*neto1outh1Eo1neto1=Eo1outo1*outo1neto1=0.74136507*0.186815602=0.138498562сетьo1=w5*внеh1+w6*внеh2+b2*1neto1outh1=w5=0.40Eo1outh1=Eo1neto1*neto1outh1=0.138498562*0.40=0.055399425\begin{array}{l} \frac{\partial E_{o 1}}{\partial o u t_{h 1}}=\frac{\partial E_{o 1}}{\partial n e t_{o 1}} * \frac{\partial n e t_{o 1}}{\partial o u t_{h 1}} \\ \frac{\partial E_{o 1}}{\partial n e t_{o 1}}=\frac{\partial E_{o 1}}{\partial o u t_{o 1}} * \frac{\partial o u t_{o 1}}{\partial n e t_{o 1}}=0.74136507 * 0.186815602=0.138498562 \\ \text { net }_{o 1}=w_{5} * \text { out }_{h 1}+w_{6} * \text { out }_{h 2}+b_{2} * 1 \\ \frac{\partial n e t_{o 1}}{\partial o u t_{h 1}}=w_{5}=0.40 \\ \frac{\partial E_{o 1}}{\partial o u t_{h 1}}=\frac{\partial E_{o 1}}{\partial n e t_{o 1}} * \frac{\partial n e t_{o 1}}{\partial o u t_{h 1}}=0.138498562 * 0.40=0.055399425 \end{array}

Аналогично рассчитать:

Eo2outh1=0.019049119\frac{\partial E_{o 2}}{\partial o u t_{h 1}}=-0.019049119

Сложите два вместе, чтобы получить общее значение:

Etotalouth1=Eo1outh1+Eo2outh1=0.055399425+0.019049119=0.036350306\frac{\partial E_{\text {total}}}{\partial o u t_{h 1}}=\frac{\partial E_{o 1}}{\partial o u t_{h 1}}+\frac{\partial E_{o 2}}{\partial o u t_{h 1}}=0.055399425+-0.019049119=0.036350306

пересчитыватьouth1neth1\frac{\partial o u t_{h 1}}{\partial n e t_{h 1}}:

внеh1=11+enetth1внеh1сетьh1=внеh1(1внеh1)=0.59326999(10.59326999)=0.241300709\begin{array}{l} \text { out }_{h 1}=\frac{1}{1+e^{-n e t} t_{h 1}} \\ \frac{\text { out }_{h 1}}{\partial \text { net }_{h 1}}=\text { out }_{h 1}\left(1-\text { out }_{h 1}\right)=0.59326999(1-0.59326999)=0.241300709 \end{array}

пересчитыватьneth1w1\frac{\partial n e t_{h 1}}{\partial w_{1}}:

neth1=w1*i1+w2*i2+b1*1neth1w1=i1=0.05\begin{array}{l} \text {net}_{h 1}=w_{1} * i_{1}+w_{2} * i_{2}+b_{1} * 1 \\ \frac{\partial \text {net}_{h 1}}{\partial w_{1}}=i_{1}=0.05 \end{array}

Наконец, умножьте три вместе:

Etotalw1=Etotalouth1*outh1neth1*neth1w1Etotalw1=0.036350306*0.241300709*0.05=0.000438568\begin{array}{l} \frac{\partial E_{t o t a l}}{\partial w_{1}}=\frac{\partial E_{t o t a l}}{\partial o u t_{h 1}} * \frac{\partial o u t_{h} 1}{\partial n e t_{h 1}} * \frac{\partial n e t_{h 1}}{\partial w_{1}} \\ \frac{\partial E_{t o t a l}}{\partial w_{1}}=0.036350306 * 0.241300709 * 0.05=0.000438568 \end{array}

Чтобы упростить формулу, используйте sigma(h1) для обозначения ошибки единицы скрытого слоя h1:

Etotalw1=(oEtotalouto*outoneto*netoouth1)*outh1neth1*neth1w1Etotalw1=(oдельтаo*who)*outh1(1outh1)*i1Etotalw1=дельтаh1i1\begin{aligned} \frac{\partial E_{t o t a l}}{\partial w_{1}} &=\left(\sum_{o} \frac{\partial E_{t o t a l}}{\partial o u t_{o}} * \frac{\partial o u t_{o}}{\partial n e t_{o}} * \frac{\partial n e t_{o}}{\partial o u t_{h 1}}\right) * \frac{\partial o u t_{h} 1}{\partial n e t_{h 1}} * \frac{\partial n e t_{h 1}}{\partial w_{1}} \\ \frac{\partial E_{t o t a l}}{\partial w_{1}} &=\left(\sum_{o} \delta_{o} * w_{h o}\right) * \text {out}_{h 1}\left(1-o u t_{h 1}\right) * i_{1} \\ \frac{\partial E_{t o t a l}}{\partial w_{1}} &=\delta_{h 1} i_{1} \end{aligned}

Наконец, обновите веса w1:

w1+=w1н*Etotalw1=0.150.5*0.000438568=0.149780716w_{1}^{+}=w_{1}-\eta * \frac{\partial E_{t o t a l}}{\partial w_{1}}=0.15-0.5 * 0.000438568=0.149780716

Таким же образом можно обновить веса w2, w3 и w4:

w2+=0.19956143w3+=0.24975114w4+=0.29950229\begin{array}{l} w_{2}^{+}=0.19956143 \\ w_{3}^{+}=0.24975114 \\ w_{4}^{+}=0.29950229 \end{array}

Таким образом, метод обратного распространения ошибки завершен, и, наконец, мы пересчитываем обновленные веса и непрерывно итерируем.

После первой итерации в этом примере общая ошибка E(total) падает с 0,298371109 до 0,291027924.

После 10 000 итераций общая ошибка составляет 0,000035085, а результат — [0,015912196, 0,984065734] (исходный ввод — [0,01, 0,99]), что доказывает, что эффект по-прежнему хорош.

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

В-четвертых, реализация Python

Весь процесс может быть реализован с помощью кода Python.

#coding:utf-8
import random
import math

#
#   参数解释:
#   "pd_" :偏导的前缀
#   "d_" :导数的前缀
#   "w_ho" :隐含层到输出层的权重系数索引
#   "w_ih" :输入层到隐含层的权重系数的索引

class NeuralNetwork:
    LEARNING_RATE = 0.5

    def __init__(self, num_inputs, num_hidden, num_outputs, hidden_layer_weights = None, hidden_layer_bias = None, output_layer_weights = None, output_layer_bias = None):
        self.num_inputs = num_inputs

        self.hidden_layer = NeuronLayer(num_hidden, hidden_layer_bias)
        self.output_layer = NeuronLayer(num_outputs, output_layer_bias)
        self.init_weights_from_inputs_to_hidden_layer_neurons(hidden_layer_weights)
        self.init_weights_from_hidden_layer_neurons_to_output_layer_neurons(output_layer_weights)

    def init_weights_from_inputs_to_hidden_layer_neurons(self, hidden_layer_weights):
        weight_num = 0
        for h in range(len(self.hidden_layer.neurons)):
            for i in range(self.num_inputs):
                if not hidden_layer_weights:
                    self.hidden_layer.neurons[h].weights.append(random.random())
                else:
                    self.hidden_layer.neurons[h].weights.append(hidden_layer_weights[weight_num])
                weight_num += 1

    def init_weights_from_hidden_layer_neurons_to_output_layer_neurons(self, output_layer_weights):
        weight_num = 0
        for o in range(len(self.output_layer.neurons)):
            for h in range(len(self.hidden_layer.neurons)):
                if not output_layer_weights:
                    self.output_layer.neurons[o].weights.append(random.random())
                else:
                    self.output_layer.neurons[o].weights.append(output_layer_weights[weight_num])
                weight_num += 1

    def inspect(self):
        print('------')
        print('* Inputs: {}'.format(self.num_inputs))
        print('------')
        print('Hidden Layer')
        self.hidden_layer.inspect()
        print('------')
        print('* Output Layer')
        self.output_layer.inspect()
        print('------')

    def feed_forward(self, inputs):
        hidden_layer_outputs = self.hidden_layer.feed_forward(inputs)
        return self.output_layer.feed_forward(hidden_layer_outputs)

    def train(self, training_inputs, training_outputs):
        self.feed_forward(training_inputs)

        # 1. 输出神经元的值
        pd_errors_wrt_output_neuron_total_net_input = [0] * len(self.output_layer.neurons)
        for o in range(len(self.output_layer.neurons)):

            # ∂E/∂zⱼ
            pd_errors_wrt_output_neuron_total_net_input[o] = self.output_layer.neurons[o].calculate_pd_error_wrt_total_net_input(training_outputs[o])

        # 2. 隐含层神经元的值
        pd_errors_wrt_hidden_neuron_total_net_input = [0] * len(self.hidden_layer.neurons)
        for h in range(len(self.hidden_layer.neurons)):

            # dE/dyⱼ = Σ ∂E/∂zⱼ * ∂z/∂yⱼ = Σ ∂E/∂zⱼ * wᵢⱼ
            d_error_wrt_hidden_neuron_output = 0
            for o in range(len(self.output_layer.neurons)):
                d_error_wrt_hidden_neuron_output += pd_errors_wrt_output_neuron_total_net_input[o] * self.output_layer.neurons[o].weights[h]

            # ∂E/∂zⱼ = dE/dyⱼ * ∂zⱼ/∂
            pd_errors_wrt_hidden_neuron_total_net_input[h] = d_error_wrt_hidden_neuron_output * self.hidden_layer.neurons[h].calculate_pd_total_net_input_wrt_input()

        # 3. 更新输出层权重系数
        for o in range(len(self.output_layer.neurons)):
            for w_ho in range(len(self.output_layer.neurons[o].weights)):

                # ∂Eⱼ/∂wᵢⱼ = ∂E/∂zⱼ * ∂zⱼ/∂wᵢⱼ
                pd_error_wrt_weight = pd_errors_wrt_output_neuron_total_net_input[o] * self.output_layer.neurons[o].calculate_pd_total_net_input_wrt_weight(w_ho)

                # Δw = α * ∂Eⱼ/∂wᵢ
                self.output_layer.neurons[o].weights[w_ho] -= self.LEARNING_RATE * pd_error_wrt_weight

        # 4. 更新隐含层的权重系数
        for h in range(len(self.hidden_layer.neurons)):
            for w_ih in range(len(self.hidden_layer.neurons[h].weights)):

                # ∂Eⱼ/∂wᵢ = ∂E/∂zⱼ * ∂zⱼ/∂wᵢ
                pd_error_wrt_weight = pd_errors_wrt_hidden_neuron_total_net_input[h] * self.hidden_layer.neurons[h].calculate_pd_total_net_input_wrt_weight(w_ih)

                # Δw = α * ∂Eⱼ/∂wᵢ
                self.hidden_layer.neurons[h].weights[w_ih] -= self.LEARNING_RATE * pd_error_wrt_weight

    def calculate_total_error(self, training_sets):
        total_error = 0
        for t in range(len(training_sets)):
            training_inputs, training_outputs = training_sets[t]
            self.feed_forward(training_inputs)
            for o in range(len(training_outputs)):
                total_error += self.output_layer.neurons[o].calculate_error(training_outputs[o])
        return total_error

class NeuronLayer:
    def __init__(self, num_neurons, bias):

        # 同一层的神经元共享一个截距项b
        self.bias = bias if bias else random.random()

        self.neurons = []
        for i in range(num_neurons):
            self.neurons.append(Neuron(self.bias))

    def inspect(self):
        print('Neurons:', len(self.neurons))
        for n in range(len(self.neurons)):
            print(' Neuron', n)
            for w in range(len(self.neurons[n].weights)):
                print('  Weight:', self.neurons[n].weights[w])
            print('  Bias:', self.bias)

    def feed_forward(self, inputs):
        outputs = []
        for neuron in self.neurons:
            outputs.append(neuron.calculate_output(inputs))
        return outputs

    def get_outputs(self):
        outputs = []
        for neuron in self.neurons:
            outputs.append(neuron.output)
        return outputs

class Neuron:
    def __init__(self, bias):
        self.bias = bias
        self.weights = []

    def calculate_output(self, inputs):
        self.inputs = inputs
        self.output = self.squash(self.calculate_total_net_input())
        return self.output

    def calculate_total_net_input(self):
        total = 0
        for i in range(len(self.inputs)):
            total += self.inputs[i] * self.weights[i]
        return total + self.bias

    # 激活函数sigmoid
    def squash(self, total_net_input):
        return 1 / (1 + math.exp(-total_net_input))

    def calculate_pd_error_wrt_total_net_input(self, target_output):
        return self.calculate_pd_error_wrt_output(target_output) * self.calculate_pd_total_net_input_wrt_input();

    # 每一个神经元的误差是由平方差公式计算的
    def calculate_error(self, target_output):
        return 0.5 * (target_output - self.output) ** 2

    def calculate_pd_error_wrt_output(self, target_output):
        return -(target_output - self.output)

    def calculate_pd_total_net_input_wrt_input(self):
        return self.output * (1 - self.output)

    def calculate_pd_total_net_input_wrt_weight(self, index):
        return self.inputs[index]


# 文中的例子:

nn = NeuralNetwork(2, 2, 2, hidden_layer_weights=[0.15, 0.2, 0.25, 0.3], hidden_layer_bias=0.35, output_layer_weights=[0.4, 0.45, 0.5, 0.55], output_layer_bias=0.6)
for i in range(10000):
    nn.train([0.05, 0.1], [0.01, 0.09])
    print(i, round(nn.calculate_total_error([[[0.05, 0.1], [0.01, 0.09]]]), 9))


#另外一个例子,可以把上面的例子注释掉再运行一下:

# training_sets = [
#     [[0, 0], [0]],
#     [[0, 1], [1]],
#     [[1, 0], [1]],
#     [[1, 1], [0]]
# ]

# nn = NeuralNetwork(len(training_sets[0][0]), 5, len(training_sets[0][1]))
# for i in range(10000):
#     training_inputs, training_outputs = random.choice(training_sets)
#     nn.train(training_inputs, training_outputs)
#     print(i, nn.calculate_total_error(training_sets))

5. Другие

Предобработка и постобработка относительно просты, а предобработка — это некоторые обычные операции преобразования изображения, методы улучшения данных и т. д. Постобработка немного отличается для каждой задачи, например, не максимальное подавление для обнаружения объектов и т. д., что можно обсудить позже.

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

Что касается того, какой фреймворк изучать, это зависит от личных предпочтений, и Pytorch, и Tensorflow подходят. Жизнь слишком коротка, я выбираю Pytorch.

6. Рекомендуемые учебные материалы

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

Некоторые материалы рекомендованы для удобства заинтересованных читателей для продолжения своего исследования.

видео:

книги:

  • «Нейронные сети и глубокое обучение»
  • «Глубокое обучение PyTorch на практике»

Проект с открытым исходным кодом:

Видео и книги, публичный аккаунт "JackCui-AI"За кулисамиОтветить"666"Есть сюрприз!

Семь, болтовня

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

Эта статья хардкорная, если она вам понравилась, я надеюсь переслать ее и увидеть большую поддержку.

Я Джек, увидимся в следующий раз.

Статья постоянно обновляется, вы можете найти [JackCui-AI] в общедоступной учетной записи WeChat, чтобы прочитать ее впервые, эта статья GitHubGitHub.com/Джек-Чери — это…Он был включен, и есть полные тестовые сайты для интервью с крупными заводами.Добро пожаловать в Star.