Сверточная нейронная сеть, часть 2: обучение алгоритмом обратного распространения ошибки

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

    Обучение сверточной нейронной сети


    На начальном этапе нейронная сеть является необученной (ненастроенной). В общем смысле под обучением понимают последовательное предъявление образа на вход нейросети, из обучающего набора, затем полученный ответ сравнивается с желаемым выходом, в нашем случае это 1 – образ представляет лицо, минус 1 – образ представляет фон (не лицо), полученная разница между ожидаемым ответом и полученным является результат функции ошибки (дельта ошибки). Затем эту дельту ошибки необходимо распространить на все связанные нейроны сети.

    Таким образом обучение нейронной сети сводится к минимизации функции ошибки, путем корректировки весовых коэффициентов синаптических связей между нейронами. Под функцией ошибки понимается разность между полученным ответом и желаемым. Например, на вход был подан образ лица, предположим, что выход нейросети был 0.73, а желаемый результат 1 (т.к. образ лица), получим, что ошибка сети является разницей, то есть 0.27. Затем веса выходного слоя нейронов корректируются в соответствии с ошибкой. Для нейронов выходного слоя известны их фактические и желаемые значения выходов. Поэтому настройка весов связей для таких нейронов является относительно простой. Однако для нейронов предыдущих слоев настройка не столь очевидна. Долгое время не было известно алгоритма распространения ошибки по скрытым слоям.

    Алгоритм обратного распространения ошибки


    Для обучения описанной нейронной сети был использован алгоритм обратного распространения ошибки (backpropagation). Этот метод обучения многослойной нейронной сети называется обобщенным дельта-правилом. Метод был предложен в 1986 г. Румельхартом, Макклеландом и Вильямсом. Это ознаменовало возрождение интереса к нейронным сетям, который стал угасать в начале 70-х годов. Данный алгоритм является первым и основным практически применимым для обучения многослойных нейронных сетей.

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

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



    Величина ошибки определяется по формуле 2.8 среднеквадратичная ошибка:



    Неактивированное состояние каждого нейрона j для образа p записывается в виде взвешенной суммы по формуле 2.9:



    Выход каждого нейрона j является значением активационной функции

    , которая переводит нейрон в активированное состояние. В качестве функции активации может использоваться любая непрерывно дифференцируемая монотонная функция. Активированное состояние нейрона вычисляется по формуле 2.10:



    В качестве метода минимизации ошибки используется метод градиентного спуска, суть этого метода сводится к поиску минимума (или максимума) функции за счет движения вдоль вектора градиента. Для поиска минимума движение должно быть осуществляться в направлении антиградиента. Метод градиентного спуска в соответствии с рисунком 2.7.



    Градиент функции потери представляет из себя вектор частных производных, вычисляющийся по формуле 2.11:



    Производную функции ошибки по конкретному образу можно записать по правилу цепочки, формула 2.12:



    Ошибка нейрона обычно записывается в виде символа δ (дельта). Для выходного слоя ошибка определена в явном виде, если взять производную от формулы 2.8, то получим t минус y, то есть разницу между желаемым и полученным выходом. Но как рассчитать ошибку для скрытых слоев? Для решения этой задачи, как раз и был придуман алгоритм обратного распространения ошибки. Суть его заключается в последовательном вычислении ошибок скрытых слоев с помощью значений ошибки выходного слоя, т.е. значения ошибки распространяются по сети в обратном направлении от выхода к входу.

    Ошибка δ для скрытого слоя рассчитывается по формуле 2.13:


    Алгоритм распространения ошибки сводится к следующим этапам:
    • прямое распространение сигнала по сети, вычисления состояния нейронов;
    • вычисление значения ошибки δ для выходного слоя;
    • обратное распространение: последовательно от конца к началу для всех скрытых слоев вычисляем δ по формуле 2.13;
    • обновление весов сети на вычисленную ранее δ ошибки.

    Алгоритм обратного распространения ошибки в многослойном персептроне продемонстрирован ниже:

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

    Расчет ошибки на подвыборочном слое


    Расчет ошибки на подвыборочном слое представляется в нескольких вариантах. Первый случай, когда подвыборочный слой находится перед полносвязным, тогда он имеет нейроны и связи такого же типа, как в полносвязном слое, соответственно вычисление δ ошибки ничем не отличается от вычисления δ скрытого слоя. Второй случай, когда подвыборочный слой находится перед сверточным, вычисление δ происходит путем обратной свертки. Для понимания обратно свертки, необходимо сперва понять обычную свертку и то, что скользящее окно по карте признаков (во время прямого распространения сигнала) можно интерпретировать, как обычный скрытый слой со связями между нейронами, но главное отличие — это то, что эти связи разделяемы, то есть одна связь с конкретным значением веса может быть у нескольких пар нейронов, а не только одной. Интерпретация операции свертки в привычном многослойном виде в соответствии с рисунком 2.8.


    Рисунок 2.8 — Интерпретация операции свертки в многослойный вид, где связи с одинаковым цветом имеют один и тот же вес. Синим цветом обозначена подвыборочная карта, разноцветным – синаптическое ядро, оранжевым – получившаяся свертка

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

    Рисунок 2.9 — Вычисление δ подвыборочного слоя за счет δ сверточного слоя и ядра

    Обратная свертка – это тот же самый способ вычисления дельт, только немного хитрым способом, заключающийся в повороте ядра на 180 градусов и скользящем процессе сканирования сверточной карты дельт с измененными краевыми эффектами. Простыми словами, нам необходимо взять ядро сверточной карты (следующего за подвыборочным слоем) повернуть его на 180 градусов и сделать обычную свертку по вычисленным ранее дельтам сверточной карты, но так чтобы окно сканирования выходило за пределы карты. Результат операции обратной свертки в соответствии с рисунком 2.10, цикл прохода обратной свертки в соответствии с рисунком 2.11.

    Рисунок 2.10 — Результат операции обратной свертки


    Рисунок 2.11 — Повернутое ядро на 180 градусов сканирует сверточную карту

    Расчет ошибки на сверточном слое


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

    Заключение


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

    Источники


    Алгоритм обратного распространения ошибки для сверточной нейронной сети

    Обратное распространение ошибки в сверточных слоях
    раз и два

    Обратное распространение ошибки в персептроне

    Еще можно почитать в РГБ диссертацию Макаренко: АЛГОРИТМЫ И ПРОГРАММНАЯ СИСТЕМА КЛАССИФИКАЦИИ
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 17

      0
      Вот нифига не понял вот какую штуку.
      1) У меня сделана свёртка для каждого ядра. После свёртки у каждого ядра стоит слой субдискретизации (pooling), за ним то что получилось отправляется на один нейрон (назову его N). Таких нейронов — по числу ядер. Они служат входами обычной полносвязной нейросети.
      2) Делаем обратное распространение ошибки для полносвязной нейросети. Приходим до одного нейрона N. Дельту мы знаем со входного слоя полносвязной нейросети, так что прогоняем её на начало нейрона. Получаем дельт по размерности результата после субдискретизации. Дальше эти дельты прогоняем через слой субдискретизации (мы ведь помним, откуда брали максимальную точку). Получаем дельт по числу точек картинки, после применения свёртки.
      3) А вот и проблема. А как веса ядра по ним модифицировать? То, что написано в этой статье, так это расчёт дельт на каждой точке исходного изображения (до свёртки). Это нужно, когда слоёв свёртки много. А на первом-то слое как быть? Как модифицировать веса, зная дельты для каждой точки свёртки?

      Что интересно, внятную статью, что и как делать вообще не могу найти. Почти всегда либо тонна математики, либо сразу ныряние в TensorFlow. А так, чтобы по-действиям описать все этапы как алгоритм — такого нет.
        0
        У меня была такая же проблема при написании диплома много лет назад. Сейсас, к сожалению, потерял источник, но может быть вот эта статья описывает процесс немного лучше: ТЫЦ
        (См. процесс обратной свертки внизу)
          +1
          Так это эта же статья и есть.
          Я нашёл, что
          Градиент для ядра свёртки можно посчитать как свёртку матрицы входа свёрточного слоя с «перевёрнутой» матрицей ошибки для выбранного ядра.

          Приложенная к этой фразе формула, правда, показывала, что градиенты получатся тоже перевёрнутые и их надо будет перевернуть для коррекции ядра.
          То есть, нужно взять исходное изображение и посчитать свёртку с перевёрнутой матрицей дельт. Как раз получится матрица размером с ядро.
          Я вчера так и сделал. Но вся фишка в том, что дельты эти даже в соединении ядро->один выходной нейрон (т.е. в части до полносвязной сети) очень маленькие. Ядро вообще практически не обучается. То ли я дельты считаю неправильно (а я считаю как для обычной нейросети, по тем же формулам), то ли где-то ошибка и я чего-то не понимаю.
            0
            Честно говоря, я опешил, когда посмотрел, что та ки есть )))
            Пятница, пора домой значит
        0
        Вроде как действительно
        Градиент для ядра свёртки можно посчитать как свёртку матрицы входа свёрточного слоя с «перевёрнутой» матрицей ошибки для выбранного ядра.


        Только есть нюанс. Вот представим, что у меня есть только свёртка (без нейронов и без функции нейрона) и я желаю настроить её ядро. Зададим очень простую задачу — сделать выход свёртки всегда равным нулю. Логично, что ядро просто должно обнулиться. Считаем свёртку и задаём дельту. Так как нелинейностей у нас нет, то дельта (как я понимаю) должна быть равна разности нуля (мы же его хотим получить) и результата свёртки (а это полученный результат). Так вот, если посчитать изменения весов ядра, то оно будет огромным, что в корне неверно. Потому что вот эта вот дельта, вообще говоря, большая. Отсюда следует, что дельту я считаю явно неправильно. Как же тогда правильно в этом случае считать дельту?
          0
          Так вот, если посчитать изменения весов ядра, то оно будет огромным, что в корне неверно

          Почему?
            0
            Почему неверно или почему огромным? Первое приводит к разносу, а второе получается, так как точек исходного изображения много (и все они положительные — это ведь цвет точки) и дельта на первом шаге тоже велика. У меня такая подстройка улетала за десяток шагов в бесконечность.
              0
              Первое. Это нормальное поведение алгоритма, при неправильно выбранном шаге.
                0
                Но тогда этот шаг будет сильно зависеть от размеров ядра и изображения. Как в таком случае его избавить от этой зависимости?
                  +1
                  Будет зависеть, но не обязательно в чистом виде. Есть куча вариантов. Из инвариантных к задаче — методы второго порядка, и методы нормирующие градиенты на их среднюю длину (Adam). Из вариантов зависящих от задачи — делить лосс на размер картинки, если выход сетки это картинка, еще можно использовать BatchNorm.
                  Так же, надо понимать, что обычно ядра инициализируют весьма специфичным образом. При правильной инициализации, не должно быть больших проблем с масштабом и зависимостью от размера ядра/числа нейронов
          0
          А вот ещё веселье. Берём обычную сеть из трёх входных нейронов и одного выходного. Забиваем на функцию нейрона — пусть будет линейной. Производная — число. Даём входы как 1,2,3, а веса как 3,2, 1. Хотим получить ноль на выходе. Первый раз получается 10. Дельта выхода, соответственно, тоже 10. Считаем эту простейшую сеть обратно и получаем на первой итерации коррекцию весов -10,-20,-30. Офигеваем. Направление верное, веса нужно уменьшать к нулю, но вот масштаб… И что интересно, с каждой итерацией всё это стремительно летит в бесконечность. При этом всё это работает, если веса задать разнородными (больше и меньше нуля) и маленькими. Что-то я вообще в обратном распространении перестал понимать, как так получается.
            0
            Это одна из проблем обучения — можно перескочить точку экстремума при слишком большом шаге, поэтому есть настраиваемый параметр обучаемости (насколько я помню из университетского курса). Грубо говоря это дробный коэффициент на который умножают дельты, чтобы обучаться медленнее, но увереннее. На википедии (ТЫЦ) называют этот коэффициент «скоростью движения»
            Также иногда используют какие-то случайные алгоритмы для подстройки весом между несколькими итерациями спуска, чтобы получить случайные значения и выйти из точки локального экстремума, если застряли.
              0
              Всё это так, но формально-то получается частная производная функции оценки по изменению веса (вот есть статья).
              Для одного слоя дельта определяется как
              image
              Тогда частная производная функции оценки (W — матрица весов омега) по изменению веса будет
              image

              Входы у нас 1,2,3, веса 3,2,1, функция нейрона линейная 1:1 (т.е. производная 1). А ошибка дельта 10. Получаем значения производных 10,20 и 30 для весов 3,2,1.
              image
              В данном случае такие шаги огромные. Коррекция выполняется как
              image
              Скорость ограничивает альфа. Но вот вопрос — про альфу известно, что она меньше 1. Но насколько? У меня она 0.25.И интересно, почему при скорости 1 сеть не делает приращение в один шаг. Ведь это вполне логично. Образ обучающий один. Функция линейная. Вся математика точная.

              А для CNN я нашёл аж три разных варианта коррекции весов ядра. Какой правильный? А фиг знает. То переворачивают изображение и умножают на дельты, то ещё и применяют функцию нейрона к изображению и перевернув умножают на дельту, то дельту переворачивают и умножают на изображение (в этом случае ещё два варианта видел — в одном ядро получится прямое, а в другом указано, что перевёрнутое — кому верить непонятно).
                0
                про альфу известно, что она меньше 1. Но насколько? У меня она 0.25

                Этот коэффициент часто подбирается эмпирически. Тут нет четких правил какое число выбрать, точно также как и нет правил по выбору топологии сети или начальных значений весов.
                Обычно в начале обучения коэффициент высокий (0.25 вроде как популярное значение для персептрона), но со временем его уменьшают дабы не переобучить сеть.
                  0
                  Проблема в том, что в указанном мной примере 0.25 очень большое значение. А в других вариантах это не так.

                  0.25 вроде как популярное значение для персептрона


                  Вот ещё есть нюанс. Персептрон — двоичная игрушка. А сеть с одним нейроном — просто сеть с одним нейроном.
                  0
                  Возможно вам стоит немного почитать про метод градиентного спуска. Если не хочется решать проблему с шагом эмпирически, то можно использовать методы line search, или методы оптимизации второго порядка (Ньютон, квазиньютон)

                  Но вот вопрос — про альфу известно, что она меньше 1

                  На самом деле не обязательно) Бывают случаи, когда выгодно брать шаг больше 1, для методов первого порядка. Для методов второго да, 1 максимальный разумный шаг
                    0
                    Возможно вам стоит немного почитать про метод градиентного спуска.


                    Так вроде ж он описан в статье, на которую я ссылался (где формулы).

            Only users with full accounts can post comments. Log in, please.