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

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

Блог разделен на следующие разделы:

  1. Краткое введение в NN
  2. Необходимость слоев
  3. Отсутствие необходимости умножения
  4. Нет необходимости в активациях
  5. Отсутствие необходимости в градиентах
  6. Заключение

Краткое введение в NN

Начнем с самого простого: одноузловой НС без функции активации:

Это функция, которая будет вычислена с помощью этой модели (с дополнительным членом смещения b):

Это выглядит знакомо? Неудивительно! Это та же самая функция, которая соответствует линейной регрессии. На самом деле, если мы используем потерю среднеквадратичной ошибки с оптимизацией градиентного спуска, эта НС является в точности линейной регрессией, что делает линейную регрессию частным случаем НС. Одноузловая НС будет иметь такую ​​же репрезентативную мощность, то есть способна предсказывать линию или плоскость:

Что, если нам нужно больше, чем просто линия? Мы могли бы попробовать добавить больше узлов и слоев:

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

Получаем, что y = X1B1+X2B2+X3B3. Это линейное уравнение! Добавление большего количества узлов и слоев не повлияло на репрезентативную мощность этой модели, она может обучаться так же хорошо (или так же плохо), как и модель с одним узлом. И это не зависит от количества дополнительных слоев или узлов, вы всегда получите линейную функцию.

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

Необходимость слоев

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

Скажем, мы хотим создать И.

Это будет представление AND в евклидовом пространстве. Мы получаем 0 (определяется как «отрицательный»), когда x1 и x2 не равны 1, и 1 (определяется как «положительный»), когда x1 и x2 равны 1:

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

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

Кроме того, помимо необходимости в функции активации, невозможно разработать NN, который может представлять XOR с одним слоем (попробуйте!).

Нам нужно как минимум два! Более того, с помощью двух слоев мы можем представить любые логические ворота. Более того, всего с двумя слоями мы можем изучить ЛЮБУЮ непрерывную функцию! Двухслойная НС — это то, что мы бы назвали универсальным аппроксиматором, он имеет бесконечную репрезентативную мощность.

Это результат вышеупомянутого XOR NN, с активацией и без нее, с диапазоном входных данных:

Итак, если для изучения любой функции достаточно двух слоев, почему вообще существует концепция «глубокого обучения»? Почему так популярно добавлять в модель столько слоев? Причин несколько, и они до сих пор оспариваются. Упомяну лишь пару:

1) Обычно вам нужно гораздо больше узлов (параметров), если у вас есть только два слоя вместо глубокой модели. Это может привести к:

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

2) Есть несколько практических причин для предпочтения большего количества слоев:

  • Трансферное обучение. Это относится к получению обученной модели для конкретной задачи, а затем продолжению ее обучения для другой задачи. Как это обычно делается, удаляя некоторые из последних слоев и заменяя их необученными перед вторым обучением. Например, предположим, что у нас есть модель, обученная классифицировать 10 животных, поэтому ее выходной слой имеет 10 узлов. Вместо этого мне нужен классификатор типа «кошка или не кошка», поэтому я беру эту обученную модель, удаляю последний слой и заменяю его слоем с двумя узлами (является кошкой vs не является кошкой ). Затем я тренирую модель, сохраняя старые веса и пользуясь старыми тренировками. Если у нас очень неглубокая сеть, каждый из слоев, вероятно, будет иметь больше соединений (поскольку нам потребуется больше узлов), поэтому замена одного слоя новым необученным приведет к потере гораздо большего количества обучающей информации.
  • Особенности обучения. Этот метод состоит в получении прибыли от извлечения изученного шаблона из подмножества обученной сети. Ярким примером является CNN, где обычно первые слои учатся извлекать основные характеристики изображений, такие как края. Мы могли бы использовать эти слои для вычисления обнаружения краев в другой задаче, где обнаружение краев — это все, что нам нужно. Это, очевидно, сложнее, если у нас есть только два слоя. На первом уровне, вероятно, потребуется научиться более сложному извлечению шаблонов, чем просто края, и более специфичному для проблемы.

Отсутствие необходимости умножения

Мы уже видели, как выглядит вычисление одноузловой NN. Вычисление для каждого узла для многоузловой NN одинаково:

Что именно означает этот расчет? Почему мы его используем?
Давайте сначала рассмотрим философию обучения НС. Подобно нейронам в мозге, поведенческая цель классической НС состоит в том, чтобы «активировать» определенные нейроны при получении определенных входных данных и не активировать их, когда эти входные данные отличаются. Мозг использует электрические сигналы и химию, НС использует числа.
Этими активациями могут быть, например, мягкие 0 и 1, если используются функции активации, такие как сигмоиды, или -1 и 1 с tanh. Но экспериментальная проверка показала, что он не должен быть таким биполярным. Например, с ReLu достаточно иметь 0 и ›0, а с LeakyReLu выходом узла может быть любое вещественное число.

Как узел решает, какие входы он должен активировать? Вычисление, которое использует узел, то, которое мы видели, является скалярным произведением. Скалярный продукт — это мера направления и величины между двумя векторами. Если вектор весов узла указывает в том же направлении, что и входной вектор, узел «активируется».

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

У нас есть эта концепция; если узел получает ввод, который каким-то образом больше похож на вес узла, чем другой ввод, он должен вывести более высокое значение (он должен «активироваться»). NN всегда используют скалярное произведение для вычисления этого сходства, но можем ли мы использовать что-то еще?

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

Мы заменим вычисление наших узлов с скалярного произведения на евклидово расстояние между весами и входными данными. В PyTorch это легко сделать, заменив torch.matmul(x, weights) на torch.cdist(x, weights.T, p=2).

Позже мы поэкспериментируем с этим новым способом вычисления узлов. На данный момент в этом разделе мы увидели, что способ вычисления NN не высечен на камне, мы можем представить альтернативы, которые могли бы даже лучше работать для конкретной проблемы. Есть ли у этой альтернативы сильные стороны? Недостатки? Может быть, он меньше страдает от исчезающих градиентов, но больше от взрывных градиентов, может быть, он менее эффективен с точки зрения вычислений, но более эффективен с точки зрения памяти…

Нет необходимости в активациях

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

Для этого мы извлечем вентиль XOR, показанный во втором разделе.
Мы создаем набор данных из четырех выборок, четырех комбинаций 0–1 2-битной строки. То есть:

x = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 1, 1, 0]

И постройте NN с 2 узлами в скрытом слое и 1 узлом в выходном слое. После 1000 итераций у нас есть обученная модель.
Чтобы показать результаты в более наглядном виде, набор данных с несколькими образцами реальных значений в диапазоне (-0,5, 1,5) соответствует модели для прогноз.

Это результат использования классической NN:

Как и ожидалось (и объяснено во втором разделе), модель не может изучить логический элемент XOR, если у него нет функции активации, поскольку линейно разделить классы 0–1 невозможно.

Но что, если мы будем использовать евклидово расстояние вместо скалярного произведения? Помните, как выглядит вывод такого узла из предыдущего раздела (рис. 1 и рис. 2): точечный узел дает плоский вывод, а евклидов — чашу, т. е. нелинейный вывод! Это означает, что сеть, использующая евклидово вычисление, по умолчанию является нелинейной и, следовательно, не нуждается ни в какой функции активации!

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

Отсутствие необходимости в градиентах

До сих пор мы видели, что можем избавиться от умножения матриц (точечные произведения), от всех слоев, кроме двух, от функций активации…
Можем ли мы также избавиться от обратного распространения?

Во-первых, зачем нам это нужно?
Одно из ограничений НС с обратным распространением заключается в том, что ее вычисления должны быть производными для вычисления градиентов. Иногда это вынуждает нас искать обходные пути, например, придумывать прокси наших истинных показателей производительности. Возможно, выбранной вами метрикой производительности является средняя абсолютная ошибка в процентах (MAPE), но, поскольку ее нельзя вывести, вместо этого вы используете среднеквадратичную ошибку (MSE) в качестве функции потерь. Что похоже, но не то же самое. Оптимизация для прокси-сервера вместо метрики, которая вам действительно важна, не идеальна.
Другая причина может заключаться в том, что вам нужна очень особенная сетевая архитектура, возможно, есть компоненты, которые нельзя преобразовать в производную альтернативу. Что делать тогда?

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

Мы проведем небольшой эксперимент, чтобы проверить оптимизацию нейронных сетей с помощью генетических алгоритмов.
Данные для изучения состоят из синтетического набора данных, созданного с помощью scikit-learn, 1000 образцов из 8 функций и 3 классов для прогнозирования.

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

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

Мы не будем расширять работу генетических алгоритмов, мы можем обратиться к этой или этой странице для получения дополнительной информации. Основные вещи, которые нам нужно знать об этом методе оптимизации, заключаются в том, что в генетическом алгоритме мы инициализируем популяцию из нескольких людей, где каждый человек будет в этом случае нашей моделью со случайно инициализированными весами. Затем мы итерируем до тех пор, пока не будет достигнута сходимость или предел итераций, применяя три шага в каждой итерации: кроссовер, который берет двух родителей, объединяет их каким-то образом и производит двух потомков; мутация, которая берет человека и случайным образом немного меняет его значения; затем отбор, который отбирает лучших особей из популяции, так что мы получаем все лучших и лучших особей в каждой итерации. После последней итерации мы сохраняем лучшего человека, которого мы создали.

Единственные части, которые будут обсуждаться, — это вычисление шага мутации и скрещивания, поскольку остальные не имеют большого секрета. из них создание этих детей осуществляется путем случайной замены узлов родителей. Таким образом, у первого потомка будут выбранные узлы от родителя A, а остальные узлы от родителя B, а у второго потомка наоборот.

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

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

Это результаты после обучения в течение 100 итераций с популяцией в 100 особей. Что касается подхода с обратным распространением, мы тренировались на 100 эпох:

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

Выводы

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

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

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

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