Митасов Андрей Павлович : другие произведения.

Металоция неведомого. Модуль Т. Тренинг

Самиздат: [Регистрация] [Найти] [Рейтинги] [Обсуждения] [Новинки] [Обзоры] [Помощь|Техвопросы]
Ссылки:


 Ваша оценка:
  • Аннотация:
    Выжимка информации из Инета по глубокому обучению нейросетей.
    Предварительный анализ.
    Крайнее изменение 09.06.2024

  
  "Мы все учились понемногу
  Чему-нибудь и как-нибудь..."
  
  Александр сергеевич Пушкин - "Евгений Онегин".
  
  Оглавление:
   Вместо предисловия.
   Начинаем с "азов".
   "Повторение мать учения".
   Погружение в математику "обратного распространения".
   "Звонок другу".
   Маленькие улучшения backpropagation.
   Пара бит про "переобучение".
   Каноническая трактовка регуляризации.
   Попытка неканонической трактовки регуляризации. Часть 1.
   Таинства подбора гиперпараметров обучения нейросетей.
   Магия аппроксимации любой функции нейросетью.
   Попытка неканонической трактовки регуляризации. Часть 2.
   "Некоторые" сложности глубокого обучения.
   Пример глубокого обучения сверточной нейросети.
   Финальные аккорды учебника по глубокому обучению.
  
  Информация к размышлению:
   Иллюстрация реального уровня понимания работы нейронок и регуляризации.
   Обучение нейросетей с помощью "дистилляции" знаний.
   Пример обучения нейросети "от входа к выходу".
   Самообучение и обратное распространение влияния.
  
  Иллюстрации:
   Тральщик "Наставник" от "Модели Kandinsky 2.1".
   Тральщики "Наставник" от "Модели Kandinsky 3.0".
   "Обучение трансформеров" от Copilot.
   Тральщик "Наставник" от "Модели Kandinsky 3.01".
   Визуализация обучения нейронок от kraidiky.
   Тральщик "Наставник" от "Модели Kandinsky 3.1".
  
  ========
  
  29.03.2024 21:41
  
  Вместо предисловия.
  В оглавление.
  
  
  Какое бы ни было бы отношение к нынешнему ажиотажу вокруг больших и малых нейросетей,
  одно можно сказать совершенно определенно:
  методы "машинного обучения" доказали свою работоспособность
  в решении большого класса самых разнообразных задач.
  Естественно, до какого-то "идеала" или "универсальной отмычки"
  им еще достаточно далеко, но и то что достижимо сейчас по-настоящему поражает.
  Поэтому имеет смысл разобраться за счет чего это получается,
  и какие перспективы есть в плане повышения их эффективности.
  
  Для меня это еще и давно откладываемая "до лучших времен" тема
  по собственному обучению и проработки вопросов в области понимания ИИ-систем.
  Так уж совпало, что практически одновременно сразу "несколько звезд сошлись"
  на этом "ИИ-небосклоне".
  Сначала это была гипотеза о "концептуальном пространстве эмбеддингов", см:
  "Заковыристая" структура вектора эмбеддинга."
  "Каково же оно "пространство эмбеддингов" нейронки?"
  Разработка которой привела к формированию отдельного модуля:
  "Металоция неведомого. Модуль Э. Эмбеддинги."
  При написании которого, оформилась, в "первом чтении",
  концепция битовых нейронных сетей (БНС), см.:
  "Первая попытка сформулировать концепцию битовой нейронной сети (БНС)".
  
  И что интересно, в какой-то момент дальнейшее развитие этих направлений,
  так или иначе начинало явно тормозиться отсутствием какой-то ясности
  в понимании того как происходит процесс обучения нейросетей
  "не в принципе, а в кожухе".
  А еще зудящей "занозой" висел один непонятный вопрос из "обучения с подкреплением"
  о какой-то чудовищной неэффективности использования в этой технологии
  метода обучения "обратным распространением ошибки",
  этого поистине "золотого молотка" всего "машинного обучения" глубоких нейросетей.
  
  Т.е. общее представление как работает этот метод у меня естественно есть,
  но вот как увязать "особенности" этого метода, со всеми теми "непонятками",
  которые постоянно возникали, при попытках какого-то более глубокого понимания
  работы различных архитектур нейросетей как-то не возникало.
  Так что, желание разобраться в этой теме возникло достаточно давно,
  но как-то все не получалось найти какую-то "точку опоры" для такой работы.
  И вот наконец-то я получил от Copilot ссылку на достаточно "древний",
  но весьма актуальный и по сей день очень фундаментальный материал на эту тему.
  
  И я решил проработать его максимально основательно.
  Так что этот модуль, во всяком случае, в начале представляет
  мой личный конспект проработки темы "метода обратного распространения ошибки"
  с "пометками на полях", отражающими мое сегодняшнее понимание этой темы.
  В дальнейшем хочется и другие методы "машинного обучения" нейросетей
  проработать также основательно. Но это пока очень отдаленные планы.
  А пока это попытка разбора и анализа "обратного распространения"
  максимально внимательно и подробно.
  
  Не все там так просто, как может по первоначалу показаться.
  И дело даже не в формулах, а в самих концепциях и деталях их реализации.
  
  "Обучение трансформеров методом обратного распространения ошибки"
  Создано с помощью искусственного интеллекта Copilot на платформе DALL? E 3.
  
Обучение трансформеров методом обратного распространения ошибки:  OIG2.JBdgsVJoQ0.HZYsyaAzq.jpg Обучение трансформеров методом обратного распространения ошибки:  OIG2.hwEAzmEYp19BJaE_1gNb.jpg
Обучение трансформеров методом обратного распространения ошибки:  OIG2.o1fEuq2DaJ2x_thbF32Q.jpg Обучение трансформеров методом обратного распространения ошибки:  OIG2.p8Z4GoqP7E1I6TzHnNQb.jpg
  
  
  ========
  
  23.03.2024 16:31
  
  Начинаем с "азов".
  В оглавление.
  
  Итак начинаем глубокое погружение в метод "обратного распространения ошибки",
  - backpropagation -
  "священный грааль" сегодняшнего машинного обучения нейросетей.
  Сначала, как и полагается, "тренировочный заплыв" с "азов"
  по более простому, но от этого не менее интересному материалу:
  
  "Простейшая нейросеть: еще раз и подробнее".
  Автор: nulovkin
  https://habr.com/ru/articles/714988/.
  6 фев 2023 в 10:00
  
  //// Начало цитирования.
  
  Введение
  
  Некоторое время назад, во время учебы в институте,
  я решил понять принцип работы нейросетей.
  Усвоить его на уровне, необходимом,
  чтобы написать небольшую нейросеть самостоятельно.
  Начать я решил с книги Тарика Рашида "Создай свою нейросеть".
  Эта статья представляет из себя краткий конспект этой книги для тех,
  кто, как и я, столкнулся с трудностями во время изучения этой темы
  и этого учебника (не в последнюю очередь благодаря проблемам редактуры).
  В процессе я надеюсь разложить все по полочкам еще раз.
  Предположу, что перемножение матриц и взятие производной
  никого из читателей не смутят и сразу пойду дальше.
  
  Итак, машинное обучение это незаменимый инструмент для решения задач,
  которые легко решаются людьми, но не классическими программами.
  Ребенок легко поймет, что перед ним буква А, а не Д,
  однако программы без помощи машинного обучения справляются с этим
  весьма средне.
  И едва ли вообще справляются при минимальных помехах.
  Нейросети же уже сейчас решают многие задачи (включая эту)
  намного лучше людей.
  Их способность обучаться на примерах
  и выдавать верный результат поистине очаровывает,
  однако за ней лежит простая математика
  и сейчас я покажу это на примере перцептрона.
  
  Описание работы нейронов
  
  Рис. Перцептрон с тремя слоями по три нейрона
  
  Каждый нейрон (или узел) принимает сигналы от узлов предыдущего слоя
  и передает на следующий.
  Каждая связь между нейронами имеет собственный вес.
  
  Таким образом, входной сигнал узла 1 слоя 1 передается
  на узел 1 слоя 2 с коэффициентом w_{11},
  на узел 2 слоя 2 с коэффициентом w_{12}и так далее.
  Все сигналы, полученные узлом уровня 2 складываются.
  //// Вот это "складывается" и есть основная/ключевая идея перцептрона
  //// и, возможно, большинства нейросетевых архитектур.
  //// Во всяком случае этот "inductive bias" лежит в основе
  //// не только многих архитектурных решений в нейросетях,
  //// но и ключевого меnода обучения - "обратного распространения ошибок".
  //// Надеюсь, это удастся показать максимально наглядно,
  //// если и не в этом материале, то в последующих.
  Это его входной сигнал.
  Таким образом сигналы передаются с уровня на уровень, до выхода.
  
  Для того, чтобы результат был более предсказуемым,
  используется функция сглаживания,
  одна из самых популярных - сигмоида y=1/(1+e^-x).
  
  Рис. Сигмоида y=1/(1+e^-x)
  
  Если каждый узел обрабатывает поступивший сигнал функцией сглаживания,
  то можно быть полностью уверенным,
  что он не выйдет за пределы от 0 до 1.
  
  Таким образом, нейрон суммирует входные сигналы,
  умноженные на веса связей,
  берет сигмоиду от результата и подает на выход.
  
  Рис. Схема узла
  
  Еще раз, для всего слоя:
  
  А как это решает задачу?
  
  Итак, как же применить нейросеть для распознавания букв на картинке?
  
  Входным сигналом для этой картинки 28 на 28 будет последовательность
  из 784 чисел от 0 до 255,
  каждое из которых шифрует цвет соответствующего пикселя.
  Итак, на входном уровне должно быть 784 узла.
  
  Информация, которую нам необходимо получить на выходе
  это "какая цифра скорее всего на картинке".
  Всего 10 вариантов.
  Значит, на выходном уровне будет 10 узлов.
  Узел, на котором сигнал будет больше
  и будет ответом нейросети на задачу
  - например, для этой картинки в идеале все узлы выходного уровня
  должны показывать на выходе ноль, а пятый - единицу.
  
  Добавим еще уровень, чтобы переход не был таким резким.
  Допустим, нейросеть будет из трех слоев - 784, 100 и 10 узлов.
  Общепринятого метода выбора точного количества узлов на промежуточных слоях
  и количества самих промежуточных слоев не существуют
  //// Сколько лет прошло с момента разработки этой и подобной архитектур,
  //// просмотрены наверно тысячи вариантов, а более-менее точных закономерностей
  //// пока не обнаружено. Есть какие-то общие рекомендации,
  //// и не похоже что ситуация в ближайшее время как-то изменится.
  //// Похоже, большинство с этим смирилось.
  //// Это как раз тот случай, когда математика "бессильна",
  //// и рулит чистая "эвристика".
  - разве что проводить эксперименты, и сравнивать результаты.
  В нашем случае первый уровень представляет пиксели входного изображения,
  третий - распознанные цифры
  а второй каким-то трудноотслеживаемым образом
  представляет закономерности, подмножества пикселей,
  которые свойственны разным цифрам.
  
  Добавим матрицы
  
  Переведем правила распространения сигнала на язык математики.
  Задача получить сигналы нового слоя,
  то есть "Умножить вес каждого узла слоя 1 на его выходную связь,
  ведущую к узлу слоя 2
  и сложить"
  на удивление сильно подходит на описание умножения матриц.
  В самом деле, расположим в каждом столбце матрицы весов веса связей,
  исходящих из одного узла
  и умножим справа на столбец входных сигналов
  и получим выходной сигнал этого слоя в столбце получившейся матрицы.
  
  Рис. Получение сигнала следующего уровня по формуле X = W*I
  
  В строках же матрицы весов будут веса связей,
  ведущих в один узел нового слоя,
  каждый из которых умножается на вес порождающего его узла.
  Очень изящно!
  Разумеется, из-за правил перемножения матриц
  высота конечного столбца будет равна высоте матрицы весов,
  а высота матрицы входных сигналов -- ширине матрицы весов.
  Для перехода из первого слоя (784 узла) во второй (100 узлов)
  в матрице весов нашей задачи понадобится таблица в 100 строк и 784 столбца.
  
  Итак, вся загадка заключается в том,
  какими именно значениями заполнена матрица весов.
  Ее заполнение называется тренировкой нейросети.
  Затем останется лишь опросить нейросеть,
  то есть решить конкретную задачу:
  
  Подать на вход картинку, то есть столбец из 784 сигналов.
  
  Умножить на него справа таблицу весов 12.
  
  Применить сигмоиду для сглаживания результатов.
  
  На результат справа умножить таблицу весов 23.
  
  Применить сигмоиду.
  
  Взять номер узла с наибольшим значением.
  
  Таким образом, из 784 значений с помощью
  всего лишь двух матричных умножений и сглаживаний
  получилось 10 чисел в диапазоне от 0 до 1.
  Номер узла с самым большим из них
  это значение цифры на картинке, как ее распознала нейросеть.
  Насколько это соответствует истине,
  зависит от тренировки нейросети.
  
  Тренировка. Обратное распространение ошибок
  
  Метод обратного распространения ошибок это сердце нейросети.
  //// Хорошая метафора. Только относящаяся не к самой нейросети,
  //// а к ее способности выполнять что-то вразумительное.
  Его суть заключается в том,
  чтобы после получения значения ошибки на последнем слое
  передать правки на предыдущие слои.
  
  Один из основных существующих подходов
  - распределять ошибку пропорционально весам связей.
  //// В основе этого подхода, если вдуматься,
  //// лежит именно тот самый "принцип суммирования входов".
  
  Рис. Обратное распространение ошибок
  
  Или то же самое, но для нескольких узлов на внешнем слое:
  //// Т.е. попытка комплексно учесть различные значения ошибок
  //// на всех узлах выходного слоя.
  
  Рис. Обратное распространение ошибки с нескольких слоев
  
  Ошибка, то есть e,
  это разница между t - желаемым значением и o - значением на выходном слое:
  e = t - o.
  
  Как мы видим, o1 высчитывается из узлов первого слоя
  с помощью связей w11 и w12,
  а значит, именно их и нужно корректировать с помощью ошибки этого узла.
  Новое значение w11 зависит от доли w11 в сумме связей, ведущих к узлу:
  \frac{w11}{w11+w21}.
  Конечно, для w21 нужно заменить w11 в числителе на w21.
  
  Теперь можно было бы приступить
  и к, собственно обратному распространению ошибки.
  Использовать данные следующего слоя для работы с предыдущим:
  
  Однако, у нас нет целевых значений для скрытого слоя.
  Не беда.
  Просто сложим ошибки всех связей,
  исходящих из этого узла,
  и получим его ошибку!
  //// Это один из "ключевых моментов" в методе "обратного распространения ошибки".
  
  Сложим, получим значение ошибки и просто повторим все еще раз.
  Пример показан ниже:
  
  Еще раз, словами:
  Ошибку Oi умножаем на долю связи w_{ki}/\sum_i W_i
  в сумме связи отдельного узла k со всеми узлами следующего уровня,
  чтобы получить ошибку узла k предыдущего слоя.
  Затем все ошибки связей из узла k складываем
  и получаем его собственную ошибку.
  И так далее.
  
  Перепишем все вышесказанное в виде матриц:
  
  Рис. Получение ошибки предыдущего слоя
  
  Удобно. Но не до конца.
  Было бы здорово избавиться от всех этих отличающихся знаменателей.
  И деления. совсем не удобно делить тысячу узлов на тысячу разных сумм.
  Было бы здорово как-то все упростить.
  Тут нам поможет тот факт,
  что для написания нейросети позволено забыть математику за третий класс
  на практике у нас будет больше двух узлов в слое.
  И значение числителя (например 0,2, 0,4 или 0,9) гораздо важнее,
  чем значение знаменателя (например 9,7, 9,3 или 8,4).
  Что приводит нас к моему любимому моменту в книге.
  Нормирующий множитель?
  Да зачем он нам?
  //// Очень остроумное решение, так как все равно используемое значение
  //// коррекции/изменения веса нужно регулировать, чтобы "не промазать".
  //// так не проще ли сразу задавать какой-то определенный нормирующий коэффициент,
  //// заодно отказавшись от необходимости использовать фактического "нормирования".
  //// Выигрыш налицо. А вот "минус" от такого решения как-то неочевиден.
  //// А "бесплатный сыр", как известно, "только в мышеловке".
  //// Но как-то об этой особенности слышать еще не приходилось.
  
  Рис. Здорово упрощенный расчет ошибки скрытого слоя
  
  Мы получили донельзя простую формулу обратного распространения ошибки
  с помощью матрицы весов и ошибки наружного слоя.
  Обратите внимание, что столбцы матрицы весов
  здесь поменяны местами со строками и наоборот,
  то есть матрица транспонирована.
  
  Рис. Итоговая формула ОРО
  
  Однако, нужно держать в уме,
  что это просто иллюстрация для идеального случая
  и понимания концепции.
  В нашей нейросети все немного сложнее.
  
  Тренировка. Обновление весов
  
  Однако, нужно напомнить,
  что мы дважды применяем сигмоиду по мере расчета веса узла.
  Кроме того, представим, что на узле ошибка 0,3.
  Если мы изменим одну связь, ведущую к этому узлу,
  то изменение других связей может снова все испортить.
  А так быть не должно.
  Интуитивно кажется, что каждая связь должна меняться
  сообразно своей роли в ошибке.
  При этом эта роль это не просто доля веса,
  ведь мы дважды применяли сигмоиду!
  
  Итак, нам нужно свести ошибку каждого узла к нулю.
  //// Еще одна "аксиома", которая не подвергается сомнению.
  //// Хотя если ставится задача "стратегического" обучения, а не "тактического",
  //// то должна быть возможность и какого-то промежуточного "игнорирования ошибки".
  Ошибка зависит от множества переменных,
  каждая из которых влияет на результат по разному.
  Звучит как задача для производной!
  
  Здесь нам пригодится метод градиентного спуска.
  Если нам известно, что связь Wij влияет на общую ошибку,
  то просто посчитаем производную
  и сделаем шаг в направлении нуля.
  //// Вот так потихоньку происходит "скрещивание" "градиентного спуска"
  //// и "обратного распространения ошибки",
  //// образуя ту "гремучую смесь", которая и обеспечила нынешний прорыв
  //// в обучении глубоких нейросетей.
  
  Нам нужно минимизировать ошибку.
  Значит, наш шаг должен вести нас к нулевой O .
  Нам нужно узнать соответствующую Wij.
  И выполнить это для каждой связи в узле,
  а затем для каждого узла в слое.
  
  Рассмотрим это для нашей многомерной функции:
  нам нужно узнать такие значения W
  (такие координаты, только не на двумерной плоскости, а во множестве измерений.
  Но это не сильно все осложнить),
  чтобы значение O было минимальным
  (спуститься в самую глубокую яму на карте).
  
  Напомню, что нужно делать все более мелкие шаги,
  чтобы не пройти центр "ямы".
  Для этого нужен специальный коэффициент, убывающий во время обучения.
  
  Также вы можете подумать,
  что легко можно забрести в неправильную "яму",
  то есть ложный минимум:
  
  К счастью, по какой-то причине для задач, подобных нашей,
  большинство ложных минимумов располагаются
  близко от основного
  и почти также глубоки.
  //// Любопытный факт, так и не получивший какого-то внятного объяснения.
  //// А ведь за любой "непоняткой" обычно кроется какое-то интересное открытие
  //// и иногда фундаментальное. Вся история физики только об этом.
  Сейчас можно об этом не беспокоиться.
  
  Самое лучшее в методе градиентного спуска,
  это его устойчивость к ошибкам.
  Если попадется несколько ошибок в тренировочных данных,
  последующие примеры постепенно сгладят эффект.
  //// Нет, это не свойство "градиентного спуска"
  //// - это свойство обучения нейросетей
  //// методом "обратного распространения ошибок",
  //// следствие того самого свойства "близости ложных минимумов".
  //// Просто еще 45 лет назад исследовал этот "градиентный спуск",
  //// на достаточно сложном "рельефе задачи"
  //// и убедился, что свойством устойчивости "к ошибкам" сам по себе
  //// он в принципе не обладает.
  //// Что, кстати, и при обучении нейросетей тоже должно проявляться,
  //// и компенсируется именно "последующими примерами" и backpropagation.
  
  Как на самом деле посчитать ошибку
  
  //// Тут очень рекомендую переключится на оригинальный текст,
  //// так как без иллюстраций понять дальнейший цитируемый текст в деталях
  //// весьма затруднительно.
  
  Для начала, вспомним, что ошибиться можно в обе стороны.
  А значит, значения ошибок будут как отрицательные, так и положительные.
  Тогда сумма ошибок может оказаться не тем больше, чем больше ошибки,
  а просто близкой к нулю.
  Значит, e = t-o как значение ошибки использовать нельзя.
  Приходит на ум модуль: e = |t-o|,
   чтобы избежать отрицательных значений.
  Однако тогда функция будет вести себя странно в районе нуля.
  //// Т.е. более разумное задание ошибки, конфликтует с чем-то еще,
  //// так до конца и невыясненным.
  Лучший вариант из всех для оценки ошибки это e=(t-o)^2.
  
  Теперь, когда мы исправили проблему подсчета ошибок,
  попробуем посчитать производную.
  dE/dWij.
  Это выражение представляет изменение значения ошибки при изменении веса узла.
  
  Перепишем функцию оценки ошибки:
  
  Рис. Е это показатель суммы всех ошибок.
  
  Получившееся выражение можно сразу упростить.
  Ошибка не зависит от всех значений на узлах,
  только от тех, что соединены с узлом k.
  Упростим выражение:
  
  Рис. Упрощенное представление функции
  
  Воспользуемся цепным правилом дифференцирования сложных функций:
  
  Теперь мы можем работать с частями этого уравнения по отдельности:
  
  \frac{dE}{do_k} = \frac{d(t_k-o_k)^2}{{do_k}} = -2(t_k-o_k)
  
  В осталось разобраться со второй частью,
  а первую подставим в общее уравнение:
  
  Перепишем выходной сигнал o_k в явном виде:
  
  Мы заменили выходной сигнал на сумму произведений каждой из связей,
  ведущих к этому узлу,
  на вес узла-источника.
  
  Вот формула, по которой дифференцируется сигмоида
  (и как хорошо, что нам не нужно это доказывать.
  Это работает):
  
  Применим это к нашей формуле и получим:
  
  Обратите внимание на то, что в последней формуле появился сомножитель
  (Одна из смущающих вещей в редактуре учебника.
  В этой формуле j под суммой и j в остальных местах, разумеется, разные,
  хотя оба представляют предыдущий уровень,
  так что здесь я обозначу индекс под суммой i.
  j находится в промежутке от 0 до i.):
  
  o_j=\frac{d(\sum_iw_{ik}*o_i)}{dw_{jk}}.
  
  Это результат применения цепного правила дифференцирования сложной функции,
  то есть производная выражения в скобках сигмоиды.
  Возможно вы, как и я поначалу, не поняли,
  почему оно именно такое.
  Что ж, это значение представляет зависимость суммы всех связей с узлом k,
  умноженных на веса их узлов от веса одной связи.
  Поскольку производная суммы равна сумме производных,
  а все прочие веса кроме w_{jk} относительно него считаются константами,
  то:
  
  \frac{d(\sum_iw_{ik}*o_i)}{dw_{jk}} = \frac{d(w_{jk}*o_j)}{dw_{jk}} = o_j * w_{jk}^0 = o_j.
  
  Таким образом, окончательный вид функции для изменения узлов
  предпоследнего слоя это
  (еще раз, помните, что на картинках j под суммой это не тот же j, что и снаружи):
  //// Да, с индексами у автора "некоторая двузначность".
  
  Рис. Градиент функции ошибки связей с выходным слоем
  
  Чтобы таким же образом изменить узлы слоя до него,
  подставим нужные связи и заменим очевидную финальную ошибку
  на посчитанную ранее ошибку скрытого слоя e_k:
  
  Рис. Градиент функции ошибки связей со скрытым слоем
  
  Применим нашу формулу, отображая тот факт,
  что результат необходимо умножить на коэфициент обучения,
  а градиент по знаку противоположен изменению связей:
  
  Перенесем W налево и покажем,
  как выглядят эти вычисления в матричной записи
  (коэффициент обучения для наглядности опущен),
  Е это значение ошибки узла,
  S это сумма произведений весов, ведущих к одному узлу,
  на их связь с этим узлом,
  на которую применили сигмоиду,
  O это сигнал на выходе из предыдущего слоя:
  
  Перепишем формулу целиком в удобном матричном виде
  (как можно было заметить в предыдущей формуле,
  последний сомножитель это транспонированная матрица
  выходных сигналов предыдущего слоя):
  
  Эту формулу будет удобно использовать в коде.
  
  Разбор примера обновления коэффициентов
  
  Если вы не совсем поняли с первого раза,
  какие значения куда подставлять,
  то разберем такой пример:
  
  Возьмем конкретно первый узел выходного слоя, где e_1=0,8.
  Мы хотим обновить весовой коэффициент w_{11}
  для связи между последними двумя слоями.
  Вспомним формулу градиента ошибки:
  
  Вместо (t_k-o_k)подставим нашу ошибку e_1=0,8.
  
  Сумма \sum _jw_{jk}o_j в данном случае равна (2,0*0,4) + (3,0*0,5) = 2,3.
  //// Тут, похоже, автор сам запутался в своих обозначениях.
  //// Во всяком случае, откуда у него взялось произведение (3,0*0,5)
  //// я так и не смог найти, хотя честно полчаса сравнивал самые
  //// разные иллюстрации и формулы в этом тексте.
  //// Откуда берется 3,0 - понятно, а вот откуда 0,5 - нет.
  //// И почему они объединяются в одном произведении в данном конкретном месте
  //// - тем более. И в комментариях никто не обратил на это внимание.
  //// Так что, считать, что я полностью понял этот материал,
  //// наверно, преждевременно.
  
  Сигмоида 1/(1+e^{-2,3}) = 0,909.
  
  Сигнал o_1=0,4.
  
  Следовательно, все значение в целом составит
  -0,8*0,909*(1-0,909)*0,4 = -0,02647.
  
  Допустим, что коэффициент обучения составляет 0,1.
  Тогда изменение веса составит -0,1*(-0,02647)=+0,002647.
  Это и есть тот довесок,
  который нам нужно добавить в связь w_{11}.
  Новое значение ее веса составит 2,002647.
  
  Еще несколько тысяч таких изменений и чаша наша полна.
  
  Пара слов о подготовке данных
  
  Рис. График нашей сигмоиды
  
  Как мы видим, при больших значениях входного сигнала
  значение сигмоиды будет изменяться очень слабо,
  вне зависимости от знака.
  Это будет означать, что нейросеть почти не будет изменяться
  и веса останутся после обучения почти такими же.
  Значит, весовые коэффициенты должны располагаться поближе к нулю
  (но не слишком, это может вызвать проблемы
  с подсчетами из-за ограничений формата с плавающей точкой).
  Нам хорошо подойдет масштабирование входных сигналов от 0,0 до 1,0
  - еще и потому, что именно такие сигналы обеспечивает сигмоида.
  Значение никогда не выйдет за пределы (0;1).
  
  Для работы нейросети необходимо указать
  начальные значения весовых коэффициентов.
  Причем, это не могут быть нули или просто одинаковые значения
  - в таких условиях они получат одинаковые правки
  и останутся совпадающими после обучения,
  что явно не даст нам хороших результатов.
  Остается указать случайные значения в приемлемом диапазоне,
  например от -1,0 до +1,0.
  Однако очевидно, что если значения весов в начале обучения
  будут близки к максимальным, то нейросеть может быстро насытиться.
  Это рассуждение, подкрепленное наблюдениями, породило эмпирическое правило:
  весовые коэффициенты должны выбираться из диапазона,
  приблизительно оцененного обратной величиной корня из количества связей,
  ведущих к узлу.
  Если к узлу ведут 3 связи, его вес должен быть случайным значением
  в промежутке (0;\frac{1}{\sqrt3}).
  
  Итоги
  
  Эта статья, представляющая конспект-пересказ
  книги Тарика Рашида "Создай свою нейросеть"
  призвана объяснить некоторые детали того,
  как проектируется и работает простой перцептрон
  и обратное распространение ошибок в нем.
  Я написал ее для того, чтобы охватить всю картину вместе,
  однако даже после столь внимательного погружения в материал
  и прояснения каждой его части
  я не уверен, что смогу написать что-то похожее,
  например распознавалку знаков,
  без заглядывания в книгу.
  Однако, я намного ближе к этому, чем какое-то время назад.
  
  Я надеюсь, что эта статья поможет таким же как я новичкам в мире нейросетей,
  кто не понял все аспекты процесса с первого раза и забросил книгу на пару лет.
  
  Я приветствую критику как от них, так и от всех остальных,
  касательно фактических ошибок, стиля подачи материала,
  неточностей, упущений и других проблем статьи,
  которые, я уверен, найдутся, поскольку раньше я ничего подобного не писал.
  
  Спасибо вам всем!
  
  ........
  
  //// Из комментариев.
  
  Akon32
  7 фев 2023 в 20:33
  
  Я помню, что градиент считается как dE/dw,
  а дальше идёт матричное дифференцирование.
  Но это теория.
  На практике градиент автоматически считает библиотека типа Keras,
  причём она считает производные для всех слоёв.
  Практика здесь далеко ушла от базовой теории
  - руками градиенты считать не нужно,
  поэтому базовая теория сейчас малополезна.
  
  Поиск по тегу "перцептрон" даёт штук 8 таких начальных статей,
  но мне кажется, что их больше (можно посмотреть по другим ключевым словам).
  Я такие комментарии по поводу перцептронов уже несколько раз писал,
  эта тема очень проста, вот и всплывает периодически.
  И это только на Хабре.
  
  ........
  
  //// Конец цитирования.
  
  Как видно из комментариев, разбираться в том как работает backpropagation
  в деталях и в "кожухе" уже давно "немодно".
  Есть "теория, доказавшая свою истину на практике",
  есть заслуживающие доверия библиотеки,
  так кому может быть интересна эта тема, покрытая "пылью веков"?
  
  А мне вот было по-настоящему интересно разобраться в том,
  что уже считается "незыблемыми аксиомами",
  а что осталось "за бортом внимания",
  именно потому, что как-то не укладывается в эти "аксиомы".
  В общем, если не считать некоторых мелких недочетов,
  то я считаю этот материал очень и очень достойным не только прочтения,
  но и внимательного изучения.
  
  Итак, "пробное погружение" в backpropagation можно считать завершенным,
  и теперь можно перейти к самой "мякотке" или, наоборот, "фундаменталке".
  
  
  =======
  
  18.03.2024 20:16
  
  "Повторение мать учения".
  В оглавление.
  
  Собственно получив ссылку на этот материал от Copilot,
  и бегло просмотрев оглавление, и появилась задумка сделать этот модуль,
  оттолкнувшись от детального разбора серьезного учебника
  по глубокому обучению нейросетей.
  Торопиться просто пробежаться по этой теме нет никакого смысла,
  так как задача стоит в том, чтобы попытаться нащупать
  не просто "болевые точки" метода обратного распространения ошибки,
  а ключевые концепции,
  которые можно было бы как-то иначе переформулировать/представить/использовать.
  И, может быть, придумать что-то более подходящее/удобное
  для битовых нейронных сетей (БНС).
  
  Так что предлагаю, поудобнее устроиться в кресле,
  и погрузиться в первую часть "архивных раскопок":
  
  "Нейросети и глубокое обучение,
  глава 1: использование нейросетей для распознавания рукописных цифр".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/456738/.
  20 июн 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap1.html
  
  //// Начало цитирования.
  
  Перед вами - перевод свободной онлайн-книги Майкла Нильсена
  ,
  http://creativecommons.org/licenses/by-nc/3.0/deed.en_GB
  распространяемой под лицензией
  Creative Commons Attribution-NonCommercial 3.0 Unported License.
  
  ......
  
  Содержание
  
  Глава 1: использование нейросетей для распознавания рукописных цифр
  https://habr.com/ru/post/456738/
  
  Глава 2: как работает алгоритм обратного распространения
  https://habr.com/ru/post/457980/
  
  Глава 3:
  
  ч.1: улучшение способа обучения нейросетей
  https://habr.com/ru/post/458724/
  
  ч.2: почему регуляризация помогает уменьшать переобучение?
  https://habr.com/ru/post/459816/
  
  ч.3: как выбрать гиперпараметры нейросети?
  https://habr.com/ru/post/460711/
  
  Глава 4: визуальное доказательство того,
  что нейросети способны вычислить любую функцию
  https://habr.com/ru/post/461659/
  
  Глава 5: почему глубокие нейросети так сложно обучать?
  https://habr.com/ru/post/462381/
  
  Глава 6:
  
  ч.1: глубокое обучение
  https://habr.com/ru/post/463171/
  
  ч.2: недавний прогресс в распознавании изображений
  https://habr.com/ru/post/464039/
  
  Послесловие: существует ли простой алгоритм для создания интеллекта?
  https://habr.com/ru/post/464735/
  ......
  
  Нейросети - прекрасная программная парадигма,
  созданная под влиянием биологии,
  и позволяющая компьютеру учиться на основе наблюдений.
  
  Глубокое обучение - мощный набор техник обучения нейросетей.
  
  Нейросети (НС) и глубокое обучение (ГО)
  на сегодня дают наилучшее решение многих задач
  из областей распознавания изображений, голоса и обработки естественного языка.
  Этот учебник научит вас многим ключевым концепциям, лежащим в основе НС и ГО.
  
  ......
  
  Автоматическое обучение на основе данных звучит многообещающе.
  Однако до 2006 года мы не знали, как обучать НС так,
  чтобы они могли превзойти более традиционные подходы,
  за исключением нескольких особых случаев.
  В 2006 были открыты техники обучения т.н. глубоких нейросетей (ГНС).
  Теперь эти техники известны, как глубокое обучение (ГО).
  Их продолжали разрабатывать,
  и сегодня ГНС и ГО достигли потрясающих результатов во многих важных задачах,
  связанных с компьютерным зрением, распознаванием речи
  и обработки естественного языка.
  
  ......
  
  Подход с упором на принципы
  
  Одно из убеждений, лежащих в основе книги, состоит в том,
  что лучше овладеть твёрдым пониманием ключевых принципов НС и ГО,
  чем нахватать знаний из длинного списка различных идей.
  Если вы хорошо разберётесь в ключевых идеях,
  вы быстро поймёте и другой новый материал.
  
  ......
  
  Практический подход
  
  ......
  
  Упражнения и задачи
  
  .......
  
  Глава 1
  
  ......
  
  В этой главе мы напишем компьютерную программу,
  реализующую НС, обучающуюся распознавать рукописные цифры.
  Программа будет всего в 74 строки длиной,
  и не будет использовать специальных библиотек для НС.
  Однако эта короткая программа сможет распознавать рукописные цифры
  с точностью более 96%, не требуя вмешательства человека.
  Более того, в дальнейших главах мы разработаем идеи,
  способные улучшить точность до 99% и более.
  
  ......
  
  Перцептроны
  
  ......
  
  Так как же работают перцептроны?
  Перцептрон принимает на вход несколько двоичных чисел x1,x2,...
  и выдаёт одно двоичное число:
  
  .....
  
  Розенблатт предложил простое правило для вычисления результата.
  Он ввёл веса, w1, w2, вещественные числа,
  выражающие важность соответствующих входных чисел для результатов.
  Выход нейрона, 0 или 1, определяется тем,
  меньше или больше некоего порога [threshold]
  взвешенная сумма $\sum_j w_jx_j$.
  Как и веса, порог - вещественное число, параметр нейрона.
  
  ......
  
  Кстати, когда я определял перцептрон,
  я сказал, что у него есть только одно выходное значение.
  Но в сети наверху перцептроны выглядят так,
  будто у них есть несколько выходных значений.
  На самом деле, выход у них только один.
  Множество выходных стрелок - просто удобный способ показать,
  что выход перцептрона используется
  как вход нескольких других перцептронов.
  Это менее громоздко, чем рисовать один разветвляющийся выход.
  
  ......
  
  Я описал перцептроны с точки зрения метода взвешивания свидетельств
  с целью принятия решения.
  Ещё один метод их использования - вычисление элементарных логических функций,
  которые мы обычно считаем основными вычислениями,
  таких, как AND, OR и NAND.
  
  ........
  
  Этот пример показывает,
  что можно использовать перцептроны для вычисления базовых логических функций.
  На самом деле, мы можем использовать сети перцептронов
  для вычисления вообще любых логических функций.
  Дело в том, что логический вентиль NAND универсален для вычислений
  - на его основе можно строить любые вычисления.
  //// Теоретически можем, а вот практически это оказывается не так.
  //// Например, имеются трудности с периодическими функциями активации,
  //// со структурами, которые можно принудительно заставить работать как хочется,
  //// но вот обучить их аналогичному поведению очень часто не удается.
  //// И это одна из проблем, которые заставляют снова и снова "изучать под лупой"
  //// все аспекты этой технологии, состоящей из двух половинок:
  //// концепции перцептрона и метода обучения обратным распространением ошибки.
  
  .......
  
  Пример с сумматором демонстрирует,
  как можно использовать сеть из перцептронов для симуляции контура,
  содержащего множество вентилей NAND.
  А поскольку эти вентили универсальны для вычислений,
  следовательно, и перцептроны универсальны для вычислений.
  //// Вот как раз именно этот пример можно рассматривать
  //// и как неуниверсальности существующего метода backpropagation,
  //// так как обучить нечто подобное с высокой точность практически невероятно.
  
  Вычислительная универсальность перцептронов
  одновременно обнадёживает и разочаровывает.
  Обнадёживает она, гарантируя, что сеть из перцептронов
  может быть настолько же мощной,
  насколько любое другое вычислительное устройство.
  Разочаровывает, создавая впечатление,
  что перцептроны - всего лишь новый тип логического вентиля NAND.
  Так себе открытие!
  
  Однако на самом деле ситуация лучше.
  Оказывается, что мы можем разработать обучающие алгоритмы,
  способные автоматически подстраивать веса
  и смещения сети из искусственных нейронов.
  Эта подстройка происходит в ответ на внешние стимулы,
  без прямого вмешательства программиста.
  Эти обучающие алгоритмы позволяют нам использовать
  искусственные нейроны способом,
  радикально отличным от обычных логических вентилей.
  Вместо того, чтобы явно прописывать контур из вентилей NAND и других,
  наши нейросети могут просто обучиться решать задачи,
  иногда такие, для которых было бы чрезвычайно сложно напрямую
  спроектировать обычный контур.
  //// А иногда неспособных воспроизвести достаточно тривиальную зависимость,
  //// во всяком случае, при сопоставимом количестве узлов и связей.
  //// Обычно в такого рода "восхвалениях нейросетей" и "машинного обучения"
  //// "почему-то" забывают упомянуть о том, что решаемые таким образом задачи
  //// требуют определенного минимального "масштаба" нейросети,
  //// чтобы она как-то более-менее могла соответствовать поставленной задаче.
  //// А вот какой должен быть этот "масштаб" "теория машинного обучения"
  //// опять "почему-то" "скромно умалчивает".
  //// И тут, по-моему, проблема в том, что полного понимания ни возможностей,
  //// ни ограничений backpropagation пока нет.
  //// А есть как-то работающие формулы и заточенные под них библиотеки,
  //// а когда их использование явно не достаточно
  //// обнаруживается только "постфактум", то бишь, экспериментально.
  
  
  Сигмоидные нейроны
  
  Обучающие алгоритмы - это прекрасно.
  Однако как разработать такой алгоритм для нейросети?
  Допустим, у нас есть сеть перцептронов,
  которую мы хотим использовать для обучения решения задачи.
  Допустим, входными данными сети могут быть
  пиксели отсканированного изображения рукописной цифры.
  И мы хотим, чтобы сеть узнала веса и смещения,
  необходимые для правильной классификации цифры.
  Чтобы понять, как может работать такое обучение,
  представим, что мы немного меняем некий вес (или смещение) в сети.
  Мы хотим,
  чтобы это небольшое изменение привело
  к небольшому изменению выходных данных сети.
  Как мы скоро увидим,
  это свойство делает возможным обучение.
  //// Очень важное утверждение для понимания всей существующей концепции
  //// не только перцептрона, но и всей методики обучения нейросетей.
  //// Т.е. для существующей концепции обучения СУЩЕСТВЕННО ВАЖНО
  //// ЛИНЕЙНОСТЬ и НЕПРЕРЫВНОСТЬ представлений данных в отдельном перцептроне,
  //// и даже во всей нейросети.
  
  //// Хочется отметить, что именно это требование и делает невозможным
  //// "реализацию любых функций" нейросетью минимального размера в общем случае.
  //// Т.е. теоретически "нейросеть минимального размера" способна реализовать
  //// достаточно сложные функциональные зависимости,
  //// если она будет хоть частично НЕЛИНЕЙНА или ПРЕРЫВИСТА.
  //// Но это входит в противоречие с требованиями "обучаемости"
  //// с помощью "линейных и непрерывных" представлений данных.
  //// И отсюда растут корни многих проблем обучения нейросетей,
  //// которые ЧАСТИЧНО удается решать за счет увеличения "масштаба" нейросетей.
  //// И решение это основано именно на "суммировании",
  //// т.е. осреднении данных, которые, сами по себе, могут быть
  //// и нелинейны и прерывисты, с точки зрения их интерпретации.
  
  Схематично мы хотим следующего
  (очевидно, такая сеть слишком проста, чтобы распознавать рукописный ввод!):
  
  Если бы небольшое изменение веса (или смещения) приводило бы
  к небольшому изменению результата на выходе,
  мы могли бы изменять веса и смещения,
  чтобы наша сеть вела себя чуть ближе к желаемому.
  К примеру, допустим, что сеть неправильно отнесла изображение к <8>,
  хотя должна была к <9>.
  Мы могли бы разобраться, как внести небольшое изменение в веса и смещения,
  чтобы сеть немного ближе подобралась к классификации изображения, как <9>.
  А потом мы бы повторяли это, изменяя веса и смещения снова и снова,
  чтобы получать всё лучший и лучший результат.
  Сеть бы училась.
  //// Данная концепция предполагает "гладкость" и "непрерывность" чего-то там,
  //// о чем также обычно "скромно умалчивается".
  //// Все как в старой солдатской песне:
  //// "Гладко было на бумаге,
  //// да забыли про овраги,
  //// а по ним ходить..."
  
  Проблема в том, что если в сети есть перцептроны,
  такого не происходит.
  Небольшое изменение весов или смещения любого перцептрона
  иногда может привести к изменению его выхода на противоположный,
  допустим, с 0 на 1.
  Такой переворот может изменить поведение остальной сети
  очень сложным образом.
  И даже если теперь наша <9> и будет правильно распознана,
  поведение сети со всеми остальными изображениями,
  вероятно, полностью изменилось таким образом,
  который сложно контролировать.
  Из-за этого сложно представить,
  как можно постепенно подстраивать веса и смещения,
  чтобы сеть постепенно приближалась к желаемому поведению.
  Возможно, существует некий хитроумный способ обойти эту проблему.
  Но нет никакого простого решения задачи обучения сети из перцептронов.
  //// Вот оно, честное признание - неизвестно как обучать "прерывистую"
  //// или дискретную систему, поэтому изменяем систему на "квазинепрерывную".
  //// Ну что ж, вполне рабочее решение:
  //// "За неимением гербовой, пишем на простой."
  
  //// Но это не значит, что для дискретных систем принципиально
  //// нет возможности найти обучающий алгоритм.
  
  //// Но зато это значит, что если где-то снова в системе,
  //// не предназначенной для работы с нелинейностью и дискретностью/прерывистостью,
  //// такое поведение все-таки как-то возникнет,
  //// то скорее всего для такой системы это плохо кончится.
  //// И, очень вероятно, что такое периодически происходит,
  //// и единственный хоть какой-то выход из этого -
  //// дальнейшее увеличение "масштаба" системы в надежде,
  //// что суммирование/усреднение "сгладит" эту нелинейность/прерывистость.
  //// Ну, или кардинальная перестройка структуры нейросети,
  //// причем, опять же практически вслепую.
  
  Эту проблему можно обойти,
  введя новый тип искусственного нейрона под названием сигмоидный нейрон.
  Они похожи на перцептроны,
  но изменены так, чтобы небольшие изменения весов и смещений
  приводили только к небольшим изменениям выходных данных.
  Это основной факт,
  который позволит сети из сигмоидных нейронов обучаться.
  //// А вот с этим согласен полностью.
  //// Только добавлю, что в качестве функции активации могут быть и другие функции,
  //// но только монотонные и непрерывные,
  //// если использовать backpropagation в существующем виде.
  
  Давайте я опишу сигмоидный нейрон.
  Рисовать мы их будем так же, как перцептроны:
  
  У него точно так же есть входные данные x1, x2,..
  Но вместо того, чтобы приравниваться к 0 или 1,
  эти входы могут иметь любое значение в промежутке от 0 до 1.
  К примеру, величина 0,638 будет допустимым значением входных данных
  для сигмоидного нейрона (СН).
  Так же, как у перцептрона, у СН есть веса для каждого входа, w1, w2,...
  и общее смещение b.
  Но его выходным значением будет не 0 или 1.
  Это будет ?(w?x+b), где ? - это сигмоида.
  
  Кстати, ? иногда называют логистической функцией,
  а этот класс нейронов - логистическими нейронами.
  Эту терминологию полезно запомнить,
  поскольку эти термины используют многие люди, работающие с нейросетями.
  Однако мы будем придерживаться сигмоидной терминологии.
  
  Определяется функция так:
  
  $ \sigma(z) \equiv \frac{1}{1+e^{-z}} \tag{3} $
  
  В нашем случае выходное значение сигмоидного нейрона
  с входными данными x1, x2,... весами w1, w2,... и смещением b
  будет считаться, как:
  
  $ \frac{1}{1+exp(-\sum_j w_jx_j - b)} \tag{4} $
  
  На первый взгляд, СН кажутся совсем не похожими на нейроны.
  Алгебраический вид сигмоиды может показаться запутанным и малопонятным,
  если вы с ним не знакомы.
  На самом деле между перцептронами и СН есть много общего,
  и алгебраическая форма сигмоиды оказывается больше технической подробностью,
  нежели серьёзным барьером к пониманию.
  
  ......
  
  Что насчёт алгебраического вида ??
  Как нам его понять?
  На самом деле, точная форма ? не так уж важна
  - важна форма функции на графике.
  Вот она:
  
  Это сглаженный вариант ступенчатой функции:
  
  Если бы ? была ступенчатой,
  тогда СН был бы перцептроном,
  поскольку у него на выходе наблюдались бы 0 или 1
  в зависимости от знака w ? x + b
  (ну, на самом деле при z = 0 перцептрон выдаёт 0,
  а ступенчатая функция - 1,
  так что в одной этой точке функцию пришлось бы поменять).
  
  Используя реальную функцию ?, мы получаем сглаженный перцептрон.
  И главным тут является гладкость функции,
  а не её точная форма.
  Гладкость означает, что небольшие изменения ?wj весов и ?b
  смещений дадут небольшие изменения ?output выходных данных.
  //// Вот где-то в этом месте неявно "кувалдой вбивается в сознание"
  //// что если уж у нас используются только сигмоидные нейроны,
  //// то это гарантия того, что "гладкость" гарантируется
  //// для всего поведения нейросети, точнее, ее внутренних данных.
  //// Это такая "ложная аксиома", о которой практически никто и не упоминает.
  //// Во всяком случае, во многих обучающих курсах об этом нет ни слова.
  
  Алгебра говорит нам, что ?output хорошо аппроксимируется так:
  
  ......
  
  Где суммирование идёт по всем весам wj,
  а ?output/?wj и ?output/?b обозначают
  частные производные выходных данных по wj и b соответственно.
  Не паникуйте, если чувствуете себя неуверенно в компании частных производных!
  Хотя формула и выглядит сложной, со всеми этими частными производными,
  на самом деле она говорит нечто совсем простое (и полезное):
  ?output - это линейная функция, зависящая от ?wj и ?b весов и смещения.
  //// Еще раз напоминаю, что это "суммирование" ключевой принцип
  //// и самого перцептрона/нейрона и всей концепции нейросети.
  Её линейность облегчает выбор небольших изменений весов
  и смещений для достижения любого желаемого небольшого смещения выходных данных.
  Так что, хотя по качественному поведению СН похожи на перцептроны,
  они облегчают понимание того,
  как можно изменить выход, меняя веса и смещения.
  
  ........
  
  Если для нас имеет значение общая форма ?,
  а не её точный вид, то почему мы используем именно такую формулу (3)?
  На самом деле позднее мы иногда будем рассматривать нейроны,
  выход которых равняется f(w ? x + b),
  где f() - некая другая функция активации.
  Главное, что меняется при смене функции - значения частных производных
  в уравнении (5).
  Оказывается, что когда мы потом подсчитываем эти частные производные,
  использование ? сильно упрощает алгебру,
  поскольку у экспонент есть очень приятные свойства при дифференцировании.
  В любом, случае, ? часто используется в работе с нейросетями,
  и чаще всего в этой книге мы будем использовать такую функцию активации.
  
  Как интерпретировать результат работы СН? Очевидно,
  главным различием между перцептронами и СН будет то,
  что СН не выдают только 0 или 1.
  Их выходными данными может быть любое вещественное число от 0 до 1,
  так что значения типа 0,173 или 0,689 являются допустимыми.
  Это может быть полезно, к примеру,
  если вам нужно, чтобы выходное значение обозначало,
  к примеру, среднюю яркость пикселей изображения,
  поступившего на вход НС.
  Но иногда это может быть неудобно.
  Допустим, мы хотим, чтобы выход сети говорил о том,
  что <на вход поступило изображение 9>
  или <входящее изображение не 9>.
  Очевидно, проще было бы, если бы выходные значения были 0 или 1,
  как у перцептрона.
  Но на практике мы можем договориться, что любое выходное значение
  не меньше 0,5 обозначало бы <9> на входе,
  а любое значение меньше 0,5, обозначало бы, что это <не 9>.
  //// Надо отметить, что переход к таким непрерывным значениям нейронов,
  //// это не только ограничение их возможностей в одном качестве,
  //// но и, наоборот, расширение их возможностей в другом качестве,
  //// например, указание соответствующей "яркости пикселей",
  //// или представив это значение как "координату" или "вероятность",
  //// но об этом более подробно будет существенно ниже,
  //// так как там тоже есть свои "подводные камни" и их немало.
  
  //// "Нет худа, без добра" и наоборот.
  //// Нужно только правильно использовать разные возможности
  //// для решения конкретных задач,
  //// а не пытаться все задачи решать одним и тем же "молотком",
  //// что, к сожалению, наблюдается слишком часто.
  //// Но для этого требуется уже не "знание", а "понимание".
  
  ......
  
  Архитектура нейросетей
  
  ......
  
  Как я уже упоминал, самый левый слой в сети называется входным слоем,
  а его нейроны - входными нейронами.
  Самый правый, или выходной слой, содержит выходные нейроны,
  или, как в нашем случае, один выходной нейрон.
  Средний слой называется скрытым,
  поскольку его нейроны не являются ни входными, ни выходными.
  Термин <скрытый>, возможно, звучит немного загадочно
  - впервые услышав его, я решил, что у него должна быть
  некая глубокая философская или математическая важность
  - однако он означает лишь <не вход и не выход>.
  У сети выше есть только один скрытый слой,
  но у некоторых сетей есть по нескольку скрытых слоёв.
  
  .......
  
  Это может сбивать с толку,
  но по историческим причинам такие сети с несколькими слоями
  иногда называют многослойными перцептронами, MLP,
  несмотря на то, что они состоят из сигмоидных нейронов, а не перцептронов.
  
  ......
  
  И если проектирование входных и выходных слоёв часто является простой задачей,
  то проектирование скрытых слоёв может оказаться сложным искусством.
  В частности, невозможно описать процесс разработки скрытых слоёв
  при помощи нескольких простых практических правил.
  //// Т.е. даже составители учебников по нейросетям, а не только студенты,
  //// не знают каких-то действительно теоретически обоснованных рекомендаций.
  //// Говорят, что теория проверяется практикой,
  //// а что говорить, когда теория не дает практических рекомендаций?
  Исследователи НС разработали множество эвристических правил
  проектирования скрытых слоёв, помогающих получать нужное поведение нейросетей.
  К примеру, такую эвристику можно использовать, чтобы понять,
  как достичь компромисса между количеством скрытых слоёв
  и временем, доступным для обучения сети.
  
  ........
  
  Пока что мы обсуждали НС, в которых выходные данные одного слоя
  используются в качестве входных для следующего.
  Такие сети называются нейросетями прямого распространения.
  Это значит, что в сети нет петель - информация всегда проходит вперёд,
  и никогда не скармливается назад.
  Если бы у нас были петли, мы бы встречали ситуации,
  в которых входные данные сигмоиды зависели бы от выходных.
  Это было бы тяжело осмыслить, и таких петель мы не допускаем.
  //// Еще одно ограничение на "произвольный характер функций",
  //// потенциально реализуемых обучаемой нейросетью.
  
  Однако существуют и другие модели искусственных НС,
  в которых возможно использовать петли обратной связи.
  Эти модели называются рекуррентными нейронными сетями (РНС).
  Идея этих сетей в том, что их нейроны активируются
  на ограниченные промежутки времени.
  Эта активация может стимулировать другие нейтроны,
  которые могут активироваться чуть позже,
  также на ограниченное время.
  Это приводит к активации следующих нейронов,
  и со временем мы получаем каскад активированных нейронов.
  Петли в таких моделях не представляют проблем,
  поскольку выход нейрона влияет на его вход
  в некий более поздний момент,
  а не сразу.
  //// А как их обучают?
  
  РНС были не такими влиятельными, как НС прямого распространения,
  в частности потому, что обучающие алгоритмы для РНС
  пока что обладают меньшими возможностями.
  Однако РНС всё равно остаются чрезвычайно интересными.
  По духу работы они гораздо ближе к мозгу,
  чем НС прямого распространения.
  Возможно, что РНС смогут решить важные задачи,
  которые при помощи НС прямого распространения решаются с большими сложностями.
  Однако чтобы ограничить область нашего изучения,
  мы сконцентрируемся на более широко применяемых НС прямого распространения.
  
  Простая сеть классификации рукописных цифр
  
  .......
  
  В выходном слое сети 10 нейронов.
  Если активируется первый нейрон, то есть, его выходное значение ? 1,
  это говорит о том, что сеть считает, что на входе был 0.
  Если активируется второй нейрон, сеть считает, что на входе был 1.
  И так далее.
  Строго говоря, мы нумеруем выходные нейроны от 0 до 9,
  и смотрим, у какого из них значение активации было максимальным.
  Если это, допустим, нейрон ?6, тогда наша сеть считает,
  что на входе была цифра 6.
  И так далее.
  
  Вы можете задуматься над тем, зачем нам использовать десять нейронов.
  Ведь мы же хотим узнать, какой цифре от 0 до 9
  соответствует входное изображение.
  Естественно было бы использовать всего 4 выходных нейрона,
  каждый из которых принимал бы двоичное значение
  в зависимости от того, ближе его выходное значение к 0 или 1.
  Четырёх нейронов будет достаточно,
  поскольку 2*4=16,
  больше, чем 10 возможных значений.
  Зачем нашей сети использовать 10 нейронов?
  Это ведь неэффективно?
  Основание для этого эмпирическое;
  мы можем попробовать оба варианта сети,
  и окажется, что для данной задачи сеть с 10-ю выходными нейронами
  лучше обучается распознавать цифры,
  чем сеть с 4-мя.
  //// Как раз о таких случая и упоминалось в тезисе
  //// о сложности обучения нейросетей с нелинейными характеристиками.
  //// Причем именно о сложности, а не о невозможности такое сделать.
  //// Просто такая сеть будет либо работать много хуже,
  //// либо должна быть большего "масштаба", либо и то и другое вместе,
  //// и, в любом случае, дольше обучаема.
  Однако остаётся вопрос, почему же 10 выходных нейронов лучше.
  Есть ли какая-то эвристика,
  которая заранее сказала бы нам,
  что следует использовать 10 выходных нейронов вместо 4?
  
  Чтобы понять, почему, полезно подумать о том, что делает нейросеть.
  Рассмотрим сначала вариант с 10 выходными нейронами.
  Сконцентрируемся на первом выходном нейроне,
  который пытается решить,
  является ли входящее изображение нулём.
  Он делает это, взвешивая свидетельства, полученные из скрытого слоя.
  А что делают скрытые нейроны?
  Допустим, первый нейрон в скрытом слое определяет,
  есть ли на картинке что-то вроде такого:
  
  .......
  
  Делать это он может, назначая большие веса пикселям,
  совпадающим с этим изображением,
  и малые веса остальным.
  Точно так же допустим, что второй, третий и четвёртый нейроны
  в скрытом слое ищут, есть ли на изображении подобные фрагменты:
  
  .......
  
  Как вы могли догадаться, все вместе эти четыре фрагмента
  дают изображение 0,
  которое мы видели ранее:
  
  .......
  
  Итак, если четыре скрытых нейрона активируются,
  мы можем заключить, что цифра равна 0.
  Конечно, это не единственное свидетельство того, что там был изображён 0
  - мы можем получить 0 и множеством других способов
  (немного сдвигая указанные изображения или слегка искажая их).
  Однако можно точно сказать, что, по крайней мере,
  в этом случае мы можем заключить, что на входе был 0.
  
  Если предположить, что сеть работает так,
  можно дать правдоподобное объяснение тому,
  почему лучше использовать 10 выходных нейронов вместо 4.
  Если бы у нас было 4 выходных нейрона,
  тогда первый нейрон пытался бы решить,
  каков самый старший бит у входящей цифры.
  И нет простого способа связать самый старший бит с простыми формами,
  приведёнными выше.
  Сложно представить какие-то исторические причины,
  по которым части формы цифры были бы как-то связаны
  с самым старшим битом выходных данных.
  //// Хорошая иллюстрация. Очень рекомендую ее внимательно продумать.
  //// И почувствовать, как часто подобные ситуации возникают
  //// в работе и обучении более сложных нейросетей.
  
  Однако всё вышесказанное подкрепляется только эвристикой.
  Ничто не говорит в пользу того,
  что трёхслойная сеть должна работать так, как я сказал,
  а скрытые нейроны должны находить простые компоненты форм.
  Возможно, хитрый алгоритм обучения
  найдёт какие-нибудь значения весов,
  которые позволят нам использовать только 4 выходных нейрона.
  Однако в качестве эвристики мой способ работает неплохо,
  и может сэкономить вам значительное время
  при разработке хорошей архитектуры НС.
  //// Вот и еще одна иллюстрации того самого "вбитого кувалдой в мозг"
  //// представления входа нейрона как суммы непрерывных величин,
  //// и, соответствующего, желания оставить все как привычно/принято
  //// за счет какого-то "хитрого алгоритма обучения".
  //// Это не значит, что такого алгоритма нельзя придумать,
  //// просто в технике обычно такие задачи "в лоб" решаются очень редко,
  //// и куда чаще решение находится на "обходном пути".
  
  Упражнения
  
  Существует способ определить побитовое представление числа,
  добавив дополнительный слой к трёхслойной сети.
  Дополнительный слой преобразует выходные значения предыдущего слоя
  в двоичный формат, как показано на рисунке ниже.
  Найдите наборы весов и смещений для нового выходного слоя.
  Предполагаем, что первые 3 слоя нейронов таковы,
  что правильный выход с третьего слоя (бывший выходной слой)
  активируется значениями не менее 0,99,
  а неправильные выходные значения не превышают 0,01.
  //// А это как раз пример нейросети которая,
  //// может решать поставленную задачу,
  //// если нужные веса будут установлены принудительно.
  //// А вот то, что они могут в такой сети быть получены в результате обучения,
  //// лично у меня, вызывает большие сомнения. Слышать о подобном не приходилось.
  //// Но могу и ошибаться. Мало ли чудес бывает в этом мире.
  
  Обучение с градиентным спуском
  
  Итак, у нас есть схема НС - как ей обучиться распознавать цифры?
  Первое, что нам понадобится - это обучающие данные,
  т.н. набор обучающих данных.
  
  .......
  
  Нам хочется найти алгоритм, позволяющим нам искать
  такие веса и смещения,
  чтобы выход сети приближался к y(x) для всех обучающих входных х.
  Чтобы количественно оценить приближение к этой цели,
  определим функцию стоимости
  (иногда называемую функцией потерь;
  в книге мы будем использовать функцию стоимости,
  однако имейте в виду и другое название):
  
  $ C(w, b) = \frac{1}{2n} \sum_x || y(x) - a ||^2 \tag{6} $
  
  Здесь
  w обозначает набор весов сети,
  b - набор смещений,
  n - количество обучающих входных данных,
  a - вектор выходных данных, когда х - входные данные,
  а сумма проходит по всем обучающим входным данным х.
  Выход, конечно, зависит от x, w и b,
  но для простоты я не стал обозначать эту зависимость.
  Обозначение ||v|| означает длину вектора v.
  Мы будем называть C квадратичной функцией стоимости;
  иногда её ещё называют среднеквадратичной ошибкой,
  или MSE.
  Если присмотреться к C, видно, что она не отрицательна,
  поскольку все члены суммы неотрицательны.
  Кроме того, стоимость C(w,b) становится малой,
  то есть, C(w,b) ? 0, именно тогда,
  когда y(x) примерно равна выходному вектору a
  у всех обучающих входных данных х.
  Так что наш алгоритм сработал хорошо,
  если сумел найти веса и смещения такие, что C(w,b) ? 0.
  И наоборот, сработал плохо, когда C(w,b) большая
  - это означает, что y(x) не совпадает с выходом
  для большого количества входных данных.
  Получается, цель обучающего алгоритма
  - минимизация стоимости C(w,b) как функции весов и смещений.
  Иначе говоря, нам нужно найти набор весов и смещений,
  минимизирующий значение стоимости.
  Мы будем делать это при помощи алгоритма под названием градиентный спуск.
  
  Зачем нам нужна квадратичная стоимость?
  Разве нас не интересует в основном
  количество правильно распознанных сетью изображений?
  Нельзя ли просто максимизировать это число напрямую,
  а не минимизировать промежуточное значение квадратичной стоимости?
  //// Очень интересный вопрос. И он не такой уж однозначный.
  Проблема в том,
  что количество правильно распознанных изображений
  не является гладкой функцией весов и смещений сети.
  По большей части, небольшие изменения весов и смещений
  не изменят количество правильно распознанных изображений.
  Из-за этого тяжело понять,
  как менять веса и смещения для улучшения эффективности.
  Если же мы будем использовать гладкую функцию стоимости,
  нам будет легко понять,
  как вносить небольшие изменения в веса и смещения,
  чтобы улучшать стоимость.
  Поэтому мы сначала сконцентрируемся на квадратичной стоимости,
  а потом уже изучим точность классификации.
  //// Т.е. в интерпретации этого автора все дело в "гладкости".
  //// А, может быть, дело в непрерывности процесса обучения,
  //// так как большую часть обучения "стоимость" будет не нулевой.
  //// А так при дискретном обучении, непонятно что делать
  //// при отсутствии ошибки?
  //// Т.е. это все опять "завязывается" на метод обучения,
  //// но ни как не привязан к решаемой задаче и структуре нейросети.
  
  Даже учитывая то, что мы хотим использовать гладкую функцию стоимости,
  вы всё равно можете интересоваться
  - почему мы выбрали квадратичную функцию для уравнения (6)?
  Разве её нельзя выбрать произвольно?
  Возможно, если бы мы выбрали другую функцию,
  мы бы получили совершенно другой набор минимизирующих весов и смещений?
  Разумный вопрос, и позднее мы вновь изучим функцию стоимости
  и внесём в неё некоторые правки.
  Однако квадратичная функция стоимости прекрасно работает
  для понимания базовых вещей в обучении НС,
  поэтому пока мы будем придерживаться её.
  //// Есть еще один аргумент в пользу "квадратичной функции стоимости",
  //// который автор не упоминает, может быть, считая самоочевидным.
  //// Квадратичная и, вообще, степенная функция обеспечивает
  //// как бы автоматическую "подстройку" шага изменения обучаемых весов
  //// к величине ошибки, теоретически существенно ускоряя обучение.
  //// Но опять же, наверняка, за счет чего-то другого.
  //// И хотелось бы точно понимать, что действительно ухудшает
  //// выбор такой "квадратичной зависимости".
  
  Подведём итог:
  наша цель в обучении НС сводится к поиску весов и смещений,
  минимизирующих квадратичную функцию стоимости C(w, b).
  Задача хорошо поставлена,
  однако пока что у неё есть много отвлекающих структур
  - интерпретация w и b как весов и смещений,
  притаившаяся на заднем плане функция ?,
  выбор архитектуры сети,
  MNIST и так далее.
  Оказывается, что мы очень многое можем понять,
  игнорируя большую часть этой структуры,
  и концентрируясь только на аспекте минимизации.
  Так что пока мы забудем об особой форме функции стоимости,
  связи с НС и так далее.
  Вместо этого мы собираемся представить,
  что у нас просто есть функция со многими переменными,
  и мы хотим её минимизировать.
  Мы разработаем технологию под названием градиентный спуск,
  которую можно использовать для решения таких задач.
  А потом мы вернёмся к определённой функции,
  которую хотим минимизировать для НС.
  
  Хорошо, допустим, мы пытаемся минимизировать некую функцию C(v).
  Это может быть любая функция
  с вещественными значениями от многих переменных v = v1, v2,:
  Заметьте, что я заменил запись w и b на v,
  чтобы показать, что это может быть любая функция
  - мы уже не зацикливаемся на НС.
  Полезно представлять себе, что у функции C есть только две переменных
  - v1 и v2:
  
  Мы бы хотели найти, где C достигает глобального минимума.
  
  ......
  
  Один из способов решения задачи - использовать алгебру
  для поиска минимума аналитическим путём.
  Мы можем вычислить производные и попытаться использовать их
  для поиска экстремума.
  Если нам повезёт, это сработает,
  когда С будет функцией от одной-двух переменных.
  Но при большом количестве переменных это превращается в кошмар.
  А для НС нам часто нужно гораздо больше переменных
  - у крупнейших НС функции стоимости сложным образом зависят
  от миллиардов весов и смещений.
  Использовать алгебру для минимизации этих функций не получится!
  
  .......
  
  Ладно, значит, алгебра не сработает.
  К счастью, существует прекрасная аналогия,
  предлагающая хорошо работающий алгоритм.
  Мы представляем себе нашу функцию чем-то вроде долины.
  С последним графиком это будет не так сложно сделать.
  И мы представляем себе шар, катящийся по склону долины.
  Наш опыт говорит нам, что шар в итоге скатится на самый низ.
  Возможно, мы можем использовать эту идею
  для поиска минимума функции?
  Мы случайным образом выберем начальную точку для воображаемого шара,
  а потом симулируем движение шара,
  как будто он скатывается на дно долины.
  Эту симуляцию мы можем использовать просто подсчитывая производные
  (и, возможно, вторые производные) С
  - они скажут нам всё о локальной форме долины,
  и, следовательно, о том, как наш шарик будет катиться.
  //// Все прекрасно в этой аналогии,
  //// кроме обоснования почему "ландшафтная парадигма"
  //// соответствует искомой задаче,
  //// а не какой-то "многоуровневый лабиринт",
  //// в котором такой "колобок" таким образом далеко не убежит.
  //// Т.е. вопрос в "неявной аксиоме" лежащей в основе такого подхода.
  
  ......
  
  ...давайте зададим вопрос:
  если бы нас назначили богом на один день,
  и мы создавали бы свои законы физики, говоря шару,
  как ему катиться
  какой закон или законы движения мы бы выбрали,
  чтобы шар всегда скатывался на дно долины?
  
  Чтобы уточнить вопрос, подумаем, что произойдёт,
  если мы передвинем шар на небольшое расстояние ?v1 в направлении v1,
  и на небольшое расстояние ?v2 в направлении v2.
  Алгебра говорит нам, что С меняется следующим образом:
  
  $ \Delta C \approx \frac{\partial C}{\partial v_1} \Delta v_1 + \frac{\partial C}{\partial v_2} \Delta v_2 \tag{7} $
  
  Мы найдем способ выбора таких ?v1 и ?v2, чтобы ?C была меньше нуля;
  то есть, мы будем выбирать их так,
  чтобы шар катился вниз.
  Чтобы понять, как это сделать, полезно определить ?v как вектор изменений,
  то есть ?v ? (?v1, ?v2)T,
  где Т - операция транспонирования,
  превращающая векторы-строки в векторы-столбцы.
  Мы также определим градиент С как вектор частных производных (?С/ ?v1, ?С/?v2)T.
  Обозначать градиентный вектор мы будем ?С:
  
  $ \nabla C \equiv (\frac{\partial C}{\partial v_1}, \frac{\partial C}{\partial v_2})^T \tag{8} $
  
  Скоро мы перепишем изменение ?C через ?v и градиент ?C.
  А пока я хочу прояснить кое-что, из-за чего люди часто подвисают на градиенте.
  Впервые встретившись с записью ?C,
  люди иногда не понимают, как они должны воспринимать символ ?.
  Что он конкретно означает?
  На самом деле можно спокойно считать ?С единым математическим объектом
  - определённым ранее вектором -
  который просто записывается с использованием двух символов.
  С этой точки зрения, ? - это как размахивать флагом,
  сообщающим о том, что "?С - это градиентный вектор".
  Существуют и более продвинутые точки зрения,
  с которых ? можно рассматривать,
  как независимую математическую сущность
  (к примеру, как оператор дифференцирования),
  однако нам они не понадобятся.
  
  С такими определениями выражение (7) можно переписать, как:
  
  $ \Delta C \approx \nabla C \cdot \Delta v \tag{9} $
  
  Это уравнение помогает объяснить,
  почему ?C называют градиентным вектором:
  он связывает изменения в v с изменениями С,
  именно так, как и ожидается от сущности под названием градиент.
  [англ. gradient - отклонение / прим. перев.]
  Однако более интересно, что это уравнение позволяет нам увидеть,
  как выбрать ?v так, чтобы ?C было отрицательным.
  
  ......
  
  Поэтому мы возьмём уравнение (10)
  для определения <закона движения> шара в нашем алгоритме градиентного спуска.
  То есть, мы будем использовать уравнение (10) для вычисления значения ?v,
  а потом будем двигать шар на это значение:
  
  $ v \rightarrow v' = v - \eta \nabla C \tag{11} $
  
  Потом мы снова применим это правило, для следующего хода.
  Продолжая повторение, мы будем понижать С,
  пока,
  как мы надеемся,
  не достигнем глобального минимума.
  
  Подытоживая, градиентный спуск работает
  через последовательное вычисление градиента ? C,
  и последующее смещение в противоположном направлении,
  что приводит к <падению> по склону долины.
  Визуализировать это можно так:
  
  .......
  
  Чтобы градиентный спуск работал правильно,
  нам нужно выбрать достаточно малое значение скорости обучения ?,
  чтобы уравнение (9) было хорошей аппроксимацией.
  В противном случае может получиться, что ?C > 0 - ничего хорошего!
  В то же время, не нужно, чтобы ? была слишком маленькой,
  поскольку тогда изменения ?v будут крохотными,
  и алгоритм будет работать слишком медленно.
  На практике ? меняется так,
  чтобы уравнение (9) давало неплохую аппроксимацию,
  и при этом алгоритм работал не слишком медленно.
  Позднее мы увидим, как это работает.
  
  Я объяснял градиентный спуск,
  когда функция С зависела только от двух переменных.
  Но всё работает так же, если С будет функцией от многих переменных.
  //// Есть ощущение, что в случае ОЧЕНЬ МНОГИХ переменных,
  //// какие-то "незначительные факторы", типа линеаризации,
  //// допущения о независимости самих переменных,
  //// отбрасывания производных высших порядков и др.,
  //// которыми можно пренебрегать при малом количестве переменных,
  //// становятся СУЩЕСТВЕННО ЗНАЧИМЕЙ с соответствующими последствиями.
  //// Но это так - мысли вслух.
  
  .......
  
  В каком-то смысле градиентный спуск можно считать
  оптимальной стратегией поиска минимума.
  Допустим, что мы пытаемся сдвинуться на ?v в позицию
  для максимального уменьшения С.
  Это эквивалентно минимизации ?C ? ?C ? ?v.
  Мы ограничим размер шага так, чтобы ||?v|| = ?
  для некоего малого постоянного ? > 0.
  Иначе говоря, мы хотим сдвинуться на небольшое расстояние
  фиксированного размера,
  и пытаемся найти направление движение,
  уменьшающее С так сильно, как это возможно.
  Можно доказать, что выбор ?v, минимизирующий ?C ? ?v,
  равняется ?v = -??C, где ? = ?/||?C||,
  определяется ограничением ||?v|| = ?.
  Так что градиентный спуск можно считать способом
  делать небольшие шаги в направлении,
  наиболее сильно уменьшающем С.
  
  ........
  
  Люди изучили множество вариантов градиентного спуска,
  включая и те, что более точно воспроизводят реальный физический шар.
  У таких вариантов есть свои преимущества,
  но и большой недостаток:
  необходимость вычисления вторых частных производных С,
  что может отнимать много ресурсов.
  Чтобы понять это, допустим, что нам надо вычислить
  все вторые частные производные ?2C / ?vj?vk.
  Если переменных vj миллион,
  тогда нам нужно вычислить примерно триллион (миллион в квадрате)
  вторых частных производных
  (на самом деле, полтриллиона, поскольку ?2C / ?vj?vk = ?2C / ?vk?vj.
  Но суть вы уловили).
  Это потребует много вычислительных ресурсов.
  Есть трюки, помогающие избежать этого,
  и поиск альтернатив градиентного спуска является
  областью активных исследований.
  Однако в этой книге мы будем использовать градиентный спуск и его варианты
  в качестве основного подхода к обучению НС.
  
  Как нам применить градиентный спуск к обучению НС?
  Нам нужно использовать его для поиска весов wk и смещений bl,
  минимизирующих уравнение стоимости (6).
  Давайте перезапишем правило обновления градиентного спуска,
  заменив переменные vj весами и смещениями.
  Иначе говоря, теперь у нашей <позиции> есть компоненты wk и bl,
  а у градиентного вектора ?C есть соответствующие компоненты ?C/?wk и ?C/?bl.
  Записав наше правило обновления с новыми компонентами, мы получим:
  
  ......
  
  Повторно применяя это правило обновления, мы можем <катиться под горку>,
  и, если повезёт, найти минимум функции стоимости.
  Иначе говоря, это правило можно использовать для обучения НС.
  
  Применению правила градиентного спуска есть несколько препятствий.
  Подробнее мы изучим их в следующих главах.
  Но пока я хочу упомянуть только одну проблему.
  Чтобы понять её, давайте вернёмся к квадратичной стоимости в уравнении (6).
  Заметьте, что эта функция стоимости выглядит, как C = 1/n ?x Cx,
  то есть это среднее по стоимости Cx ? (||y(x)?a||2)/2
  для отдельных обучающих примеров.
  На практике для вычисления градиента ?C нам нужно вычислять градиенты ?Cx
  отдельно для каждого обучающего входа x,
  а потом усреднять их, ?C = 1/n ?x ?Cx.
  К сожалению, когда количество входных данных будет очень большим,
  это займёт очень много времени,
  и такое обучение будет проходить медленно.
  
  Для ускорения обучения можно использовать стохастический градиентный спуск.
  Идея в том, чтобы приблизительно вычислить градиент ?C,
  вычислив ?Cx для небольшой случайной выборки обучающих входных данных.
  Посчитав их среднее, мы можем быстро получить
  хорошую оценку истинного градиента ?C,
  и это помогает ускорить градиентный спуск,
  и, следовательно, обучение.
  //// Вот тут, честно признаюсь, в данный момент у меня какое-то непонимание,
  //// чем отличается "правильный градиентный спуск" от "стохастического".
  //// Что ж придется разбираться. Может быть, надо и с Copilot проконсультироваться.
  
  //// Смысл моего недопонимания "правильного градиентного спуска" в том,
  //// что в моем понимании это классический "сферический конь в вакууме".
  //// Т.е. красивая концепция не имеющая в данной задаче практического смысла.
  //// И дело даже не в том, что нужно на каждом шаге "спуска" делать
  //// колоссальные вычисления по всем обучающим данным,
  //// включая еще, возможно, не известные при "дообучении",
  //// о чем говорит автор.
  
  //// Дело в "ландшафтной концепции" представления задачи,
  //// для которой пытаются применить градиентный спуск.
  //// Сама по себе "ландшафтная концепция" предполагает какой-то
  //// ФИКСИРОВАННЫЙ "ландшафт" решения задачи.
  //// Одновременно с этим вычисление частных производных градиента
  //// предполагает фиксированность большей части весов при этом вычислении.
  //// Иначе "расчетчики сойдут с ума" в попытке учесть все возможные
  //// последствия изменений.
  //// Это, надеюсь, достаточно понятно.
  
  //// А вот то, что "ландшафт" задачи обучения весов нейросети
  //// является отнюдь не фиксированным, а "зыбучим",
  //// изменяющимся при каждом новом обучающем примере,
  //// уже далеко не так очевидно.
  //// Это даже без различных нелинейностей в активационных функциях нейронов.
  //// Тут лучше бы работала "концепция лабиринта",
  //// в котором есть еще и "открывающиеся/закрывающиеся порталы",
  //// при прохождении определенного отрезка маршрута.
  
  //// Связано это, в первую очередь, со сложной структурой значений
  //// элементов эмбеддинга и самим процессом обучения.
  //// И это отдельный и очень длинный разговор. Если интересно, см.:
  //// "Металоция неведомого. Модуль Э. Эмбеддинги."
  
  //// А в данном контексте важно понимать,
  //// что ЛЮБОМ изменении весов нейронов "ландшафт" может необратимо измениться,
  //// и вычислять "правильный градиент" СМЫСЛА НЕТ.
  //// Собственно этого никто "находясь в здравом уме и трезвой памяти"
  //// делать даже не пытается, а молчаливо используют "стохастический градиент".
  //// А "правильный градиент" используют только в "умных текстах".
  
  Формулируя более точно, стохастический градиентный спуск
  работает через случайную выборку
  небольшого количества m обучающих входных данных.
  Мы назовём эти случайные данные X1, X2,.., Xm,
  и назовём их мини-пакетом.
  Если размер выборки m будет достаточно большим,
  среднее значение ?CXj будет достаточно близким к среднему по всем ?Cx,
  то есть
  
  $ \frac{\sum^m_{j=1} \nabla C_{X_j}}{m} \approx \frac{\sum_x \nabla C_x}{n} = \nabla C \tag{18} $
  
  где вторая сумма идёт по всему набору обучающих данных.
  Поменяв части местами, мы получим
  
  $ \nabla C \approx \frac{1}{m} \sum^m_{j=1} \nabla C_{X_j} \tag{19} $
  
  что подтверждает, что мы можем оценить общий градиент,
  вычислив градиенты для случайно выбранного мини-пакета.
  
  Чтобы связать это непосредственно с обучением НС,
  допустим, что wk и bl обозначают веса и смещения нашей НС.
  Тогда стохастический градиентный спуск выбирает
  случайный мини-пакет входных данных, и обучается на них
  
  $ w_k \rightarrow w'_k = w_k - \frac{\eta}{m} \sum_j \frac{\partial C_{X_j}}{\partial w_k} \tag{20} $
  
  $ b_l \rightarrow b'_l = b_l - \frac{\eta}{m} \sum_j \frac{\partial C_{X_j}}{\partial b_l} \tag{21} $
  
  где идёт суммирование по всем обучающим примерам Xj в текущем мини-пакете.
  Затем мы выбираем ещё один случайный мини-пакет и обучаемся на нём.
  И так далее, пока мы не исчерпаем все обучающие данные,
  что называется окончанием обучающей эпохи.
  В этот момент мы начинаем заново новую эпоху обучения.
  //// Интересно, есть какие-то исследования по теме оптимального выбора
  //// размера "мини-пакета"?
  
  Кстати, стоит отметить,
  что соглашения по поводу масштабирования функции стоимости и обновлений весов
  и смещений мини-пакетом разнятся.
  В уравнении (6) мы масштабировали функцию стоимости в 1/n раз.
  Иногда люди опускают 1/n,
  суммируя стоимости отдельных обучающих примеров,
  вместо вычисления среднего.
  Это полезно, когда общее количество обучающих примеров заранее неизвестно.
  Такое может случиться,
  например, когда дополнительные данные появляются в реальном времени.
  Таким же образом правила обновления мини-пакета (20) и (21)
  иногда опускают член 1/m перед суммой.
  Концептуально это ни на что не влияет,
  поскольку это эквивалентно изменению скорости обучения ?.
  Однако на это стоит обращать внимание при сравнении различных работ.
  
  Стохастический градиентный спуск можно представлять себе,
  как политическое голосование:
  гораздо проще взять выборку в виде мини-пакета,
  чем применить градиентный спуск к полной выборке
  - точно так же, как опрос на выходе из участка провести проще,
  чем провести полноценные выборы.
  К примеру, если наш обучающий набор имеет размер n = 60 000, как MNIST,
  и мы сделаем выборку мини-пакета размером m = 10,
  то в 6000 раз ускорит оценку градиента!
  Конечно, оценка не будет идеальной
  - в ней будет статистическая флуктуация -
  но ей и не надо быть идеальной:
  нам лишь надо двигаться в примерно том направлении,
  которое уменьшает С,
  а это значит, что нам не нужно точно вычислять градиент.
  На практике стохастический градиентный спуск
  - распространённая и мощная техника обучения НС,
  и база большинства обучающих технологий,
  которые мы разработаем в рамках книги.
  
  .......
  
  Реализация сети для классификации цифр
  
  .......
  
  Из этого стоит вынести урок о том,
  что отладка НС не является тривиальной задачей,
  и это, как и обычное программирование, частью искусство.
  //// Программирование это не искусство - это инженерная дисциплина.
  //// Причем с ударением на оба слова сразу,
  //// а "дисциплина" строго по классику - "как осознанная необходимость".
  //// Это я за 45 лет выучил на собственной шкуре,
  //// хотя тоже начинал с "классики",
  //// с того самого трехтомника Кнута "Искусство программирования".
  Вы должны обучиться этому искусству отладки,
  //// Это тоже должна быть "дисциплина", а не "искусство"
  //// и, тем более "шаманство".
  чтобы получать хорошие результаты от НС.
  В целом, нам необходимо выработать эвристику
  для выбора хороших гиперпараметров и хорошей архитектуры.
  
  .......
  
  Обычно программисты считают,
  что для решения подобной сложной задачи
  требуется сложный алгоритм.
  Но даже НС в работе-рекордсмене используют довольно простые алгоритмы,
  являющиеся небольшими вариациями тех, что мы рассмотрели в этой главе.
  Вся сложность автоматически появляется во время обучения
  на основе обучающих данных.
  В каком-то смысле, мораль наших результатов и тех,
  что содержатся в более сложных работах, в том, что для некоторых задач
  
  сложный алгоритм <= простой алгоритм обучения + хорошие обучающие данные
  
  К глубокому обучению
  
  Хотя наша сеть демонстрирует впечатляющую эффективность,
  достигается она загадочным способом.
  Веса и смешения сети автоматически обнаруживаются.
  Значит, у нас нет готового объяснения того,
  как сеть делает то, что делает.
  Можно ли найти какой-то способ понять базовые принципы
  классификации сетью рукописных цифр?
  И можно ли, учитывая их, улучшить результат?
  
  Переформулируем эти вопросы более жёстко:
  допустим, что через несколько десятилетий НС превратятся
  в искусственный интеллект (ИИ).
  Поймём ли мы, как этот ИИ работает?
  Возможно, сети останутся непонятными для нас,
  с их весами и смещениями, поскольку они назначаются автоматически.
  В ранние годы исследований ИИ люди надеялись,
  что попытки создания ИИ также помогут нам понять принципы,
  лежащие в основе интеллекта, и, может быть,
  даже работы человеческого мозга.
  Однако в итоге может оказаться,
  что мы не будем понимать ни мозг,
  ни то, как работает ИИ!
  
  Чтобы разобраться с этими вопросами,
  давайте вспомним об интерпретации искусственных нейронов,
  данной мною в начале главы
  - что это способ взвешивать свидетельства.
  Допустим, мы хотим определить, есть ли на изображении лицо человека:
  
  К этой проблеме можно подходить так же,
  как к распознаванию рукописного ввода:
  используя пиксели изображений в качестве входных данных для НС,
  а на выходе НС будет один нейрон, который будет говорить,
  <Да, это лицо>, или <Нет, это не лицо>.
  
  Допустим, мы сделаем это, но не используя алгоритм обучения.
  Мы попробуем вручную создать сеть,
  выбирая подходящие веса и смещения.
  Как мы можем к этому подступиться?
  Забыв на минуту о НС, мы могли бы разбить задачу на подзадачи:
  есть ли у изображения глаз в левом верхнем углу?
  Есть ли глаз в правом верхнем углу?
  Есть ли посередине нос?
  Есть ли внизу посередине рот?
  Есть ли вверху волосы? И так далее.
  
  Если ответы на несколько из этих вопросов положительные,
  или даже <вероятно, да>,
  тогда мы заключаем, что на изображении, возможно, есть лицо.
  И наоборот, если ответы отрицательные, то лица, вероятно, нет.
  
  Это, конечно, примерная эвристика,
  и у неё множество недостатков.
  Возможно, это лысый человек, и у него нет волос.
  Возможно, нам видна только часть лица, или лицо под углом,
  так что некоторые части лица закрыты.
  И всё же эвристика говорит о том, ч
  то если мы можем решить подзадачи при помощи нейросетей,
  то, возможно, мы можем создать НС для распознавания лиц,
  комбинируя сети для подзадач.
  Ниже приведена возможная архитектура такой сети,
  в которой прямоугольниками обозначены подсети.
  Это не совсем реалистичный подход к решению задачи распознавания лиц:
  он нужен, чтобы помочь нам интуитивно разобраться в работе нейросетей.
  
  В прямоугольниках - подзадачи:
  есть ли у изображения глаз в левом верхнем углу?
  Есть ли глаз в правом верхнем углу?
  Есть ли посередине нос?
  Есть ли внизу посередине рот?
  Есть ли вверху волосы?
  И так далее.
  
  Возможно, что и подсети тоже можно разобрать на составляющие.
  Возьмём вопрос с наличием глаза в левом верхнем углу.
  Его можно разобрать на вопросы типа:
  <Есть ли бровь?>, <Есть ли ресницы?>, <Есть ли зрачок?> и так далее.
  Конечно, в вопросах должна содержаться информация о расположении
  - <Расположена ли бровь слева вверху, над зрачком?>, и так далее -
  но давайте пока упростим.
  Поэтому сеть, отвечающую на вопрос о наличии глаза,
  можно разобрать на составляющие:
  
  <Есть ли бровь?>, <Есть ли ресницы?>, <Есть ли зрачок?>
  
  Эти вопросы можно дальше разбивать на мелкие,
  по шагам через многие слои.
  В итоге мы будем работать с подсетями,
  отвечающие на такие простые вопросы,
  что их легко можно разобрать на уровне пикселей.
  Эти вопросы могут касаться,
  к примеру, наличия или отсутствия простейших форм
  в определённых местах изображения.
  На них смогут ответить отдельные нейроны, связанные с пикселями.
  
  В итоге получится сеть, разбивающая очень сложные вопросы
  - наличие на изображении лица -
  на очень простые вопросы,
  на которые можно отвечать на уровне отдельных пикселей.
  Она будет делать это через последовательность из многих слоёв,
   в которых первые слои отвечают
  на очень простые и конкретные вопросы об изображении,
  а последние создают иерархию из более сложных и абстрактных концепций.
  Сети с такой многослойной структурой
  - двумя или большим количеством скрытых слоёв -
  называются глубокими нейросетями (ГНС).
  
  Конечно, я не говорил о том,
  как сделать это рекурсивное разбиение по подсетям.
  //// А это самое главное. То чего сейчас вообще непонятно как сделать.
  Определённо непрактично будет вручную подбирать веса и смещения.
  Мы бы хотели использовать обучающие алгоритмы,
  чтобы сеть автоматически обучалась весам и смещениям
  - а через них и иерархии концепций -
  на основе обучающих данных.
  //// Цель заманчивая, но почему-то думается, что в основе такой технологии
  //// будет не только сеть другой конструкции, но и другой механизм обучения,
  //// в котором если и будет "градиентный спуск", то далеко не на ведущей роли.
  Исследователи в 1980-х и 1990-х пытались
  использовать стохастический градиентный спуск и обратное распространение
  для тренировки ГНС.
  К сожалению, за исключением нескольких особых архитектур,
  у них ничего не получилось.
  Сети обучались, но очень медленно,
  и на практике это было слишком медленно для того,
  чтобы это можно было как-то использовать.
  
  С 2006 года было разработано несколько технологий,
  позволяющих обучать ГНС.
  Они основаны на стохастическом градиентном спуске и обратном распространении,
  но содержат и новые идеи.
  Они позволили обучать гораздо более глубокие сети
  - сегодня люди спокойно обучают сети с 5-10 слоями.
  //// А надо как минимум на два порядка больше,
  //// если замахиваться на описанный выше подход.
  И оказывается, что они гораздо лучше решают многие проблемы,
  чем неглубокие НС,
  то есть сети с одним скрытым слоем.
  Причина, конечно, в том, что ГНС могут создавать
  сложную иерархию концепций.
  Это похоже на то,
  как языки программирования используют модульные схемы и идеи абстракций,
  чтобы на них можно было создавать сложные компьютерные программы.
  Сравнивать глубокую НС с неглубокой НС
  - примерно как сравнивать язык программирования,
  умеющий делать вызовы функций,
  с языком, этого не умеющим.
  Абстракция в НС выглядит не так, как в языках программирования,
  но имеет такую же важность.
  
  .........
  
  //// Конец цитирования.
  
  Какой главный вывод можно сделать из этого материала?
  что существующий "триумфальный симбиоз"
  "сигмоидного нейрона", "градиентного спуска", "обратного распространения",
  "квадратичной ошибки" и, наверно, еще чего-то, что осталось вне поля зрения,
  таят в себе целый комплекс и "неявных аксиом" и "зародышей проблем".
  
  И, самое главное, не позволяют сделать практически никаких предсказаний
  о результатах проектирования новой конкретной модели.
  Т.е. нынешняя "теория машинного обучения"
  пока не является "инженерной дисциплиной".
  
  
  =========
  
  24.03.2024 15:40
  
  Погружение в математику "обратного распространения".
  В оглавление.
  
  Продолжаем погружаться в глубины "глубокого обучения".
  Возможно, это самый трудный материал в этом модуле
  с точки зрения обилия "математической абракадабры".
  Но ведь можно смотреть не на запись формул,
  а на их содержание/интерпретацию,
  чтобы понять не только используемые идеи/концепции,
  но сопутствующие им возможности и ограничения.
  
  И именно с этой точки зрения предлагаемый материал
  существенно отличается от десятков, а может и сотен подобных.
  Поэтому предлагаю поглубже вдохнуть,
  открыть в соседнем окне сам материал, чтобы видеть оригинальные иллюстрации,
  кстати достаточно информативные.
  И спокойно нырнуть в таинственные глубины
  математики "обратного распространения ошибки".
  Нет там ничего особенно головоломного, чтобы заранее пугаться:
  
  "Нейросети и глубокое обучение,
  глава 2: как работает алгоритм обратного распространения".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/457980/.
  1 июл 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap2.html
  
  //// Начало цитирования.
  
  В прошлой главе мы видели,
  как нейросети могут самостоятельно обучаться весам и смещениям
  с использованием алгоритма градиентного спуска.
  Однако в нашем объяснении имелся пробел:
  мы не обсуждали подсчёт градиента функции стоимости.
  А это приличный пробел!
  В этой главе я расскажу быстрый алгоритм для вычисления подобных градиентов,
  известный, как обратное распространение.
  
  Впервые алгоритм обратного распространения придумали в 1970-х,
  но его важность не была до конца осознана вплоть до знаменитой работы 1986 года,
  которую написали Дэвид Румельхарт, Джоффри Хинтон и Рональд Уильямс.
  В работе описано несколько нейросетей,
  в которых обратное распространение работает гораздо быстрее,
  чем в более ранних подходах к обучению,
  из-за чего с тех пор можно было использовать нейросеть
  для решения ранее неразрешимых проблем.
  Сегодня алгоритм обратного распространения
  - рабочая лошадка обучения нейросети.
  
  Эта глава содержит больше математики, чем все остальные в книге.
  Если вам не особенно по нраву математика,
  у вас может возникнуть искушение пропустить эту главу
  и просто относиться к обратному распространению,
  как к чёрному ящику,
  подробности работы которого вы готовы игнорировать.
  Зачем тратить время на их изучение?
  
  Причина, конечно, в понимании.
  В основе обратного распространения лежит
  выражение частной производной dC / dw
  функции стоимости C по весу w (или смещению b) сети.
  Выражение показывает, насколько быстро меняется стоимость
  при изменении весов и смещений.
  И хотя это выражение довольно сложное,
  у него есть своя красота,
  ведь у каждого его элемента есть естественная и интуитивная интерпретация.
  Поэтому обратное распространение
  - не просто быстрый алгоритм для обучения.
  Он даёт нам подробное понимание того,
  как изменение весов и смещений меняет всё поведение сети.
  А это стоит того, чтобы изучить подробности.
  
  Учитывая всё это, если вы хотите просто пролистать эту главу
  или перепрыгнуть к следующей, ничего страшного.
  Я написал остальную книгу так,
  чтобы она была понятной,
  даже если считать обратное распространение чёрным ящиком.
  Конечно, позднее в книге будут моменты,
  с которых я делаю отсылки к результатам этой главы.
  Но в тот момент вам должны быть понятны основные заключения,
  даже если вы не отслеживали все рассуждения.
  //// Ну, а я в этом месте могу сказать,
  //// что перескочить через эту главу, значит расписаться в том,
  //// что не сделал даже попытки ПОНЯТЬ МАГИЮ обучения нейросетей.
  
  Для разогрева:
  быстрый матричный подход вычисления выходных данных нейросети
  
  Перед обсуждением обратного распространения,
  давайте разогреемся быстрым матричным алгоритмом
  для вычисления выходных данных нейросети.
  Мы вообще-то уже встречались с этим алгоритмом к концу предыдущей главы,
  но я описал его быстро, поэтому его стоит заново рассмотреть подробнее.
  В частности, это будет хороший способ приспособиться к записи,
  используемой в обратном распространении, но в знакомом контексте.
  
  Начнём с записи, позволяющей нам недвусмысленно обозначать веса в сети.
  Мы будем использовать wljk для обозначения веса связи нейрона ?k
  в слое ?(l-1) с нейроном ?j в слое ?l.
  Так, к примеру, на диаграмме ниже показан
  вес связи четвёртого нейрона второго слоя со вторым нейроном третьего слоя:
  
  Сначала такая запись кажется неуклюжей,
  и требует некоторых усилий на привыкание.
  Однако вскоре она покажется вам простой и естественной.
  Одна её особенность - порядок индексов j и k.
  Вы могли бы решить, что разумнее было бы использовать j
  для обозначения входного нейрона, а k - для выходного,
  а не наоборот, как у нас.
  Причину такой особенности я объясню ниже.
  
  Сходные обозначения мы будем использовать для смещений и активаций сети.
  В частности, blj будет обозначать смещение нейрона ?j в слое ?l.
  alj будет обозначать активацию нейрона ?j в слое ?l.
  На следующей диаграмме показаны примеры использования этой записи:
  
  С такой записью активация alj нейрона ?j в слое ?l
  связана с активацией в слое ?(l-1) следующим уравнением
  (сравните с уравнением (4) и его обсуждением в прошлой главе):
  
  $ a^l_j = \sigma (\sum_k w^l_{jk} a^{l?1}_k + b^l_j) \tag{23} $
  
  где сумма идёт по всем нейронам k в слое (l-1).
  Чтобы перезаписать это выражение в матричном виде,
  мы определим матрицу весов wl для каждого слоя l.
  Элементы матрицы весов - это просто веса,
  соединённые со слоем ?l,
  то есть, элемент в строке ?j и столбце ?k будет wljk.
  Сходным образом для каждого слоя l мы определяем вектор смещения bl.
  Вы, наверное, догадались, как это работает
  - компонентами вектора смещения будут просто значения blj,
  по одному компоненту для каждого нейрона в слое ?l.
  И, наконец, мы определим вектор активации al,
  компонентами которого будут активации alj.
  
  Последним ингредиентом, необходимым для того,
  чтобы перезаписать (23), будет матричная форма векторизации функции ?.
  С векторизацией мы вскользь столкнулись в прошлой главе
  - идея в том, что мы хотим применить функцию ? к каждому элементу вектора v.
  Мы используем очевидную запись ?(v) для обозначения
  поэлементного применения функции.
  То есть, компонентами ?(v) будут просто ?(v)j = ?(vj).
  Для примера, если у нас есть функция f(x) = x2,
  то векторизованная форма f даёт нам
  
  $ f( \begin{bmatrix} 2\\ 3 \end{bmatrix} ) = \begin{bmatrix} f(2)\\ f(3) \end{bmatrix} = \begin{bmatrix} 4\\ 9 \end{bmatrix} \tag{24} $
  
  то есть, векторизованная f просто возводит в квадрат каждый элемент вектора.
  
  Учитывая все эти формы записи, уравнение (23) можно переписать
  в красивой и компактной векторизованной форме:
  
  $ a^l = \sigma(w^l a^{l?1} + b^l) \tag{25} $
  
  Такое выражение позволяет нам более глобально взглянуть
  на связь активаций одного слоя с активациями предыдущего:
  мы просто применяем матрицу весов к активациям,
  добавляем вектор смещения и потом применяем сигмоиду.
  Кстати, именно эта запись и требует использования записи wljk.
  Если бы мы использовали индекс j для обозначения входного нейрона,
  а k для выходного, нам пришлось бы заменить матрицу весов в уравнении (25)
  на транспонированную.
  Это небольшое, но раздражающее изменение,
  и мы бы потеряли простоту заявления (и размышления)
  о <применении матрицы весов к активациям>.
  Такой глобальный подход проще и лаконичнее
  (и использует меньше индексов!),
  //// Но больше умственной энергии на понимание/привыкание.
  чем понейронный.
  Это просто способ избежать индексного ада,
  не теряя точности обозначения происходящего.
  Также это выражение полезно на практике,
  поскольку большинство матричных библиотек предлагают
  быстрые способы перемножения матриц,
  сложения векторов и векторизации.
  Код в прошлой главе непосредственно пользовался этим выражением
  для вычисления поведения сети.
  
  Используя уравнение (25) для вычисления al,
  мы вычисляем промежуточное значение zl ? wlal?1+bl.
  Эта величина оказывается достаточно полезной для именования:
  мы называем zl взвешенным входом нейронов слоя ?l.
  Позднее мы активно будем использовать этот взвешенный вход.
  Уравнение (25) иногда записывают через взвешенный вход,
  как al = ?(zl).
  Стоит также отметить, что у zl есть компоненты
  $ z^l_j = \sum_k w^l_{jk} a^{l?1}_k + b^l_j $,
  то есть, zlj - это всего лишь
  взвешенный вход функции активации нейрона j в слое l.
  //// Интересно, это значение "взвешенного входа" при работе/обучении нейросетей
  //// где хранится?
  //// Или это нужно только для понимания последующих формул?
  
  Два необходимых предположения по поводу функции стоимости
  
  Цель обратного распространения -
  вычислить частные производные ?C/?w и ?C/?b функции стоимости C
  для каждого веса w и смещения b сети.
  Чтобы обратное распространение сработало,
  нам необходимо сделать два главных предположения
  по поводу формы функции стоимости.
  Однако перед этим полезно будет представлять себе пример функции стоимости.
  Мы используем квадратичную функцию из прошлой главы (уравнение (6)).
  В записи из предыдущего раздела она будет иметь вид
  
  $ C = \frac{1}{2n}\sum_x ||y(x) ? a^L(x)||^2 \tag{26} $
  
  где: n - общее количество обучающих примеров;
  сумма идёт по всем примерам x;
  y=y(x) - необходимые выходные данные;
  L обозначает количество слоёв в сети;
  aL = aL (x) - вектор выхода активаций сети, когда на входе x.
  
  Ладно, так какие нам нужны предположения касательно функции стоимости С,
  чтобы применять обратное распространение?
  Первое - функцию стоимости можно записать
  как среднее C = 1/n ?x Cx функций стоимости Cx
  для отдельных обучающих примеров x.
  Это выполняется в случае квадратичной функции стоимости,
  где стоимость одного обучающего примера Cx = 1/2 ||y ? aL||2.
  Это предположение будет верным и для всех остальных функций стоимости,
  которые встретятся нам в книге.
  //// Стоит запомнить этот момент.
  //// Чем-то это напоминает "среднюю температуру по палате".
  //// Вряд ли это не имеет каких-то "отрижительных" и/или "полоцательных" следствий.
  //// И это точно связано с концепцией "фиксированного ландшафта" решения.
  
  Это предположение нужно нам потому,
  что на самом деле обратное распространение позволяет нам вычислять
  частные производные ?C/?w и ?C/?b,
  усредняя по обучающим примерам.
  Приняв это предположение, мы предположим,
  что обучающий пример x фиксирован,
  и перестанем указывать индекс x,
  записывая стоимость Cx как C.
  Потом мы вернём x, но пока что лучше его просто подразумевать.
  
  Второе предположение касательно функции стоимости
  - её можно записать как функцию выхода нейросети:
  
  К примеру, квадратичная функция стоимости удовлетворяет этому требованию,
  поскольку квадратичную стоимость одного обучающего примера x можно записать,
  как
  
  $ C = 1/2 || y?a^L ||^2 = 1/2 \sum_j (y_j ? a^L_j)^2 \tag{27} $
  
  что и будет функцией выходных активаций.
  Конечно, эта функция стоимости также зависит от желаемого выхода y,
  и вы можете удивиться, почему мы не рассматриваем C как функцию ещё и от y.
  Однако вспомним, что входной обучающий пример x фиксирован,
  поэтому выход y тоже фиксирован.
  В частности, его мы не можем изменить, меняя веса и смещения,
  то есть, это не то, что выучивает нейросеть.
  Поэтому имеет смысл считать C функцией от только выходных активаций aL,
  а y - просто параметром, помогающим её определять.
  //// Не очень, на мой взгляд, внятная формулировка.
  //// Во всяком случае, я не понял вот этого
  //// "не можем изменить, меняя веса и смещения".
  //// Кажется, что что-то важное упускаю.
  
  //// Может быть тот случай, когда "выход y" представляет собой
  //// "координату", или "вероятность", или "интенсивность"
  //// или еще что-то МНОГОЗНАЧНОЕ.
  //// И тогда используемые в данном материале рассуждения,
  //// могут "не совсем" соответствовать таким случаям,
  //// и выводимые общие формулы "обратного распространения",
  //// возможно, оказываются не совсем "общими".
  
  //// Но моей математической подготовки и понимания этого параграфа
  //// явно не хватает, чтобы это как-то раскрыть/осмыслить.
  //// Но, на всякий случай, постараюсь запомнить этот момент.
  
  Произведение Адамара s?t
  
  Алгоритм обратного распространения основан
  на обычных операциях линейной алгебры
  - сложении векторов, умножении вектора на матрицу, и т.д.
  Однако одна из операций используется менее часто.
  Допустим, s и t - два вектора одной размерности.
  Тогда через s?t мы обозначим поэлементное перемножение двух векторов.
  Тогда компоненты s?t будут просто (s?t)j = sjtj. Например:
  
  $ \begin{bmatrix} 1\\ 2 \end{bmatrix} \odot \begin{bmatrix} 3\\ 4 \end{bmatrix} = \begin{bmatrix} 1 * 3\\ 2 * 4 \end{bmatrix} = \begin{bmatrix} 3\\ 8 \end{bmatrix} \tag{28} $
  
  Такое поэлементное произведение иногда называют произведением Адамара
  или произведением Шура.
  Мы будем называть его произведением Адамара.
  Хорошие библиотеки для работы с матрицами обычно имеют
  быструю реализацию произведения Адамара,
  и это бывает удобно при реализации обратного распространения.
  
  Четыре фундаментальных уравнения в основе обратного распространения
  
  Обратное распространение связано с пониманием того,
  как изменение весов и смещений сети меняет функцию стоимости.
  По сути, это означает подсчёт частных производных ?C/?wljk и ?C/?blj.
  Но для их вычисления сначала мы вычисляем промежуточное значение ?lj,
  которую мы называем ошибкой в нейроне ?j в слое ?l.
  Обратное распространение даст нам процедуру для вычисления ошибки ?lj,
  а потом свяжет ?lj с ?C/?wljk и ?C/?blj.
  
  Чтобы понять, как определяется ошибка,
  представьте, что в нашей нейросети завёлся демон:
  
  Он сидит на нейроне ?j в слое ?l.
  При поступлении входных данных демон нарушает работу нейрона.
  Он добавляет небольшое изменение ?zlj к взвешенному входу нейрона,
  и вместо того, чтобы выдавать ?(zlj), нейрон выдаст ?(zlj + ?zlj).
  Это изменение распространится и через следующие слои сети,
  что в итоге изменит общую стоимость на (?C/?zlj) * ?zlj.
  
  Но наш демон хороший, и он пытается помочь вам улучшить стоимость,
  то есть, найти ?zlj, уменьшающее стоимость.
  Допустим, значение ?C/?zlj велико (положительное или отрицательное).
  Тогда демон может серьёзно уменьшить стоимость,
  выбрав ?zlj со знаком, противоположным ?C/?zlj.
  А если же ?C/?zlj близко к нулю,
  тогда демон не может сильно улучшить стоимость, меняя взвешенный вход zlj.
  Так что, с точки зрения демона, нейрон уже близок к оптимуму
  (это, конечно, верно только для малых ?zlj.
  Допустим, таковы ограничения действий демона).
  Поэтому в эвристическом смысле ?C/?zlj является мерой ошибки нейрона.
  
  Под мотивацией от этой истории определим ошибку ?lj нейрона j в слое l, как
  
  $ \delta l_j \equiv \frac{\partial C}{\partial z^l_j} \tag{29} $
  
  По обычному нашему соглашению мы используем ?l для обозначения вектора ошибок,
  связанного со слоем l.
  Обратное распространение даст нам способ подсчитать ?l для любого слоя,
  а потом соотнести эти ошибки с теми величинами,
  которые нас реально интересуют, ?C/?wljk и ?C/?blj.
  
  Вас может интересовать, почему демон меняет взвешенный вход zlj.
  Ведь было бы естественнее представить,
  что демон изменяет выходную активацию alj,
  чтобы мы использовали ?C/?alj в качестве меры ошибки.
  На самом деле, если сделать так,
  то всё получается очень похожим на то,
  что мы будем обсуждать дальше.
  Однако в этом случае представление обратного распространения
  будет алгебраически чуть более сложным.
  Поэтому мы остановимся на варианте ?lj = ?C/?zlj в качестве меры ошибки.
  
  В задачах классификации термин <ошибка> иногда означает
  количество неправильных классификаций.
  К примеру, если нейросеть правильно классифицирует 96,0% цифр,
  то ошибка будет равна 4,0%.
  Очевидно, это совсем не то, что мы имеем в виду под векторами ?.
  Но на практике обычно можно без труда понять,
  какое значение имеется в виду.
  
  План атаки:
  обратное распространение основано на четырёх фундаментальных уравнениях.
  Совместно они дают нам способ вычислить как ошибку ?l,
  так и градиент функции стоимости.
  Я привожу их ниже.
  Не нужно ожидать их мгновенного освоения.
  Вы будете разочарованы.
  Уравнения обратного распространения настолько глубоки,
  что для хорошего их понимания требуется ощутимое время и терпение,
  и постепенное углубление в вопрос.
  Хорошие новости в том, что это терпение окупится сторицей.
  Поэтому в данном разделе наши рассуждения только начинаются,
  помогая вам идти по пути глубокого понимания уравнений.
  
  Вот схема того, как мы будем углубляться в эти уравнения позже:
  я дам их краткое доказательство,
  помогающее объяснить, почему они верны;
  мы перепишем их в алгоритмической форме в виде псевдокода,
  и увидим, как реализовать его в реальном коде на python;
  в последней части главы мы выработаем интуитивное представление
  о значении уравнений обратного распространения,
  и о том, как их можно найти с нуля.
  Мы будем периодически возвращаться к четырём фундаментальным уравнениям,
  и чем глубже вы будете их понимать,
  тем более комфортными, и возможно, красивыми и естественными
  они будут вам казаться.
  
  Уравнение ошибки выходного слоя, ?L: компоненты ?L считаются, как
  
  $ \delta^L_j = \frac{\partial C}{\partial a^L_j} \sigma' (z^L_j) \tag{BP1} $
  
  Очень естественное выражение.
  Первый член справа, ?C / ?aLj, измеряет,
  насколько быстро стоимость меняется как функция выходной активации ?j.
  Если, к примеру, C не особенно зависит от конкретного выходного нейрона j,
  тогда ?Lj будет малым, как и ожидается.
  Второй член справа, ?'(zLj), измеряет,
  насколько быстро функция активации ? меняется в zLj.
  
  Заметьте, что всё в (BP1) легко подсчитать.
  В частности, мы вычисляем zLj при подсчёте поведения сети,
  и на вычисление ?'(zLj) уйдёт незначительно больше ресурсов.
  Конечно, точная форма ?C / ?aLj зависит от формы функции стоимость.
  Однако, если функция стоимости известна,
  то не должно быть проблем с вычислением ?C / ?aLj.
  К примеру, если мы используем квадратичную функцию стоимости,
  тогда C = 1/2 ?j (yj ? aLj)2,
  поэтому ?C / ?aLj = (aLj ? yj), что легко подсчитать.
  
  Уравнение (BP1) - это покомпонентное выражение ?L.
  Оно совершенно нормальное, но не записано в матричной форме,
  которая нужна нам для обратного распространения.
  Однако, его легко переписать в матричной форме, как
  
  $ \delta^L =\nabla_a C \odot \sigma'(z^L) \tag{BP1a} $
  
  Здесь ?a C определяется, как вектор,
  чьими компонентами будут частные производные ?C / ?aLj.
  Его можно представлять, как выражение скорости изменения C
  по отношению к выходным активациям.
  Легко видеть, что уравнения (BP1a) и (BP1) эквивалентны,
  поэтому далее мы будем использовать (BP1) для отсылки к любому из них.
  К примеру, в случае с квадратичной стоимостью,
  у нас будет ?a C = (aL - y),
  поэтому полной матричной формой (BP1) будет
  
  $ \delta^L = (a^L - y) \odot \sigma'(z^L) \tag{30} $
  
  Всё в этом выражении имеет удобную векторную форму,
  и его легко вычислить при помощи такой библиотеки, как, например, Numpy.
  
  Выражение ошибки ?l через ошибку в следующем слое, ?l+1: в частности,
  
  $ \delta^l = ((w^{l+1})^T \delta^{l+1}) \cdot \sigma'(z^l) \tag{BP2} $
  
  где (wl+1)T - транспонирование весовой матрицы wl+1 для слоя ?(l+1).
  
  Уравнение кажется сложным,
  но каждый его элемент легко интерпретировать.
  Допустим, мы знаем ошибку ?l+1 для слоя (l+1).
  Транспонирование весовой матрицы, (wl+1)T,
  можно представить себе, как перемещение ошибки назад по сети,
  что даёт нам некую меру ошибки на выходе слоя ?l.
  Затем мы считаем произведение Адамара ??'(zl).
  Это продвигает ошибку назад через функцию активации в слое l,
  давая нам значение ошибки ?l во взвешенном входе для слоя l.
  
  Комбинируя (BP2) с (BP1),
  мы можем подсчитать ошибку ?l для любого слоя сети.
  Мы начинаем с использования (BP1) для подсчёта ?L,
  затем применяем уравнение (BP2) для подсчёта ?L-1,
  затем снова для подсчёта ?L-2,
  и так далее, до упора по сети в обратную сторону.
  //// А вот интересный вопрос: пользуясь этими формулами,
  //// можно дойти действительно до "полного упора", т.е. входного слоя,
  //// и тогда, что будет означать "ошибка на входном слое"?
  //// Как-то не приходилось встречать попыток не только использования
  //// или интерпретации такой "ошибки на входе",
  //// а даже простого упоминания такой сущности.
  //// А ведь она что-то все-таки означает и как-то может быть использована.
  
  Уравнение скорости изменения стоимости по отношению к любому смещению в сети:
  в частности:
  
  $ \frac{\partial C}{\partial b^l_j} = \delta^l_j \tag{BP3} $
  
  То есть, ошибка ?lj точно равна скорости изменения ?C / ?blj.
  Это превосходно, поскольку (BP1) и (BP2) уже рассказали нам,
  как подсчитывать ?lj.
  Мы можем перезаписать (BP3) короче, как
  
  $ \frac{\partial C}{\partial b} = \delta \tag{31} $
  
  где ? оценивается для того же нейрона, что и смещение b.
  
  Уравнение для скорости изменения стоимости по отношению к любому весу в сети:
  в частности:
  
  $ \frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j \tag{BP4} $
  
  Отсюда мы узнаём, как подсчитать частную производную ?C/?wljk
  через значения ?l и al-1,
  способ расчёта которых нам уже известен.
  Это уравнение можно переписать в менее загруженной индексами форме:
  
  $ \frac{\partial C}{\partial w} = a_{\rm in} \delta_{\rm out} \tag{32} $
  
  где ain - активация нейронного входа для веса w,
  а ?out - ошибка нейронного выхода от веса w.
  Если подробнее посмотреть на вес w и два соединённых им нейрона,
  то можно будет нарисовать это так:
  //// Честно признаюсь, что в этом месте данного текста "подзавис",
  //// как минимум, на полчаса.
  //// Совершенно контринтуитивной показалась эта формула и иллюстрация.
  //// Интуитивно представлялось, что в этой формуле должно как-то присутствовать
  //// собственно вес этой связи. А его нет.
  //// И только после долгих раздумий пришло понимание,
  //// что в формуле отражается ЗНАЧЕНИЕ ИЗМЕНЕНИЯ веса,
  //// уже как-то отнормированное к собственно значению веса.
  
  //// К сожалению автор счел, что эта формула доступна для самостоятельного вывода,
  //// и не стал ее раскрывать, оставив для самостоятельного упражнения.
  //// Честно признаюсь, с этим упражнением я не справился.
  //// И поверил в правильность записи формулы автором BP4.
  //// Но "узелок на память" завязал, на предмет поиска в других источниках.
  
  //// Особое сожаление в этом случае у меня вызывает то,
  //// что формула BP4 очень важна для понимания механизма
  //// "быстрой коррекции весов" при обратном распространении.
  //// Я ее, если и не понял, то "принял" опираясь на понимание формулы BP3.
  //// Но очень бы хотелось посмотреть на весь механизм ее вывода,
  //// именно на предмет отсутствия в ней каких-то "непроговоренных особенностей".
  
  Приятное следствие уравнения (32) в том,
  что когда активация ain мала, ain ? 0,
  член градиента ?C/?w тоже стремится к нулю.
  В таком случае мы говорим, что вес обучается медленно,
  то есть, не сильно меняется во время градиентного спуска.
  Иначе говоря, одним из следствий (BP4) будет то,
  что весовой выход нейронов с низкой активацией обучается медленно.
  
  Из (BP1)-(BP4) можно почерпнуть и другие идеи.
  Начнём с выходного слоя.
  Рассмотрим член ?'(zLj) в (BP1).
  Вспомним из графика сигмоиды из прошлой главы,
  что она становится плоской, когда ?(zLj) приближается к 0 или 1.
  В данных случаях ?'(zLj) ? 0.
  Поэтому вес в последнем слое будет обучаться медленно,
  если активация выходного нейрона мала (? 0) или велика (? 1).
  В таком случае обычно говорят,
  что выходной нейрон насыщен,
  и в итоге вес перестал обучаться
  (или обучается медленно).
  Те же замечания справедливы и для смещений выходного нейрона.
  
  Сходные идеи можно получить и касательно более ранних слоёв.
  В частности, рассмотрим член ?'(zl) в (BP2).
  Это значит, что ?lj, скорее всего, будет малой
  при приближении нейрона к насыщению.
  А это, в свою очередь, означает,
  что любые веса на входе насыщенного нейрона будут обучаться медленно
  (правда, это не сработает, если у wl+1T?l+1 будут достаточно большие элементы,
  компенсирующие небольшое значение ?'(zLj)).
  
  Подытожим:
  мы узнали, что вес будет обучаться медленно,
  если либо активация входного нейрона мала,
  либо выходной нейрон насыщен,
  то есть его активация мала или велика.
  
  В этом нет ничего особенно удивительного.
  И всё же, эти наблюдения помогают улучшить наше представление о том,
  что происходит при обучении сети.
  Более того, мы можем подойти к этим рассуждениям с обратной стороны.
  Четыре фундаментальных уравнения справедливы для любой функции активации,
  а не только для стандартной сигмоиды
  (поскольку, как мы увидим далее,
  в доказательствах не используются свойства сигмоиды).
  Поэтому эти уравнения можно использовать для разработки функций активации
  с определёнными нужными свойствами обучения.
  Для примера, допустим, мы выбрали функцию активации ?,
  непохожую на сигмоиду,
  такую, что ?' всегда положительна и не приближается к нулю.
  Это предотвратить замедление обучения,
  происходящее при насыщении обычных сигмоидных нейронов.
  Позднее в книге мы увидим примеры,
  где функция активации меняется подобным образом.
  Учитывая уравнения (BP1)-(BP4),
  мы можем объяснить, зачем нужны такие модификации,
  и как они могут повлиять на ситуацию.
  
  ......
  
  Итог: уравнения обратного распространения
  
  Задачи
  
  Альтернативная запись уравнений обратного распространения.
  Я записал уравнения обратного распространения
  с использованием произведения Адамара.
  Это может сбить с толку людей, не привыкших к этому произведению.
  Есть и другой подход, на основе обычного перемножения матриц,
  который может оказаться поучительным для некоторых читателей.
  Покажите, что (BP1) можно переписать, как
  
  $ \delta^L = \Sigma'(z^L) \nabla_a C \tag{33} $
  
  где ?'(zL) - квадратная матрица,
  у которой по диагонали расположены значения ?'(zLj),
  а другие элементы равны 0.
  Учтите, что эта матрица взаимодействует с ?a C
  через обычное перемножение матриц.
  
  Покажите, что (BP2) можно переписать, как
  
  $ \delta^l = \Sigma'(z^l) (w^{l+1})^T \delta^{l+1} \tag{34} $
  
  Комбинируя предыдущие задачи, покажите, что:
  
  $ \delta^l = \Sigma'(z^l) (w^{l+1})^T \ldots \Sigma'(z^{L-1}) (w^L)^T \Sigma'(z^L) \nabla_a C \tag{35} $
  
  Для читателей, привычных к матричному перемножению,
  это уравнение будет легче понять, чем (BP1) и (BP2).
  Я концентрируюсь на (BP1) и (BP2)
  потому, что этот подход оказывается быстрее реализовать численно.
  [здесь ? - это не сумма (?), а заглавная ? (сигма) / прим. перев.]
  
  Доказательство четырёх фундаментальных уравнений (необязательный раздел)
  
  Теперь докажем четыре фундаментальных уравнения (BP1)-(BP4).
  Все они являются следствиями цепного правила
  (правила дифференцирования сложной функции)
  из анализа функций многих переменных.
  Если вы хорошо знакомы с цепным правилом,
  настоятельно рекомендую попробовать посчитать производные самостоятельно
  перед тем, как продолжить чтение.
  
  Начнём с уравнения (BP1), которое даёт нам выражение для выходной ошибки ?L.
  Чтобы доказать его, вспомним, что, по определению:
  
  $ \delta^L_j = \frac{\partial C}{\partial z^L_j} \tag{36} $
  
  Применяя цепное правило,
  перепишем частные производные через частные производные по выходным активациям:
  
  $ \delta^L_j = \sum_k \frac{\partial C}{\partial a^L_k} \frac{\partial a^L_k}{\partial z^L_j} \tag{37} $
  
  где суммирование идёт по всем нейронам k в выходном слое.
  Конечно, выходная активация aLk нейрона ?k зависит
  только от взвешенного входа zLj для нейрона ?j, когда k=j.
  Поэтому ?aLk / ?zLj исчезает, когда k ? j.
  В итоге мы упрощаем предыдущее уравнение до
  
  $ \delta^L_j = \frac{\partial C}{\partial a^L_j} \frac{\partial a^L_j}{\partial z^L_j} \tag{38} $
  
  Вспомнив, что aLj = ?(zLj), мы можем переписать второй член справа,
  как ?'(zLj),
  и уравнение превращается в
  
  $ \delta^L_j = \frac{\partial C}{\partial a^L_j} \sigma'(z^L_j) \tag{39} $
  
  то есть, в (BP1) в покомпонентном виде.
  
  Затем докажем (BP2),
  дающее уравнение для ошибки ?l через ошибку в следующем слое ?l+1.
  Для этого нам надо переписать ?lj = ?C / ?zlj
  через ?l+1k = ?C / ?zl+1k.
  Это можно сделать при помощи цепного правила:
  
  $ \delta^l_j = \frac{\partial C}{\partial z^l_j} \tag{40} $
  
  $ = \sum_k \frac{\partial C}{\partial z^{l+1}_k} \frac{\partial z^{l+1}_k}{\partial z^l_j} \tag{41} $
  
  $ = \sum_k \frac{\partial z^{l+1}_k}{\partial z^l_j} \delta^{l+1}_k \tag{42} $
  
  где в последней строчке мы поменяли местами два члена справа,
  и подставили определение ?l+1k.
  Чтобы вычислить первый член на последней строчке, отметим, что
  
  $ z^{l+1}_k = \sum_j w^{l+1}_{kj} a^l_j +b^{l+1}_k = \sum_j w^{l+1}_{kj} \sigma(z^l_j) +b^{l+1}_k \tag{43} $
  
  Продифференцировав, получим
  
  $ \frac{\partial z^{l+1}_k}{\partial z^l_j} = w^{l+1}_{kj} \sigma'(z^l_j). \tag{44} $
  
  Подставив это в (42), получим
  
  $ \delta^l_j = \sum_k w^{l+1}_{kj} \delta^{l+1}_k \sigma'(z^l_j). \tag{45} $
  
  То есть, (BP2) в покомпонентной записи.
  
  Остаётся доказать (BP3) и (BP4).
  Они тоже следуют из цепного правила,
  примерно таким же методом, как и два предыдущих.
  Оставлю их вам в качестве упражнения.
  
  Упражнение
  
  Докажите (BP3) и (BP4).
  
  //// Как я уже отметил выше, с этим упражнением я не справился.
  
  Вот и всё доказательство
  четырёх фундаментальных уравнений обратного распространения.
  Оно может показаться сложным.
  Но на самом деле это просто результат аккуратного применения цепного правила.
  Говоря менее лаконично, обратное распространение можно представить себе,
  как способ подсчёта градиента функции стоимости
  через систематическое применение цепного правила
  из анализа функций многих переменных.
  И это реально всё, что представляет собой обратное распространение
  - остальное просто детали.
  
  Алгоритм обратного распространения
  
  Уравнения обратного распространения дают нам
  метод подсчёта градиента функции стоимости.
  Давайте запишем это явно в виде алгоритма:
  
  Вход x:
  назначить соответствующую активацию a1 для входного слоя.
  
  Прямое распространение:
  для каждого l = 2,3,:,L вычислить zl = wlal?1+bl и al = ?(zl).
  
  Выходная ошибка ?L:
  вычислить вектор ?L = ?a C ? ?'(zL).
  
  Обратное распространение ошибки:
  для каждого l = L?1,L?2,:,2 вычислить ?l = ((wl+1)T?l+1) ? ?'(zl).
  
  Выход:
  градиент функции стоимости задаётся
  $\frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j$ и $\frac{\partial C}{\partial b^l_j} = \delta^l_j$.
  
  Посмотрев на алгоритм, вы поймёте,
  почему он называется обратное распространение.
  Мы вычисляем векторы ошибки ?l задом наперёд,
  начиная с последнего слоя.
  Может показаться странным, что мы идём по сети назад.
  Но если подумать о доказательстве обратного распространения,
  то обратное движение является следствием того,
  что стоимость - это функция выхода сети.
  Чтобы понять, как меняется стоимость в зависимости от ранних весов и смещений,
  нам нужно раз за разом применять цепное правило,
  идя назад через слои,
  чтобы получить полезные выражения.
  
  Упражнения
  
  Обратное распространение с одним изменённым нейроном.
  Допустим, мы изменили один нейрон в сети с прямым распространением так,
  чтобы его выход был f(?j wjxj+b),
  где f - некая функция, не похожая на сигмоиду.
  Как нам поменять алгоритм обратного распространения в данном случае?
  
  Обратное распространение с линейными нейронами.
  Допустим, мы заменим обычную нелинейную сигмоиду на ?(z) = z по всей сети.
  Перепишите алгоритм обратного распространения для данного случая.
  
  Как я уже пояснял ранее, алгоритм обратного распространения
  вычисляет градиент функции стоимости для одного обучающего примера, C = Cx.
  На практике часто комбинируют обратное распространение с алгоритмом обучения,
  например, со стохастическим градиентным спуском,
  когда мы подсчитываем градиент для многих обучающих примеров.
  В частности, при заданном мини-пакете m обучающих примеров,
  следующий алгоритм применяет градиентный спуск на основе этого мини-пакета:
  
  Вход: набор обучающих примеров.
  
  Для каждого обучающего примера x назначить
  соответствующую входную активацию ax,1 и выполнить следующие шаги:
  
  Прямое распространение для каждого l=2,3,..,L
  вычислить zx,l = wlax,l?1+bl и ax, l = ?(zx,l).
  
  Выходная ошибка ?x,L:
  вычислить вектор ?x,L = ?a Cx ? ?'(zx,L).
  
  Обратное распространение ошибки:
  для каждого l=L?1,L?2,:,2 вычислить ?x,l = ((wl+1)T?x,l+1) ? ?'(zx,l).
  
  Градиентный спуск:
  для каждого l=L,L?1,:,2
  обновить веса согласно правилу
  $w^l \rightarrow w^l-\frac{\eta}{m} \sum_x \delta^{x,l} (a^{x,l-1})^T$,
  и смещения согласно правилу
  $b^l \rightarrow b^l-\frac{\eta}{m} \sum_x \delta^{x,l}$.
  
  Конечно, для реализации стохастического градиентного спуска
  на практике также понадобится внешний цикл,
  генерирующий мини-пакеты обучающих примеров,
  и внешний цикл,
  проходящий по нескольким эпохам обучения.
  Для простоты я их опустил.
  
  Код для обратного распространения
  
  Поняв абстрактную сторону обратного распространения,
  теперь мы можем понять код,
  использованный в предыдущей главе,
  реализующий обратное распространение.
  
  ........
  
  Большую часть работы делают строки
  delta_nabla_b, delta_nabla_w = self.backprop(x, y),
  использующие метод backprop для подсчёта частных производных
  ?Cx/?blj и ?Cx/?wljk.
  Метод backprop почти повторяет алгоритм предыдущего раздела.
  Есть одно небольшое отличие
  - мы используем немного другой подход к индексированию слоёв.
  Это сделано для того, чтобы воспользоваться особенностью python,
  отрицательными индексами массива,
  позволяющими отсчитывать элементы назад, с конца.
  l[-3] будет третьим элементом с конца массива l.
  Код backprop приведён ниже,
  вместе со вспомогательными функциями,
  используемыми для подсчёта сигмоиды,
  её производной и производной функции стоимости.
  С ними код получается законченным и понятным.
  Если что-то неясно, обратитесь к первому описанию кода с полным листингом.
  
  ........
  
  В каком смысле обратное распространение является быстрым алгоритмом?
  
  В каком смысле обратное распространение является быстрым алгоритмом?
  Для ответа на этот вопрос рассмотрим ещё один подход к вычислению градиента.
  Представьте себе ранние дни исследований нейросетей.
  Возможно, это 1950-е или 1960-е годы,
  и вы - первый человек в мире,
  придумавший использовать для обучения градиентный спуск!
  Но чтобы это сработало, вам нужно подсчитать градиент функции стоимости.
  Вы вспоминаете алгебру и решаете посмотреть,
  можно ли использовать цепное правило для вычисления градиента.
  Немного поигравшись, вы видите, что алгебра кажется сложной,
  и вы разочаровываетесь.
  Вы пытаетесь найти другой подход.
  Вы решаете считать стоимость функцией только весов C=C(w)
  (к смещениям вернёмся чуть позже).
  Вы нумеруете веса w1, w2,...
  и хотите вычислить ?C/?wj для веса wj.
  Очевидный способ - использовать приближение
  
  $ \frac{\partial C}{\partial w_{j}} \approx \frac{C(w+\epsilon e_j)-C(w)}{\epsilon} \tag{46} $
  
  Где ? > 0 - небольшое положительное число,
  а ej - единичный вектор направления j.
  Иначе говоря, мы можем приблизительно оценить ?C/?wj,
  вычислив стоимость C для двух немного различных значений wj,
  а потом применить уравнение (46).
  Та же идея позволит нам подсчитать частные производные ?C/?b по смещениям.
  
  Подход выглядит многообещающим.
  Концептуально простой, легко реализуемый,
  использует только несколько строк кода.
  Он выглядит гораздо более многообещающим,
  чем идея использования цепного правила для подсчёта градиента!
  
  К сожалении, хотя такой подход выглядит многообещающим,
  при его реализации в коде оказывается,
  что работает он крайне медленно.
  Чтобы понять, почему, представьте, что у нас в сети миллион весов.
  Тогда для каждого веса wj нам нужно вычислить C(w + ?ej),
  чтобы подсчитать ?C/?wj.
  А это значит, что для вычисления градиента нам нужно вычислить
  функцию стоимости миллион раз,
  что потребует миллион прямых проходов по сети (на каждый обучающий пример).
  А ещё нам надо подсчитать C(w),
  так что получается миллион и один проход по сети.
  
  Хитрость обратного распространения в том,
  что она позволяет нам одновременно вычислять все частные производные ?C/?wj,
  используя только один прямой проход по сети,
  за которым следует один обратный проход.
  Грубо говоря, вычислительная стоимость обратного прохода примерно такая же,
  как у прямого.
  
  Поэтому общая стоимость обратного распространения примерно такая же,
  как у двух прямых проходов по сети.
  Сравните это с миллионом и одним прямым проходом,
  необходимым для реализации метода (46)!
  Так что, хотя обратное распространение внешне выглядит более сложным подходом,
  в реальности он куда как более быстрый.
  
  Впервые это ускорение сполна оценили в 1986,
  и это резко расширило диапазон задач, решаемых с помощью нейросетей.
  В свою очередь, это привело к увеличению количества людей,
  использующих нейросети.
  Конечно, обратное распространение - не панацея.
  Даже в конце 1980-х люди уже натолкнулись на её ограничения,
  особенно при попытках использовать обратное распространение
  для обучения глубоких нейросетей,
  то есть сетей со множеством скрытых слоёв.
  Позже мы увидим, как современные компьютеры
  и новые хитрые идеи позволяют использовать обратное распространение
  для обучения таких глубоких нейросетей.
  
  Обратное распространение: в общем и целом
  
  Как я уже объяснил, обратное распространение являет нам две загадки.
  Первая, что на самом деле делает алгоритм?
  Мы выработали схему обратного распространения ошибки от выходных данных.
  Можно ли углубиться дальше,
  получить более интуитивное представление о происходящем
  во время всех этих перемножений векторов и матриц?
  Вторая загадка - как вообще кто-то мог обнаружить обратное распространение?
  Одно дело, следовать шагам алгоритма или доказательству его работы.
  Но это не значит, что вы так хорошо поняли задачу,
  что могли изобрести этот алгоритм.
  Есть ли разумная цепочка рассуждений, способная привести нас
  к открытию алгоритма обратного распространения?
  В этом разделе я освещу обе загадки.
  
  Чтобы улучшить понимание работы алгоритма,
  представим, что мы провели небольшое изменение ?wljk некоего веса wljk:
  
  Это изменение веса приведёт к изменению выходной активации
  соответствующего нейрона:
  
  Это приведёт к изменению всех активаций следующего слоя:
  
  Эти изменения приведут к изменениям следующего слоя, и так далее,
  вплоть до последнего,
  а потом к изменениям функции стоимости:
  
  Изменение ?C связано с изменением ?wljk уравнением
  
  $ \Delta C \approx \frac{\partial C}{\partial w^l_{jk}} \Delta w^l_{jk} \tag{47} $
  
  Из этого следует, что вероятным подходом к вычислению ?C/?wljk
  будет тщательное отслеживание распространения небольшого изменения wljk,
  приводящего к небольшому изменению в C.
  Если мы сможем это сделать,
  тщательно выражая по пути всё в величинах,
  которые легко вычислить, то мы сможем вычислить и ?C/?wljk.
  
  Давайте попробуем.
  Изменение ?wljk вызывает небольшое изменение ?alj
  в активации нейрона j в слое l.
  Это изменение задаётся
  
  $ \Delta a^l_j \approx \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk} \tag{48} $
  
  Изменение активации ?alj приводит к изменениям
  во всех активациях следующего слоя, (l+1).
  Мы сконцентрируемся только на одной из этих изменённых активаций,
  допустим, al+1q,
  
  Это приведёт к следующим изменениям:
  
  $ \Delta a^{l+1}_q \approx \frac{\partial a^{l+1}_q}{\partial a^l_j} \Delta a^l_j \tag{49} $
  
  Подставляя уравнение (48), получаем:
  
  $ \Delta a^{l+1}_q \approx \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk} \tag{50} $
  
  Конечно, изменение ?al+1q изменит и активации в следующем слое.
  Мы даже можем представить путь по всей сети от wljk до C,
  где каждое изменение активации приводит к изменению следующей активации,
  и, наконец, к изменению стоимости на выходе.
  Если путь проходит через активации alj, al+1q,:,aL?1n, aLm,
  тогда итоговое выражение будет
  
  $ \Delta C \approx \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk} \tag{51} $
  
  То есть, мы выбираем член вида ?a/?a
  для каждого следующего проходимого нами нейрона,
  а также для члена ?C / ?aLm в конце.
  Это представление изменений в C из-за изменений в активациях
  по данному конкретному пути сквозь сеть.
  Конечно, существует много путей, по которым изменение в wljk
  может пройти и повлиять на стоимость,
  а мы рассматривали только один из них.
  Чтобы подсчитать общее изменение C разумно предположить,
  что мы должны просуммировать все возможные пути от веса до конечной стоимости:
  
  $ \Delta C \approx \sum_{mnp\ldots q} \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk} \tag{52} $
  
  где мы просуммировали все возможные выборы для промежуточных нейронов по пути.
  Сравнивая это с (47), мы видим, что:
  
  $ \frac{\partial C}{\partial w^l_{jk}} = \sum_{mnp\ldots q} \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}}. \tag{53} $
  
  Уравнение (53) выглядит сложно.
  Однако у него есть приятная интуитивная интерпретация.
  Мы подсчитываем изменение C по отношению к весам сети.
  Оно говорит нам, что каждое ребро между двумя нейронами сети
  связано с фактором отношения,
  являющимся только лишь частной производной активации одного нейрона
  по отношению к активации другого нейрона.
  У ребра от первого веса до первого нейрона фактор отношения равен ?alj / ?wljk.
  Коэффициент отношения для пути
  - это просто произведение коэффициентов по всему пути.
  А общий коэффициент изменения ?C / ?wljk
  является суммой коэффициентов по всем путям
  от начального веса до конечной стоимости.
  Эта процедура показана далее, для одного пути:
  
  Пока что мы давали эвристический аргумент,
  способ представить происходящее при изменении весов сети.
  Позвольте мне обрисовать дальнейший вариант мышления на эту тему
  для развития данного аргумента.
  Во-первых, можно вывести точные выражение
  для всех отдельных частных производных в уравнении (53).
  Это легко сделать с использованием несложной алгебры.
  После этого можно попробовать понять,
  как записать все суммы по индексам в виде произведений матриц.
  Это оказывается утомительной задачей,
  требующей терпения,
  но не чем-то экстраординарным.
  После всего этого и максимального упрощения
  вы увидите, что получился ровно тот же самый
  алгоритм обратного распространения!
  Поэтому алгоритм обратного распространения можно представлять себе,
  как способ вычисления суммы коэффициентов по всем путям.
  Или, если переформулировать,
  алгоритм обратного распространения
  - хитроумный способ отслеживания небольших изменений весов (и смещений),
  когда они распространяются по сети,
  достигают выхода и влияют на стоимость.
  
  Здесь я не буду делать всего этого.
  Это дело малопривлекательное, требующее тщательной проработки деталей.
  Если вы готовы к такому, вам может понравиться этим заниматься.
  Если нет, то надеюсь, что подобные размышления дадут вам
  некоторые идеи по поводу целей обратного распространения.
  
  Что насчёт другой загадки
  - как вообще можно было открыть обратное распространение?
  На самом деле, если вы последуете по обрисованному мною пути,
  вы получите доказательство обратного распространения.
  К несчастью, доказательство будет длиннее и сложнее
  чем то, что я описал ранее.
  Так как же было открыто то короткое
  (но ещё более загадочное) доказательство?
  Если записать все детали длинного доказательства,
  вам сразу бросятся в глаза несколько очевидных упрощений.
  Вы применяете упрощения,
  получаете более простое доказательство,
  записываете его.
  А затем вам опять на глаза попадаются несколько очевидных упрощений.
  И вы повторяете процесс.
  После нескольких повторений получится то доказательство,
  что мы видели ранее - короткое, но немного непонятное,
  поскольку из него удалены все путеводные вехи!
  Я, конечно, предлагаю вам поверить мне на слово,
  однако никакой загадки происхождения приведённого доказательства
  на самом деле нет.
  Просто много тяжёлой работы по упрощению доказательства,
  описанного мною в этом разделе.
  
  Однако в этом процессе есть один хитроумный трюк.
  В уравнении (53) промежуточные переменные
  - это активации, типа al+1q.
  Хитрость в том, чтобы перейти к использованию взвешенных входов,
  типа zl+1q, в качестве промежуточных переменных.
  Если не пользоваться этим,
  и продолжать использовать активации,
  полученное доказательство будет немногим более сложным,
  чем данное ранее в этой главе.
  //// Так я и не понял: эти "взвешенные ходы" реальные,
  //// т.е. как-то соответствующие каким-то "ячейкам памяти"
  //// или чисто "виртуальные", т.е. используемые только в формальной записи.
  //// А сам по себе прием известен в ТРИЗ
  //// вроде как, под названием "использовать промежуточный результат".
  //// Стоит запомнить это его применение.
  
  .......
  
  //// Конец цитирования.
  
  Очень трудный был материал, несмотря на то,
  что он как раз наиболее понятный из множества аналогичных по этой теме.
  И труден он даже не потому, что много математики,
  как раз кое в чем этой "чистой математики" мне чуть-чуть не хватило.
  Сложен в том, что упомянуто много деталей "обратного распространения",
  обычно не удостаиваемых внимания,
  но которые нужно как-то уложить в достаточно полную и непротиворечивую систему.
  
  Что-то в голове явно оформилось, но не скажу, что до конца,
  и есть над чем работать при проработке следующих глав,
  такого замечательного учебника.
  Так что, впереди следующие "погружения".
  
  
  ========
  
  26.03.2024 21:47
  
  "Звонок другу".
  В оглавление.
  
  Все-таки надо стараться не накапливать "технический долг"
  даже в процессе обучения "машинному обучению".
  Вот я и решил закрыть парочку, оставшихся у меня "непоняток"
  при проработке предыдущих материалов, обратившись за помощью к Copilot.
  
  24.03.2024 19:28
  
  .....
  
  //// Спасибо, Copilot. Общее представление о том, как должна выводится
  //// эта формула я имею.
  //// Но конкретно в тексте данной статьи эта формула какая-то совсем короткая
  //// без всяких производных и даже без собственно значения вес и функций активации.
  //// Вот этот текст:
  //// "Уравнение для скорости изменения стоимости по отношению к любому весу в сети:
  //// в частности:
  ////
  //// Отсюда мы узнаём, как подсчитать частную производную ?C/?wljk
  //// через значения ?l и al-1, способ расчёта которых нам уже известен.
  //// Это уравнение можно переписать в менее загруженной индексами форме:
  ////
  //// где ain - активация нейронного входа для веса w,
  //// а ?out - ошибка нейронного выхода от веса w.
  //// Если подробнее посмотреть на вес w и два соединённых им нейрона,
  //// то можно будет нарисовать это так:"
  ////
  //// Т.е. значение производной изменения веса равна
  //// произведению активации предыдущего слоя на ошибку следующего слоя.
  //// И вроде как интуитивно я понимаю, что все, наверное, верно
  //// но как это получается понять не могу.
  
  > Copilot 19:52
  
  > Давайте попробуем разобраться в этом вопросе.
  > Формула, о которой идет речь, отражает
  > один из ключевых моментов алгоритма обратного распространения ошибки
  >- как изменение веса влияет на общую ошибку сети.
  > В контексте нейронных сетей,
  > это изменение часто выражается через градиент функции потерь
  > по отношению к весам.
  
  > Формула, которую вы упомянули, говорит о том,
  > что градиент функции потерь ( \frac{\partial C}{\partial w_{ljk}} )
  > по отношению к весу ( w_{ljk} ) на ( l )-м слое
  > можно вычислить как произведение активации ( a_{in} ) предыдущего слоя
  > на ошибку ( \delta_{out} ) следующего слоя.
  > В математической форме это выглядит так:
  
  > $$\frac{\partial C}{\partial w_{ljk}} = a_{in} \cdot \delta_{out}$$Здесь:
  
  >  ( a_{in} ) - это активация нейрона на предыдущем слое,
  > который связан с весом ( w_{ljk} ).
  >  ( \delta_{out} ) - это градиент ошибки по активации нейрона на текущем слое,
  > который также связан с весом ( w_{ljk} ).
  
  > Это уравнение показывает,
  > что для обновления веса ( w_{ljk} ),
  > нам нужно знать, насколько сильно активация предыдущего нейрона
  > влияет на ошибку,
  > и насколько сильно сам вес влияет на активацию текущего нейрона.
  
  > Почему это работает?
  > Потому что в процессе обучения мы хотим минимизировать функцию потерь,
  > и для этого нам нужно знать направление,
  > в котором нужно изменить веса,
  > чтобы ошибка уменьшилась.
  > Градиент функции потерь по весам дает нам это направление.
  
  > Если говорить более наглядно, представьте,
  > что у вас есть крутящийся вентилятор,
  > и вы хотите замедлить его вращение.
  > Вы знаете, что если нажать на одно из лопастей в определенном направлении,
  > вентилятор замедлится.
  > В контексте нейронной сети, ( a_{in} ) - это ваша рука,
  > ( \delta_{out} ) - это сила и направление нажатия,
  > а ( w_{ljk} ) - это лопасть вентилятора.
  > Вычисляя ( a_{in} \cdot \delta_{out} ),
  > вы определяете, как именно нужно нажать на лопасть,
  > чтобы добиться желаемого эффекта.
  
  > Надеюсь, это объяснение помогло вам лучше понять,
  > как работает формула и почему она так важна
  > для процесса обучения нейронных сетей.
  
  ......
  
  /// Спасибо, Copilot. Вроде все понимаю,
  /// но почему-то интуитивно представлялось,
  /// что в этой формуле в какой-то форме будет присутствовать
  /// собственно значение веса w_{ljk},
  /// А его нет.
  /// И я не могу понять, где он "сокращается" или, наоборот, учтен.
  /// Собственно вопрос именно в этом:
  /// где спряталось "значение w_{ljk}"
  /// или почему я его и не должен видеть?
  /// Так, может быть, более понятно суть моего недопонимания этой формулы.
  
  > Copilot 20:05
  
  > Ваш вопрос очень важен для понимания механизма обучения нейронных сетей.
  > Давайте рассмотрим, почему в формуле градиента ошибки по весу ( w_{ljk} )
  > не присутствует сам вес.
  
  > В контексте обратного распространения ошибки,
  > когда мы вычисляем градиент функции потерь по весу ( w_{ljk} ),
  > мы фактически спрашиваем:
  > "Как изменение этого веса повлияет на общую ошибку сети?".
  > Мы не интересуемся текущим значением веса,
  > а хотим знать, как его небольшое изменение изменит ошибку.
  
  > Формула, которую вы упомянули:
  > $$\frac{\partial C}{\partial w_{ljk}} = a_{in} \cdot \delta_{out}$$
  > говорит о том, что градиент ошибки по весу
  > равен произведению активации предыдущего нейрона (( a_{in} ))
  > и градиента ошибки по активации следующего нейрона (( \delta_{out} )).
  > Здесь ( w_{ljk} ) не появляется напрямую,
  > потому что мы рассматриваем его влияние
  > через изменение активации следующего нейрона.
  
  > Вес ( w_{ljk} ) "учтен" в том смысле,
  > что он влияет на активацию следующего нейрона,
  > и это влияние мы уже учитываем,
  > когда вычисляем ( \delta_{out} ).
  > То есть, когда мы вычисляем градиент ошибки по активации следующего нейрона,
  > мы уже учитываем, как изменение веса повлияет на эту активацию,
  > и, следовательно, на ошибку.
  
  > Если бы мы рассматривали производную активации по весу,
  > тогда в формуле присутствовал бы сам вес:
  
  > $$\frac{\partial a_{out}}{\partial w_{ljk}} = a_{in}$$
  
  > Здесь мы видим, что изменение активации выходного нейрона (( a_{out} ))
  > по отношению к весу (( w_{ljk} ))
  > пропорционально активации входного нейрона (( a_{in} )),
  > и в этом случае значение веса не учитывается,
  > потому что мы рассматриваем линейную зависимость
  > между весом и активацией.
  
  > Надеюсь, это объяснение помогло вам лучше понять,
  > почему в формуле градиента ошибки по весу
  > не фигурирует сам вес.
  
  ......
  
  //// Большое спасибо, Copilot.
  //// Надеюсь, я понял и теперь долго сохраню это понимание.
  
  
  25.03.2024 21:23
  
  ......
  
  //// Вопрос очень конкретный и, наверно, простой и короткий.
  //// В тексте, в котором описывается вывод формул обратного распространения ошибки
  //// Встретился такой абзац:
  //// "Используя уравнение (25) для вычисления al,
  //// мы вычисляем промежуточное значение zl ? wlal?1+bl.
  //// Эта величина оказывается достаточно полезной для именования:
  //// мы называем zl взвешенным входом нейронов слоя ?l.
  //// Позднее мы активно будем использовать этот взвешенный вход."
  
  //// Вопрос в том является ли это "промежуточное значение",
  //// так сказать, "виртуальным",
  //// Т.е. используемым только для вывода формул,
  //// Или все-таки "реальным",
  //// в том смысле, что при прямом проходе
  //// эти значения запоминаются в каких-то ячейках памяти,
  //// и затем используются при обратном распространении.
  //// Понятно, что это зависит от конкретной реализации алгоритма,
  //// Но стало интересно:
  //// как это реализуется в широко распространенных библиотеках машинного обучения?
  
  > Copilot 21:33
  
  > Величина ( z_l ), которую вы упомянули,
  > и называемую взвешенным входом,
  > является действительно "реальной" в контексте обучения нейросетей.
  > В процессе прямого распространения (forward pass),
  > когда данные проходят через сеть,
  > для каждого слоя вычисляются активации нейронов.
  > Эти активации вычисляются как функция от взвешенного входа,
  > который в свою очередь является линейной комбинацией
  > входных данных предыдущего слоя и весов текущего слоя, плюс смещение (bias).
  
  > Взвешенный вход ( z_l ) используется
  > не только для вывода формул в теоретических расчетах,
  > но и сохраняется в памяти во время прямого прохода.
  > Это делается для того, чтобы во время обратного распространения ошибки
  > (backward pass)
  > можно было эффективно вычислить градиенты функции потерь по весам и смещениям.
  > Значения ( z_l ) необходимы для вычисления градиентов по активациям и весам,
  > так как они входят в производные функций активации,
  > которые используются при обновлении весов.
  
  > В широко распространенных библиотеках машинного обучения,
  > таких как TensorFlow и PyTorch,
  > этот процесс автоматизирован.
  > Когда вы строите модель и запускаете обучение,
  > библиотека автоматически сохраняет необходимые значения
  > во время прямого прохода и использует их во время обратного прохода
  > для вычисления градиентов.
  > Это одна из причин, почему обучение глубоких нейронных сетей
  > требует значительного объема оперативной памяти,
  > так как необходимо хранить все промежуточные значения
  > для каждого элемента обучающего набора данных.
  > Это также объясняет, почему глубокое обучение
  > часто использует графические процессоры (GPU)
  > или специализированные процессоры для машинного обучения (TPU),
  > которые имеют большое количество быстрой памяти,
  > оптимизированной для таких операций.
  
  //// Спасибо за исчерпывающий ответ, Copilot. Все понятно.
  //// Только хотелось бы задать еще один связанный с ним вопрос, но уже по ТРИЗ.
  //// Какому приему ТРИЗ соответствует такое сохранение промежуточных значений,
  //// И последующее их повторное использование?
  
  > Copilot 21:42
  
  > Сохранение промежуточных значений и их последующее использование
  > в контексте ТРИЗ может соответствовать нескольким приемам,
  > но один из наиболее подходящих
  > - это прием "использование внутренних ресурсов системы".
  > Этот прием подразумевает использование уже имеющихся элементов в системе
  > для достижения цели или решения задачи.
  > В случае с нейросетями, промежуточные значения,
  > полученные во время прямого прохода, являются внутренними ресурсами,
  > которые затем используются для обратного распространения ошибки
  > и обновления весов.
  > Это позволяет оптимизировать процесс обучения
  > и делает его более эффективным,
  > что соответствует принципу идеальности в ТРИЗ
  > - достижение максимального результата с минимальными усилиями
  > https://practicum.yandex.ru/blog/chto-takoe-metod-triz/.
  
  //// Спасибо, просто здорово, Copilot.
  
  С этими непонятками, вроде, разобрались.
  А вопрос про "стохастический градиентный спуск"
  я решил задать немного позже
  Появились мысли как это можно увязать с другой темой,
  а именно, с концепцией "терраформирования ландшафта" задачи/решения.
  Так что, это пока не к спеху. Надо все это получше продумать.
  
  
  =========
  
  31.03.2024 17:31
  
  Маленькие улучшения backpropagation.
  В оглавление.
  
  Продолжаем "погружаться" в не очень хитрые мудрености backpropagation
  - метода "обратного распространения ошибки".
  Данный материал не слишком сложный, формул не много, и они не сложны,
  а самое приятно, что по факту они толком то и не нужны,
  чтобы понять смысл наиболее распространенных ухищрений
  по улучшению результатов стандартного backpropagation.
  Зато на нем можно увидеть возможность совершенно других направлений
  совершенствования "обратного распространения",
  которые "почему-то" как-то "не на слуху":
  
  "Нейросети и глубокое обучение,
  глава 3, ч.1: улучшение способа обучения нейросетей".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/458724/.
  8 июл 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap3.html
  
  //// Начало цитирования.
  
  .......
  
  Среди техник, которым мы научимся в этой главе:
  лучший вариант на роль функции стоимости,
  а именно функция стоимости с перекрёстной энтропией;
  четыре т.н. метода регуляризации
  (регуляризации L1 и L2, исключение нейронов [dropout],
  искусственное расширение обучающих данных),
  улучшающих обобщаемость наших НС за пределы обучающих данных;
  лучший метод инициализации весов сети;
  набор эвристических методов,
  помогающих выбирать хорошие гиперпараметры для сети.
  Я также рассмотрю и несколько других техник, чуть более поверхностно.
  Эти обсуждения по большей части не зависят друг от друга,
  поэтому их можно по желанию перепрыгивать.
  Мы также реализуем множество технологий в рабочем коде
  и используем их для улучшения результатов,
  полученных для задачи классификации рукописных цифр, изученной в главе 1.
  
  Конечно, мы рассматриваем лишь малую толику огромного количества техник,
  разработанных для использования с нейросетями.
  Суть в том, что лучший способ войти в мир изобилия доступных техник
  - это подробное изучение нескольких самых важных из них.
  Овладение этими важными техниками не только полезно само по себе,
  оно ещё углубит ваше понимание того,
  какие проблемы могут возникать при использовании нейросетей.
  В итоге вы будете подготовлены для быстрой адаптации новых техник по необходимости.
  
  Функция стоимости с перекрёстной энтропией
  
  Большинству из нас неприятно быть неправым.
  Вскоре после начала обучения игре на пианино
  я дал небольшой концерт перед аудиторией.
  Я нервничал, и начал играть произведение на октаву ниже, чем надо.
  Я запутался, и не мог продолжать, пока кто-то не указал мне на ошибку.
  Мне было очень стыдно.
  Однако, хотя это и неприятно, мы также очень быстро обучаемся,
  решив, что мы ошиблись.
  И уж точно в следующий раз, когда я выступал перед аудиторией,
  я играл в нужной октаве!
  И наоборот, мы обучаемся медленнее,
  когда наши ошибки определены не очень хорошо.
  
  В идеале мы ожидаем,
  что наши нейросети будут обучаться быстро на своих ошибках.
  Происходит ли это на практике?
  Для ответа на этот вопрос посмотрим на надуманный пример.
  В нём участвует нейрон всего с одним входом:
  
  .......
  
  Мы обучаем этот нейрон делать нечто до смешного простое:
  принять на вход 1 и выдать 0.
  Конечно, решение такой тривиальной задачи мы могли бы найти,
  подобрав вес и смещение вручную,
  не используя обучающий алгоритм.
  Однако довольно полезно будет попытаться использовать градиентный спуск,
  чтобы получить в результате обучения вес и смещение.
  Давайте посмотрим на то, как обучается нейрон.
  
  Для определённости я выберу изначальный вес 0,6 и изначальное смещение 0,9.
  Это некие общие величины, назначенные в качестве отправной точки,
  и я не выбирал их специально.
  Изначально нейрон на выходе выдаёт 0,82,
  поэтому нам нужно многому научиться,
  чтобы он приблизился к желаемому выводу 0,0.
  В оригинале статьи есть интерактивная форма,
  на которой можно кликнуть и наблюдать процесс обучения.
  Это не записанная заранее анимация,
  браузер реально вычисляет градиент,
  а потом использует его для обновления веса и смещения,
  и демонстрирует результат.
  Скорость обучения ?=0,15, достаточно медленная,
  чтобы могли видеть, что происходит,
  но достаточно быстрая, чтобы обучение шло за секунды.
  Функция стоимости С - квадратичная, введённая в первой главе.
  Я вскоре напомню вам об её точной форме,
  поэтому не обязательно возвращаться и рыться там.
  Обучение можно запускать несколько раз, просто нажимая на кнопку .
  
  Как видите, нейрон быстро выучивает вес и смещение, понижающие стоимость,
  и даёт на выходе 0,09.
  Это не совсем желаемый результат 0,0, но достаточно неплохой.
  Допустим, что мы вместо этого выберем начальные вес и смещение 2,0.
  В данном случае изначальный выход будет равен 0,98, что совсем неверно.
  Давайте посмотрим, как в этом случае нейрон будет учиться выдавать 0.
  
  Хотя этот пример использует ту же скорость обучения (?=0,15),
  мы видим, что обучение проходит медленнее.
  Порядка 150 первых эпох веса и смещения почти не меняются.
  Затем обучение разгоняется,
  и, почти как в первом примере, нейрон быстро движется к 0,0.
  такое поведение странное, не похожее на обучение человека.
  Как я сказал в начале, мы часто быстрее всего учимся,
  когда сильно ошибаемся.
  Но мы только что видели, как наш искусственный нейрон с большим трудом учится,
  сильно ошибаясь - гораздо труднее,
  чем когда он ошибался немного.
  Более того, оказывается, что такое поведение возникает
  не только в нашем простом примере,
  но и в НС более общего назначения.
  //// Очень интересное замечание. Завяжу-ка "узелок на память".
  //// Нужно подумать, как с этим обстоят дело в битовых нейросетях?
  //// И что из этого следует?
  Почему обучение идёт так медленно?
  Можно ли найти способ избежать данной проблемы?
  
  Чтобы понять источник проблемы, вспомним,
  что наш нейрон обучается через изменение веса и смещения со скоростью,
  определяемой частными производными функции стоимости, ?C/?w и ?C/?b.
  Так что сказать <обучение идёт медленно>,
  это всё равно, что сказать, что эти частные производные малы.
  Проблема в том, чтобы понять, почему они малы.
  Для этого давайте вычислим частные производные.
  Вспомним, что мы используем квадратичную функцию стоимости,
  которая задаётся уравнением (6):
  
  $ C = \frac{(y-a)^2}{2} \tag{54} $
  
  где a - выход нейрона, когда на входе используется x=1,
  и y=0 - желаемый выход.
  Чтобы записать это непосредственно через вес и смещение,
  вспомним, что a=?(z), где z=wx+b.
  Используя цепное правило для дифференцирования по весу и смещению, получаем:
  
  $ \frac{\partial C}{\partial w} = (a-y)\sigma'(z) x = a \sigma'(z) \tag{55} $
  
  $ \frac{\partial C}{\partial b} = (a-y)\sigma'(z) = a \sigma'(z) \tag{56} $
  
  где я подставил x=1 и y=0.
  Чтобы понять поведение этих выражений,
  давайте подробнее взглянем на член \sigma'(z) справа. Вспомним форму сигмоиды:
  
  ........
  
  Из графика видно, что когда выход нейрона близок к 1,
  кривая становится очень плоской,
  и \sigma'(z) становится маленькой.
  Уравнения (55) и (56) говорят нам о том,
  что ?C/?w и ?C/?b становятся очень маленькими.
  Отсюда и растёт замедление обучения.
  Более того, как мы увидим чуть позже,
  замедление обучения происходит,
  по сути, по той же причине и в НС более общего характера,
  а не только в нашем простейшем примере.
  
  //// А зачем мы применяем "сигмоиду"?
  //// Чтобы ограничить диапазон значений
  //// и оставить функцию активации непрерывной,
  //// гладкой и легко вычисляемой и ее самой и ее производной.
  //// И это входит в конфликт/противоречие с требованием "скорости обучения".
  //// Типичное техническое противоречие.
  //// И как же оно решается?
  
  Представляем функцию стоимости с перекрёстной энтропией
  
  Как нам быть с замедлением обучения?
  Оказывается, мы можем решить проблему,
  заменив квадратичную функцию стоимости другой функцией стоимости,
  известной под названием перекрёстной энтропии.
  Чтобы понять перекрёстную энтропию,
  отойдём от нашей простейшей модели.
  Допустим, мы обучаем нейрон с несколькими входными значениями x1,x2,:
  соответствующими весами w1,w2,: и смещением b:
  
  ......
  
  Выход нейрона, конечно, будет a=?(z),
  где z=?jwjxj+b - взвешенная сумма входов.
  Мы определяем функцию стоимости с перекрёстной энтропией для данного нейрона,
  как
  
  $ C = -\frac{1}{n} \sum_x \left[y \ln a + (1-y ) \ln (1-a) \right] \tag{57} $
  
  где n - общее количество единиц обучающих данных,
  сумма идёт по всем обучающим данным x,
  а y - соответствующий желаемый выход.
  
  Не очевидно, что у равнение (57) решает проблему замедления обучения.
  Честно говоря, даже не очевидно,
  что имеет смысл называть это функцией стоимости!
  Перед тем, как обратиться к замедлению обучения,
  посмотрим, в каком смысле перекрёстную энтропию можно интерпретировать
  как функцию стоимости.
  //// Ну, в принципе никаких особых ограничений,
  //// чтобы назвать самые "хитроумные формулы" функцией стоимости,
  //// как-то "забыли" определить.
  //// Только какие-то общие соображения, причем явно не проговоренные.
  //// И это, на мой взгляд, идеологически правильно,
  //// так надо говорить не о "функции стоимости",
  //// а о функции "управления обучением".
  //// И тогда это уже может указывать на куда более сложную стратегию обучения,
  //// чем просто "реакция" на каждый отдельный обучающий пример.
  //// В принципе те же самые "мини-батчи" можно рассматривать,
  //// как на самую элементарную/зачаточную стратегию обучения.
  
  Два свойства в особенности делают разумным интерпретацию перекрёстной энтропии
  как функции стоимости.
  Во-первых, она больше нуля, то есть, C>0.
  Чтобы увидеть это, отметьте,
  что (а) все отдельные члены суммы в (57) отрицательны,
  поскольку оба логарифма берутся от чисел в диапазоне от 0 до 1,
  и (б) перед суммой стоит знак минуса.
  //// Тоже интересный момент.
  //// Существующая концепция "обратного распространения ошибки"
  //// "по умолчанию" не предполагает "отрицательную стоимость",
  //// т.е. не ошибку/штраф за неправильный результат,
  //// а, наоборот, поощрение/вознаграждение за удачный результат.
  //// Может быть с этим и связана низкая эффективность
  //// "обратного распространения ошибки" в методах "обучения с подкреплением",
  //// т.к. требует очень нетривиальной "конвертации" "поощрения" в "ошибку".
  
  Во-вторых, если реальный выход нейрона близок к желаемому выходу
  для всех обучающих входов x,
  тогда перекрестная энтропия будет близка к нулю.
  Для доказательства нам нужно будет предположить,
  что желаемые выходы y будут равны либо 0, либо 1.
  Обычно так и бывает при решении проблем классификации,
  или вычислении булевых функций.
  Чтобы понять, что происходит, если не делать такого предположения,
  обратитесь к упражнениям в конце раздела.
  
  Чтобы доказать это, представим,
  что y=0 и a?0 for для некоего входного x.
  Так будет, когда нейрон хорошо обрабатывает такой вход.
  Мы видим, что первый член выражения (57)
  для стоимости исчезает, поскольку y=0,
  а второй будет равен ?ln(1?a) ?0.
  То же выполняется, когда y=1 и a?1.
  Поэтому вклад стоимости будет небольшим,
  если реальный выход будет близким к желаемому.
  
  Подытоживая, получим, что перекрёстная энтропия положительна,
  и стремится к нулю, когда нейрон лучше вычисляет желаемый выход y
  для всех обучающих входов x.
  Наличия обоих свойств мы ожидаем у функции стоимости.
  И действительно, оба эти свойства выполняет и квадратичная стоимость.
  Поэтому, для перекрёстной энтропии это хорошие новости.
  Однако у функции стоимости с перекрёстной энтропией есть преимущество,
  поскольку, в отличии от квадратичной стоимости,
  она избегает проблемы замедления обучения.
  Чтобы увидеть это, давайте подсчитаем частную производную стоимости
  с перекрёстной энтропией по весам.
  Подставим a=?(z) в (57), дважды применим цепное правило, и получим:
  
  $ \frac{\partial C}{\partial w_j} = -\frac{1}{n} \sum_x \left( \frac{y }{\sigma(z)} -\frac{(1-y)}{1-\sigma(z)} \right) \frac{\partial \sigma}{\partial w_j} \tag{58} $
  
  $ = -\frac{1}{n} \sum_x \left( \frac{y}{\sigma(z)} -\frac{(1-y)}{1-\sigma(z)} \right)\sigma'(z) x_j \tag{59} $
  
  Приводя к общему знаменателю и упростив, получим:
  
  $ \frac{\partial C}{\partial w_j} = \frac{1}{n} \sum_x \frac{\sigma'(z) x_j}{\sigma(z) (1-\sigma(z))} (\sigma(z)-y). \tag{60} $
  
  Используя определение сигмоиды, ?(z)=1/(1+e?z) и немножко алгебры,
  можно показать, что ??(z) = ?(z)(1 ? ?(z)).
  Проверить это я попрошу вас в упражнении далее,
  но пока что примем это, как истину.
  Члены ??(z) и ?(z)(1??(z)) сокращаются, и это приводит к
  
  $ \frac{\partial C}{\partial w_j} = \frac{1}{n} \sum_x x_j(\sigma(z)-y). \tag{61} $
  
  Прекрасное выражение.
  Из него следует, что скорость, с которой обучаются веса,
  контролируется ?(z)?y, то есть, ошибкой на выходе.
  Чем больше ошибка, тем быстрее обучается нейрон.
  Этого можно было интуитивно ожидать.
  Этот вариант избегает замедления обучения,
  вызванного членом \sigma'(z)
  в аналогичном уравнении для квадратичной стоимости (55).
  Когда мы используем перекрёстную энтропию,
  член \sigma'(z) сокращается,
  и нам уже не приходится волноваться о его малости.
  Это сокращение - особое чудо,
  гарантируемое функцией стоимости с перекрёстной энтропией.
  На самом деле, конечно, это не совсем чудо.
  Как мы увидим позднее,
  перекрёстную энтропию специально выбрали именно за это свойство.
  //// Или сконструировали, под конкретную функцию активации?
  //// Да нет, наверно, это все-таки более общая формула.
  //// А интересно, как она используется для глубинных слоев нейросети?
  
  Сходным образом можно вычислить частную производную для смещения.
  Не буду приводить заново все детали, но можно легко проверить, что
  
  $ \frac{\partial C}{\partial b} = \frac{1}{n} \sum_x (\sigma(z)-y). \tag{62} $
  
  Это опять-таки помогает избежать замедления обучения из-за члена \sigma'(z)
  в аналогичном у равнении для квадратичной стоимости (56).
  
  .....
  
  
  Вернёмся к нашему надуманному примеру, с которым мы игрались ранее,
  и посмотрим, что случится, если вместо квадратичной стоимости
  мы будем использовать перекрёстную энтропию.
  Чтобы настроиться, мы начнём со случая,
  в котором квадратичная стоимость отлично сработала,
  когда начальный вес был 0,6 а смещение - 0,9.
  В оригинале статьи есть интерактивная форма,
  в которой можно нажать кнопку и посмотреть,
  что происходит при замене квадратичной стоимости на перекрёстную энтропию.
  
  Ничего удивительного, нейрон в данном случае обучается прекрасно, как и ранее.
  Теперь посмотрим на случай, в котором раньше нейрон застревал,
  с весом и смещением, начинающимися с величины 2,0.
  
  ......
  
  Успех!
  На этот раз нейрон обучился быстро, как мы и хотели.
  Если наблюдать пристально, можно увидеть,
  что наклон кривой стоимости изначально более крутой,
  по сравнению с плоским регионом соответствующей кривой квадратичной стоимости.
  Эту крутость даёт нам перекрёстная энтропия,
  и не даёт застрять там, где мы ожидаем наискорейшее обучение нейрона,
  когда он начинает с очень больших ошибок.
  
  Я не сказал, какая скорость обучения использовалась в последних примерах.
  Ранее с квадратичной стоимостью мы использовали ?=0,15.
  Должны ли мы использовать такую же скорость и в новых примерах?
  На самом деле, меняя функцию стоимости,
  нельзя точно сказать,
  что значит - использовать <такую же> скорость обучения;
  это будет сравнения яблок с апельсинами.
  Для обеих функций стоимости я экспериментировал,
  подыскивая скорость обучения, позволяющую увидеть происходящее.
  Если вам всё же интересно, то в последних примерах ?=0,005.
  
  Вы можете возразить, что изменение скорости обучения лишает графики смысла.
  Кому какая разница, как быстро обучается нейрон,
  если мы могли произвольно выбирать скорость обучения?
  Но это возражение не учитывает главного.
  Смысл графиков не в абсолютной скорости обучения,
  а в том, как меняется эта скорость.
  При использовании квадратичной функции обучение идёт медленнее,
  если нейрон сильно ошибается,
  а потом идёт быстрее, когда нейрон подходит к нужному ответу.
  С перекрёстной энтропией обучение идёт быстрее,
  когда нейрон сильно ошибается.
  И эти утверждения не зависят от заданной скорости обучения.
  
  Мы исследовали перекрёстную энтропию для одного нейрона.
  Однако это легко обобщить на сети со многими слоями и многими нейронами.
  Допустим, что y=y1, y2,... - желаемые значения выходных нейронов,
  то есть, нейронов в последнем слое,
  а aL1, aL2,.. - сами выходные значения.
  Тогда перекрёстную энтропию можно определить, как:
  
  $ C = -\frac{1}{n} \sum_x \sum_j \left[y_j \ln a^L_j + (1-y_j) \ln (1-a^L_j) \right] \tag{63} $
  
  Это то же самое, что уравнение (57),
  только теперь наша ?j суммирует по всем выходным нейронам.
  Не буду подробно разбирать производную,
  однако разумно предположить, что с использованием выражения (63)
  мы можем избежать замедления в сетях с многими нейронами.
  Если интересно, вы можете взять производную в задаче ниже.
  
  Между прочим, используемый мною термин <перекрёстная энтропия>
  запутал некоторых ранних читателей книги,
  поскольку он противоречит другим источникам.
  В частности, нередко перекрёстную энтропию определяют
  для двух распределений вероятности, pj и qj, как ?jpjlnqj.
  Это определение можно связать с (57),
  если считать один сигмоидный нейрон выдающим распределение вероятности,
  состоящее из активации нейрона a и дополняющей её величины 1-a.
  
  Однако, если у нас в последнем слое много сигмоидных нейронов,
  вектор aLj обычно не даёт распределения вероятностей.
  В итоге определение типа ?jpjlnqj лишено смысла,
  поскольку мы не работаем с распределениями вероятности.
  Вместо этого (63) можно представлять себе,
  как просуммированный набор перекрёстных энтропий каждого нейрона,
  где активация каждого нейрона интерпретируется
  как часть двухэлементного распределения вероятности
  (конечно, в наших сетях нет никаких вероятностных элементов,
  поэтому это на самом деле никакие не вероятности).
  В этом смысле (63) будет обобщением перекрёстной энтропии
  для распределений вероятностей.
  
  Когда использовать перекрёстную энтропию вместо квадратичной стоимости?
  На самом деле, перекрёстную энтропию почти всегда будет использовать лучше,
  если выходные нейроны у вас сигмоидные.
  //// А если сигмоидальны промежуточные нейроны?
  Чтобы понять это, вспомним, что настраивая сеть,
  мы обычно инициализируем веса и смещения при помощи
  некоего случайного процесса.
  Может так получиться, что этот выбор приведёт к тому,
  что сеть будет совершенно неверно интерпретировать
  некие обучающие входные данные
  - к примеру, выходной нейрон будет стремиться к 1,
  когда должен стремиться к 0, или наоборот.
  Если мы используем квадратичную стоимость,
  которая замедляет обучение,
  она не остановит обучение совсем,
  поскольку веса будут продолжать обучаться на других обучающих примерах,
  но такая ситуация, очевидно, является нежелательной.
  
  Упражнения
  
  Один подвох перекрёстной энтропии состоит в том,
  что сначала может быть трудно запомнить соответствующие роли y и a.
  Легко запутаться, как будет правильно,
  -[ylna+(1-y)ln(1-a)] или -[alny+(1-a)ln(1-y)].
  Что будет со вторым выражением, когда y=0 или 1?
  Влияет ли эта проблема на первое выражение?
  Почему?
  
  В обсуждении единственного нейрона в начале раздела,
  я говорил, что перекрёстная энтропия мала,
  если ?(z)?y для всех обучающих входящих данных.
  Аргумент основывался на том, что y равен 0 или 1.
  Обычно в задачах классификации так и есть,
  но в других задачах (например, регрессии)
  y иногда может принимать значения между 0 и 1.
  Покажите, что перекрёстная энтропия всё равно минимизируется,
  когда ?(z)=y для всех обучающих входов.
  Когда так происходит, значение перекрёстной энтропии равно
  $ C = -\frac{1}{n} \sum_x [y \ln y+(1-y) \ln(1-y)] \tag{64} $
  
  Величину -[ylny+(1-y)ln(1-y)] иногда называют бинарной энтропией.
  
  
  Задачи
  
  Многослойные сети с многими нейронами.
  В записи из последнего раздела покажите,
  что для квадратичной стоимости частная производная по весам в выходном слое равна
  
  $ \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j) \sigma'(z^L_j) \tag{65} $
  
  Член ?'(zLj) заставляет обучение замедляться,
  когда нейрон склоняется к неверному значению.
  Покажите, что для функции стоимости с перекрёстной энтропией
  выходная ошибка ?L для одного обучающего примера x задаётся уравнением
  
  $ \delta^L = a^L-y \tag{66} $
  
  Используйте это выражение, чтобы показать,
  что частная производная по весам в выходном слое задаётся уравнением
  
  $ \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j) \tag{67} $
  
  Член ?'(zLj) исчез,
  поэтому перекрёстная энтропия избегает проблемы замедления обучения,
  не только при использовании с одним нейроном,
  но и в сетях с многими слоями и многими нейронами.
  С небольшим изменением этот анализ подходит и для смещений.
  Если это неочевидно для вас,
  вам лучше проделать и этот анализ также.
  
  Использование квадратичной стоимости с линейными нейронами во внешнем слое.
  Допустим, у нас многослойная сеть с многими нейронами.
  Допустим, в финальном слое все нейроны линейные,
  то есть сигмоидная функция активации не применяется,
  а их выход просто определяется, как aLj = zLj.
  Покажите, что при использовании квадратичной функции стоимости
  выходная ошибка ?L для одного обучающего примера x задаётся
  
  $ \delta^L = a^L-y \tag{68} $
  
  Как и в прошлой задаче, используйте это выражение,
  чтобы показать, что частные производные по весам и смещениям
  во внешнем слое определяются, как
  
  $ \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j) \tag{69} $
  
  $ \frac{\partial C}{\partial b^L_{j}} = \frac{1}{n} \sum_x (a^L_j-y_j) \tag{70} $
  
  Это показывает, что если выходные нейроны линейные,
  тогда квадратичная стоимость не вызовет никаких проблем с замедлением обучения.
  В этом случае квадратичная стоимость вполне подходит для использования.
  
  //// Т.е. в отношении выходного слоя требования СОГЛАСОВАНИЯ
  //// функции активации и функции стоимости ошибки
  //// являются вполне разумными, и полностью согласуются с "приемами ТРИЗ".
  
  Использование перекрёстной энтропии для классификации цифр из MNIST
  
  Перекрёстную энтропию легко реализовать в виде части программы,
  обучающей сеть при помощи градиентного спуска и обратного распространения.
  Позже мы сделаем это, разработав улучшенную версию
  нашей ранней программы классификации рукописных цифр из MNIST, network.py.
  Новая программа называется network2.py, и включает
  не только перекрёстную энтропию,
  но и несколько других техник, разработанных в этой главе.
  А пока посмотрим, насколько хорошо наша новая программа
  классифицирует цифры MNIST.
  Как и в главе 1, мы будем использовать сеть с 30 скрытыми нейронами,
  и мини-пакетом размером в 10.
   Установим скорость обучения ?=0,5 и будем обучаться 30 эпох.
  
  Как я уже говорил, нельзя точно сказать,
  какая скорость обучения подойдёт в каком случае,
  поэтому я экспериментировал с подбором.
  Правда, существует способ очень грубо эвристически связать
  скорость обучения с перекрёстной энтропией и квадратичной стоимостью.
  Раньше мы видели, что в членах градиента для квадратичной стоимости
  есть дополнительный член ?'=?(1-?).
  Допустим, мы усредним эти значения для ?, ?10d? ? (1??)=1/6.
  Видно, что (очень грубо) квадратичная стоимость
  в среднем обучается в 6 раз медленнее для той же скорости обучения.
  Это говорит о том, что хорошей отправной точкой будет
  поделить скорость обучения для квадратичной функции на 6.
  Конечно, это совершенно не строгий аргумент,
  и не стоит принимать его слишком серьёзно.
  Но он иногда может быть полезным в качестве отправной точки.
  
  ........
  
  Отметьте, кстати, что команда net.large_weight_initializer()
  используется для инициализации весов и смещений
  так же, как описано в главе 1.
  Нам нужно прогнать её, потому что позже
  мы изменим инициализацию весов по умолчанию.
  В итоге, после запуска всех указанных выше команд,
  мы получим сеть, работающую с точностью в 95,49%.
  Это очень близко к результату из первой главы, 95.42%,
  использовавшему квадратичную стоимость.
  //// Не понял. А где же преимущество "перекрестной энтропии"?
  
  Давайте также посмотрим на случай,
  где мы используем 100 скрытых нейронов и перекрёстную энтропию,
  а всё остальное оставляем таким же.
  В этом случае точность получается 96,82%.
  Это серьёзное улучшение по сравнению с результатами из первой главы,
  где мы достигли точности в 96.59%, используя квадратичную стоимость.
  Изменение может показаться небольшим,
  но подумайте о том, что ошибка упала с 3,41% до 3,18%.
  То есть, мы устранили примерно 1/14 ошибок.
  Это довольно неплохо.
  //// Но "тринадцать из четырнадцати" все-таки остались.
  //// Разве это действительно существенное улучшение?
  
  Довольно приятно, что функция стоимости с перекрёстной энтропией
  даёт нам сходные или лучшие результаты по сравнению с квадратичной стоимостью.
  Однако они не доказывают однозначно, что перекрёстная энтропия - лучший выбор.
  Дело в том, что я вовсе не старался выбирать гиперпараметры
  - скорость обучения, размер мини-пакета, и т.д.
  Чтобы улучшение получилось более убедительным,
  нам нужно как следует заняться их оптимизацией.
  Но результаты всё равно вдохновляющие,
  и подтверждают наши теоретические выкладки о том,
  что перекрёстная энтропия - лучший выбор,
  чем квадратичная функция стоимости.
  
  В этом ключе пройдёт вся эта глава
  и, в принципе, остаток книги.
  Мы будем вырабатывать новую технику, испытывать её,
  и получать <улучшенные результаты>.
  Конечно, хорошо, что мы видим эти улучшения.
  Но интерпретировать их всегда сложно.
  Убедительно будет только,
  если мы увидим улучшения после серьёзной работы по оптимизации
  всех остальных гиперпараметров.
  А это довольно сложная работа,
  требующая больших вычислительных ресурсов,
  и обычно мы не будем заниматься таким тщательным расследованием.
  Вместо этого мы будем идти дальше на базе неформальных тестов,
  как тех, что приведены выше.
  Но вам нужно иметь в виду,
  что такие тесты не являются однозначным доказательством,
  и внимательно следить за теми случаями,
  когда аргументы начинают сбоить.
  
  Пока что мы подробно обсуждали перекрёстную энтропию.
  Зачем тратить столько сил,
  если она даёт такое небольшое улучшение наших результатов по MNIST?
  Позже в этой главе мы увидим другие техники
  - в частности, регуляризацию -
  дающие куда как более сильные улучшения.
  Так зачем мы концентрируемся на перекрёстной энтропии?
  В частности потому, что перекрёстная энтропия
  - это часто используемая функция стоимости,
  поэтому в ней стоит хорошо разобраться.
  Но более важной причиной будет то,
  что насыщение нейронов - важная в области нейросетей проблема,
  к которой мы будем постоянно возвращаться на протяжении книги.
  Поэтому я так подробно обсуждал перекрёстную энтропию,
  поскольку это хорошая лаборатория для того,
  чтобы начать разбираться в насыщении нейронов
  и в том, как можно искать подходы к этой проблеме.
  
  Что означает перекрёстная энтропия?
  Откуда она берётся?
  
  Наше обсуждение перекрёстной энтропии вращалось
  вокруг алгебраического анализа и практической реализации.
  Это полезно, но в итоге остаются без ответа
  более широкие концептуальные вопросы,
  например: что означает перекрёстная энтропия?
  Есть ли интуитивный способ её представлять?
  Как люди вообще могли придумать перекрёстную энтропию?
  
  Начнём с последнего:
  что могло подвигнуть нас на размышление о перекрёстной энтропии?
  Допустим, мы обнаружили замедление обучения, описанное ранее,
   и поняли, что его причиной были члены \sigma'(z) в уравнениях (55) и (56).
  Немного поглазев на эти уравнения, мы могли бы задуматься,
  нельзя ли выбрать такую функцию стоимости,
  чтобы член \sigma''(z) исчез.
  Тогда стоимость C = Cx одного обучающего примера удовлетворяла бы уравнениям:
  
  $ \frac{\partial C}{\partial w_j} = x_j(a-y) \tag{71} $
  
  $ \frac{\partial C}{\partial b } = (a-y) \tag{72} $
  
  Если бы мы выбрали функцию стоимости, делающую их истинными,
  то они бы довольно просто описали бы интуитивное понимание того,
  что чем больше изначальная ошибка, тем быстрее обучается нейрон.
  Они бы также устранили проблему с замедлением обучения.
  На самом деле, начав с этих уравнений, мы бы показали,
  что возможно вывести форму перекрёстной энтропии,
  просто следуя математическому чутью.
  Чтобы увидеть это, отметим, что, исходя из цепного правила, мы получаем:
  
  $ \frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} \sigma'(z) \tag{73} $
  
  Используя в последнем уравнении \sigma'(z) = \sigma(z)(1-\sigma(z)) = a(1-a),
  получим:
  
  $ \frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} a(1-a) \tag{74} $
  
  Сравнив с уравнением (72), получим:
  
  $ \frac{\partial C}{\partial a} = \frac{a-y}{a(1-a)} \tag{75} $
  
  Интегрируя это выражение по a, получим:
  
  $ C = -[y \ln a + (1-y) \ln (1-a)]+ {\rm constant} \tag{76} $
  
  Это вклад отдельного обучающего примера x в функцию стоимости.
  Чтобы получить полную функцию стоимости,
  нам нужно усреднить по всем обучающим примерам, и мы приходим к:
  
  $ C = -\frac{1}{n} \sum_x [y \ln a +(1-y) \ln(1-a)] + {\rm constant} \tag{77} $
  
  Константа тут - средняя по отдельным константам каждого из обучающих примеров.
  Как видим, уравнения (71) и (72) уникальным образом определяют
  форму перекрёстной энтропии,
  вплоть до общей константы.
  Перекрёстную энтропию не доставали волшебным образом из воздуха.
  Её можно было найти простым и естественным образом.
  
  Что насчёт интуитивного представления о перекрёстной энтропии?
  Как нам её себе представлять?
  Подробное объяснение привело бы к тому,
  что мы бы обогнали наш учебный курс.
  Однако можно упомянуть о существовании
  стандартного способа интерпретации перекрёстной энтропии,
  происходящего из области теории информации.
  Грубо говоря, перекрёстная энтропия - это мера неожиданности.
  //// Обязательно надо запомнить.
  Например, наш нейрон пытается подсчитать функцию xy=y(x).
  Но вместо этого он подсчитывает функцию xa=a(x).
  Допустим, мы представляем себе a,
  как оценку нейроном вероятности того, что y=1,
  а 1-a - вероятность того, что правильным значением для y будет 0.
  Тогда перекрёстная энтропия измеряет то,
  насколько мы <удивлены>, в среднем,
  когда обнаруживаем истинное значение y.
  Мы не сильно удивлены, если выход нами ожидаем,
  и сильно удивлены, если выход неожиданный.
  Конечно, я не давал строгого определения <удивлению>,
  поэтому всё это можно показаться пустым разглагольствованием.
  Но на самом деле в теории информации существует
  точный способ определения неожиданности.
  К сожалению, мне неизвестно ни одного примера хорошего,
  короткого и самодостаточного обсуждения этого момента в интернете.
  Но если вам интересно копнуть поглубже,
  то в статье в Википедии есть хорошая общая информация,
  которая отправит вас в нужном направлении.
  Детали можно почерпнуть из 5-й главы, касающейся неравенства Крафта,
  в книжке по теории информации [англ.].
  
  Задача
  
  Мы подробно обсудили замедление обучения,
  которое может произойти при насыщении нейронов в сетях
  с использованием квадратичной функции стоимости при обучении.
  Ещё один фактор, способный подавлять обучение
  - наличие члена xj в уравнении (61).
  Из-за него, когда выход xj приближается к нуля,
  соответствующий вес wj будет обучаться медленно.
  Поясните, почему невозможно устранить член xj
  выбором какой-нибудь хитроумной функции стоимости.
  //// Объяснить не могу, да и не сильно хочется,
  //// а вот новую задачку для себя для метода обратного распространения,
  //// похоже, увидел.
  //// Но она, по-видимому, вообще "родимое пятно" самой архитектуры
  //// сигмоидного нейрона.
  
  Softmax (функция мягкого максимума)
  
  В данной главе мы по большей части будем использовать
  функцию стоимости с перекрёстной энтропией
  для решения проблем замедления обучения.
  Однако мне хочется кратко обсудить ещё один подход к этой проблеме,
  основанный на т.н. softmax-слоях нейронов.
  Мы не будем использовать Softmax-слои в оставшейся части главы,
  поэтому, если вы очень торопитесь, можете пропустить этот раздел.
  Однако в Softmax всё же стоит разобраться,
  в частности, потому, что она интересна сама по себе,
  и в частности потому, что мы будем использовать Softmax-слои в главе 6,
  в нашем обсуждении глубоких нейросетей.
  
  Идея Softmax состоит в том,
  чтобы определить новый тип выходного слоя для НС.
  Он начинается так же, как сигмоидный слой,
  с формирования взвешенных входов
  $z^L_j = \sum_{k} w^L_{jk} a^{L-1}_k + b^L_j$.
  Однако мы не применяем сигмоиду для получения ответа.
  В Softmax-слое мы применяем Softmax-функцию к zLj.
  Согласно ей, активация aLj выходного нейрона ?j равна:
  
  $ a^L_j = \frac{e^{z^L_j}}{\sum_k e^{z^L_k}} \tag{78} $
  
  где в знаменателе мы суммируем по всем выходным нейронам.
  
  Если Softmax-функция вам незнакома,
  уравнение (78) покажется вам загадочным.
  Совершенно неочевидно, зачем нам использовать такую функцию.
  Также неочевидно,
  что она поможет нам решить проблему замедления обучения.
  Чтобы лучше понять уравнение (78),
  предположим, что у нас есть сеть с четырьмя выходными нейронами
  и четырьмя соответствующими взвешенными входами,
  которые мы будем обозначать, как zL1, zL2, zL3 и zL4.
  В оригинале статьи имеются интерактивные регулировочные ползунки,
  которым назначены возможные значения взвешенных входов
  и график соответствующих выходных активаций.
  Хорошей отправной точкой для их изучения будет
  использование нижнего ползунка для увеличения zL4.
  
  ......
  
  Увеличивая zL4, можно наблюдать увеличение соответствующей выходной активации, aL4,
  и уменьшение остальных выходных активаций.
  При уменьшении zL4 aL4 будет уменьшаться,
  а все остальные выходные активации - увеличиваться.
  Присмотревшись, вы увидите, что в обоих случаях
  общее изменение других активаций точно компенсирует изменение,
  происходящее в aL4.
  Причина этого в наличии гарантии того,
  что все выходные активации в сумме дают 1,
  что мы можем доказать при помощи уравнения (78) и кое-какой алгебры:
  
  $ \sum_j a^L_j = \frac{\sum_j e^{z^L_j}}{\sum_k e^{z^L_k}} = 1 \tag{79} $
  
  В итоге, с увеличением aL4 остальные выходные активации
  обязаны уменьшаться на то же значение в сумме,
  чтобы гарантировать, что сумма всех выходных активаций будет равной 1.
  И, конечно, сходные утверждения будут верны для всех остальных активаций.
  
  Из уравнения (78) также следует, что все выходные активации положительны,
  поскольку функция экспоненты положительна.
  Сочетая это с наблюдением из предыдущего параграфа,
  получим, что выход Softmax-слоя будет набором положительных чисел,
  дающих в сумме 1.
  Иначе говоря, выход Softmax-слоя можно представить,
  как распределение вероятности.
  
  То, что выход Softmax-слоя - это распределение вероятности,
  весьма приятно.
  //// Но никак не обосновано кроме "сумме равной единице".
  Во многих задачах удобно иметь возможность
  интерпретировать
  //// Вот именно "интерпретировать", т.е. "предполагать",
  //// и пытаться делать из этого какие=то выводы.
  //// Иногда забывая при этом, что само это "предположение"
  //// подчиняется некоторому "распределению вероятности",
  //// т.е. в конкретном случае может быть очень далеким
  //// от "действительного положения вещей".
  выходные активации aLj как оценку сетью вероятности того,
  что правильным вариантом булет j.
  Так что, к примеру в задаче классификации MNIST
  мы можем интерпретировать aLj как оценку сетью вероятности того,
  что правильным вариантом классификации цифры будет j.
  
  И наоборот, если выходной слой был сигмоидным,
  тогда мы определённо не можем предполагать,
  что активации формируют распределение вероятности.
  Я не буду доказывать это строго,
  но разумно считать, что активации сигмоидного слоя
  в общем случае не формируют распределение вероятности.
  Поэтому с использованием сигмоидного выходного слоя
  мы не получим такой простой интерпретации выходных активаций.
  
  Упражнение
  
  Составьте пример, показывающий,
  что в сети с сигмоидным выходным слоем выходные активации aLj
  не всегда в сумме дают 1.
  
  Мы начинаем немного разбираться в Softmax-функции и том,
  как ведут себя Softmax-слои.
  Просто чтобы подвести промежуточный итог:
  экспоненты в уравнении (78) гарантируют,
  что все выходные активации будут положительными.
  Сумма в знаменателе уравнения (78) гарантирует,
  что выход Softmax в сумме даст 1.
  Поэтому этот вид уравнения уже не кажется загадочным:
  это естественный способ гарантировать,
  чтобы выходные активации формировали распределение вероятности.
  Softmax можно представить себе,
  как способ изменения масштаба zLj с последующим сжатием их в кучку
  для формирования распределения вероятности.
  
  Упражнения
  
  Монотонность Softmax.
  Покажите, что ?aLj / ?zLk положительна, если j=k,
  и отрицательна, если j?k.
  Как следствие, увеличение zLj
  гарантированно увеличивает соответствующую выходную активацию aLj,
  и уменьшает все остальные выходные активации.
  Мы уже видели это эмпирически на примере ползунков,
  однако данное доказательство будет строгим.
  
  Нелокальность Softmax.
  Приятной особенностью сигмоидных слоёв является то,
  что выход aLj - функция соответствующего взвешенного входа, aLj = ?(zLj).
  Поясните, почему с Softmax-слоем это не так:
  любая выходная активация aLj зависит от всех взвешенных входов.
  
  
  Задача
  
  Инвертирование Softmax-слоя.
  //// Наверно, тут лучше было бы сказать "обращение", а не "инвертирование",
  //// т.к. речь идет обратной трансляции ошибки через этот слой.
  Допустим, у нас есть НС с выходным Softmax-слоем и активации aLj известны.
  Покажите, что соответствующие взвешенные входы имеют форму
  zLj = ln aLj + C,
  где C - константа, не зависящая от j.
  
  Проблема замедления обучения
  
  Мы уже достаточно близко познакомились с Softmax-слоями нейронов.
  Но пока что мы не видели, как Softmax-слои позволяют нам
  решить проблему замедления обучения.
  Чтобы понять это, давайте определим функцию стоимости
  на основе <логарифм-правдоподобия>.
  Мы будем использовать x для обозначения обучающего входа сети,
  и y для соответствующего желаемого выхода.
  Тогда ЛПС, связанная с этим обучающим входом, будет:
  
  $ C \equiv -\ln a^L_y \tag{80} $
  
  Так что, если мы, к примеру, обучаемся на изображениях MNIST,
  и на вход пошло изображение 7, тогда ЛПС будет равной -ln aL7.
  Чтобы понять это интуитивно,
  рассмотрим случай, когда сеть хорошо справляется с распознаванием,
  то есть, уверена, что на входе 7.
  В этом случае она оценит значение соответствующей вероятности aL7
  как близкое к 1,
  поэтому стоимость -ln aL7 будет малой.
  И наоборот, если сеть работает плохо,
  то вероятность aL7 будет меньше,
  а стоимость -ln aL7 будет больше.
  Поэтому ЛПС ведёт себя так, как можно ожидать от функции стоимости.
  
  Что насчёт проблемы замедления обучения?
  Для её анализа вспомним, что главное в замедлении
  - поведение величин ?C/?wLjk и ?C/?bLj.
  Не буду подробно расписывать взятие производной
  - попрошу вас сделать это в задачах,
  но с применением кое-какой алгебры можно показать, что:
  
  $ \frac{\partial C}{\partial b^L_j} = a^L_j-y_j \tag{81} $
  
  $ \frac{\partial C}{\partial w^L_{jk}} = a^{L-1}_k (a^L_j-y_j) \tag{82} $
  
  Я тут немного поиграл с обозначениями, и использую немного не так,
  как в прошлом параграфе.
  Там y обозначало желаемый выход сети
  - то есть, если на выходе <7>, то на входе было изображение 7.
  А в этих уравнениях y обозначает вектор выходных активаций,
  соответствующий 7,
  то есть вектор, у которого все нули, кроме единички в 7-й позиции.
  
  Эти уравнения такие же, как и аналогичные выражения,
  полученные нами в более раннем анализе перекрёстной энтропии.
  Сравните, к примеру, уравнения (82) и (67).
  Это то же уравнение, хотя в последнем проведено
  усреднение по обучающим примерам.
  И, как и в первом случае,
  эти выражения гарантируют отсутствие замедления обучения.
  Полезно представлять себе, что выходной Softmax-слой с ЛПС
  довольно сильно похожи на слой с сигмоидным выходом
  и стоимостью на основе перекрёстной энтропии.
  
  Учитывая их схожесть, что нужно использовать
  - сигмоидный выход и перекрёстную энтропию,
  или Softmax-выход и ЛПС?
  На самом деле, во многих случаях хорошо работают оба подхода.
  Хотя далее в этой главе мы будем использовать сигмоидный выходной слой
  со стоимостью на основе перекрёстной энтропии.
  Позже, в главе 6, мы иногда будем использовать Softmax-выход и ЛПС.
  Причина изменений - сделать некоторые из следующих сетей
  более похожими на сети, встречающиеся в некоторых влиятельных научных работах.
  С более общей точки зрения, Softmax и ЛПС стоит использовать,
  когда вам нужно интерпретировать выходные активации как вероятности.
  Такое нужно не всегда, но может оказаться полезным
  в задачах классификации (типа MNIST),
  куда входят не пересекающиеся классы.
  
  Задачи
  
  Выведите уравнения (81) и (82).
  
  Откуда взялось название Softmax?
  Допустим, мы изменим Softmax-функцию так,
  чтобы выходные активации задавались уравнением
  
  $ a^L_j = \frac{e^{c z^L_j}}{\sum_k e^{c z^L_k}} \tag{83} $
  
  где c - положительная константа.
  Отметим, что c = 1 соответствует стандартной Softmax-функции.
  Но используя другое значение c, мы получим другую функцию,
  которая качественно всё равно будет похожей на Softmax.
  Покажите, что выходные активации формируют распределение вероятности,
  как и в случае с обычной Softmax.
  Допустим, мы сделаем c очень большой, то есть c  &inf;.
  Какого ограничивающее значение выходных активаций aLj?
  После решения этой задачи должно быть ясно,
  почему функция с c = 1 считается <смягчённой версией> функции максимума.
  Отсюда и происходит термин softmax.
  
  Обратное распространение с Softmax и ЛПС.
  В прошлой главе мы вывели алгоритм обратного распространения для сети,
  содержащей сигмоидные слои.
  Чтобы применить этот алгоритм к сети и Softmax-слоями,
  нам надо вывести выражение для ошибки ?Lj ? ?C/?zLj.
  Покажите, что подходящим выражением будет
  
  $ \delta^L_j = a^L_j -y_j \tag{84} $
  
  Используя это выражение,
  мы можем применить алгоритм обратного распространения к сети,
  используя выходной Softmax-слой и ЛПС.
  
  Переобучение и регуляризация
  
  У нобелевского лауреата Энрико Ферми как-то спросили мнение
  по поводу математической модели,
  предложенной несколькими коллегами для решения
  важной нерешённой физической проблемы.
  Модель прекрасно соответствовала эксперименту,
  но Ферми отнёсся к ней скептически.
  Он спросил, сколько свободных параметров в ней можно менять.
  <Четыре>, - сказали ему.
  Ферми ответил:
  <Помню, как мой друг Джонни фон Нейман любил говорить,
  что с четырьмя параметрами туда можно запихнуть и слона,
  а с пятью можно заставить его махать хоботом>.
  
  Смысл истории, конечно, в том,
  что модели с большим количеством свободных параметров
  могут описывать удивительно широкий круг явлений.
  Даже если такая модель хорошо работает с доступными данными,
  это не делает её автоматически хорошей моделью.
  Это просто может означать, что у модели достаточно свободы,
  чтобы она могла описать почти любой набор данных заданного размера,
  не выявляя основной идеи явления.
  Когда это происходит, модель хорошо работает с существующими данными,
  но не сможет обобщить новую ситуацию.
  Истинная проверка модели - её способность делать предсказания
  в ситуациях, с которыми она не сталкивалась ранее.
  
  Ферми и фон Нейман подозрительно относились к моделям с четырьмя параметрами.
  У нашей НС с 30 скрытыми нейронами для классификации цифр MNIST
  есть почти 24 000 параметров!
  Это довольно много параметров.
  У нашей НС с 100 скрытыми нейронами есть почти 80 000 параметров,
  а у передовых глубоких НС этих параметров иногда миллионы или даже миллиарды.
  Можем ли мы доверять результатам их работы?
  
  Давайте усложним эту проблему, создав ситуацию,
  в которой наша сеть плохо обобщает новую для неё ситуацию.
  //// Сеть не "обобщает". Нигде не доказано, что она что-то там обобщает.
  //// Она просто "машет хоботом" в задачах, интерполяции и экстраполяции,
  //// и "машет" по-разному в разных поддиапазонах.
  //// А интерпретация этого как "обобщение", это "некоторое преувеличение",
  //// со своим, причем неизвестным, распределением вероятности.
  //// К сожалению, об этом нужно постоянно напоминать,
  //// так именно такими фразами и "слагаются мифы и легенды"
  //// относительно самых различных свойств нейросетей.
  Мы будем использовать НС с 30 скрытыми нейронами и 23 860 параметрами.
  Но мы не будем обучать сеть при помощи всех 50 000 изображений MNIST.
  Вместо этого используем только первые 1000.
  Использование ограниченного набора сделает проблему обобщения более очевидной.
  Мы будем обучаться так, как и раньше,
  используя функцию стоимости на основе перекрёстной энтропии,
  со скоростью обучения ?=0,5 и размером мини-пакета 10.
  Однако мы будем обучаться 400 эпох,
  что немного больше, чем было раньше,
  поскольку обучающих примеров у нас не так много.
  Давайте используем network2, чтобы посмотреть на то,
  как меняется функция стоимости:
  
  ........
  
  Используя результаты, мы можем построить график изменения стоимости
  при обучении сети (графики сделаны при помощи программы overfitting.py):
  
  Выглядит обнадёживающе, идёт гладкое уменьшение стоимости, как и ожидалось.
  Учтите, что я показал только эпохи с 200 по 399.
  В итоге мы видим в увеличенном масштаба поздние этапы обучения,
  на которых, как мы увидим далее, и происходит всё самое интересное.
  
  Теперь посмотрим, как меняется точность классификации на проверочных данных
  во времени:
  
  .......
  
  Тут я снова увеличил график.
  В первые 200 эпох, которых тут не видно, точность растёт почти до 82%.
  Затем обучение постепенно замедляется.
  Наконец, примерно на 280-й эпохе точность классификации перестаёт улучшаться.
  На поздних эпохах наблюдаются лишь небольшие стохастические флуктуации
  вокруг значения точности, достигнутого на 280-й эпохе.
  Сравните это с предыдущим графиком,
  где стоимость, связанная с обучающими данными, плавно уменьшается.
  Если изучать только эту стоимость,
  то будет казаться, что модель улучшается.
  Однако результаты работы с проверочными данными говорят нам,
  что это улучшение - лишь иллюзия.
  Как и в модели, которая не понравилась Ферми,
  то, что наша сеть изучает после 280-й эпохи,
  уже не обобщается на проверочных данных.
  Поэтому это обучение перестаёт быть полезным.
  Мы говорим, что после 280-й эпохи сеть переобучается,
  или переподгоняется [overfitting or overtraining].
  //// Возможно, что на этом последующем этапе нужно применять
  //// уже какую-то иную методику обучения,
  //// или хотя бы другую "функцию стоимости",
  //// чтобы обучить модель как-то по-иному.
  //// Увеличение обучающего датасета за счет других, например, синтетически данных
  //// это, наверняка, далеко не единственно возможный способ.
  //// Можно ведь попробовать заставить обучаться модель,
  //// подсовывая не совсем "честные" оценки ошибки.
  
  //// Пару дней назад как раз о таком способе прочитал,
  //// когда в оценку ошибки в любом случае добавляют какую-то константу,
  //// и это "почему-то" улучшает качество обучения модели.
  //// Но это как-то противоречит тезису о "обобщающей способности" нейросети.
  //// Что в случае такой константной составляющей ошибки "обобщается"?
  
  Вы можете задуматься над тем, не является ли проблемой то,
  что я изучаю стоимость на основе обучающих данных,
  а не точности классификации проверочных данных.
  Иначе говоря, возможно, проблема в том, что мы сравниваем яблоки с апельсинами.
  Что будет, если мы сравним стоимость обучающих данных со стоимостью проверочных,
  то есть, будем сравнивать сравнимые меры?
  Или, возможно, мы могли бы сравнить точность классификации как обучающих,
  так и проверочных данных?
  На самом деле, то же явление проявляется вне зависимости от того,
  как проводить сравнение.
  Но изменяются детали.
  К примеру, давайте посмотрим стоимость проверочных данных:
  
  .......
  
  Видно, что стоимость проверочных данных улучшается примерно до 15-й эпохи,
  а потом вообще начинает ухудшаться,
  хотя стоимость обучающих данных продолжает улучшаться.
  Это ещё один признак переобученной модели.
  //// Точнее ее более тонкой "настройки" на обучающие данные.
  //// Можно ведь взглянуть на это дело и так,
  //// что нейросеть старается наиболее точно соответствовать нашим требованиям,
  //// оформленным в виде функции стоимости, а вовсе не тому,
  //// что предполагается/хочется от нее получить.
  //// Тут явное техническое противоречие между способом управления обучением,
  //// и желаемым результатом.
  
  //// И тут явно требуется как минимум "двухфазное обучение".
  //// Первая фаза реальное обучение параметров нейросети на примерах датасета.
  //// Так сказать задание каркаса/скелета решений нейросети,
  //// так сказать "закалка заготовки".
  //// А вторая фаза - это попытка "допилить напильником" , так сказать "полировка"
  //// или, может быть лучше, "мягкий отпуск/отжиг заготовки".
  //// под требования интерполяции/экстраполяции.
  
  //// Причем, если продолжить эту аналогию с "обработкой металлов",
  //// то сразу напрашивается даже не "двухфазное",
  //// а "многостадийная обработка",
  //// включая "легирование", "ковку", "нагревание", "охлаждение", "закалку" и т.д.
  //// с РАЗЛИЧНЫМИ параметрами этих процедур.
  
  //// И если для "интерполяции" какое-то частное решение уже найдено,
  //// например, та же самая "добавка", константная или переменная/случайная,
  //// к функции ошибок/стоимости,
  //// то для "экстраполяции" таких приемов, вроде, еще не найдено.
  
  Однако встаёт вопрос, какую эпоху мы должны считать точкой,
  в которой переобучение начинает преобладать над обучением - 15 или 280?
  С практической точки зрения нас всё же интересует
  улучшение точности классификации проверочных данных,
  а стоимость - это всего лишь посредник точности классификации.
  Поэтому имеет смысл считать эпоху 280 точкой,
  после которой переобучение начинает преобладать над обучением нашей НС.
  
  Ещё один признак переобучения можно увидеть
  в точности классификации обучающих данных:
  
  ........
  
  Точность растёт, доходя до 100%.
  То есть, наша сеть правильно классифицирует все 1000 обучающих изображений!
  Тем временем, проверочная точность вырастает лишь до 82,27%.
  То есть, наша сеть лишь изучает особенности обучающего набора,
  а не учится распознавать цифры вообще.
  Похоже на то, что сеть просто запоминает обучающий набор,
  //// Точнее, подстраивается под процесс обучения.
  //// И если хочется что-то изменить в получающемся результате,
  //// то, скорее всего, нужно вносить изменение в процесс обучения.
  недостаточно хорошо поняв цифры для того,
  чтобы обобщить это на проверочный набор.
  //// Вот нагляднейший пример того, как миф "обобщающей способности нейросети"
  //// создает устойчивую психологическую инерцию,
  //// не позволяющую как-то по иному, взглянуть на суть проблемы.
  
  Переобучение - серьёзная проблема НС.
  Особенно это верно для современных НС,
  в которых обычно есть огромное количество весов и смещений.
  Для эффективного обучения нам нужен способ определять,
  когда возникает переобучение, чтобы не переобучать.
  //// Да не "возникает переобучение", а поведение нейросети,
  //// отражает методику обучения.
  //// И происходит это всегда, начиная с самого первого обучающего примера,
  //// но если в начале обучения такое поведение нейросети всячески приветствуется,
  //// см. разделы про ускорение обучения,
  //// то на финишном этапе это как раз и составляет проблему.
  //// "Нет худа без добра" и наоборот.
  //// И тут претензия не к нейросети, а к "однобокости", "негибкости"
  //// методики обучения.
  //// Не с "переобучением" нейросети надо бороться,
  //// а с недостаточной гибкостью методики обучения.
  А ещё нам хотелось бы уметь уменьшать эффекты переобучения.
  
  Очевидный способ обнаружить переобучение - использовать подход выше,
  следить за точностью работы с проверочными данными в процессе обучения сети.
  Если мы увидим, что точность на проверочных данных уже не улучшается,
  надо прекращать обучение.
  //// Или менять функцию ошибки/стоимости.
  Конечно, строго говоря, это не обязательно будет признаком переобучения.
  Возможно, точность работы с проверочными и с обучающими данными
  прекратят улучшаться одновременно.
  И всё же применение такой стратегии предотвратит переобучение.
  //// Не-а. "Рожденный ползать - летать не может".
  //// Такое явление как "adversarial attack" этот подход точно исключить не может.
  //// Хотя причиной этого явления точно также считается "переобучение".
  
  А мы будем использовать небольшую вариацию этой стратегии.
  Вспомним, что когда мы загружаем в MNIST данные, мы делим их на три набора:
  
  >>> import mnist_loader
  >>> training_data, validation_data, test_data = \
  ... mnist_loader.load_data_wrapper()
  
  Пока что мы использовали training_data и test_data,
  и игнорировали validation_data [подтверждающие].
  В validation_data содержится 10 000 изображений,
  отличающихся как от 50 000 изображений обучающего набора MNIST,
  так и от 10 000 изображений проверочного набора.
  Вместо использования test_data для предотвращения переобучения
  мы будем использовать validation_data.
  //// А в чем разница?
  Для этого мы будем использовать практически ту же стратегию,
  что была описана выше для test_data.
  То есть, мы будем вычислять точность классификации validation_data
  в конце каждой эпохи.
  Как только точность классификации validation_data насытится,
  мы перестанем обучаться.
  Эта стратегия называется ранней остановкой.
  Конечно, на практике мы не сможем сразу же узнать, что точность насытилась.
  Вместо этого мы будем продолжать обучение,
  пока не удостоверимся в этом
  (причём решить, когда нужно остановиться, не всегда просто,
  и можно использовать для этого более или менее агрессивные подходы).
  
  Зачем использовать validation_data для предотвращения переобучения,
  а не test_data?
  Это часть более общей стратегии
  - использовать validation_data для оценки
  разных вариантов выбора гиперпараметров
  - количества эпох для обучения, скорости обучения, наилучшей архитектуры сети, и т.д.
  Эти оценки мы используем, чтобы найти и присвоить хорошие значения гиперпараметрам.
  И хотя я пока ещё этого не упоминал,
  частично благодаря этому я и сделал выбор гиперпараметров
  в ранних примерах в книге.
  
  Конечно, это замечание не отвечает на вопрос о том,
  почему мы используем validation_data, а не test_data,
  для предотвращения переобучения.
  Оно просто заменяет ответ на более общий вопрос
  - почему мы используем validation_data, а не test_data,
  для выбора гиперпараметров?
  Чтобы понять это, учтите, что при выборе гиперпараметров
  нам, скорее всего, придётся выбирать из множества их вариантов.
  Если мы будем назначать гиперпараметры на основе оценок из test_data,
  мы, возможно, слишком сильно подгоним эти данные именно под test_data.
  То есть, мы, возможно, найдём гиперпараметры,
  хорошо подходящие под особенности конкретных данных из test_data,
  однако работа нашей сети не будет обобщаться на другие наборы данных.
  Этого мы избегаем, подбирая гиперпараметры при помощи validation_data.
  А потом, получив нужные нам ГП,
  мы проводим итоговую оценку точности с использованием test_data.
  Это даёт нам уверенность в том,
  что наши результаты работы с test_data
  являются истинной мерой степени генерализации НС.
  Иначе говоря, подтверждающие данные
  - это такие особые обучающие данные,
  помогающие нам обучиться хорошим ГП.
  Такой подход к поиску ГП иногда называют методом удержания,
  поскольку validation_data <удерживают> отдельно от training_data.
  
  На практике, даже после оценки качества работы на test_data
  мы захотим поменять наше мнение и попробовать другой подход
  - возможно, другую архитектуру сети -
  который будет включать поиски нового набора ГП.
  В этом случае не возникнет ли опасность того,
  что мы излишне приспособимся к test_data?
  Не потребуется ли нам потенциально бесконечное количество наборов данных,
  чтобы мы были уверены в том,
  что наши результаты хорошо обобщаются?
  В целом это глубокая и сложная проблема.
  Но для наших практических целей мы не будем
  слишком сильно переживать по этому поводу.
  Мы просто нырнём с головой в дальнейшие исследования,
  используя простой метод удержания
  на основе training_data, validation_data и test_data,
  как описано выше.
  
  Пока что мы рассматривали переобучение с использованием 1000 обучающих изображений.
  Что будет, если мы используем полный обучающий набор из 50 000 изображений?
  Все остальные параметры мы оставим без изменений
  (30 скрытых нейронов, скорость обучения 0,5, размер мини-пакета 10),
  но будем обучаться 30 эпох с использованием всех 50 000 картинок.
  Вот график, на котором показана точность классификации на обучающих данных
  и проверочных данных.
  Отметьте, что здесь я использовал проверочные [test],
  а не подтверждающие [validation] данные,
  чтобы результаты было проще сравнивать с более ранними графиками.
  
  ......
  
  Видно, что показатели точности на проверочных и обучающих данных
  остаются ближе друг к другу, чем при использовании 1000 обучающих примеров.
  В частности, наилучшая точность классификации, 97,86%,
  всего на 2,53% выше, чем 95,33% проверочных данных.
  Сравните с ранним разрывом в 17,73%!
  Переобучение происходит, но сильно уменьшилось.
  Наша сеть гораздо лучше обобщает информацию,
  переходя с обучающих на проверочные данные.
  В целом, один из лучших способов уменьшения переобучения
  - увеличение объёма обучающих данных.
  //// А какие еще есть способы?
  //// А есть ли какие-то ограничения на объем обучающих данных,
  //// от "количества параметров"?
  Взяв достаточно обучающих данных,
   сложно переобучить даже очень крупную сеть.
  //// А очень малую?
  К сожалению, получить обучающие данные бывает дорого и/или сложно,
  поэтому такой вариант не всегда оказывается практичным.
  
  Регуляризация
  
  Увеличение количества обучающих данных
  - один из способов уменьшения переобучения.
  Есть ли другие способы уменьшения проявлений переобучения?
  Один из возможных подходов - уменьшение размера сети.
  Правда, у больших сетей возможностей потенциально больше чем у малых,
  поэтому к такому варианту мы прибегаем неохотно.
  
  К счастью, существуют и другие техники, способные уменьшить переобучение,
  даже когда у нас фиксированы размер сети и обучающих данных.
  Они известны, как техники регуляризации.
  В данной главе я опишу одну из наиболее популярных техник,
  которую иногда называют ослаблением весов,
  или регуляризацией L2.
  Её идея в том, чтобы добавить к функции стоимости дополнительный член
  под названием член регуляризации.
  //// Оказывается, я опять "изобретаю велосипед".
  Вот перекрёстная энтропия с регуляризацией:
  
  $ C = -\frac{1}{n} \sum_{xj} \left[ y_j \ln a^L_j+(1-y_j) \ln (1-a^L_j)\right] +
  \frac{\lambda}{2n} \sum_w w^2 \tag{85} $
  
  Первый член - обычное выражение для перекрёстной энтропии.
  Но мы добавили второй, а именно, сумму квадратов всех весов сети.
  Он масштабируется множителем ?/2n,
  где ?>0 - это параметр регуляризации,
  а n, как обычно - размер обучающего набора.
  Мы обсудим, как выбрать ?.
  //// Не, это немного не то. Это "одноколесный велосипед",
  //// а я "изобретал многоколесный".
  Также стоит отметить, что в член регуляризации не входят смещения.
  Об этом ниже.
  
  Конечно, возможно регуляризировать и другие функции стоимости,
  например, квадратичную.
  Это можно сделать схожим образом:
  
  $ C = \frac{1}{2n} \sum_x \|y-a^L\|^2 + \frac{\lambda}{2n} \sum_w w^2 \tag{86} $
  
  В обоих случаях можно записать регуляризированную функцию стоимости, как
  
  $ C = C_0 + \frac{\lambda}{2n} \sum_w w^2 \tag{87} $
  
  где C0 - оригинальная функция стоимости без регуляризации.
  
  Интуитивно ясно, что смысл регуляризации склонить сеть к предпочтению более малых весов, при прочих равных.
  //// А чем такое "склонение" в более предпочтительно?
  Крупные веса будут возможны,
  только если они значительно улучшают первую часть функции стоимости.
  Иначе говоря, регуляризация - это способ выбора компромисса
  между нахождением малых весов и минимизацией изначальной функции стоимости.
  Важно, что эти два элемента компромисса зависят от значения ?:
   когда ? мала, мы предпочитаем минимизировать оригинальную функцию стоимости,
  а когда ? велика, то предпочитаем малые веса.
  
  Совершенно не очевидно, почему выбор подобного компромисса
  должен помочь уменьшить переобучение!
  Но оказывается, помогает.
  //// Оно и должно помогать, хотя бы потому,
  //// что на один и тот же обучающий пример в разных эпохах
  //// будет добавлено к ошибке/стоимости разные значения.
  //// Этакое "помешивание в бокале".
  //// А вот нужно ли это "перемешивание" привязывать к весам параметров,
  //// мне кажется, вопрос достаточно дискуссионный.
  Мы разберёмся в том, почему он помогает, в следующей секции.
  Но сначала давайте поработаем с примером,
  показывающим, что регуляризация действительно уменьшает переобучение.
  
  Чтобы сконструировать пример, сначала нам нужно понять,
  как применить обучающий алгоритм со стохастическим градиентным спуском
  к регуляризованной НС.
  В частности, нам надо знать, как подсчитывать частные производные,
  ?C/?w и ?C/?b для всех весов и смещений в сети.
  После взятия частных производных в уравнении (87) получим:
  
  $ \frac{\partial C}{\partial w} = \frac{\partial C_0}{\partial w} + \frac{\lambda}{n} w \tag{88} $
  
  $ \frac{\partial C}{\partial b} = \frac{\partial C_0}{\partial b} \tag{89} $
  
  Члены ?C0/?w и ?C0/?w можно вычислить через ОР, как описано в предыдущей главе.
  Мы видим, что подсчитать градиент регуляризованной функции стоимости легко:
  просто нужно, как обычно, использовать ОР,
  а потом добавить ?/n w к частной производной всех весовых членов.
  Частные производные по смещениям не меняются,
  поэтому правило обучения градиентным спуском для смещений
  не отличается от обычного:
  
  $ b \rightarrow b -\eta \frac{\partial C_0}{\partial b} \tag{90} $
  
  Правило обучения для весов превращается в:
  
  $ w \rightarrow w-\eta \frac{\partial C_0}{\partial w}-\frac{\eta \lambda}{n} w \tag{91} $
  
  $ = \left(1-\frac{\eta \lambda}{n}\right) w -\eta \frac{\partial C_0}{\partial w} \tag{92} $
  
  Всё то же самое, что и в обычном правиле градиентного спуска,
  кроме того, что мы сначала масштабируем вес w на множитель 1 - ??/n.
  Это масштабирование иногда называют ослаблением весов,
  поскольку оно уменьшает веса.
  На первый взгляд кажется, что веса неудержимо стремятся к нулю.
  Но это не так, поскольку другой член может привести к увеличению весов,
  если это приводит к уменьшению нерегуляризованной функции стоимости.
  //// Не знаю, может быть я чего-то не понимаю,
  //// но в этом подходе с регуляризацией весов через их "ослабление",
  //// мне видится определенное противоречие в логике обучения.
  //// С одной стороны представления о том как данный "вес" оказывает влияние
  //// на ВСЕ поведение нейросети для ВСЕХ обучающих примеров точно неизвестно,
  //// следовательно, его априорное уменьшение по какому-то абстрактному критерию,
  //// это, вообще-то, игра "в орлянку" т.е. "фифти-фифти".
  //// С другой стороны, это действие как-то вообще игнорирует
  //// так распиаренную "генерализующую способность нейросети",
  //// т.е. тупо по чуть-чуть меняем все веса,
  //// с верой в то, что все как-то само "рассосется" в нужном направлении.
  //// Т.е. налицо определенное "двоемыслие".
  
  //// Но характерно, что это дает какой-то эффект.
  //// И тогда вопрос надо ставить так - а за счет чего это может происходить.
  //// Может быть дело не "в уменьшении весов", а их стохастическом изменении,
  //// которое вполне может быть достигнуто и другими способами,
  //// изменив методику обучения.
  
  Хорошо, пусть градиентный спуск работает так.
  Что насчёт стохастического градиентного спуска?
  Ну, как и в нерегуляризованном варианте стохастического градиентного спуска,
  мы можем оценить ?C0/?w через усреднение по мини-пакету m обучающих примеров.
  Поэтому регуляризованное правило обучения
  для стохастического градиентного спуска превращается в (см. уравнение (20)):
  
  $ w \rightarrow \left(1-\frac{\eta \lambda}{n}\right) w -\frac{\eta}{m} \sum_x \frac{\partial C_x}{\partial w} \tag{93} $
  
  где сумма идёт по обучающим примерам x в мини-пакете,
  а Cx - нерегуляризованная стоимость для каждого обучающего примера.
  Всё то же самое, что и в обычно правиле стохастического градиентного спуска,
  за исключением 1 - ??/n, фактора ослабления веса.
  Наконец, для полноты картины,
  позвольте записать регуляризованное правило для смещений.
  Оно, естественно, точно такое же, как и в нерегуляризованном случае
  (см. уравнение (21)):
  
  $ b \rightarrow b - \frac{\eta}{m} \sum_x \frac{\partial C_x}{\partial b} \tag{94} $
  
  где сумма идёт по обучающим примерам x в мини-пакете.
  
  Давайте посмотрим, как регуляризация меняет эффективность нашей НС.
  Мы будем использовать сеть с 30 скрытыми нейронами, мини-пакет размера 10,
  скорость обучения 0,5, и функцию стоимости с перекрёстной энтропией.
  Однако на этот раз мы используем параметр регуляризации ?=0,1.
  В коде я назвал эту переменную lmbda,
  поскольку слово lambda зарезервировано в python
  для не связанных с нашей темой вещей.
  Я также снова использовал test_data again вместо validation_data.
  Но я решил использовать test_data,
  поскольку результаты можно сравнивать напрямую с нашими ранними,
  нерегуляризованными результатами.
  Вы легко можете поменять код так, чтобы он использовал validation_data,
  и убедиться, что результаты получаются схожими.
  
  .......
  
  Стоимость обучающих данных постоянно уменьшается,
  как и в раннем случае, без регуляризации:
  
  .......
  
  Но на этот раз точность на test_data продолжает увеличиваться
  в течение всех 400 эпох:
  
  .......
  
  Очевидно, регуляризация подавила переобучение.
  Более того, точность значительно возросла,
  и пиковая точность классификации достигает 87,1%, по сравнению с пиком 82,27%,
  достигнутым в случае без регуляризации.
  И вообще, мы почти наверняка достигаем лучших результатов,
  продолжая обучение после 400 эпох.
  Судя по всему, эмпирически,
  регуляризация заставляет нашу сеть лучше обобщать знания,
  //// Да не "обобщать", а подстраиваться под режим обучения.
  //// Нейросеть с градиентным спуском обратным распространением ошибки
  //// - это алгоритм подстройки параметров, а не алгоритм "обобщения".
  //// И он делает ровно то, что ему предписано, и "ни на миллиметр больше".
  //// А "магия обобщения" - это очень вредный миф,
  //// хотя и такой приятный для слуха.
  //// Который слишком часто заканчивается не очень хорошо,
  //// если слепо на него полагаться.
  и значительно уменьшает эффекты переобучения.
  //// И опять же не "переобучение", а, как бы лучше подобрать термин,
  //// а эффект "крупнозернистой структуры",
  //// соответствующий "зернистости" обучающих данных.
  //// Регуляризация в данном случае выступает как процесс "дробления"
  //// более крупных "зерен", на более "мелкие".
  //// Переводит "крупнодисперсную" структуру решений нейросети,
  //// в более "мелкодисперную".
  //// Отсюда и улучшение результатов на тестовой выборке.
  
  //// Если опять же вернуться к аналогии с "обработкой металлов",
  //// то это процесс аналогичный ...
  //// ультразвуковой или электромагнитной обработке процессов литья,
  //// когда таким воздействием повышается "дисперсность" структуры металла,
  //// предотвращается возникновение внутренних трещин, крупных кристаллов/зерен,
  //// и много чего еще - зависит от техпроцесса.
  //// Вот такая аналогия, мне кажется более практичной,
  //// чем "мантры" про "магическую способность обобщения" нейросетей,
  //// и "страшилки" про переобучение.
  
  Что произойдёт, если мы оставим наше искусственное окружение,
  в котором используется всего 1 000 обучающих картинок,
  и вернёмся к полному набору из 50 000 изображений?
  Конечно, мы уже увидели, что переобучение представляет
  куда как меньшую проблему с полным набором из 50 000 изображений.
  Помогает ли улучшить результат регуляризация?
  Давайте оставим прежние значения гиперпараметров
  - 30 эпох, скорость 0,5, размер мини-пакета 10.
  Однако, нам нужно поменять параметр регуляризации.
  Дело в том, что размер n обучающего набора скакнул от 1000 до 50 000,
  а это меняет фактор ослабления весов 1 - ??/n.
  Если мы продолжим использовать ?=0,1,
  это означало бы, что веса ослабляются куда меньше,
  и в итоге эффект от регуляризации уменьшается.
  Мы компенсируем это, приняв ?=5,0.
  
  Хорошо, давайте обучим нашу сеть, сначала повторно инициализировав веса:
  
  .......
  
  Мы получаем результаты:
  
  .......
  
  Много всего приятного.
  Во-первых, наша точность классификации на проверочных данных подросла,
  с 95,49% без регуляризации до 96,49% с регуляризацией.
  Это серьёзное улучшение.
  //// "Семь из девяти ошибок остается".
  //// Кто рискнет такую систему использовать
  //// в контуре управления безопасностью?
  Во-вторых, можно видеть, что разрыв между результатами работы
  на обучающем и проверочном наборах гораздо ниже, чем раньше, менее 1%.
  Разрыв всё равно приличный,
  но мы, очевидно, достигли значительного прогресса в уменьшении переобучения.
  ///// Но до требования "5 девяток" еще "палкой не докинуть",
  ///// а для обычных требований безопасности надо вообще "девять девяток",
  ///// совершенно ясно, что такой подход не даст таких решений
  ///// вряд ли когда-нибудь, если ничего не менять "в консерватории".
  
  Наконец, посмотрим, какую точность классификации мы получим
  при использовании 100 скрытых нейронов и параметра регуляризации &lambda=5,0.
  Не буду приводить подробный анализ переобучения,
  это делается просто ради интереса,
  чтобы посмотреть, насколько большой точности можно достигнуть
  с нашими новыми хитростями:
  функцией стоимости с перекрёстной энтропией и регуляризацией L2.
  
  ........
  
  Конечный результат - точность классификации в 97,92% на подтверждающих данных.
  Большой скачок по сравнению со случаем с 30 скрытыми нейронами.
  Можно подстроить ещё немного, запустить процесс на 60 эпох с ?=0,1 и ?=5,0,
  и преодолеть барьер в 98%,
  достигнув точность 98,04 на подтверждающих данных.
  Неплохо для 152 строк кода!
  
  Я описал регуляризацию как способ уменьшения переобучения
  и увеличения точности классификации.
  Но это не единственные её преимущества.
  Эмпирически, испробовав через множество запусков нашу сеть MNIST,
  меняя каждый раз веса, я обнаружил,
  что запуски без регуляризации иногда <застревали>,
  очевидно, попав в локальный минимум функции стоимости.
  В итоге разные запуски иногда выдавали сильно разные результаты.
  А регуляризация, наоборот, позволяет получать
  гораздо легче воспроизводимые результаты.
  //// Это все тот же вопрос с "дисперсности" "обучающих данных" и метода обучения,
  //// но это отдельная большая тема.
  //// Но сам факт примечательный, и его запомнить.
  //// "Играя в орлянку" с весами нейросети,
  //// "локальные минимумы" оказываются не так страшны.
  
  Почему так получается?
  Эвристически, когда у функции стоимости нет регуляризации,
  длина вектора весов, скорее всего, будет расти, при прочих равных.
  Со временем это может привести к очень большому вектору весов.
  А из-за этого вектор весов может застрять,
  показывая примерно в одном и том же направлении,
  поскольку изменения из-за градиентного спуска
  делают лишь крохотные изменения в направлении при большой длине вектора.
  Я считаю, что из-за этого явления нашему алгоритму обучения
  очень тяжело как следует изучить пространство весов,
  и, следовательно, тяжело найти хороший минимум функции стоимости.
  //// Вообще-то. Такого рода заключения хорошо бы сопроводить иллюстрацией.
  //// Например, распределением весов. Это так легко сделать.
  //// Или сделать "регуляризацию наоборот" - увеличивая веса,
  //// или вообще менять чуть-чуть случайно,
  //// и показать, что такая "регуляризация", точнее "хаотизация",
  //// точно/гарантированно НЕ работает.
  
  //// Но почему-то таких работ никто не считает нужным либо делать,
  //// либо публиковать.
  //// Может быть потому, что такие практические результаты,
  //// "не совсем" согласуется с "красивой" и "правильной" теорией.
  
  //// А вот если все-таки рассматривать предложенную регуляризацию,
  //// просто как способ повышения "мелкодисперности" решения,
  //// без относительности направления уменьшения/увеличения весов,
  //// то способность преодолевать "локальные минимумы" в "функции стоимости"
  //// как-то не кажется слишком загадочной.
  
  .......
  
  //// Из комментариев.
  
  spiral17
  21 авг 2019 в 21:27
  
  Да, спасибо! С темой знаком достаточно давно,
  но все равно обнаружил неизвестные мне вещи из-за того,
  что автор разбирает тему подробно до болтов.
  
  .......
  
  //// Конец цитирования.
  
  В общем, слепая вера в "магические свойства" нейросетей,
  мифы об их "обобщающих свойствах" и "опасности переобучения",
  в сумме не позволяют подойти к backpropagation
  просто как основы нормального многоступенчатой технологии
  получения требуемого результата.
  А не упования на какую-то "единственно верную"
  или идеальную функцию ошибки/стоимости.
  
  
  =======
  
  02.04.2024 21:39
  
  Пара бит про "переобучение".
  В оглавление.
  
  Буквально вчера на Хабре появилась сама по себе интересная
  и весьма информативная статься про "пространство эмбеддингов":
  
  "Как устроено пространство, в котором думают языковые модели?"
  Автор: Razant (Anton Razzhigaev)
  https://habr.com/ru/companies/airi/articles/804515/
  1 апр 2024 в 16:38
  
  Разбирать и цитировать ее текст здесь не буду, кому интересно см.:
  "Анизотропия и внутренняя размерность "пространства эмбеддингов".
  
  Разве что. приведу ключевую мысль этого материала:
  
  \\\ Ещё раз - у всех LLM во время обучения присутствуют две фазы:
  \\\ инфляция эмбеддингов и их последующая компрессия.
  
  А вот фрагмент дискуссии в комментариях приведу полностью
  - уж очень он контрастирует с изложением в предыдущем фрагменте
  "страшилкой переобучения".
  
  \\\ YuriySeverinov
  \\\ 2 часа назад
  
  \\\ Год-два назад встречал статью,
  \\\ выводы которой заключались в том,
  \\\ что если продолжать учить модель длительное время
  \\\ после того, как она переобучилась,
  \\\ эффект переобучения постепенно начинает пропадать.
  \\\ В ней было сделано предположение,
  \\\ что модель начинает со временем выучивать не конкретные наблюдения,
  \\\ а реальные взаимосвязи и растет ее обобщающая способность.
  
  \\\ Может этот эффект как раз и был связан с тем,
  \\\ что сперва модель формирует большое количество размерностей,
  \\\ а потом начинает их снижать?
  
  \\\ Razant
  \\\ 2 часа назад
  
  \\\ Вы говорите про явление Grokking.
  \\\ https://arxiv.org/pdf/2201.02177.pdf
  //// Гроккинг: обобщение, выходящее за рамки переобучения,
  //// на небольших алгоритмических наборах данных
  //// Алетея Пауэр, Юрий Бурда, Харри Эдвардс, Игорь Бабушкин, Ведант Мисра
  
  \\\ Да, похоже, что это явление и компрессия репрезентаций очень плотно связаны.
  \\\ Схожая интуиция была в статье про OmniGrok.
  \\\ https://arxiv.org/pdf/2210.01117.pdf
  //// Omnigrok: Грокинг за пределами алгоритмических данных
  //// Цимин Лю, Эрик Дж . Мишо, Макс Тегмарк
  
  \\\ Было бы очень интересно посмотреть что происходит с внутренней размерностью
  \\\ при переходе от оверфита к генерализации,
  \\\ предположу что там будет "ступенька"
  \\\ на графике внутренней размерности.
  
  Меня очень заинтересовали эти "Grokking" и "OmniGrok",
  но моих познаний в "замежной мове" явно недостаточно,
  чтобы сделать из указанных ссылок более-менее точные цитаты.
  А машинный перевод тоже получился весьма корявым и неоднозначным.
  
  Но общий смысл действительно такой, как обсуждался в комментариях,
  такие явления действительно можно обнаружить и даже как-то ими управлять.
  Разве что, авторы этих статей исследовали
  достаточно ограниченный класс задач,
  и делать крупные обобщения все-таки остерегаются.
  
  Но, на мой мой взгляд, в этом случае важен сам факт, что такое решение
  - преодоление состояния "переобучения" дальнейшим обучением системы -
  в принципе возможно.
  Если вернуться к "металлургической метафоре" обучения нейросети,
  то такой процесс можно сравнить с "финишной полировкой",
  обязательной, но долгой и нудной,
  если не использовать соответствующий инструмент.
  
  Осталось дело "за малым" - научиться этим пользоваться,
  и подобрать подходящий инструмент.
  
  
  =========
  
  09.04.2024 20:45
  
  Каноническая трактовка регуляризации.
  В оглавление.
  
  эффект приемов регуляризации при обучении нейросетей интересен тем,
  что при очевидном положительном эффекте, подтвержденном значительной практикой,
  он имеет весьма "туманные" теоретические обоснования.
  Нельзя сказать, что их совсем нет, но то, что они явно не достаточны
  для ясного понимания механизма работы этих приемов.
  И, соответственно, отсутствуют какие-то четкие ориентиры
  в каком-то обоснованном выборе из достаточно большого количества этих приемов.
  
  Поэтому в следующем "погружении" в глубокое обучение
  попробуем сделать попытку, если и не окончательно разобраться
  с этой весьма интересной темой, то хотя бы наметить контуры возможного решения:
  
  "Нейросети и глубокое обучение, глава 3, ч.2:
  почему регуляризация помогает уменьшать переобучение?"
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/459816/.
  15 июл 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap3.html#why_does_regularization_help_reduce_overfitting
  
  //// Начало цитирования.
  
  Эмпирически мы увидели, что регуляризация помогает уменьшать переобучение.
  //// "Эмпирически мы увидели" незначительное повышение качества,
  //// а вот имеет это повышение отношение к "переобучению" совсем не ясно.
  //// Нет ни точного определения "переобучения", ни явных способов его измерения.
  //// То, что модель на обучающих данных показывает результаты,
  //// отличающиеся от результатов на тестовых данных,
  //// куда вероятнее, определяется тем, что "наши ожидания",
  //// что нейросеть обладает именно такой формой "обобщения",
  //// которая бы соответствовала бы тестовым данным,
  //// мягко говоря, мало чем обоснованы.
  Это вдохновляет - но, к сожалению,
  не очевидно, почему регуляризация помогает.
  //// Именно потому, что "регуляризация" рассматривается,
  //// как способ "борьбы с переобучением".
  //// А вот если рассматривать это просто как один из способов "повышения качества",
  //// то, может быть, какое-то объяснение и найдется.
  Обычно люди объясняют это как-то так:
  в каком-то смысле, менее крупные веса имеют меньшую сложность,
  что обеспечивает более простое и действенное объяснение данных,
  поэтому им надо отдавать предпочтение.
  Однако это слишком краткое объяснение,
  а некоторые его части могут показаться сомнительными или загадочными.
  Давайте-ка развернём эту историю и изучим её критическим взглядом.
  Для этого предположим, что у нас есть простой набор данных,
  для которого мы хотим создать модель:
  
  .....
  
  По смыслу, здесь мы изучаем явление реального мира,
  и x и y обозначают реальные данные.
  Наша цель - построить модель, позволяющую нам предсказывать y как функцию x.
  Мы могли бы попробовать использовать нейросеть для создания такой модели,
  но я предлагаю нечто более простое:
  я попробую моделировать y как многочлен от x.
  Я буду делать это вместо нейросетей,
  поскольку использование многочленов делает объяснение особенно понятным.
  Как только мы разберёмся со случаем многочлена, мы перейдём к НС.
  На графике выше имеется десять точек,
  что означает, что мы можем найти
  уникальный многочлен 9-го порядка y = a0x9+a1x8+...+a9,
  абсолютно точно укладывающийся в данные.
  И вот график этого многочлена.
  
  ......
  
  Идеальное попадание.
  Но мы можем получить неплохое приближение,
  используя линейную модель y = 2x
  
  ......
  
  Какая из них лучше?
  Какая с большей вероятностью окажется истинной?
  Какая будет лучше обобщаться на другие примеры того же явления реального мира?
  //// А если расширить круг моделей: а как насчет многочлена 10 порядка?
  //// Или одиннадцатого или стоодиннадцатого порядка?
  //// Разве нельзя подобрать соответствующие коэффициенты к таким многочленам,
  //// так чтобы они пусть не точно, хотя, наверняка, можно и точно,
  //// но достаточно близко описывали приведенную зависимость данных?
  //// Тут главный вопрос: а сколько таких многочленов может быть?
  //// Мне кажется что их будет даже не миллионы, а "триллиарды в степени N".
  //// "Нет, N мало - бери M". Короче, бесконечное количество вариантов.
  //// И вот это "бесконечное количество" стоит запомнить.
  //// Чуть дальше мы к нему вернемся.
  
  Сложные вопросы.
  И на них нельзя получить точные ответы,
  не имея дополнительной информации по поводу лежащего в основе данных
  явления реального мира.
  Однако давайте рассмотрим две возможности:
  (1) модель с многочленом 9-го порядка истинно описывает явление реального мира,
  и поэтому, обобщается идеально;
  (2) правильная модель - это y=2x,
  но у нас имеется дополнительный шум,
  //// А если это не "шум", а "гармоническая осцилляция" или что-то еще более хитрое?
  связанный с погрешностью измерений,
  поэтому модель подходит не идеально.
  
  Априори нельзя сказать,
  какая из двух возможностей правильная
  (или что не существует некоей третьей).
  //// И даже не "третьей", а "бесконечного множества" различных возможностей.
  Логически, любая из них может оказаться верной.
  И различие между ними нетривиально.
  Да, на основе имеющихся данных можно сказать,
  что между моделями имеется лишь небольшое отличие.
  Но допустим, мы хотим предсказать значение y,
  соответствующее какому-то большому значению x,
  гораздо большему, чем любое из показанных на графике.
  Если мы попытаемся это сделать,
  тогда между предсказаниями двух моделей появится огромная разница,
  поскольку в многочлене 9-го порядка доминирует член x9,
  а линейная модель линейной и остаётся.
  
  Одна точка зрения на происходящее
  - заявить, что в науке нужно использовать более простое объяснение,
  если это возможно.
  Когда мы находим простую модель, объясняющую многие опорные точки,
  нам так и хочется закричать: <Эврика!>.
  Ведь маловероятно, что простое объяснение появится чисто случайно.
  Мы подозреваем, что модель должна выдавать некую связанную с явлением правду.
  В данном случае модель y=2x+шум кажется гораздо более простой,
  чем y = a0x9+a1x8+...
  Было бы удивительно, если бы простота возникла случайно,
  поэтому мы подозреваем, что y = 2x+шум выражает некую лежащую в основе истину.
  С этой точки зрения модель 9-го порядка просто изучает влияние местного шума.
  И хотя модель 9-го порядка идеально работает
  для данных конкретных опорных точек,
  она не сможет обобщиться на другие точки,
  в результате чего у линейной модели с шумом
  предсказательные возможности будут лучше.
  //// А как насчет промежуточных точек?
  //// Теми самыми из тестового набора?
  //// И откуда взялось убеждение, что решение в виде "простая модель + шум",
  //// лучше "сложная модель + много меньший шум"?
  //// В технике той же радиосвязи уже давно от такого ушли,
  //// в сторону все более и более сложных алгоритмов/моделей/схем.
  
  Давайте посмотрим,
  что означает эта точка зрения для нейросетей.
  Допустим, в нашей сети в основном имеются малые веса,
  как обычно бывает в регуляризированных сетях.
  Благодаря небольшим весам поведение сети не меняется сильно
  при изменении нескольких случайных входов там и сям.
  В итоге регуляризированной сети сложно выучить эффекты местного шума,
  присутствующие в данных.
  //// А если это не "шум"?
  Это похоже на стремление к тому,
  чтобы отдельные свидетельства не сильно влияли на выход сети в целом.
  //// И в итоге даже "три девятки" для большинства нейросетей является
  //// недостижимым рубежом. А нам требуется МИНИМУМ "шесть девяток".
  Регуляризированная сеть вместо этого обучается реагировать
  на такие свидетельства,
  которые часто встречаются в обучающих данных.
  И наоборот, сеть с крупными весами
  может довольно сильно менять своё поведение
  в ответ на небольшие изменения входных данных.
  Поэтому нерегуляризированная сеть может использовать большие веса
  для обучения сложной модели,
  содержащей много информации о шуме в обучающих данных.
  Короче говоря, ограничения регуляризированных сетей
  позволяют им создавать относительно простые модели на основе закономерностей,
  часто встречающихся в обучающих данных,
  и они устойчивы к отклонениям, вызванным шумом в обучающих данных.
  Есть надежда, что это заставит наши сети изучать именно само явление,
  и лучше обобщать полученные знания.
  //// Опять эта мантра про "обощение" И откровенно неубедительное объяснение
  //// принципа действия "эффекта регуляризации".
  //// Свой вариант объяснения этого эффекта постараюсь изложить чуть ниже,
  //// там это будет более к месту.
  
  Учитывая всё сказанное, идея того,
  чтобы отдавать предпочтения более простым объяснениям,
  должна заставить вас нервничать.
  Иногда люди называют эту идею <бритвой Оккама> и рьяно применяют её,
  будто бы она обладает статусом общего научного принципа.
  Но это, разумеется, не общий научный принцип.
  Нет никакой априорной логической причины
  предпочитать простые объяснения сложным.
  Иногда более сложное объяснение оказывается правильным.
  
  Позвольте описать два примера того,
  как более сложное объяснение оказалось правильным.
  В 1940-х физик Марсель Шейн объявил об открытии новой частицы.
  Компания, на которую он работал, General Electric, была в восторге,
  и широко распространила публикацию об этом событии.
  Однако физик Ханс Бете отнёсся к нему скептически.
  Бете посетил Шейна и изучил пластинки со следами новой частицы Шейна.
  Шейн показывал Бете пластинку за пластинкой,
  но на каждой из них Бете находил какую-либо проблему,
  говорившую о необходимости отказа от этих данных.
  Наконец, Шейн показал Бете пластинку, выглядевшую годно.
  Бете сказал, что это, возможно, просто статистическое отклонение.
  Шейн: <Да, но шансы на то, что это из-за статистики,
  даже по вашей собственной формуле, один к пяти>.
  Бете: <Однако я уже посмотрел на пять пластинок>.
  Наконец, Шейн сказал:
  <Но каждую мою пластинку, каждое хорошее изображение вы объясняли
  какой-то другой теорией,
  а у меня есть одна гипотеза, объясняющая все пластинки сразу,
  из которой следует, что речь идёт о новой частице>.
  Бете ответил:
  <Единственное отличие между моими и вашими объяснениями в том,
  что ваши неправильные, а мои правильные.
  Ваше единое объяснение неверно, а все мои объяснения верны>.
  Впоследствии выяснилось, что природа согласилась с Бете,
  и частица Шейна испарилась.
  //// Как просто было когда-то "открывать" и "закрывать" новые частицы.
  //// Примерно как сейчас с новыми "практиками" машинного обучения.
  
  Во втором примере, в 1859 году астроном Урбен Жан Жозеф Леверье обнаружил,
  что форма орбиты Меркурия не соответствует теории всемирного тяготения Ньютона.
  Существовало крохотное отклонение от этой теории,
  и тогда было предложено несколько вариантов решения проблемы,
  которые сводились к тому, что теория Ньютона в целом верна,
  и требует лишь небольшого изменения.
  А в 1916 году Эйнштейн показал, что это отклонение можно хорошо объяснить
  с использованием его общей теории относительности,
  радикально отличающейся от ньютоновской гравитации
  и основанной на куда как более сложной математике.
  Несмотря на эту дополнительную сложность,
  сегодня принято считать, что объяснение Эйнштейна верно,
  а Ньютоновская гравитация неверна даже в модифицированной форме.
  Так получается, в частности, потому, что сегодня нам известно,
  что теория Эйнштейна объясняет многие другие явления,
  с которыми у теории Ньютона были сложности.
  Более того, что ещё более поразительно,
  теория Эйнштейна точно предсказывает несколько явлений,
  которых Ньютоновская гравитация не предсказывала вообще.
  Однако эти впечатляющие качества не были очевидными в прошлом.
  Если судить исходя из одной лишь простоты,
  то некоторая модифицированная форма Ньютоновской теории
  выглядела бы привлекательнее.
  //// А куда отнести всю фактологию, которую относят к "переобучению"?
  //// Так будем считать, что нейросети "переобучаются",
  //// т.е. якобы точно выучивают обучающую выборку,
  //// и поэтому показывают худшие результаты на тестовой?
  //// А то, что они и обучающую выборку с точностью "пять девяток"
  //// осилить не в состоянии - это куда отнести?
  //// А что стоит за такими явлениями как "Grokking" и "Omnigrok",
  //// которые упоминались в предыдущем фрагменте?
  //// Какие в этом случае "механика" и "относительность"?
  
  Из этих историй можно извлечь три морали.
  Во-первых, иногда довольно сложно решить,
  какое из двух объяснений будет <проще>.
  Во-вторых, даже если бы мы и приняли такое решение,
  простотой нужно руководствоваться крайне осторожно!
  В-третьих, истинной проверкой модели является не простота,
  а то, насколько хорошо она предсказывает новые явления
  в новых условиях поведения.
  
  Учитывая всё это и проявляя осторожность,
  примем эмпирический факт
  - регуляризированные НС обычно обобщаются лучше, чем нерегуляризированные.
  Поэтому далее в книге мы будем часто использовать регуляризацию.
  Упомянутые истории нужны лишь для того, чтобы объяснить,
  почему никто пока ещё не разработал
  полностью убедительное теоретическое объяснение тому,
  почему регуляризация помогает сетям проводить обобщение.
  //// Потому что нейросети НЕ ОБОБЩАЮТ,
  //// а подгоняют "рельеф решения" под "ландшафт задачи",
  //// который во многом зависит и от функции ошибки и регуляризационных алгоритмов.
  //// И пока объяснения пытаются выстроить от этого "обобщения",
  //// внятного объяснения вряд ли можно ожидать скоро.
  Исследователи продолжают публиковать работы,
  где пытаются испробовать различные подходы к регуляризации,
  сравнивать их, смотря, что лучше работает,
  и пытаясь понять, почему различные подходы работают хуже или лучше.
  Так что к регуляризации можно относиться, как к клуджу.
  \\\ техн., жарг. клудж - устройство, программа или часть программы,
  \\\ которые теоретически не должны работать,
  \\\ но почему-то работают
  Когда она, довольно часто, помогает,
  у нас нет полностью удовлетворительного системного понимания происходящего
  - только неполные эвристические и практические правила.
  
  Здесь скрывается и более глубокий набор проблем,
  идущих к самому сердцу науки.
  Это вопрос обобщения.
  Регуляризация может дать нам вычислительную волшебную палочку,
  помогающую нашим сетям лучше обобщать данные,
  но не даёт принципиального понимания того,
  как работает обобщение,
  и какой лучший подход к нему.
  
  Эти проблемы восходят к проблеме индукции,
  известное осмысление которой проводил шотландский философ Дэвид Юм
  в книге "Исследование о человеческом познании" (1748).
  Проблеме индукции посвящена "теорема об отсутствии бесплатных обедов"
  Дэвида Уолперта и Уильяма Макреди (1977).
  
  А это особенно досадно,
  поскольку в обычной жизни люди феноменально хорошо умеют обобщать данные.
  Покажите несколько изображений слона ребёнку,
  и он быстро научится распознавать других слонов.
  Конечно, он иногда может ошибиться,
  к примеру, перепутать носорога со слоном,
  но в целом этот процесс работает удивительно точно.
  Вот, у нас есть система - мозг человека -
  с огромным количеством свободных параметров.
  И после того, как ему показывают одно или несколько обучающих изображений,
  система обучается обобщать их до других изображений.
  Наш мозг, в каком-то смысле,
  удивительно хорошо умеет регуляризировать!
  Но как мы это делаем?
  На данный момент нам это неизвестно.
  Думаю, что в будущем мы выработаем
  боле мощные технологии регуляризации в искусственных нейросетях,
  техники, которые в итоге позволят НС обобщать данные,
  исходя из ещё менее крупных наборов данных.
  //// Еще одна иллюстрация, когда зациклившись на проблеме "обобщения",
  //// пытаются представить работу алгоритма обучения нейросети
  //// по аналогии с устройством совершенно иного принципа действия
  //// - в мозгу нет обратного распространения ошибки -
  //// и закономерно не получают в итоге ничего кроме общих фраз.
  
  На самом деле, наши сети и так уже обобщают куда лучше,
  чем можно было ожидать априори.
  Сеть со 100 скрытыми нейронами обладает почти 80 000 параметров.
  У нас есть только 50 000 изображений в обучающих данных.
  Это всё равно, как пытаться натянуть многочлен 80 000 порядка
  на 50 000 опорных точек.
  По всем признакам наша сеть должна ужасно переобучиться.
  И всё же, как мы видели, такая сеть на самом деле довольно неплохо обобщает.
  Почему так происходит?
  Это не совсем понятно.
  Была высказана гипотеза,
  что <динамика обучения градиентным спуском в многослойных сетях
  подвержена саморегуляризации>.
  Это чрезвычайная удача,
  но и довольно тревожный факт,
  поскольку мы не понимаем, почему так происходит.
  Тем временем мы примем прагматичный подход,
  и будем использовать регуляризацию везде, где только можно.
  Нашим НС это будет на пользу.
  //// Вот так "нейронаука" на факту превращается в "шаманскую практику".
  
  Позвольте мне закончить этот раздел, вернувшись к тому,
  что я раньше не объяснил:
  что регуляризация L2 не ограничивает смещения.
  Естественно, было бы легко изменить процедуру регуляризации,
  чтобы она регуляризировала смещения.
  Но эмпирически это часто не меняет результаты каким-то заметным образом,
  поэтому, до некоторой степени, заниматься регуляризацией смещений, или нет
  - вопрос соглашения.
  Однако стоит отметить, что крупное смещение
  не делает нейрон чувствительным ко входам так, как крупные веса.
  Поэтому нам не нужно беспокоиться по поводу крупных смещений,
  позволяющим нашим сетям обучаться шуму в обучающих данных.
  В то же время, разрешив большие смещения,
  мы делаем наши сети более гибкими в их поведении
  - в частности, крупные смещения облегчают насыщение нейронов,
  чего нам бы хотелось.
  По этой причине обычно мы не включаем смещения в регуляризацию.
  //// Надо будет этот вопрос проработать с Copilot.
  //// Глядишь, что-то интересное удастся выцепить,
  //// какой-то не очень обоснованный вывод в этом параграфе.
  
  Иные техники регуляризации
  
  Существует множество техник регуляризации, кроме L2.
  На самом деле, было разработано уже столько техник,
  что я бы при всём желании не смог кратко описать их все.
  В этом разделе я кратенько опишу три других подхода к уменьшению переобучения:
  регуляризацию L1,
  исключение [dropout]
  и искусственное увеличение обучающего набора.
  Мы не будем изучать их так глубоко, как предыдущие темы.
  Вместо этого мы просто познакомимся с ними,
  а заодно оценим разнообразие существующих техник регуляризации.
  
  Регуляризация L1
  
  В данном подходе мы изменяем нерегуляризованную функцию стоимости,
  добавляя сумму абсолютных значений весов:
  
  $ C = C_0 + \frac{\lambda}{n} \sum_w |w| \tag{95} $
  
  Интуитивно это похоже на регуляризацию L2,
  штрафующую за большие веса и заставляющую сеть предпочитать малые веса.
  Конечно, член регуляризации L1 не похож на член регуляризации L2,
  поэтому не стоит ожидать ровно такого же поведения.
  Давайте попробуем понять, в чём поведение сети,
  обученной при помощи регуляризации L1,
  отличается от сети, обученной при помощи регуляризации L2.
  
  Для этого посмотрим на частные производные функции стоимости.
  Дифференцируя (95), получаем:
  
  $ \frac{\partial C}{\partial w} = \frac{\partial C_0}{\partial w} + \frac{\lambda}{n} \, {\rm sgn}(w) \tag{96} $
  
  где sgn(w) - знак w,
  то есть, +1, если w положительная,
  и -1, если w отрицательная.
  При помощи этого выражения мы влёгкую модифицируем обратное распространение
  так, чтобы оно выполняло стохастический градиентный спуск
  при помощи регуляризации L1.
  Итоговое правило обновление для L1-регуляризованной сети:
  
  $ w \rightarrow w' = w-\frac{\eta \lambda}{n} \mbox{sgn}(w) - \eta \frac{\partial C_0}{\partial w} \tag{97} $
  
  где, как обычно, ?C/?w можно по желанию оценить
  через усреднённое значение мини-пакета.
  Сравним это с правилом обновления регуляризации L2 (93):
  
  $ w \rightarrow w' = w\left(1 - \frac{\eta \lambda}{n} \right) - \eta \frac{\partial C_0}{\partial w} \tag{98} $
  
  В обоих выражениях действие регуляризации
  заключается в уменьшении весов.
  Это совпадает с интуитивным представлением о том,
  что оба типа регуляризации штрафуют большие веса.
  Однако уменьшаются веса по-разному.
  В регуляризации L1 веса уменьшаются на постоянное значение, стремясь к 0.
  В регуляризации L2 веса уменьшаются на значение, пропорциональное w.
  Поэтому когда у какого-то веса оказывается большое значение |w|,
  регуляризация L1 уменьшает вес не так сильно, как L2.
  И наоборот, когда |w| мало, регуляризация L1 уменьшает вес гораздо больше,
  чем регуляризация L2.
  В итоге регуляризация L1 стремится сконцентрировать веса сети
  в относительно небольшом числе связей высокой важности,
  а другие веса стремятся к нулю.
  //// Эдакое мягкое прореживание связей.
  //// И самое интересное, почему это работает?
  
  Я слегка сгладил одну проблему в предыдущем обсуждении
  - частная производная ?C/?w не определена, когда w=0.
  Это потому, что у функции |w| имеется острый <излом> в точке w=0,
  поэтому там её дифференцировать нельзя.
  Но это не страшно.
  Мы просто применим обычное, нерегуляризированное правило
  для стохастического градиентного спуска, когда w=0.
  Интуитивно, в этом нет ничего плохого
  - регуляризация должна уменьшать веса,
  и, очевидно, она не может уменьшить вес, уже равный 0.
  Точнее говоря, мы будем использовать уравнения (96) и (97) с условием,
  что sgn(0)=0.
  Это даст нам удобное и компактное правило для стохастического градиентного спуска
  с регуляризацией L1.
  
  Исключение [dropout]
  
  Исключение - совершенно другая техника регуляризации.
  В отличие от регуляризации L1 и L2,
  исключение не занимается изменением функции стоимости.
  Вместо этого мы изменяем саму сеть.
  Давайте я объясню базовую механику работы исключения,
  перед тем, как углубляться в тему того, почему оно работает
  и с какими результатами.
  
  Допустим, мы пытаемся обучить сеть:
  
  В частности, допустим, у нас есть обучающие входные данные x
  и соответствующий желаемый выход y.
  Обычно мы бы обучали её прямым распространением x по сети,
  а потом обратным распространением, чтобы определить вклад градиента.
  Исключение изменяет этот процесс.
  Мы начинаем со случайного и временного удаления половины скрытых нейронов сети,
  оставляя без изменений входные и выходные нейроны.
  После этого у нас останется примерно такая сеть.
  Отметьте, что исключённые нейроны, те, что временно удалены,
  всё равно отмечены на схеме:
  
  ......
  
  Мы передаём x прямым распространением по изменённой сети,
  а потом обратно распространяем результат, тоже по изменённой сети.
  После того, как мы проделаем это с мини-пакетом примеров,
  мы обновляем соответствующие веса и смещения.
  Потом мы повторяем этот процесс,
  сначала восстанавливая исключённые нейроны,
  потом выбирая новое случайное подмножество скрытых нейронов для удаления,
  оцениваем градиент для другого мини-пакета, и обновляем веса и смещения сети.
  
  Повторяя этот процесс снова и снова,
  мы получим сеть, выучившую некие веса и смещения.
  Естественно, эти веса и смещения выучивались в условиях,
  при которых половина скрытых нейронов была исключена.
  И когда мы запускаем сеть по полной,
  у нас будет в два раза больше активных скрытых нейронов.
  Для компенсации этого мы ополовиниваем веса, исходящие от скрытых нейронов.
  
  Процедура исключения может показаться странной и произвольной.
  Почему она должна помочь с регуляризацией?
  Чтобы объяснить происходящее,
  я хочу, чтобы вы на время забыли про исключение,
  и представили обучение НС стандартным способом.
  В частности, представьте, что мы обучаем несколько разных НС,
  используя одинаковые обучающие данные.
  Конечно, сети сначала могут различаться,
  и иногда обучение может давать разные результаты.
  В таких случаях мы могли бы применить какое-либо усреднение
  или схему голосования, чтобы решить, какой из выходов принимать.
  К примеру, если мы обучили пять сетей,
  и три из них классифицируют цифру, как <3>,
  тогда, вероятно, это и правда тройка.
  А две других сети, вероятно, просто ошибаются.
  Такая схема усреднения часто оказывается полезным
  (пусть и дорогим) способом уменьшения переобучения.
  Причина в том, что разные сети могут переобучаться по-разному,
  и усреднение может помочь с устранением подобного переобучения.
  //// Очень хорошая аналогия, но ее стоило бы еще "чуть-чуть" развить.
  //// А что если действительно при обучении нейросети происходит
  //// КОНКУРИРУЮЩЕЕ обучение МНОЖЕСТВА подсетей
  //// даже если не используется регуляризация?
  //// И мифическая "обобщающая способность" нейросети
  //// просто проявление СУММЫ реакций огромного количества подсетей.
  
  //// Возьмите эту мысль на обдумывания, не отвергая ее "с порога".
  //// Чуть ниже попробую показать, что не настолько уж "завиральная".
  
  Как всё это связано с исключением? Эвристически,
  когда мы исключаем разные наборы нейтронов,
  это похоже на то, как если бы мы обучали разные НС.
  Поэтому процедура исключения похожа на усреднение эффектов
  по очень большому количеству разных сетей.
  Разные сети переобучаются по-разному,
  //// И "недообучаются" то же "по разному",
  //// и сама процедура обучения у каждой подсети идет чуть-чуть по разному.
  поэтому есть надежда,
  что средний эффект исключения уменьшит переобучение.
  //// Как там насчет когнитивистской эвристики о "мудрости толпы"?
  \\\ Мудрость толпы (англ. Wisdom of the crowd)
  \\\ - коллективное мнение разнообразной независимой группы лиц,
  \\\ а не одного эксперта.
  \\\ Этот процесс, хотя и не является новым для информационной эпохи,
  \\\ был выдвинут в центр внимания социальных информационных сайтов,
  \\\ таких как Quora, Reddit, Stack Exchange, Wikipedia, Yahoo! Answers
  \\\ и других веб-ресурсов,
  \\\ которые полагаются на коллективные человеческие знания[1].
  \\\ Объяснение этого явления заключается в том,
  \\\ что существует своеобразный шум, связанный с каждым отдельным суждением,
  \\\ и взятие среднего значения по большому количеству ответов
  \\\ каким-то образом поможет подавить эффект этого шума[2].
  \\\ https://cyclowiki.org/wiki/Мудрость_толпы
  
  Связанное с этим эвристическое объяснение пользы исключения
  даётся в одной из самых ранних работ, использовавших эту технику:
  https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf
  <Эта техника уменьшает сложную совместную адаптацию нейронов,
  поскольку нейрон не может полагаться на присутствие определённых соседей.
  В итоге ему приходиться обучаться более надёжным признакам,
  которые могут быть полезными в совместной работе
  со многими различными случайными подмножествами нейронов>.
  Иначе говоря, если представить нашу НС, как модель, делающую предсказания,
  то исключение будет способом гарантировать устойчивость модели
  к потерям отдельных частей свидетельств.
  В этом смысле техника напоминает регуляризации L1 и L2,
  стремящиеся уменьшать веса,
  и делающие таким способом сеть более устойчивой
  к потерям любых отдельных связей в сети.
  //// Вот опять же попытка представить обучающие примеры,
  //// как "нечто с шумом".
  //// Но ведь если данные предельно чистые,
  //// но просто с очень сложной зависимостью,
  //// разве подход к ним как к "чему-то с шумом"
  //// уже гарантированно НЕ позволит на тестовой выборке получить
  //// "заветные шесть девяток"?
  
  Естественно, истинная мера полезности исключения
  - её огромные успехи в улучшении эффективности нейросетей.
  В оригинальной работе, где был представлен этот метод,
  http://arxiv.org/pdf/1207.0580.pdf
  он применялся ко множеству разных задач.
  Нас особенно интересует то,
  что авторы применили исключение к классификации цифр из MNIST,
  используя простейшую сеть с прямым распространением,
  похожую на ту, что рассматривали мы.
  В работе отмечается, что до тех пор наилучшим результатом
  для подобной архитектуры была точность в 98,4%.
  Они улучшили её до 98,7%,
  используя комбинацию исключения и изменённой формы регуляризации L2.
  Настолько же впечатляющие результаты были получены
  и для многих других задач, включая распознавание образов и речи,
  и обработку естественного языка.
  Исключение было особенно полезным в обучении крупных глубоких сетей,
  где часто остро встаёт проблема переобучения.
  //// Вот опять же "логическая нестыковка" - чем более крупная модель,
  //// тем больше у нее свободных параметров,
  //// так почему же она "предпочитает переобучаться",
  //// а не "обобщать" все более и более сложные зависимости.
  //// Даже странно, что такое несоответствие в даже на одной странице
  //// "почему-то" старательно игнорируется в большинстве учебных материалов.
  //// А может быть и вообще во всех проработанных мной.
  //// Вот не могу вспомнить ни одного примера упоминания этой "нестыковки",
  //// не говоря уже о попытках ее как-то раскрыть/объяснить.
  
  //// А вот если представлять нейросеть как "толпу" подсетей
  //// самых разных размеров,
  //// то тогда среди них, наверняка, найдется даже не одна, а много,
  //// которые могут страдать от "классического переобучения".
  //// Хотя я считаю, что и это "не совсем так",
  //// но, может быть, этот аргумент облегчит восприятие любой нейросети
  //// как "сети сетей", точнее, "ансамблей", а не отдельных нейронов.
  
  Искусственное расширение набора обучающих данных
  
  Ранее мы видели, что наша точность классификации MNIST
  упала до 80 с чем-то процентов,
  когда мы использовали всего 1000 обучающих изображений.
  И неудивительно - с меньшим количеством данных наша сеть
  встретит меньше вариантов написания цифр людьми.
  Давайте попробуем обучить нашу сеть из 30 скрытых нейронов,
  используя разные объёмы обучающего набора,
  чтобы посмотреть на изменение эффективности.
  Мы обучаем, используя размер мини-пакета в 10, скорость обучения ? = 0,5,
  параметр регуляризации ?=5,0,
  и функцию стоимости с перекрёстной энтропией.
  Мы будем обучать сеть 30 эпох с использованием полного набора данных,
  и увеличивать количество эпох пропорционально уменьшению объёма обучающих данных.
  Чтобы гарантировать одинаковый фактор уменьшения весов
  для разных наборов обучающих данных,
  мы будем использовать параметр регуляризации ?=5,0 с полным обучающим набором,
  и пропорционально уменьшать его с уменьшением объёмов данных.
  
  ......
  
  Видно, что точность классификации значительно подрастает
  с увеличением объёмов обучающих данных.
  Вероятно, этот рост будет продолжаться с дальнейшим увеличением объёмов.
  Конечно, судя по графику выше, мы приближаемся к насыщению.
  Однако, допустим, что мы переделаем этот график
  на логарифмическую зависимость от объёма обучающих данных:
  
  ......
  
  Видно, что в конце график всё равно стремится вверх.
  Это говорит о том, что если мы возьмём гораздо более массивный объём данных
  - допустим, миллионы или даже миллиарды рукописных примеров, а не 50 000 -
  тогда мы, вероятно, получим гораздо лучше работающую сеть
  даже такого небольшого размера.
  //// А как же "опасность переобучения"?
  //// Или большие объемы данных ГАРАНТИРОВАННО устраняют эту проблему?
  
  Достать больше обучающих данных - прекрасная идея.
  К сожалению, это может обойтись дорого,
  поэтому на практике не всегда возможно.
  Однако есть и другая идея, способная сработать почти так же хорошо
  - искусственно увеличить набор данных.
  К примеру, допустим, мы возьмём изображение пятёрки из MNIST,
  и немного повернём его, градусов на 15:
  
  .......
  
  Это явно та же цифра.
  Но на пиксельном уровне она сильно отличается от изображений,
  имеющихся в базе MNIST.
  Разумно предположить, что добавление этого изображения
  к обучающему набору данных может помочь нашей сети узнать больше
  о классификации изображений.
  Более того, мы, очевидно, не ограничены возможностью добавления
  всего одного изображения.
  Мы можем расширить наши обучающие данные,
  сделав несколько небольших поворотов всех обучающих картинок из MNIST,
  а потом использовав расширенный набор обучающих данных
  для увеличения эффективности сети.
  
  Эта идея весьма мощная, и её широко используют.
  Посмотрим на результаты из научной работы,
  применившей несколько вариаций этой идеи к MNIST.
  Одна из архитектур рассматриваемых ими сетей была похожа на ту,
  что используем мы
  - сеть с прямым распространением с 800 скрытыми нейронами,
  использующую функцию стоимости с перекрёстной энтропией.
  Запустив эту сеть со стандартным обучающим набором MNIST,
  они получили точность классификации в 98,4%.
  Но затем они расширили обучающие данные,
  используя не только описанною мною выше вращение,
  но и перенос и искажение изображений.
  Обучив сеть на расширенных данных, они повысили её точность до 98,9%.
  Также они экспериментировали с т.н. <эластичными искажениями>,
  особым типом искажений изображения,
  призванным устранить случайные колебания мускулов руки.
  Используя эластичные искажения для расширения данных,
  они достигли точности в 99,3%.
  По сути, они расширяли опыт их сети,
  выдавая ей различные вариации рукописного текста,
  встречающиеся в реальных почерках.
  
  Варианты этой идеи можно использовать для улучшения показателей
  множества задач по обучению,
  не только для распознавания почерка.
  Общий принцип - расширить обучающие данные, применяя к ним операции,
  отражающие вариации, встречающиеся в реальности.
  Такие вариации несложно придумать.
  Допустим, мы создаём НС для распознавания речи.
  Люди могут распознавать речь даже при наличии таких искажений,
  как фоновый шум.
  Поэтому можно расширить данные, добавив фонового шума.
  Также мы способны распознавать ускоренную и замедленную речь.
  Это ещё один способ расширения обучающих данных.
  Эти техники используются не всегда
  - к примеру, вместо расширения обучающего набора через добавления шума,
  может оказаться более эффективным подчищать входные данные,
  применяя к ним фильтр шума.
  И всё же, стоит иметь в виду идею расширения обучающего набора,
  и искать способы её применения.
  
  Упражнение
  
  Как мы обсудили выше, один из способов расширить обучающие данные из MNIST
  - использовать небольшие повороты обучающих картинок.
  Какая проблема может появиться,
  если мы допустим повороты картинок на любые углы?
  //// Я с этим упражнением не справился - в голову ничего путного не пришло.
  //// Видимо, моя встроенная нейросеть слегка "переобучилась".
  
  Отступление, касающееся больших данных
  и о смысле сравнения точности классификаций
  
  Давайте вновь взглянем на то,
  как точность нашей НС изменяется в зависимости от размера обучающего набора:
  
  Допустим, что вместо использования НС мы бы использовали
  другую технологию машинного обучения для классификации цифр.
  К примеру, попробуем использовать метод опорных векторов
  (support vector machine, SVM),
  с которым мы кратко встречались в главе 1.
  Как и тогда, не волнуйтесь, если вы не знакомы с SVM,
  нам не надо разбираться в его деталях.
  Мы будем использовать SVM за счёт библиотеки scikit-learn.
  Вот, как меняется эффективность SVM в зависимости от размера обучающего набора.
  Для сравнения я нанёс на график и результаты работы НС.
  
  .......
  
  Вероятно, первое, что бросается в глаза
  - НС превосходит SVM на любом размере обучающего набора.
  Это хорошо, хотя не стоит делать из этого далеко идущих выводов,
  поскольку я использовал предустановленные настройки scikit-learn,
  а над нашей НС мы довольно серьёзно поработали.
  Менее яркий, но более интересный факт, следующий из графика, состоит в том,
  что если мы обучим наш SVM с использованием 50 000 изображений,
  то он сработает лучше (точность в 94,48%), чем наша НС,
  обученная на 5000 изображений (93,24%).
  Иначе говоря, увеличение объёма обучающих данных
  иногда компенсирует разницу в алгоритмах МО.
  
  Может произойти ещё нечто более интересное.
  Допустим, мы пытаемся решить задачу с использованием двух алгоритмов МО, A и B.
  Иногда бывает так, что алгоритм A опережает алгоритм B
  на одном наборе обучающих данных,
  а алгоритм B опережает алгоритм A на другом наборе обучающих данных.
  Выше мы этого не увидели
  - тогда графики бы пересеклись -
  но такое бывает.
  Правильный ответ на вопрос:
  <Превосходит ли алгоритм A алгоритм B?>
  на самом деле такой:
  <А какой обучающий набор данных вы используете?>
  
  Всё это необходимо учитывать, как во время разработки,
  так и во время чтения научных работ.
  Многие работы концентрируются на поиске новых трюков
  для выжимания лучших результатов на стандартных наборах данных для измерения.
  <Наша супер-пупер технология дала нам улучшение на X%
  на стандартном сравнительном наборе Y>
  - каноническая форма заявления в таком исследовании.
  Иногда подобные заявления на самом деле бывают интересными,
  но стоит понимать,
  что они применимы только в контексте определённого обучающего набора.
  Представьте себе альтернативную историю,
  в которой люди, изначально создавшие сравнительный набор,
  получили исследовательский грант покрупнее.
  Они могли бы использовать дополнительные деньги
  для сбора дополнительных данных.
  Вполне возможно, что <улучшение> супер-пупер технологии исчезло бы
  на большем наборе данных.
  Иначе говоря, суть улучшения может оказаться просто случайностью.
  //// Или, что более вероятно, срабатывающей на определенном этапе обучения.
  //// Снова напомню концепцию многокритериального/многоступенчатого обучения.
  Из этого в область практического применения нужно вынести следующую мораль:
  нам необходимо как улучшение алгоритмов,
  так и улучшение обучающих данных.
  Нет ничего плохого в том, чтобы искать улучшенные алгоритмы,
  но убедитесь, что вы не концентрируетесь на этом,
  игнорируя более лёгкий способ выиграть при помощи увеличения объёма
  или качества обучающих данных.
  
  Задача
  
  Исследовательская задача.
  Как наши алгоритмы МО будут вести себя в пределе
  на очень больших наборах данных?
  Для любого заданного алгоритма естественно попытаться определить
  понятие асимптотической эффективности в пределе
  на самом деле больших данных.
  Дешёвый и сердитый подход к этой задаче
  - попытаться подобрать кривые под графики,
  подобные тем, что приведены выше,
  а потом экстраполировать кривые в бесконечность.
  Однако можно возразить, что разные подходы к подбору кривых
  могут дать разное представление об асимптотическом пределе.
  Сможете ли вы оправдать результаты экстраполяции
  для какого-то определённого класса кривых?
  //// Мне представляется, что скорее "нет" чем "да".
  //// Во всяком случае, мне еще ни разу такие графики/экстраполяции не встречались.
  В таком случае, сравните асимптотические пределы нескольких алгоритмов МО.
  //// Мимо. Нет таких данных.
  
  Итоги
  
  Мы закончили наше погружение в переобучение и регуляризацию.
  Мы, конечно, ещё вернёмся к этим проблемам.
  Как я уже несколько раз упомянул,
  переобучение - большая проблема в области НС,
  особенно по мере того, как компьютеры становятся всё мощнее,
  и мы можем обучать всё более крупные сети.
  В итоге возникает насущная необходимость
  разработать эффективные методики регуляризации
  для уменьшения переобучения,
  поэтому данная область сегодня является весьма активной.
  //// Не регуляризацией единой живет сейчас машинное обучение.
  
  Инициализация весов
  
  Когда мы создаём наши НС, нам необходимо делать выбор
  начальных значений весов и смещений.
  Пока что мы выбирали их согласно предписаниям,
  кратко описанным мною в главе 1.
  Напомню, что мы выбирали веса и смещения на основе
  независимого распределения Гаусса
  с математическим ожиданием 0 и среднеквадратичным отклонением 1.
  Этот подход хорошо сработал,
  однако он кажется довольно произвольным,
  поэтому стоит пересмотреть его и подумать,
  нельзя ли найти лучший способ назначения изначальных весов и смещений,
  и, возможно, помочь нашим НС учиться быстрее.
  
  Оказывается, можно довольно серьёзно улучшить процесс инициализации
  по сравнению с нормализованным распределением Гаусса.
  Чтобы разобраться в этом, допустим,
  мы работаем с сетью с большим количеством входных нейронов,
  - скажем, с 1000.
  И допустим, мы использовали нормализованное распределение Гаусса
  для инициализации весов, соединённых с первым скрытым слоем.
  Пока что я сфокусируюсь только на весах,
  соединяющие входные нейроны с первым нейроном в скрытом слое,
  и проигнорирую остальную часть сети:
  
  Для простоты представим, что мы пытаемся обучать сеть входом x,
  в котором половина входных нейронов включены,
  то есть, имеют значение 1, а половина - выключены,
  то есть, имеют значение 0.
  Следующий аргумент работает и в более общем случае,
  но вам проще будет понять его на этом особом примере.
  Рассмотрим взвешенную сумму z = ?jwjxj+b входов для скрытого нейрона.
  500 членов суммы исчезают, поскольку соответствующие xj равны 0.
  Поэтому z - это сумма 501 нормализованных гауссовых случайных переменных,
  500 весов и 1 дополнительное смещение.
  Поэтому и само значение z имеет гауссово распределение
  с математическим ожиданием 0 и среднеквадратичным отклонением √501 ~ 22,4.
  То есть, у z довольно широкое гауссово распределение, без острых пиков:
  
  ......
  
  В частности, из этого графика видно, что |z|,
  скорее всего, будет довольно крупным,
  то есть, z > 1 или z < -1.
  В таком случае выход скрытых нейронов ?(z) будет очень близок к 1 или 0.
  Это значит, что наш скрытый нейрон насытится.
  И когда это произойдёт, как нам уже известно,
  небольшие изменения весов будут давать крохотные изменения
  в активации скрытого нейрона.
  Эти крохотные изменения, в свою очередь,
  практически не затронут остальные нейтроны в сети,
  и мы увидим соответствующие крохотные изменения в функции стоимости.
  В итоге эти веса будут обучаться очень медленно,
  когда мы используем алгоритм градиентного спуска.
  Это похоже на задачу, которую мы уже обсуждали в этой главе,
  в которой выходные нейроны, насыщенные на неверных значениях,
   заставляют обучение замедляться.
  Раньше мы решали эту проблему, хитроумно выбирая функцию стоимости.
  К сожалению, хотя это помогло с насыщенными выходными нейронами,
  это совсем не помогает с насыщением скрытых нейронов.
  //// Ага, как я и предполагал, для глубинных слоев "логистический нейрон"
  //// - существенный "тормоз" на пути "обратного распространения",
  //// и, похоже, применять такую активацию в глубине нейросети
  //// надо очень обдуманно и осторожно.
  
  Сейчас я говорил о входящих весах первого скрытого слоя.
  Естественно, те же аргументы применимы и к следующим скрытым слоям:
  если веса в поздних скрытых слоях инициализируются
  с использованием нормализованных гауссовых распределений,
  их активации часто будут близки к 0 или 1,
  и обучение будет идти очень медленно.
  
  Есть ли способ выбрать лучшие варианты инициализации для весов и смещений,
  чтобы мы не получали такого насыщения,
  и могли избежать замедления обучения?
  Допустим, у нас будет нейрон с количеством входящих весов nin.
  Тогда нам надо инициализировать эти веса случайными гауссовыми распределениями
  с математическим ожиданием 0 и среднеквадратичным отклонением 1/√nin.
  То есть, мы сжимаем гауссианы,
  и уменьшаем вероятность насыщения нейрона.
  Затем мы выберем гауссово распределение для смещений
  с математическим ожиданием 0 и среднеквадратичным отклонением 1,
  по причинам, к которым я вернусь чуть позже.
  Сделав такой выбор, мы вновь получим, что z = ?jwjxj + b
  будет случайной переменной с гауссовым распределением
  с математическим ожиданием 0,
  однако с гораздо более выраженным пиком, чем раньше.
  Допустим, как и раньше, что 500 входов равны 0, и 500 равны 1.
  Тогда легко показать (см. упражнение ниже),
  что z имеет гауссово распределение с математическим ожиданием 0
  и среднеквадратичным отклонением √(3/2) = 1,22...
  Этот график с гораздо более острым пиком,
  настолько, что даже на картинке ниже ситуация несколько преуменьшена,
  поскольку мне пришлось поменять масштаб вертикальной оси
  по сравнению с предыдущим графиком:
  
  ......
  
  Такой нейрон насытится с гораздо меньшей вероятностью,
  и, соответственно, с меньшей вероятностью столкнётся с замедлением обучения.
  //// Т.е., по сути, большинство инициализируемых весов
  //// имеют существенно меньшее значение, чем в исходном алгоритме.
  
  Упражнение
  
  .....
  
  Выше я упоминал, что мы и дальше будем инициализировать смещения, как и раньше,
  на основе независимого распределения Гаусса
  с математическим ожиданием 0 и среднеквадратичным отклонением 1.
  И это нормально,
  поскольку не сильно увеличивает вероятность насыщения наших нейронов.
  На самом деле инициализация смещений особого значения не имеет,
  если мы сумеем избежать проблемы насыщения.
  Некоторые даже пытаются инициализировать все смещения нулём,
  и полагаются на то, что градиентный спуск сможет выучить подходящие смещения.
  Но поскольку вероятность того, что это на что-то повлияет, мала,
  мы продолжим использовать ту же процедуру инициализации, что и ранее.
  
  Давайте сравним результаты старого и нового подходов инициализации весов
  с использованием задачи по классификации цифр из MNIST.
  Как и ранее, мы будем использовать 30 скрытых нейронов,
  мини-пакет размером в 10, параметр регуляризации &lambda=5,0,
  и функцию стоимости с перекрёстной энтропией.
  Мы будем постепенно уменьшать скорость обучения с ?=0,5 до 0,1,
  поскольку так результаты будут немного лучше видны на графиках.
  Обучаться можно с использованием старого метода инициализации весов:
  
  ......
  
  Также можно обучаться при помощи нового подхода к инициализации весов.
  Это даже проще, ведь по умолчанию network2 инициализирует веса
  при помощи нового подхода.
  Это значит, что мы можем опустить вызов net.large_weight_initializer() ранее:
  
  .......
  
  Строим график (при помощи программы weight_initialization.py):
  
  ......
  
  В обоих случаях получается точность классификации в районе 96%.
  Итоговая точность почти совпадает в обоих случаях.
  Но новая техника инициализации доходит до этой точки гораздо, гораздо быстрее.
  В конце последней эпохи обучения старый подход к инициализации весов
  достигает точности в 87%,
  а новый подход уже подходит к 93%.
  //// Судя по графику в тексте должно стоять "в конце первой эпохи обучения"
  //// а не "последней эпохи". Но что есть, то есть.
  Судя по всему, новый подход к инициализации весов
  начинает с гораздо лучшей позиции,
  благодаря чему мы получаем хорошие результаты гораздо быстрее.
  //// Очень полезная информация.
  //// Получается, что "одну девятку" можно получить уже
  //// в рамках одной эпохи обучения.
  //// И в этом вся сила "обратного распространения ошибки" с регуляризацией,
  //// и более разумной инициализацией.
  //// А вот то, что происходит в последующих эпохах "упрямо твердит",
  //// что что-то нужно "менять в консерватории".
  То же явление наблюдается,
  если построить результаты для сети с 100 нейронами:
  //// Т.е. это мало зависит и от масштаба сети и, возможно, размера датасета,
  //// а отражает во "всем великолепии" "блеск и нищету"
  //// существующих методов машинного обучения.
  //// "В грамм добыча - в годы труды".
  //// Но ведь в начале сеть обучалась достаточно быстро,
  //// так что же происходит за рамками первых двух-трех эпох обучения?
  //// Опять же тема, которую как-то избегают обсуждать.
  
  ......
  
  В данном случае две кривые не встречаются.
  Однако мои эксперименты говорят, что если добавить ещё немножко эпох,
  то точности начинают почти совпадать.
  Поэтому на базе этих экспериментов можно сказать,
  что улучшение инициализации весов только ускоряет обучение,
  но не меняет итоговой эффективности сети.
  Однако в главе 4 мы увидим примеры НС,
  у которых долгосрочная эффективность серьёзно улучшается
  в результате инициализации весов через 1/√nin.
  Поэтому, улучшается не только скорость обучения,
  но иногда и итоговая эффективность.
  
  Подход к инициализации весов через 1/√nin
  помогает улучшать обучение нейросетей.
  Предлагались и другие техники инициализации весов,
  многие из которых основываются на этой базовой идее.
  Не буду рассматривать их здесь,
  поскольку для наших целей хорошо работает и 1/√nin.
  Если вам интересно, порекомендую почитать обсуждение
  на страницах 14 и 15 в работе от 2012 года за авторством Йошуа Бенджио.
  http://arxiv.org/pdf/1206.5533v2.pdf
  
  ......
  
  Возвращаемся к распознаванию рукописных цифр: код
  
  ......
  
  Среди более интересных изменений - включение L2 регуляризации.
  Хотя это большое концептуальное изменение,
  его настолько легко реализовать, что вы могли не заметить это в коде.
  По большей части, это просто передача параметра lmbda разным методам,
  особенно Network.SGD.
  Вся работа проводится в одной строчке программы,
  четвёртой с конца в методе Network.update_mini_batch.
  Там мы изменяем правило обновления градиентного спуска,
  чтобы оно включало ослабление веса.
  Изменение крохотное, но серьёзно влияющее на результаты!
  
  Это, кстати, часто бывает при реализации новых техник в нейросетях.
  Мы тысячи слов потратили на обсуждение регуляризации.
  Концептуально это довольно тонкая и сложная для понимания вещь.
  Однако её можно тривиальным образом добавить к программе!
  Неожиданно часто сложные техники получается реализовывать
  с небольшими изменениями кода.
  //// А с другой стороны, такое простое включение, может приводить
  //// и, скорее всего, приводит к тому, что понимание того
  //// какую собственно регуляризацию, когда именно и как именно
  //// применять в каждом конкретном случае,
  //// уже не так чтобы и требуется.
  //// Можно просто попытаться "поиграться" с подключением разных функций
  //// и посмотреть на конечные результаты.
  //// Вот так и воспитывается школа "истинных шаманов датасатанизма".
  
  ......
  
  //// Из комментариев.
  
  masai
  15 июл 2019 в 15:24
  
  Со стороны канонической математики вся эта эвристика выглядит как
  - <подогнать теорию под результат>
  
  Ну так это так и работает, это именно математика.
  У нас есть генеральная совокупность
  и какое-то априорное предположение о его распределении.
  Это может быть как вера в бритву Оккама,
  так и какое-то следствие из теории, описывающей предметную область.
  
  Если мы подбираем параметры модели так,
  чтобы результаты наблюдений имели наибольшую вероятность,
  то это метод максимального правдоподобия.
  Вот он как раз и переобучается.
  И это не очень логично, использовать такой метод.
  У нас же есть какие-то априорные предположения,
  а мы их не используем.
  
  А если мы применим теорему Байеса и учтём наши априорные знания,
  то получится оценка апостериорного максимума.
  //// К сожалению, автор этого комментария не дал более точных указаний
  //// как получить эту "оценку апостериорного максимума"
  //// для задач регуляризации нейросетей,
  //// а моих знаний не хватает, чтобы хотя бы представить ее общий вид.
  Если расписать функцию потерь в этом случае,
  то как раз и появится регуляризационное слагаемое.
  //// Вера в "единственно верную функцию" детектед.
  //// Дело не "максимальном правдоподобии" или "Байесе",
  //// вопрос в том почему "регуляризация" имеет положительный эффект,
  //// а не, наоборот, отрицательный -
  //// ведь мы, по факту, принудительно "смещаем прицел"
  //// "главного калибра" машинного обучения
  //// - метода обратного распространения ошибки.
  
  Рассуждения про бритву Оккама - это здорово,
  но они не объясняют с математической точки зрения,
  почему нужна регуляризация и почему она именно такая.
  А с помощью теоремы Байеса это всё отлично выводится.
  
  Скажем, L2 - это не просто из головы взяли, что надо в квадрат возводить.
  Этот регуляризационный член появляется
  из априорного предположения о нормальности распределения шума.
  Так что это очень даже каноничная математика.
  //// А откуда известно о "нормальном распределении шума",
  //// допустим, в идеально чистых данных?
  //// А регуляризация и в этом случае дает какой-то прирост качества обучения.
  
  С другой стороны, если модель очень сложная,
  то мало кто заморачивается с выводами
  (так как иногда исследование просто не провести из-за запредельной сложности),
  а просто экспериментируют. :)
  Но понимать, откуда у регуляризации ноги растут, я думаю, полезно.
  //// А это понимание действительно есть?
  //// Или все объясняется "гауссовским шумом"?
  
  phenik
  17 июл 2019 в 17:58
  
  Рассуждения автора во вводной части представляются спорными.
  Он сравнивает два метода описания экспериментальных данных
  - аппроксимацию с помощью многочлена и линейную регрессию.
  И задается вопросом, какой метод даст лучшие предсказания
  за пределами области определения данных.
  Но это разные задачи,
  и кажется странным сравнивать результаты предсказания по ним.
  Первая, как можно точнее описать поведение данных,
  вторая - выявить тренд.
  Соответственно, если обучать нейросеть,
  то и критерии должны быть разными.
  К этому никакого отношения не имеет бритва Оккама.
  Если задаться вопросом - какая зависимость имеет место в действительности,
  если это результаты измерений,
  то для этого нужно понять происхождение отклонений.
  Связано это с ошибками измерений,
  или присуще поведению самого явления?
  На практике это бывает иногда сложно понять.
  Но в этом и состоит работа экспериментатора.
  
  Дальнейшие рассуждения с бритвой Оккама кажутся вовсе ошибочными.
  Пример с частицей Шейна, в полном соответствии с принципом Оккама,
  не сложнее описывается, как утверждает автор, а именно проще.
  Для каждой из пластин Бете находит объяснение не привлекающее излишнюю сущность
  - новую частицу,
  т.е. его описание проще, а не сложнее.
  Второй пример, с гравитацией, вообще не подпадает
  под действие этого методологического принципа,
  т.к. закон тяготения Ньютона и ОТО находятся
  во взаимоотношении регулируемом принципом соответствия,
  и первый является частным случаем второй,
  в предельном случае слабого гр. потенциала.
  
  ......
  
  никто пока ещё не разработал полностью убедительное
  теоретическое объяснение тому,
  почему регуляризация помогает сетям проводить обобщение.
  
  Если исходить из обучения человека,
  имея ввиду, в общем случае и процесс познания, как самообучения,
  то обобщению предшествует процедура абстрагирования,
  связанная с удалением несущественных признаков.
  В этом смысле регуляризацию в НС можно рассматривать,
  как аналог абстрагирования у человека.
  //// Еще одна версия объяснения "регуляризации"
  //// на основе аналогии с обучением человека.
  Если посмотреть на определение абстрагирования,
  то можно увидеть многообразие ее разновидностей.
  То есть и здесь нет единого механизма,
  к которому сводилась бы эта процедура.
  Возможно поэтому нет и единого математического описания регуляризации.
  Но это предположение,
  математики не раз находили решение таких сложных задач)
  
  На абстрагирование, и регуляризацию в НС,
  можно посмотреть с другой точки зрения,
  как на сжатие информации с потерями.
  В какой-то момент эволюция установила,
  что условные рефлексы полезно вырабатывать
  не только для целостных сенсорных образов,
  но и для примитивов сжатия.
  Это подстегнуло процесс дальнейшего сжатия информации,
  вплоть до появления абстрактных понятий у человека,
  и их использования в процессе мышления.
  Таким образом, эволюция решила сразу две задачи,
  произвела сжатие информации, уменьшив требования к вычислительным ресурсам мозга,
  и нашла результатам сжатия применение во все более усложняющемся мышлении,
  как полезного приспособления для выживания видов.
  
  А это особенно досадно,
  поскольку в обычной жизни люди феноменально хорошо умеют обобщать данные:
  Думаю, что в будущем мы выработаем боле мощные технологии регуляризации
  в искусственных нейросетях,
  техники, которые в итоге позволят НС обобщать данные,
  исходя из ещё менее крупных наборов данных.
  
  Да, а для начала хотя бы реализовать в НС эту способность,
  которая имеется уже у детей)
  
  ..........
  
  //// Конец цитирования.
  
  В общем, как-то не убедил меня ни варианты объяснения "регуляризации"
  ни на основе "обобщающей способности", ни на основе "гауссовского шума",
  если так можно классифицировать приведенные выше объяснения.
  А вот возможность попытаться объяснить "эффект регуляризации"
  на руководствуясь концепцией представления нейросети
  как "ансамбля ансамблей", т.е. комбинации/наложения множества подсетей
  всерьез заинтересовала и увлекла.
  
  Но, наверно, внятно изложить ее в паре абзацев не получится,
  а этот фрагмент и так уж получился очень объемным,
  так что я попытаюсь сформулировать и обосновать эту концепцию
  в отдельном фрагменте.
  Вот только надо постараться "собрать в кучку" достаточно разрозненные мысли,
  и как-то это еще и более-менее последовательно изложить.
  
  
  =========
  
  13.04.2024 11:56
  
  Попытка неканонической трактовки регуляризации. Часть 1.
  В оглавление.
  
  Давйте попробуем взглянуть на возможность объяснения "эффекта регуляризации"
  с точки зрения представления обучения и работы нейросети
  не как единого целого, а как суммы работы "ансамбля ансамблей",
  т.е. "сети подсетей".
  И посмотрим может ли такой подход что-то не только объяснить,
  но и подсказать что-то более-менее интересное/практичное/полезное.
  
  Итак, "начнем от печки".
  Имеется некая система, фактически "черный ящик", называемый нейросетью,
  и набор обучающих данных, возможно, не очень чистых - точно мы об этом не знаем.
  И нам требуется, чтобы "черный ящик" не только запомнил именно эти данные,
  но и был способен их "обобщить",
  т.е. давать верные результаты не только на этих данных,
  но и на других данных из этой же области.
  Причем, априорно неизвестно ни о каких-то закономерностях в этих данных,
  ни степень их "чистоты", т.е. наличия в них какого-то "шума".
  Вся надежда на "магию обобщения" этого "черного ящика".
  И все оправдания, когда это получается как-то "не очень",
  сводятся то ли к "переобучению", то ли к "недообучению",
  а в итоге недостаточном размере то ли "обучающих данных",
  то ли "черного ящика", то ли времени "обучения,
  то ли, вообще, "благосклонности небес".
  
  Ну, насчет "благосклонности небес" спорить глупо
  - это, наверно, всегда очень существенный фактор и от нас не зависит.
  А вот все остальное уже область нашей ответственности,
  помноженной на степень нашего понимания происходящего.
  Иначе не остается ничего другого как следовать рекомендациям
  из известного анекдота про "английские газоны":
  "поливать" - добавлять все больше и больше обучающих данных -
  и "стричь" - регуляризировать и варьировать гиперпараметры -
  "и так триста лет".
  
  А можно ли как-то по-другому?
  Давайте разбираться.
  Обычно описание обучение/работу нейросетей пытаются делать
  на примере линейной регрессии, так как это приведено в предыдущем фрагменте.
  Вот только проблема в том, что это описание как правило сводится
  к рекомендациям желательности получить более простую систему с "шумом",
  а вот относительно получения более сложной системы отношение неоднозначное.
  Ну, к вопросу "шума" еще вернемся.
  А пока отметим, что чисто исторически такая трактовка объяснения работы нейросетей
  сложилась еще "во времена Очакова и покоренья Крыма",
  то бишь, исходного представления нейросети классическим перцептроном
  с одним скрытым слоем и ЛИНЕЙНЫМ выходным слоем.
  Причем количество нейронов/связей в таких сетях не сильно превышало
  размерность входных данных,
  и по этому сопоставление обучения/работы такой нейросети
  достаточно близко соответствовало алгоритмам многомерной линейной регрессии.
  Интересно, что и качество работы таких нейросетей
  достаточно близко соответствовало многомерной линейной модели с "шумом".
  С тех пор "много воды утекло в Стиксе",
  архитектуры нейросетей и методы их обучения существенно изменились,
  а такая трактовка осталась практически неизменной.
  Хотя к существующим архитектурам, на мой взгляд,
  это уже мало применимо.
  И вот почему.
  
  Не будем нарушать "сложившуюся традицию" и попытаемся рассмотреть,
  что же собственно стоит изменить при рассмотрении нейросетей,
  с точки "линейной регрессии", но уже не "классической".
  Во-первых, это то, что масштаб нейросетей даже самых простых стал таким,
  что количество "свободных параметров", т.е. количества нейронов и связей,
  существенно превосходят размерность входных и выходных данных,
  а иногда и количества обучающих данных.
  И уже только поэтому обычное представление решение
  как суммы ограниченного количества слагаемых:
  y = a0 + a1*x**1 + a2*x**2+...+an*x**n
  можно поставить под сомнение.
  
  Тут можно было бы указать еще и на то,
  что если бы такое решение и соответствовало бы реальным сложным зависимостям
  обучающих данных - с "шумом" или без "шума" не так важно -
  то "феномена нейросетей" никто бы даже не заметил
  Проще было бы вычислить такой многочлен
  и не мучиться ни с непредсказуемым обучением нейросетей,
  ни с весьма затратным их инференсом.
  Однако же нейросети такое "простое решение" переиграли по всем параметрам,
  хотя в начале своей истории ничего подобного никак не демонстрировали.
  И это связано с началом использованием в архитектуре нейросетей
  НЕЛИНЕЙНЫХ элементов, хотя бы в форме "сигмоидных нейронов", слоев "softmax" и др.
  
  Вот держа эту "нелинейность" в уме, попробуем снова вернуть
  к "традиционной трактовке" нейросетей как "линейной регрессии".
  В прошлом фрагменте я пытался отметить, то место в "каноничесокй трактовке"
  на котором рассмотрение вариантов возможностей представления решений
  обычно заканчивалось. А заканчивалось оно на варианте,
  когда составляется многочлен с количеством свободных параметров соответствующих
  количеству входных данных.
  Мол дальше рассматривать бессмысленно с математической точки зрения.
  Но если все-таки переступить через "каноны"
  и попробовать представить решение полиномом "стопятьсотого порядка"?
  
  Что запрещает такое сделать?
  То что нет однозначного решения?
  Но ведь это как раз соответствует реалиям нейросетей,
  в которой различная инициализация параметров,
  которые можно считать неким аналогом исходных данных,
  а еще и различная последовательность обучающих примеров
  приводят к различным конечным состояниям и разной результативности.
  То есть, принципиальных запретов на такое представление нет.
  
  Теперь делаем следующий шаг.
  Представим этот полином "стопятьсотого порядка"
  как сумму "триллиарда" полиномов различных степеней.
  Что такое представление не имеет смысла, так как все равно суммируются?
  Правильно, действительно не имеет,
  НО только при использовании в архитектуре нейросети
  ТОЛЬКО линейных элементов.
  А вот теперь вспоминаем про НЕЛИНЕЙНЫЕ элементы нейросети,
  и тогда представление результата в виде суммы отдельных полиномов
  "начинает играть новыми красками".
  Фактически каждый такой отдельный "полином" можно рассматривать
  как представление поведение какой-то внутренней "подсети" или "ансамбля параметров"
  целой нейросети.
  
  Т.е. нейросеть это как "муравейник", внутри которого живут "отдельные муравьи",
  причем многие "муравьи" "на поверхность могут никогда в жизни не вылезать",
  т.е. "подсети" совершенно необязательно представлять
  как какой-то "срез" всей сети от входного до выходного слоя.
  Вполне возможны чисто внутренние "подсети"/"ансамбли",
  имеющие связи только с глубокими слоями всей нейросети.
  
  Собственно, вся эта отсылка к "линейной регрессии" была только и не столько
  как попытка хоть как-то даже не обосновать такое представление нейросетей
  - понятно, что это достаточно "неформальное обоснование -
  а иллюстрацией того, что это никак не противоречит "математическим основам".
  Но зато такое представление нейросети, как "ансамбля ансамблей"
  позволяет хоть как-то подступиться к вопросам "эффектов регуляризации"
  чуть-чуть более конструктивно, чем в "канонической интерпретации".
  
  На этом будем считать "вводную часть" законченной,
  чтобы можно было идти дальше, не шарахаясь от термина "подсеть"/"ансамбль".
  
  Давайте попробуем представить как такие подсети формируются.
  Причем тут интересно самое начало обучения.
  Итак имеем случайным образом инициализированную нейросеть,
  которой предъявляется самый первый пример
  - для упрощения считаем, что размер мини-батча равен единице.
  Методом обратного распространения вносятся согласованные коррективы
  в большое количество связей всей нейросети,
  так чтобы выход этой сети при предъявлении этого же примера был бы
  в соответствии с функцией стоимости/ошибки лучше, чем предыдущий.
  Соответственно, следующий обучающий пример также можно рассматривать
  как приводящий из предыдущего состояния в обновленное.
  
  И теперь есть интересная возможность ПРЕДСТАВИТЬ
  это обновленное состояние нейросети либо как просто промежуточное состояние
  - как это обычно считается -
  а можно как некую виртуальную "подсеть" преобразующую предыдущее состояние
  - в данном случае первоначальную инициализацию -
  в какое-то более приемлемое с точки зрения процесса обучения реакцию
  для данных входных данных.
  
  Тут нужно вспомнить, что в отношении нейросети есть парочка "проклятых вопросов",
  не имеющим в настоящее время приемлемого решения.
  Это где и как именно нейросеть "запоминает" какие-то обучающие примеры,
  на которые обычно имеют ввиду при ссылках на пресловутое "переобучение".
  И, одновременно, "неясность" как именно реализуется не менее пресловутая
  "обобщающая способность" нейросети.
  
  Так вот, если рассматривать КАЖДОЕ преобразование параметров нейросети
  при обучении как отдельную "подсеть"/"ансамбль" ЗАПОМИНАЮЩИХ
  не сам обучающий пример,
  а именно преобразование предыдущего состояния в обновленное,
  то представляется, что можно через такое "несколько усложненное" представление
  подойти к "проклятым вопросам" чуть-чуть с другой стороны.
  
  Еще раз, допустив возможность представления обучения/реакции целой нейросети,
  как одновременною обучение/работу ОЧЕНЬ большого количества "подсетей"/"ансамблей",
  появляется возможность рассматривать эти "подсети"
  не только в пространственной "проекции", но и во ВРЕМЕННОЙ "проекции".
  Т.е. представлять работу нейросети как "овеществленную историю обучения",
  а не как обычное "мгновенное состояние".
  
  Зачем это надо?
  Пока точно сказать не могу - может ничего и не получится,
  этой идее/гипотезе еще и дня "от роду" нет.
  Но если вспомнить из истории науки какие последствия оказала
  казалось бы абстрактная идея "флюксий" - "исчисления бесконечно малых" -
  то можно предполагать, что попытка представить текущего поведения нейросетей
  как "КОНЕЧНОЙ суммы ИСТОРИИ обучения"
  тоже может оказать не совсем уж бесплодной.
  //// Еще одна уже техническая аналогия такого представления - БИХ-фильтры,
  //// фильтры с бесконечной импульсной характеристикой,
  //// только здесь в качестве элементов "памяти"/"обратной связи"
  //// используются/подразумеваются сами текущие значения параметров нейросети.
  Во всяком случае, хоть какое-то представление о том,
  как реализуется "память нейросети", такой подход обеспечивает/позволяет.
  И теперь интересно как это можно использовать.
  
  Первое, что приходит в голову это то,
  что рассматривая такую "временную последовательность подсетей",
  представляется, что влияние самых первых обучающих примеров
  имеет существенно большее значение чем последующих.
  Так как их "влияние" через эти "первые подсети" проявляется во всех последующих
  не только из-за их очередности,
  но, скорее всего, еще из-за того, что первоначальные изменения в "подсетях"
  из-за их первоначальной случайной инициализации еще и максимальна.
  
  А отсюда можно предположить,
  что последовательность первых обучающих примеров вовсе не так уж "безобидна".
  Представляется, что, наверно, первые обучающие примеры должны быть
  максимально разнообразны,
  или, наоборот, максимально близкими друг другу и к "среднему".
  Во всяком случае, интересно было бы почитать про такого рода эксперименты.
  Но обычно самое начало процесса обучения остается вне "фокуса внимания" исследователей,
  так как считается, что последующее обучение все равно все "выравнивает".
  и интересно только конечное качество.
  Но ведь с чего-то "переобучение" все-таки начинается,
  и может быть это закладывается на самых первых шагах обучения.
  А то что привязать это "переобучение" к конкретному обучающему примеру/примерам
  просто так никому не удается, так ведь большинство моделей обучается
  по случайной последовательности примеров,
  и никто не пытается как-то эту последовательность отслеживать.
  Наоборот, считается, что "Великий Рэндом" как раз и "дарует счастье".
  //// Честно говоря, я и сам так считал
  //// в начале всей этой эпопеи изучения нейросетей,
  //// но это было так давно - уже целый год назад,
  //// и с тех пор пришло понимание, что все намного-намного сложнее
  //// и, одновременно, проще, если пытаться использовать другие подходы.
  
  Вообще-то, мысль о том, что последовательность обучающих примеров
  имеет достаточно важное значение в конечном результате обучения,
  уже достаточно крутится в голове, и уже не раз озвучивалась.
  Так что, возможно, предыдущий абзац это попытка "подогнать"
  одну гипотезу под другую, без всякого объективного основания.
  Но можно взглянуть на это и по другому
  - как попытку выстроить систему взаимосвязанных гипотез,
  обеспечивающих преодоление какого барьера инерционного/информационного
  или просто догматического.
  
  Можно даже обосновать попытку выстроить такой "круг гипотез",
  сославшись на метод "кругового доказательства" Платона.
  Но при этом напомнить, что этот метод "настоящая наука" отвергает,
  следуя заветам/силлогизмам ученика Платона - Аристотеля.
  Хотя "метод Аристотеля" предполагает в качестве исходной точки рассуждении
  использовать некие "аксиомы" - "безусловные и непререкаемые истины".
  Но в том то и дело что в области машинного обучения нейросетей
  таких "аксиом" как-то не наблюдается.
  Практически под любой факт из этой области находится контраргумент.
  
  Поэтому "круг гипотез" отнюдь не самый плохой метод в такой ситуации.
  Очень рекомендую тем, кого заинтересовал такой подход к поиску решений
  в области, где отсутствуют нужная информация или новые идеи,
  наряду с очень высокими барьерами психологической инерции,
  для "домашнего чтения" короткий и хороший рассказ Валентины Журавлевой:
  "Приключение"
  https://libking.ru/books/sf-/sf/61185-valentina-zhuravleva-priklyuchenie.html,
  
  Так что я продолжу попытку выстраивать "круг гипотез".
  
  Рассмотрим первый, самый начальный этап обучения нейросети,
  так называемый инфляционный период" обучения,
  скажем, в рамках первой эпохи обучения,
  во время которого нейросети предъявляются все примеры из обучающего набора.
  В рамках канонической трактовки на этом этапе происходит
  начальное обучение нейросети путем последовательной настройки параметров.
  Причем улучшение качества сети практически линейно возрастает
  по мере предъявления новых примеров,
  и может достигать в конце первой эпохи точности в "одну девятку", то бишь, 90%.
  
  Как правило, этот этап обучения практически не исследуется,
  так как, вроде, и так все ясно - "сеть обобщает".
  Вопрос в том, как это происходит?
  Вообще-то существует, как минимум, два способа "обобщения".
  Первый, который наиболее желанный/приветствуемый и, одновременно, самый сложный,
  через выявление внутренних закономерностей, построения модели,
  и выдвижения гипотез на основе этой модели,
  с последующей ее корректировкой на основе сопоставления прогноза с реальностью.
  Второй, много проще, через простейшее "осреднение" неточных предсказаний.
  Та самая "мудрость толпы", тоже известная со времен Аристотеля.
  
  Так вот, рассматривая реакцию нейросети как сумму реакций
  "виртуально-исторических подсетей" становится совершенно очевидно,
  что этап "инфляции" при обучении нейросетей
  это явно проявление "мудрости толпы", то бишь,
  банального "усреднения" запомненных примеров.
  И тут в явном виде проявляется и закон "больших чисел"
  и "гауссовское распределение" ошибок,
  и применимость "модели с шумом".
  И причина здесь, в первую очередь в том,
  что несмотря на достаточно сильную связь между последовательными
  "виртуальными подсетями" они все-таки достаточно "разношерстны"
  из-за случайной начальной инициализации,
  и как следствие достаточно значительных отличий
  между начальным и конечным состоянием этих "виртуальных подсетей".
  И это соответствует большей "внутренней размерностью",
  обнаруживаемой/замеренной на начальном этапе обучения.
  
  Соответственно, представляется разумным на этом этапе
  обеспечивать максимально возможную "разношерстность", "внутреннюю размерность"
  самых первых примеров обучения, или даже всей первой эпохи обучения.
  и это вполне соответствует "каноническим" рекомендациям из предыдущего фрагмента
  о целесообразности сильного уменьшения инициализационных значений параметров,
  чтобы не ограничивать их вариабельность при обучении
  за счет попадания в "зону насыщения" нелинейных элементов.
  
  Т.е. в начале обучения предпочтительнее максимально линейная модель,
  обеспечивающая более быстрое и, наверно, более "гармоничное"/"многстороннее"
  достижение некоторого максимально возможного уровня качества для этапа "инфляции".
  Тут наверно, даже важнее "гармоничность"/"разнообразие" в ущерб "скорости"
  - все равно этот этам обучения нейросети самый непродолжительный -
  а вот какой при этом закладывается потенциал для успешности этапа "компрессии",
  толком похоже никто не исследовал.
  Но есть такое народные "наблюдения": "горбатого могила исправит"
  или "рожденный ползать - летать не может",
  и, наверно, стоит к ним прислушаться и при обучении нейросетей.
  
  Так что, может быть,
  на этом этапе - начального обучения - вклад регуляризации и дропаута
  стоит даже существенно увеличить.
  Но это только "теорехтическое" предположение и, возможно, неверное,
  так как пока никаких экспериментальных/подтверждающих данных по этому вопросу,
  мне лично, пока не встречалось,
  Но это предположение основывается на том, как представляется работа
  механизмов регуляризации и дропаута в рамках концепции "ансамбля ансамлей".
  
  Проще всего описать эти представления по отношению к методам "дропаута".
  Исключение каких-то связей при обновлении весов по факту создает
  новую "ветку" дальнейшего развития "подсетей", явно повышая их "разнообразие",
  "разношерстность" и в итоге внутреннюю размерность нейросети.
  Соответственно, это больше приближает эти "подсети" к интерпретации "независимые",
  и, следовательно, больше соответствуя концепции "больших чисел",
  то бишь, какому-то стандартному вероятностному распределению.
  Вопрос: "какому именно" - "гауссовскому", "равномерному", "биномиальному" и т.п., -
  явно не по моим математическим способностям.
  Но, в любом случае, это должно/может способствовать большему внутреннему
  "разнообразию" "подсетей"/"ансамблей",
  которое, наверняка, как-то пригодится на этапе "компрессии",
  просто за счет большего количества "степеней свободы".
  Но опять же, это больше "теорехтическое" предположение.
  
  Для регуляризаций типа L1 или L2 представление немного посложнее.
  С одной стороны, их можно рассматривать и в русле "канонической трактовки",
  как смещение и параметров/весов в каком-то предположительно желаемом направлении,
  а с другой стороны, и как своеобразный способ "аугментации" данных,
  с целью их большего "разнообразия",
  а с третьей стороны, как достаточно "прямолинейную" попытку,
  добиться от нейросети "обобщающих свойств", на основе предположения о том,
  как это "обобщение" реализуется.
  И так как эти методы как-то практически работают,
  то любое из этих представлений имеет под собой основание.
  
  Но какое-то интуитивное чувство, что регуляризации типа L1 или L2
  на этапе "инфляции" следует применять значительно осторожнее, чем дропаут.
  Это скорее инструмент этапа "компрессии",
  когда требуется довести точность нейросети до уровня "две девятки",
  за счет внутреннего согласования "подсетей".
  "Но это не точно".
  
  Вообще-то, и время на сегодня кончается, и "кувшин моих мыслей показывает дно",
  так что запланированное рассмотрение этапа "компрессии" нейросети
  сегодня никак уже не получается.
  Да и следующий фрагмент учебника по глубокому обучению тоже стоило бы
  предварительно проработать, чтобы подойти к самой "мякотке"
  - регуляризации на этапе "компрессии" -
  собственно к тому, что больше всего интересует "адептов" машинного обучения.
  
  Так что на этом я и закончу эту часть описания концепции "ансамбля ансамблей"
  в приложении к механизмам работы "эффектов регуляризации".
  Продолжение следует.
  
  
  =========
  
  14.04.2024 10:42
  
  Таинства подбора гиперпараметров обучения нейросетей.
  В оглавление.
  
  Все теоретические знания, требуют проверки практикой,
  и то насколько "теория нейронауки" далека от практики,
  по-настоящему можно ощутить только при реальном обучении нейросети,
  когда нужно из каких-то соображений выбрать какое-то конкретное значение:
  
  "Нейросети и глубокое обучение, глава 3, ч.3:
  как выбрать гиперпараметры нейросети?"
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/460711/.
  22 июл 2019 в 07:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap3.html#why_does_regularization_help_reduce_overfitting
  
  //// Начало цитирования.
  
  До сих пор я не объяснял, как я выбираю значения гиперпараметров
  - скорость обучения ?, параметр регуляризации ?, и так далее.
  Я просто выдавал неплохо работающие значения.
  На практике же, когда вы используете нейросеть для атаки на проблему,
  может быть сложно найти хорошие гиперпараметры.
  Представьте, к примеру, что нам только что рассказали о задаче MNIST,
  и мы начали работать над ней, ничего не зная
  по поводу величин подходящих гиперпараметров.
  Допустим, что нам случайно повезло,
  и в первых экспериментах мы выбрали многие гиперпараметры так,
  как уже делали в этой главе:
  30 скрытых нейронов, размер мини-пакета 10, обучение за 30 эпох
  и использование перекрёстной энтропии.
  Однако мы выбрали скорость обучения ?=10,0,
  и параметр регуляризации ?=1000,0.
  И вот, что я увидел при таком прогоне:
  
  .......
  
  Наша классификация работает не лучше случайной выборки!
  Наша сеть работает как генератор случайного шума!
  
  <Ну, это легко поправить, - могли бы сказать вы,
  - просто уменьшите такие гиперпараметры,
  как скорость обучения и регуляризацию>.
  К сожалению, априори у вас нет информации по поводу того,
  что именно эти гиперпараметры вам нужно подстроить.
  Может быть, главная проблема в том,
  что наши 30 скрытых нейронов никогда не будут работать,
  вне зависимости от того, как выбираются остальные гиперпараметры?
  Может, нам надо не меньше 100 скрытых нейронов? Или 300?
  Или множество скрытых слоёв?
  Или другой подход к кодированию выхода?
  Может, наша сеть учится, но надо обучать её больше эпох?
  Может, размер мини-пакетов слишком мал?
  Может, у нас получилось бы лучше,
  вернись мы к квадратичной функции стоимости?
  Может, нам надо попробовать другой подход к инициализации весов?
  И так далее, и тому подобное.
  В пространстве гиперпараметров легко потеряться.
  И это может доставить реально много неудобств,
  если ваша сеть очень большая,
  или использует огромные объёмы обучающих данных,
  и вы можете обучать её часы, дни или недели,
  не получая результатов.
  В такой ситуации ваша уверенность начинает сдавать.
  Может, нейросети были неправильным подходом для решения вашей задачи?
  Может, вам уволиться и заняться пчеловодством?
  
  В данном разделе я объясню некоторые эвристические подходы,
  которые можно использовать для настройки гиперпараметров в нейросети.
  Цель - помочь вам выработать рабочий процесс,
  позволяющий вам достаточно хорошо настраивать гиперпараметры.
  Конечно, я не смогу покрыть всю тему оптимизации гиперпараметров.
  Это огромная область, и эта не та задача,
  которую можно решить полностью,
  или по правильным стратегиям решения которой имеется всеобщее согласие.
  Всегда есть возможность попробовать ещё какой-нибудь трюк,
  чтобы выжать дополнительные результаты из вашей нейросети.
  Но эвристика в данном разделе должна дать вам отправную точку.
  
  Общая стратегия
  
  При использовании нейросети для атаки новой проблемы,
  первая сложность - получить от сети нетривиальные результаты,
  то есть, превышающие случайную вероятность.
  Это может оказаться удивительно сложным делом,
  особенно когда вы сталкиваетесь с новым классом задач.
  Давайте посмотрим на некоторые стратегии,
  которые можно использовать при подобном затруднении.
  
  Допустим, к примеру, что вы впервые атакуете задачу MNIST.
  Вы начинаете с большим энтузиазмом,
  но полная неудача вашей первой сети вас немного обескураживает,
  как это описано в примере выше.
  Тогда нужно разобрать проблему по частям.
  Нужно избавиться от всех обучающих и подтверждающих изображений,
  кроме изображений нулей и единиц.
  Потом попытаться обучить сеть отличать 0 от 1.
  Эта задача не только по существу проще, чем различение всех десяти цифр,
  она также уменьшает количество обучающих данных на 80%,
  ускоряя обучение в 5 раз.
  Это позволяет гораздо быстрее проводить эксперименты,
  и даёт вам возможность быстрее понять, как создать хорошую сеть.
  
  Можно ещё сильнее ускорить эксперименты,
  низведя сеть до минимального размера,
  который с большой вероятностью сможет осмысленно обучаться.
  Если вы считаете, что сеть [784, 10] с большой вероятностью
  сможет классифицировать цифры MNIST лучше, чем случайная выборка,
  то начинайте эксперименты с неё.
  Это будет гораздо быстрее, чем обучать [784, 30, 10],
  а до неё уже можно дорасти потом.
  
  Ещё одно ускорение экспериментов можно получить,
  увеличив частоту отслеживания.
  В программе network2.py мы отслеживаем качество работы в конце каждой эпохи.
  Обрабатывая по 50 000 изображений за эпоху,
  нам приходится ждать довольно долго
  - примерно по 10 секунд на эпоху на моём ноутбуке при обучении сети [784, 30, 10]
  - перед тем, как получить обратную связь о качестве обучения сети.
  Конечно, десять секунд - это не так уж и долго,
  но если вы хотите попробовать несколько десятков разных гиперпараметров,
  это начинает раздражать,
  а если вы хотите попробовать сотни или тысячи вариантов,
  это уже просто опустошает.
  Обратную связь можно получать гораздо быстрее,
  отслеживая точность подтверждения чаще,
  например, каждые 1000 обучающих изображений.
  Кроме того, вместо использования полного набора
  из 10 000 подтверждающих изображений,
  мы можем получить оценку гораздо быстрее,
  используя всего 100 подтверждающих изображений.
  Главное, чтобы сеть увидела достаточно изображений,
  чтобы реально обучаться,
  и чтобы получить достаточно хорошую оценку эффективности.
  Конечно, наша network2.py пока не обеспечивает такого отслеживания.
  Но в качестве костылей для достижения такого эффекта
  в целях иллюстрации, мы обрежем наши обучающие данные
  до первых 1000 изображений MNIST.
  Попробуем посмотреть, что происходит
  (для простоты кода я не использовал идею того,
  чтобы оставить только изображения 0 и 1
  - это тоже можно реализовать, приложив чуть больше усилий).
  
  ........
  
  Всё ещё получаем чистый шум, но у нас есть большое преимущество:
   обратная связь обновляется за доли секунды, а не каждые десять секунд.
  Это значит, вы можете гораздо быстрее экспериментировать
  с выбором гиперпараметров,
  или даже проводить эксперименты со множеством разных гиперпараметров
  почти одновременно.
  
  В примере выше я оставил значение ? равным 1000,0, как и раньше.
  Но поскольку мы изменили количество обучающих примеров,
  нам надо поменять и ?, чтобы ослабление весов было тем же.
  Это значит, что мы меняем ? на 20,0.
  В таком случае получится следующее:
  
  ........
  
  Ага! У нас есть сигнал.
  Не особенно хороший, но есть.
  Это уже можно взять за отправную точку, и изменять гиперпараметры,
  чтобы попробовать получить дальнейшие улучшения.
  Допустим, мы решили, что нам надо поднять скорость обучения
  (как вы, наверно, поняли, решили мы неправильно,
  по причине, которую мы обсудим позднее,
  но давайте пока попробуем так сделать).
  Для проверки нашей догадки мы выкручиваем ? до 100,0:
  
  ........
  
  Всё плохо! Судя по всему, наша догадка была неверна,
  и проблема была не в слишком низком значении скорости обучения.
  Пытаемся подкрутить ? до небольшого значения 1,0:
  
  .......
  
  //// Интересно, что в этом примере результаты первой эпохи лучше чем последующих.
  //// Случайность, скорее всего, но может быть в этом что-то есть.
  //// Во всяком случае, используемая регуляризация на первом этапе
  //// явно не должна быть слишком сильной.
  
  Вот так лучше! И так мы можем продолжать и далее,
  подкручивая каждый гиперпараметр,
  и постепенно улучшая эффективность.
  Изучив ситуацию и найдя улучшенное значение для ?,
  мы переходим к поиску хорошего значения для ?.
  Затем проведём эксперимент с более сложной архитектурой,
  допустим, с сетью из 10 скрытых нейронов.
  Затем вновь подстроим параметры для ? и ?.
  Затем увеличим сеть до 20 скрытых нейронов.
  Ещё немного подстроим гиперпараметры.
  И так далее, оценивая на каждом шаге эффективность
  при помощи части наших подтверждающих данных,
  и используя эти оценки для подбора всё лучших гиперпараметров.
  В процессе улучшений на то, чтобы увидеть влияние подстройки гиперпараметров,
  уходит всё больше времени,
  поэтому мы можем постепенно уменьшать частоту отслеживания.
  
  В качестве общей стратегии такой подход выглядит многообещающе.
  Однако я хочу вернуться к тому первому шагу поиска гиперпараметров,
  позволяющих сети вообще хоть как-то обучиться.
  На самом деле, даже в приведённом примере
  ситуация получилась слишком оптимистичной.
  Работа с сетью, которая ничему не обучается,
  может оказаться чрезвычайно раздражающей.
  Можно по нескольку дней подстраивать гиперпараметры,
  и не получать осмысленных ответов.
  Поэтому я хотел бы ещё раз подчеркнуть,
  что на ранних стадиях нужно убедиться,
  что вы можете получать быструю обратную связь от экспериментов.
  Интуитивно может казаться,
  что упрощение проблемы и архитектуры вас лишь замедлит.
  На самом деле, это ускоряет процесс,
  поскольку вы сможете гораздо быстрее найти сеть с осмысленным сигналом.
  Получив такой сигнал, вы часто сможете получать быстрые улучшения
  при подстройке гиперпараметров.
  Как и во многих жизненных ситуациях, самым сложным бывает начать процесс.
  //// "Дорога в десять тысяч лье, начинается с первого шага".
  //// И этот шаг, желательно, чтобы был хоть в чем-то результативным.
  //// Иначе это может быть "топтанием на месте", а не "началом Пути".
  
  Ладно, это общая стратегия.
  Теперь давайте взглянем на конкретные рекомендации
  по назначению гиперпараметров.
  Сконцентрируюсь на скорости обучения ?, параметре регуляризации L2 ?,
  и размере мини-пакета.
  Однако многие замечания будут применимы и к другим гиперпараметрам,
  включая связанные с архитектурой сети,
  другими формами регуляризации,
  и некоторые гиперпараметры, с которыми мы познакомимся в книге далее,
  например, коэффициент импульса.
  
  Скорость обучения
  
  Допустим, мы запустили три сети MNIST с тремя разными скоростями обучения,
  ?=0,025, ?=0,25 и ?=2,5, соответственно.
  Остальные гиперпараметры мы оставим такими,
  какие они были в прошлых разделах - 30 эпох,
  размер мини-пакета 10, ?=5,0.
  Мы также вернёмся к использованию всех 50 000 обучающих изображений.
  Вот график, показывающий поведение стоимости обучения
  (создан программой multiple_eta.py):
  
  ......
  
  При ?=0,025 стоимость уменьшается плавно до последней эпохи.
  С ?=0,25 стоимость сначала уменьшается,
  однако после 20 эпох она насыщается,
  поэтому большая часть изменений оказываются малыми
  и, очевидно, случайными колебаниями.
  С ?=2,5 стоимость сильно колеблется прямо с самого начала.
  Чтобы понять причину этих колебаний,
  вспомним, что стохастический градиентный спуск
  должен постепенно спускать нас в долину функции стоимости:
  
  .......
  
  Данная картинка помогает интуитивно представить происходящее,
  но не является полным и всеобъемлющим объяснением.
  Если говорить точнее, но кратко,
  то градиентный спуск использует аппроксимацию первого порядка
  для функции стоимости,
  чтобы понять, как уменьшать стоимость.
  Для более крупных ? становятся более важными
  члены функции стоимости более высокого порядка,
  и они могут доминировать в поведении, ломая градиентный спуск.
  Это особенно вероятно при приближении к минимумам
  и локальным минимумам функции стоимости,
  поскольку рядом с такими точками градиент становится маленьким,
  из-за чего членам более высокого порядка становится легче доминировать.
  
  Однако, если ? будет слишком крупной, то шаги будут такими большими,
  что могут перепрыгнуть минимум, из-за чего алгоритм
  будет карабкаться вверх из долины.
  Вероятно, именно это и заставляет стоимость осциллировать при ?=2,5.
  Выбор ?=0,25 приводит к тому,
  что начальные шаги действительно ведут нас по направлению
  к минимуму функции стоимости,
  и только когда мы подбираемся к нему,
  мы начинаем испытывать трудности с перепрыгиванием.
  А когда мы выбираем ?=0,025,
  у нас таких трудностей в течение первых 30 эпох нет.
  Конечно, выбор такого малого значения ? создаёт другую трудность
  - а именно, замедляет стохастический градиентный спуск.
  Лучшим подходом было бы начать с ?=0,25, обучиться 20 эпох,
  а потом перейти к ?=0,025.
  Позднее мы обсудим такую переменную скорость обучения.
  А пока остановимся на вопросе поиска
  одного подходящего значения для скорости обучения ?.
  
  Имея это в виду, мы можем выбрать ? следующим образом.
  Сначала мы оцениваем пороговое значение ?,
  при котором стоимость обучающих данных сразу начинает уменьшаться,
  а не колеблется и не увеличивается.
  Эта оценка не обязательно должна быть точной.
  Оценить порядок можно, начав с ?=0,01.
  Если стоимость уменьшается в первые несколько эпох,
  то стоит последовательно пробовать ?=0,1, затем 1,0,
  и так далее, пока не найдётся значение,
  при котором стоимость колеблется или увеличивается в первые эпохи.
  И наоборот, если стоимость колеблется
  или увеличивается в первые эпохи при ?=0,01,
  тогда попробуйте ?=0,001, ?=0,0001,
  пока не найдёте значение,
  при котором стоимость уменьшается в первые несколько эпох.
  Эта процедура даст вам порядок порогового значения ?.
  По желанию, вы можете уточнять вашу оценку,
  выбрав наибольшее значение для ?,
  при котором стоимость уменьшается в первые эпохи,
  например, ?=0,5 или ?=0,2
  (сверхточность тут не нужна).
  Это даёт нам оценку порогового значения ?.
  
  Реальное значение ?, очевидно, не должно превышать выбранное пороговое.
  На самом деле, чтобы значение ? оставалось полезным в течение многих эпох,
  вам лучше использовать значение раза в два меньше порогового.
  Такой выбор обычно позволит вам обучаться множество эпох
  без сильного замедления обучения.
  
  В случае данных MNIST следование этой стратегии приведёт
  к оценке порогового порядка значения ? в 0,1.
  После некоторых уточнений мы получим значение ?=0,5.
  Следуя приведённому выше рецепту,
  нам следует использовать значение ?=0,25 для нашей скорости обучения.
  Но на самом деле я обнаружил, что значение ?=0,5 хорошо работало
  в течение 30 эпох,
  поэтому я не беспокоился по поводу его уменьшения.
  
  Всё это выглядит довольно прямолинейно.
  Однако использование стоимости обучения для выбора ?,
  кажется, противоречит тому, что я говорил ранее
  - что мы выбираем гиперпараметры,
  оценивая эффективность сети при помощи избранных подтверждающих данных.
  На самом деле мы будем использовать точность подтверждения,
  чтобы подобрать гиперпараметры регуляризации, размер мини-пакета
  и такие параметры сети, как количество слоёв и скрытых нейронов,
  и так далее.
  Почему мы делаем всё по-другому в случае скорости обучения?
  Честно говоря, этот выбор обусловлен
  моими личными эстетическими предпочтениями,
  и, вероятно, предвзят.
  Аргументация такова,
  что другие гиперпараметры должны улучшать конечную точность классификации
  на проверочном наборе,
  поэтому имеет смысл выбирать их на основе точности подтверждения.
  Однако скорость обучения
  лишь косвенно влияет
  на конечную точность классификации.
  //// А вот тут, у меня есть сомнения. Но пока без особых оснований.
  //// Но "узелок на память" стоит завязать.
  Её основная цель - контролировать размер шага градиентного спуска,
  и отслеживать стоимость обучения наилучшим образом
  для того, чтобы распознавать слишком большой размер шага.
  Но всё же это личное эстетическое предпочтение.
  На ранних стадиях обучения стоимость обучения обычно уменьшается,
  только если увеличивается точность подтверждения,
  поэтому на практике не должно иметь значения то,
  какой критерий использовать.
  
  Использование ранней остановки для определения количества эпох обучения
  
  Как мы уже упоминали в этой главе, ранняя остановка означает,
  что в конце каждой эпохи нам нужно подсчитать
  точность классификации на подтверждающих данных.
  Когда она перестаёт улучшаться, прекращаем работу.
  В итоге установка количества эпох становится простым делом.
  В частности, это означает, что нам не надо специально выяснять,
  как количество эпох зависит от других гиперпараметров.
  Это происходит автоматически.
  Более того, ранняя остановка также автоматически не даёт нам
  переобучиться.
  //// И опять "узелок на память".
  //// Тут надо хорошенько по-разбираться с "эффектом гроккинга".
  //// Не все тут так просто.
  Это, конечно, хорошо, хотя на ранних стадиях экспериментов
  может быть полезно отключить раннюю остановку,
  чтобы вы могли увидеть признаки переобучения
  и использовать их для подстройки подхода к регуляризации.
  
  Для реализации РО нам нужно более конкретно описать,
  что означает <остановка улучшения точности классификации>.
  Как мы видели, точность может очень сильно прыгать туда и сюда,
  даже когда общая тенденция улучшается.
  Если мы остановимся в первый раз, когда точность уменьшится,
  то мы почти наверняка не дойдём до возможных дальнейших улучшений.
  Подход лучше - прекратить обучение,
  если наилучшая точность классификации не улучшается достаточно долгое время.
  Допустим, к примеру, что мы занимаемся MNIST.
  Тогда мы можем решить прекратить процесс,
  если точность классификации не улучшалась за последние десять эпох.
  Это гарантирует, что мы не остановимся слишком рано,
  из-за неудачи при обучении,
  но и не будем ждать вечно каких-то улучшений,
  которые так и не произойдут.
  //// Нет, тут нужно какое-то другое обоснование,
  //// ведь можно продолжить обучение, что-то изменив,
  //// например, в той же регуляризации или функции стоимости/ошибки.
  
  Это правило <без улучшений за десять эпох>
  хорошо подходит для первичного исследования MNIST.
  Однако сети иногда могут выйти на плато
  близ определённой точности классификации,
  остаться там довольно долгое время,
  а потом снова начать улучшаться.
  //// Тот самый "эффект гроккинга".
  Если вам нужно достичь очень хорошей эффективности,
  то правило <без улучшений за десять эпох>
  может быть для этого слишком агрессивным.
  Поэтому я рекомендую использовать правило <без улучшений за десять эпох>
  для первичных экспериментов,
  и постепенно принимает более мягкие правила,
  когда вы начнёте лучше понимать поведение вашей сети:
  <без улучшений за двадцать эпох>, <без улучшений за пятьдесят эпох>,
  и так далее.
  Конечно, это даёт нам ещё один гиперпараметр для оптимизации!
  Но на практике этот гиперпараметр обычно легко настроить
  для получения хороших результатов.
  А для задач, отличных от MNIST,
  правило <без улучшений за десять эпох> может оказаться слишком агрессивным,
  или недостаточно агрессивным,
  в зависимости от частностей конкретной задачи.
  Однако немного поэкспериментировав,
  обычно довольно легко найти подходящую стратегию ранней остановки.
  
  Мы пока не использовали раннюю остановку в наших экспериментах с MNIST.
  Всё из-за того, что мы проводили много сравнений различных подходов к обучению.
  Для таких сравнений полезно использовать одинаковое количество эпох во всех случаях.
  Однако стоит изменить network2.py, введя в программу РО.
  
  Задачи
  
  Измените network2.py так, чтобы там появилась РО
  по правилу <без изменений за n эпох>, где n - настраиваемый параметр.
  
  Придумайте правило ранней остановки,
  отличное от <без изменений за n эпох>.
  В идеале, правило должно искать компромисс
  между получением точности с высоким подтверждением
  и достаточно небольшим временем обучения.
  Добавьте правило в network2.py,
  и запустите три эксперимента по сравнению точностей подтверждения
  и количества эпох обучения с правилом <без изменений за 10 эпох>.
  
  План изменения скорости обучения
  
  Пока мы держали скорость обучения ? постоянной.
  Однако часто бывает полезно изменять её.
  На ранних этапах процесса обучения
  веса с большой вероятностью будут назначены совершенно неправильно.
  Поэтому лучше будет использовать большую скорость обучения,
  которая заставит веса меняться побыстрее.
  Затем можно уменьшить скорость обучения,
  чтобы сделать более тонкую подстройку весов.
  
  Как нам наметить план изменения скорости обучения?
  Тут можно применять множество подходов.
  Один естественный вариант - использовать ту же базовую идею, что и в РО.
  Мы удерживаем скорость обучения постоянной,
  пока точность подтверждения не начнёт ухудшаться.
  Затем уменьшаем СО на некоторую величину,
  допустим, в два или в десять раз.
  Повторяем это много раз,
  до тех пор, пока СО не окажется в 1024 (или в 1000) раз меньше начальной.
  И заканчиваем обучение.
  
  План изменения скорости обучения может улучшить эффективность,
  а также открывает огромные возможности по выбору плана.
  И это может стать головной болью
  - можно целую вечность провести за оптимизацией плана.
  Для первых экспериментов я бы предложил использовать одно,
  постоянное значение СО.
  Это даст вам хорошее первое приближение.
  Позже, если вы захотите выжать из сети наилучшую эффективность,
  стоит поэкспериментировать с планом изменения скорости обучения
  так, как я это описал.
  В достаточно легко читаемой научной работе 2010 года
  http://arxiv.org/abs/1003.0358
  демонстрируются преимущества переменных скоростей обучения при атаке на MNIST.
  
  Упражнение
  
  Измените network2.py так,
  чтобы она реализовывала следующий план изменения скорости обучения:
  уполовинить СО каждый раз,
  когда точность подтверждения удовлетворяет правилу <без изменений за 10 эпох>,
  и прекратить обучение, когда скорость обучения упадёт до 1/128 от начальной.
  
  Параметр регуляризации ?
  
  Я рекомендую начинать вообще без регуляризации (?=0,0),
  //// А почему? Хотя у меня примерно схожие предположения/рекомендации,
  //// но совершенно по другим причинам.
  и определить значение ?, как указано выше.
  Используя выбранное значение ?,
  мы затем можем использовать подтверждающие данные
  для выбора хорошего значения ?.
  Начите с ?=1,0
  (хорошего аргумента в пользу именно такого выбора у меня нет),
  а потом увеличивайте или уменьшайте его в 10 раз,
  чтобы повышать эффективность в работе с подтверждающими данными.
  Найдя правильный порядок величины,
  можно подстраивать значение ? более точно.
  После этого нужно снова вернуться к оптимизации ?.
  
  Упражнение
  
  Возникает искушение использовать градиентный спуск,
  чтобы попытаться выучить хорошие значения для таких гиперпараметров,
  как ? и ?.
  Можете ли вы догадаться о препятствии,
  не дающем использовать градиентный спуск для определения ??
  Можете ли вы догадаться о препятствии,
  не дающем использовать градиентный спуск для определения ??
  //// Честно признаюсь, я не догадался.
  
  Как я выбрал гиперпараметры в начале книги
  
  Если вы используете рекомендации из этого раздела,
  вы увидите, что подобранные значения ? и ?
  не всегда точно соответствуют тем, что я использовал ранее.
  Просто у книги есть ограничения по тексту,
  из-за которых иногда было непрактично заниматься оптимизацией гиперпараметров.
  Вспомните обо всех сравнениях разных подходов к обучению,
  которыми мы занимались
  - сравнения квадратичной функции стоимости и перекрёстной энтропии,
  старых и новых методов инициализации весов,
  запуски с и без регуляризации, и так далее.
  Чтобы эти сравнения были осмысленными,
  я пытался не менять гиперпараметры между сравниваемыми подходами
  (или правильно их масштабировать).
  Конечно, нет причин для того, чтобы одни и те же гиперпараметры
  были оптимальными для всех разных подходов к обучению,
  поэтому используемые мною гиперпараметры были результатом компромисса.
  
  В качестве альтернативы я бы мог попытаться
  оптимизировать все гиперпараметры для каждого подхода к обучению по максимуму.
  Это был бы более хороший и честный подход,
  поскольку мы бы взяли всё самое лучшее от каждого подхода к обучению.
  Однако мы провели десятки сравнений,
  и на практике это было бы слишком затратно с вычислительной точки зрения.
  Поэтому я решил остановиться на компромиссе,
  использовать достаточно хорошие
  (но не обязательно оптимальные)
  варианты гиперпараметров.
  
  Размер мини-пакета
  
  Как нужно выбирать размер мини-пакета?
  Для ответа на этот вопрос, давайте сначала предположим,
  что мы занимаемся онлайн-обучением, то есть, используем мини-пакет размера 1.
  
  Очевидная проблема с онлайн-обучением состоит в том,
  что использование мини-пакетов, состоящих из единственного обучающего примера,
  приведёт к серьёзным ошибкам в оценке градиента.
  Но на самом деле эти ошибки не представят такой уж серьёзной проблемы.
  Причина в том, что отдельные оценки градиента не должны быть сверхточными.
  Нам лишь нужно получить достаточно точную оценку для того,
  чтобы наша функция стоимости снижалась.
  Это, как если бы вы пытались попасть на северный магнитный полюс,
  но у вас был бы ненадёжный компас,
  при каждом измерении ошибающийся на 10-20 градусов.
  Если вы будете достаточно часто сверяться с компасом,
  и в среднем он будет указывать верное направление,
  вы в итоге сможете добраться до северного магнитного полюса.
  
  Если учитывать этот аргумент,
  кажется, что нам стоит использовать онлайн-обучение.
  Но на самом деле ситуация оказывается несколько более сложной.
  В задаче к последней главе я указал,
  что для вычисления обновления градиента
  для всех примеров в мини-пакете одновременно
  можно использовать матричные техники, а не цикл.
  В зависимости от подробностей вашего железа
  и библиотеки для линейной алгебры
  может оказаться гораздо быстрее вычислять оценку для мини-пакета
  размером, допустим, 100,
  чем вычислять оценку градиента для мини-пакета в цикле
  для 100 обучающих примеров.
  Это может оказаться, допустим, всего в 50 раз медленнее, а не в 100.
  
  Сперва кажется, что это нам не сильно помогает.
  С размером мини-пакета в 100 правило обучения для весов выглядит, как:
  
  $ w \rightarrow w' = w-\eta \frac{1}{100} \sum_x \nabla C_x \tag{100} $
  
  где суммирование идёт по обучающим примерам в мини-пакете. Сравните с
  
  $ w \rightarrow w' = w-\eta \nabla C_x \tag{101} $
  
  для онлайн-обучения.
  
  Даже если на обновление мини-пакета уйдёт в 50 раз больше времени,
  всё равно онлайн-обучение кажется лучшим вариантом,
  поскольку обновляться мы будем гораздо чаще.
  Но допустим, однако, что в случае с мини-пакетом
  мы увеличили скорость обучения в 100 раз,
  тогда правило обновления превращается в:
  
  $ w \rightarrow w' = w-\eta \sum_x \nabla C_x \tag{102} $
  
  Это похоже на 100 отдельных ступеней онлайн-обучения со скоростью обучения ?.
  Однако на одну ступень онлайн-обучения уходит всего в 50 раз больше времени.
  Конечно, на самом деле это не ровно 100 ступеней онлайн-обучения,
  поскольку в мини-пакете все ?Cx оцениваются для одного и того же набора весов,
  в отличие от кумулятивного обучения, происходящего в онлайн-случае.
  И всё же кажется, что использование более крупных мини-пакетов ускорит процесс.
  //// И тут хотелось бы по-больше экспериментальных данных это во-первых.
  //// А во-вторых, я просто убежден, что обучение на последовательных
  //// этапах обучения "троганья с места", "инфляции", "компрессии",
  //// "стабилизации" и "стагнации" должны быть различным.
  //// Соответственно, и размер батча должен быть разным на разных этапах.
  //// Но это лучше рассмотреть отдельно.
  
  Учитывая все эти факторы, выбор лучшего размера мини-пакета - это компромисс.
  //// В технике "компромисс" часто следствие не найденного хорошего решения.
  Выберете слишком маленький,
  и не получите всё преимущество хороших матричных библиотек,
  оптимизированных для быстрого железа.
  Выберете слишком большой,
  и не будете обновлять веса достаточно часто.
  Вам необходимо выбрать компромиссное значение,
  максимизирующее скорость обучения.
  К счастью, выбор размера мини-пакета,
  при котором скорость максимизируется,
  относительно независима от других гиперпараметров
  (кроме общей архитектуры),
  поэтому, чтобы найти хороший размер мини-пакета,
  не обязательно их оптимизировать.
  Следовательно, достаточно будет использовать приемлемые
  (не обязательно оптимальные) значения у других гиперпараметров,
  а потом попробовать несколько разных размеров мини-пакетов,
  масштабируя ?, как указано выше.
  Постройте график зависимости точности подтверждения от времени
  (реального прошедшего времени, не эпох!),
  и выбирайте размер мини-пакета,
  дающий наиболее быстрое улучшение быстродействия.
  С выбранным размером мини-пакета можете перейти
  к оптимизации других гиперпараметров.
  
  Конечно, как вы уже, без сомнения, поняли,
  в нашей работе такой оптимизации я не проводил.
  В нашей реализации НС вообще не используется
  быстрый подход к обновлению мини-пакетов.
  Я просто использовал размер мини-пакета 10,
  не комментируя и не объясняя его, почти во всех примерах.
  А вообще мы могли бы ускорить обучение, уменьшив размер мини-пакета.
  Я этого не делал, в частности, потому,
  что мои предварительные эксперименты предполагали,
  что ускорение будет довольно скромным.
  Но в практических реализациях нам бы однозначно хотелось реализовать
  наиболее быстрый подход к обновлениям мини-пакетов,
  и попытаться оптимизировать их размер,
  чтобы максимизировать общую скорость.
  
  Автоматизированные техники
  
  Я описывал эти эвристические подходы, как нечто,
  что нужно подстраивать руками.
  Ручная оптимизация - хороший способ получить представление о работе НС.
  Однако, и, впрочем, неудивительно,
  огромная работа уже проделана над автоматизацией этого проекта.
  Распространённой техникой является поиск по решётке,
  систематически просеивающий решётку в пространстве гиперпараметров.
  Обзор достижений и ограничений этой техники
  (а также рекомендации по легко реализуемым альтернативам)
  можно найти в работе 2012 года.
  http://dl.acm.org/citation.cfm?id=2188395
  Было предложено множество сложных техник.
  Не буду делать обзор их всех,
  но хочу отметить многообещающую работу 2012 года,
  http://papers.nips.cc/paper/4522-practical-bayesian-optimization-of-machine-learning-algorithms.pdf
  использовавшую байесовскую оптимизацию гиперпараметров.
  Код из работы открыт всем,
  и с определённым успехом использовался и другими исследователями.
  //// Термин "определённый успех" рождает "определенный оптимизм"
  //// и, одновременно, "определенный скепсис".
  
  Суммируем
  
  Пользуясь практическими правилами, которые я описал,
  вы не получите от своей НС совершенно наилучшие результаты из всех возможных.
  Но они, вероятно, обеспечат вам хорошую отправную точку
  и фундамент для дальнейших улучшений.
  В частности, я в основном описывал гиперпараметры независимо.
  На практике между ними существует связь.
  Вы можете экспериментировать с ?,
  решить, что нашли правильное значение,
  потом начать оптимизировать ?,
  и обнаружить, что это нарушает вашу оптимизацию ?.
  На практике полезно двигаться в разные стороны,
  постепенно приближаясь к хорошим значениям.
  //// Этакий "гипер-мета-градиентный спуск".
  Превыше прочего учтите, что описанные мною эвристические подходы
  - это простые практические правила,
  но не нечто, вырезанное в камне.
  Вам нужно искать признаки того, что что-то не работает,
  и иметь желание экспериментировать.
  В частности, тщательно отслеживать поведение вашей нейросети,
  особенно точность подтверждения.
  
  Сложность выбора гиперпараметров усугубляется тем,
  что практические знания по их выбору
  размазаны по множеству исследовательских работ и программ,
  а часто находятся только в головах отдельных практиков.
  Существует огромное множество работ с описаниями того,
  как следует поступать
  (часто противоречащие друг другу).
  Однако существует несколько особенно полезных работ,
  синтезирующих и выделяющих крупную часть этих знаний.
  В работе Йошуа Бенджио от 2012 года
  http://arxiv.org/abs/1206.5533
  даются практические рекомендации по использованию обратного распространения
  и градиентного спуска для обучения НС,
  включая и глубокие НС.
  Множество деталей Бенджио описывает гораздо подробнее. Чем я,
  включая систематический поиск гиперпараметров.
  Ещё одна хорошая работа - работа 1998 года Йанна Лекуна и др.
  http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
  Обе работы появляются в чрезвычайно полезной книге 2012 года,
  где собрано множество трюков, часто используемых в НС:
  "Нейросети: хитрости ремесла".
  http://www.springer.com/computer/theoretical+computer+science/book/978-3-642-35288-1
  Книжка дорогая, но многие её статьи были выложены в интернет их авторами,
  и их можно найти в поисковиках.
  
  Из этих статей, и, особенно из собственных экспериментов,
  становится ясно одно:
  задачу оптимизации гиперпараметров нельзя назвать полностью решённой.
  Всегда существует ещё один трюк,
  который можно попробовать для улучшения эффективности.
  У писателей есть поговорка,
  что книгу нельзя закончить, а можно только бросить.
  То же верно и для оптимизации НС:
  пространство гиперпараметров настолько огромно,
  что оптимизацию нельзя закончить, а можно лишь прекратить,
  оставив НС потомкам.
  Так что вашей целью будет разработка рабочего процесса,
  позволяющего вам быстро провести неплохую оптимизацию,
  и при этом оставляющего вам возможность по необходимости
  попробовать более детальные варианты оптимизации.
  
  Трудности с подбором гиперпараметров заставляют некоторых людей жаловаться,
  что НС требуют слишком много усилий по сравнению с другими техниками МО.
  Я слышал много вариантов жалоб типа:
  <Да, хорошо настроенная НС может выдать наилучшую эффективность при решении задачи.
  Но, с другой стороны, я могу попробовать случайный лес
  [или SVM, или любую другую вашу любимую технологию],
  и она просто работает.
  У меня нет времени разбираться с тем, какая НС мне подойдёт>.
  Конечно, с практической точки зрения хорошо иметь под ругой
  лёгкие в применении техники.
  Это особенно хорошо, когда вы только начинаете работать с задачей,
  и ещё непонятно, может ли вообще МО помочь её решить.
  С другой стороны, если вам важно достичь оптимальных результатов,
  вам может понадобиться испытать несколько подходов,
  требующих более специальных знаний.
  Было бы здорово, если бы МО всегда было лёгким делом,
  но не существует причин, по которым оно априори должно быть тривиальным.
  //// Кроме, пожалуй, одной - хорошей, согласующейся с практикой, теорией.
  //// А если вместо "теории" набор "полуэвристических/полушаманских" практик,
  //// то да, ориентиров в блужданиях по многомерному пространству гиперпараметров,
  //// действительно, совсем не много.
  
  Другие техники
  
  Каждая из техник, проработанных в этой главе, ценна сама по себе,
  но это не единственная причина, по которой я их описал.
  Более важно ознакомиться с некоторыми из проблем,
  которые могут встретиться в области НС,
  и со стилем анализа, который может помочь их преодолеть.
  В каком-то смысле, мы учимся тому, как размышлять о НС.
  В оставшейся части главы я кратко опишу набор других техник.
  Их описания будут не такими глубокими, как у предыдущих,
  но должны передать некие ощущения, касающиеся разнообразия техник,
  встречающихся в области НС.
  
  Вариации стохастического градиентного спуска
  
  Стохастический градиентный спуск через обратное распространение
  хорошо послужил нам во время атаки на задачу классификации рукописных цифр из MNIST.
  Однако к оптимизации функции стоимости есть множество других подходов,
  и иногда они показывают эффективность,
  превосходящую таковую у стохастического градиентного спуска с мини-пакетами.
  В данной секции я кратко опишу два таких подхода,
  гессиан и импульс.
  
  Гессиан
  
  Для начала давайте отложим в сторону НС.
  Вместо этого просто рассмотрим абстрактную проблему
  минимизации функции стоимости C от многих переменных, w=w1,w2,...,
  то есть, C=C(w).
  По теореме Тейлора функцию стоимости в точке w можно аппроксимировать:
  
  $ C(w+\Delta w) = C(w) + \sum_j \frac{\partial C}{\partial w_j} \Delta w_j \nonumber \\ + \frac{1}{2} \sum_{jk} \Delta w_j \frac{\partial^2 C}{\partial w_j \partial w_k} \Delta w_k + \ldots \tag{103} $
  
  Мы можем переписать это компактнее, как
  
  $ C(w+\Delta w) = C(w) + \nabla C \cdot \Delta w + \frac{1}{2} \Delta w^T H \Delta w + \ldots \tag{104} $
  
  где ?C - обычный вектор градиента,
  а H - матрица, известная, как матрица Гессе,
  на месте jk в которой находится ?2C/?wj?wk. //// Используются вторые производные.
  Допустим, мы аппроксимируем C,
  отказавшись от членов высшего порядка,
  скрывающихся за многоточием в формуле:
  
  $ C(w+\Delta w) \approx C(w) + \nabla C \cdot \Delta w + \frac{1}{2} \Delta w^T H \Delta w \tag{105} $
  
  Используя алгебру, можно показать,
  что выражение с правой стороны можно минимизировать, выбрав:
  
  $ \Delta w = -H^{-1} \nabla C \tag{106} $
  
  Строго говоря, для того, чтобы это был именно минимум, а не просто экстремум,
  нужно предположить, что матрица Гессе определеннее положительна.
  Интуитивно это значит, что функция С похожа на долину,
  а не на гору или седловину.
  
  Если (105) будет хорошим приближением к функции стоимости,
  стоит ожидать, что переход от точки w к точке w+?w=w?H?1?C
  должен значительно уменьшить функцию стоимости.
  Это предлагает возможный алгоритм минимизации стоимости:
  
  Выбрать начальную точку w.
  
  Обновить w до новой точки, w?=w?H?1?C, где гессиан H и ?C вычисляются в w.
  
  Обновить w' до новой точки, w??=w??H??1??C, где гессиан H и ?C вычисляются в w'.
  
  ......
  
  
  На практике, (105) является лишь приближением, и лучше брать шаги поменьше.
  Мы сделаем это, постоянно обновляя w на величину ?w=??H?1?C,
  где ? - это скорость обучения.
  
  Такой подход к минимизации функции стоимости известен, как оптимизация Гессе.
  Существуют теоретические и эмпирические результаты,
  показывающие, что методы Гессе сходятся к минимуму за меньшее количество шагов,
  чем стандартный градиентный спуск.
  В частности, посредством включения информации об изменениях второго порядка
  в функции стоимости,
  в подходе Гессе возможно избежать многих патологий,
  встречающихся в градиентном спуске.
  Более того, существуют версии алгоритма обратного распространения,
  которые можно использовать для вычисления гессиана.
  
  Если оптимизация Гессе такая классная,
  что же мы не используем её в наших НС?
  К сожалению, хотя у неё много желанных свойств,
  есть и одно очень нежелательное:
  её очень сложно применять на практике.
  Часть проблемы - огромный размер матрицы Гессе.
  Допустим, у нас есть НС с 10**7 весов и смещений.
  Тогда в соответствующей матрице Гессе будет 10**7 * 10**7 = 10**14 элементов.
  Слишком много!
  В итоге вычислять H?1?C на практике получается очень сложно.
  Но это не значит, что о ней бесполезно знать.
  Множество вариантов градиентного спуска вдохновлено оптимизацией Гессе,
  они просто избегают проблемы чрезмерно больших матриц.
  Давайте взглянем на одну такую технику,
  градиентный спуск на основе импульса.
  
  Градиентный спуск на основе импульса
  
  Интуитивно, преимущество оптимизации Гессе состоит в том,
  что она включает не только информацию о градиенте,
  но и информацию о его изменении.
  Градиентный спуск на основе импульса основан на схожей интуиции,
  однако избегает крупных матриц из вторых производных.
  Чтобы понять технику импульса,
  вспомним нашу первую картинку градиентного спуска,
  в которой мы рассматривали шар, скатывающийся в долину.
  Тогда мы увидели, что градиентный спуск, вопреки своему имени,
  лишь немного напоминает шар, падающий на дно.
  Техника импульса изменяет градиентный спуск в двух местах,
  что делает его более похожим на физическую картину.
  Во-первых, она вводит понятие <скорости> для параметров,
  которые мы пытаемся оптимизировать.
  Градиент пытается изменить скорость,
  а не <местоположение> напрямую,
  похоже на то, как физические силы меняют скорость,
  и лишь косвенно влияют на местоположение.
  Во-вторых, метод импульса представляет нечто вроде члена для трения,
  который постепенно уменьшает скорость.
  
  Давайте дадим более математически точное определение.
  Введём переменные скорости v=v1,v2,...,
  по одной на каждую соответствующую переменную wj
  (в нейросети эти переменные, естественно, включают все веса и смещения).
  Затем мы меняем правило обновления градиентного спуска ww? = w???C на
  
  $ v \rightarrow v' = \mu v - \eta \nabla C \tag{107} $
  
  $ w \rightarrow w' = w+v' \tag{108} $
  
  В уравнениях ? - это гиперпараметр, управляющий количеством торможения,
  или трения системы.
  Чтобы понять смысл уравнений, сначала полезно рассмотреть случай,
  в котором ?=1, то есть, когда трение отсутствует.
  В таком случае изучение уравнений показывает,
  что теперь <сила> ?C меняет скорость v,
  а скорость управляет скоростью изменения w.
  Интуитивно, скорость можно набрать,
  постоянно добавляя к ней члены градиента.
  Это значит, что если градиент движется примерно в одном направлении
  в течение нескольких этапов обучения,
  мы можем набрать достаточно большую скорость движения в этом направлении.
  Представьте, к примеру, что происходит при движении вниз по склону:
  
  .....
  
  С каждым шагом вниз по склону скорость увеличивается,
  и мы движемся всё быстрее и быстрее ко дну долины.
  Это позволяет технике скорости работать гораздо быстрее,
  чем стандартному градиентному спуску.
  Конечно, проблема в том, что, достигнув дна долины, мы его проскочим.
  Или, если градиент будет меняться слишком быстро,
  могло бы оказаться, что мы движемся в обратном направлении.
  В этом и смысл введения гиперпараметра ? в (107).
  Ранее я сказал, что ? управляет количеством трения в системе;
  точнее, количество трения нужно представлять себе в виде 1-?.
  Когда ?=1, как мы увидели, трения нет,
  и скорость полностью определяется градиентом ?C.
  И наоборот, когда ?=0, трения очень много, скорость не набирается,
  и уравнения (107) и (108) сводятся к обычным уравнениям градиентного спуска,
  ww? = w???C.
  На практике, использование значения ? в промежутке между 0 и 1
  может дать нам преимущество возможности набора скорости
  без опасности проскочить минимум.
  Такое значение для ? мы можем выбрать при помощи
  отложенных подтверждающих данных примерно так же,
  как выбирали значения для ? и ?.
  
  Пока я избегал присваивания имени гиперпараметру ?.
  Дело в том, что стандартное имя для ? было выбрано плохо:
  он называется коэффициентом импульса.
  Это может сбить вас с толку,
  поскольку ? совсем не похож не понятие импульса из физики.
  Он куда сильнее связан с трением.
  Однако термин <коэффициент импульса> широко используется,
  поэтому мы тоже продолжим его использовать.
  
  Приятная особенность техники импульса заключается в том,
  что для изменения реализации градиентного спуска
  с целью включить в неё эту технику не требуется почти ничего делать.
  Мы всё ещё можем использовать обратное распространение для подсчёта градиентов,
  как и ранее, и использовать такие идеи,
  как проверка стохастически выбранных мини-пакетов.
  В этом случае мы можем получить некоторые преимущества оптимизации Гессе,
  используя информацию об изменении градиента.
  Однако всё это происходит без недостатков,
  и лишь с небольшими изменениями кода.
  На практике техника импульса широко используется
  и часто помогает ускорять обучение.
  
  Упражнения
  
  Что пойдёт не так, если мы будем использовать ?>1 в технике импульса?
  Что пойдёт не так, если мы будем использовать ?<0 в технике импульса?
  
  Задача
  
  Добавьте стохастический градиентный спуск на основе импульса в network2.py.
  
  Другие подходы к минимизации функции стоимости
  
  Было разработано и множество других подходов к минимизации функции стоимости,
  и по поводу наилучшего подхода согласия не достигнуто.
  Углубляясь в тему нейросетей, полезно покопаться и в других технологиях,
  понять, как они работают, какие у них сильные и слабые стороны,
  и как применять их на практике.
  В упомянутой мною ранее работе вводятся и сравниваются несколько таких техник,
  включая спаренный градиентный спуск и метод BFGS
  (а также изучите близко связанный с ним метод BFGS с ограничением памяти,
  или L-BFGS).
  Ещё одна технология, недавно показавшая многообещающие результаты,
  это ускоренный градиент Нестерова, улучшающая технику импульса.
  Однако для многих задач хорошо работает простой градиентный спуск,
  особенно при использовании импульса,
  поэтому мы будем придерживаться стохастического градиентного спуска до конца книги.
  
  Другие модели искусственного нейрона
  
  Пока что мы создавали наши НС с использованием сигмоидных нейронов.
  В принципе, НС, построенная на сигмоидных нейронах,
  может вычислить любую функцию.
  Но на практике сети, построенные на других моделях нейронов,
  иногда опережают сигмоидные.
  В зависимости от применения, сети, основанные на таких альтернативных моделях,
  могут быстрее обучаться, лучше обобщать на проверочные данные,
  или делать и то, и другое.
  Давайте я упомяну парочку альтернативных моделей нейронов,
  чтобы дать вам представление о некоторых широко применяемых вариантах.
  
  Возможно, простейшей вариацией будет танг-нейрон,
  заменяющий сигмоидную функцию гиперболическим тангенсом.
  Выход танг-нейрона со входом x, вектором весов w и смещением b задаётся, как
  
  $ \tanh(w \cdot x+b) \tag{109} $
  
  где tanh, естественно, гиперболический тангенс.
  Оказывается, что он очень близко связан с сигмоидным нейроном.
  Чтобы это увидеть, вспомним, что tanh определяется, как
  
  $ \tanh(z) \equiv \frac{e^z-e^{-z}}{e^z+e^{-z}} \tag{110} $
  
  Применив немного алгебры, легко видеть, что
  
  $ \sigma(z) = \frac{1+\tanh(z/2)}{2} \tag{111} $
  
  то есть, tanh - это просто масштабирование сигмоиды.
  Графически также можно видеть, что у функции tanh та же форма, что и у сигмоиды:
  
  ......
  
  
  Одно различие между танг-нейронами и сигмоидными нейронами состоит в том,
  что выход первых простирается от -1 до 1, а не от 0 до 1.
  Это значит, что при создании сети на основе танг-нейронов
  вам может понадобиться нормализовать ваши выходы
  (и, в зависимости от деталей применения, возможно, и входы)
  немного не так, как в сигмоидных сетях.
  
  Как и сигмоидные, танг-нейроны, в принципе, могут подсчитать любую функцию
  (хотя с этим и существуют некоторые подвохи),
  размечая входы от -1 до 1.
  Более того, идеи обратного распространения
  и стохастического градиентного спуска точно так же легко применять
  к танг-нейронам, как и к сигмоидным.
  
  Упражнение
  
  Докажите уравнение (111).
  
  Нейрон какого типа стоит использовать в сетях, танг или сигмоидный?
  Ответ, мягко говоря, неочевиден!
  Однако существуют теоретические аргументы
  и некоторые эмпирические свидетельства того,
  что танг-нейроны иногда работают лучше.
  Давайте кратенько пройдёмся по одному из теоретически аргументов
  в пользу танг-нейронов.
  Допустим, мы используем сигмоидные нейроны,
  и все активации в сети будут положительными.
  Рассмотрим веса wl+1jk, входящие для нейрона ?j в слое ?l+1.
  Правила обратного распространения (BP4) говорят нам,
  что связанный с этим градиент будет равен alk?l+1j.
  Поскольку активации положительны,
  знак этого градиента будет таким же, как у ?l+1j.
  Это означает, что если ?l+1j положительна,
  тогда все веса wl+1jk будут уменьшаться во время градиентного спуска,
  а если ?l+1j отрицательна, тогда все веса wl+1jk будут увеличиваться
  во время градиентного спуска.
  Иначе говоря, все веса, связанные с одним и тем же нейроном,
  будут либо увеличиваться, либо уменьшаться совместно.
  А это проблема, поскольку, возможно,
  потребуется увеличивать некоторые веса, уменьшая другие.
  Но это может произойти, только если у некоторых входных активаций
  будут разные знаки.
  Что говорит о необходимости замены сигмоиды другой функцией активации,
  например, гиперболическим тангенсом,
  позволяющей активациям быть как положительными, так и отрицательными.
  И действительно, поскольку tanh симметричен относительно нуля,
  tanh(?z) = ?tanh(z),
  можно ожидать, что, грубо говоря, активации в скрытых слоях
  будут поровну распределены между положительными и отрицательными.
  Это поможет гарантировать отсутствие систематического смещения
  в обновлениях весов в ту или иную сторону.
  
  Насколько серьёзно стоит рассматривать этот аргумент?
  Ведь он эвристический, не даёт строгого доказательства того,
  что танг-нейроны превосходят сигмоидные.
  Возможно, у сигмоидных нейронов есть некие свойства,
  компенсирующие эту проблему?
  И действительно, во многих случаях функция tanh показала
  от минимальных до никаких преимуществ по сравнению с сигмоидой.
  К сожалению, у нас не существует простых и быстро реализуемых способов
  проверить, нейрон какого типа будет обучаться быстрее
  или покажет себя эффективнее в обобщении для какого-то конкретного случая.
  
  Другой вариант сигмоидного нейрона - выпрямленный линейный нейрон,
  или выпрямленная линейная единица [rectified linear unit, ReLU].
  Выход ReLU со входом x, вектором весов w и смещением b задаётся так:
  
  $ \max(0, w \cdot x+b) \tag{112} $
  
  Графически выпрямляющая функция max(0,z) выглядит так:
  
  .....
  
  Такие нейроны, очевидно, сильно отличаются и от сигмоидных, и от танг-нейронов.
  Однако они похожи в том, что тоже могут быть использованы
  для вычисления любой функции, и их можно обучать,
  используя обратное распространение и стохастический градиентный спуск.
  
  Когда нужно использовать ReLU вместо сигмоидных или танг-нейронов?
  В последних работах по распознаванию изображений (1, 2, 3, 4)
  были обнаружены серьёзные преимущества использования ReLU почти по всей сети.
  Однако, как и с танг-нейронами,
  у нас пока нет по-настоящему глубокого понимания того,
  когда именно ReLU будут предпочтительнее,
  и почему.
  //// Очень важно об этом не забвать.
  Чтобы получить некое представление о некоторых проблемах,
  вспомните, что сигмоидные нейроны прекращают обучаться при насыщении,
  то есть, когда выход близок к 0 или 1.
  Как мы уже много раз видели в этой главе,
  проблема состоит в том, что члены ?' уменьшают градиент,
  что замедляет обучение.
  Танг-нейроны страдают от похожих трудностей при насыщении.
  При этом увеличение взвешенного входа на ReLU
  никогда не заставит его насытиться,
  поэтому соответственного замедления обучения не произойдёт.
  С другой стороны, когда взвешенный ввод на ReLU будет отрицательным,
  градиент исчезает,
  и нейрон вообще перестаёт обучаться.
  Это лишь пара из множества проблем,
  делающих нетривиальной задачу понимания того,
  когда и как ReLU ведут себя лучше сигмоидных или танг-нейронов.
  
  Я нарисовал картину неопределённости,
  подчёркивая, что у нас пока нет твёрдой теории выбора функций активации.
  И действительно, эта проблема ещё сложнее, чем я описал,
  поскольку возможных функций активации существует бесконечно много.
  Какая из них даст нам наиболее быстро обучающуюся сеть?
  Какая даст наибольшую точность в тестах?
  Я удивлён, насколько мало было по-настоящему глубоких
  и систематических исследований этих вопросов.
  В идеале у нас должна быть теория,
  подробно говорящая нам о том, как выбирать
  (и, возможно, на лету менять)
  //// "О, тепленькая пошла". Вот только пока не слышно о таких решениях.
  наши функции активации.
  С другой стороны, нас не должно останавливать
  отсутствие полноценной теории!
  У нас уже есть мощные инструменты,
  и с их помощью мы можем достичь значительного прогресса.
  //// "Нам нельзя ждать милостей от природы после того, что мы с ней сделали".
  До конца книги я буду использовать сигмоидные нейроны в качестве основных,
  поскольку они хорошо работают и дают конкретные иллюстрации ключевых идей,
  относящихся к НС.
  Но учитывайте, что те же самые идеи можно применять и к другим нейронам,
  и в этих вариантах есть свои преимущества.
  
  Истории из мира нейросетей
  
  Вопрос:
  какой подход вы применяете при использовании и исследовании техник МО,
  которые поддерживаются практически исключительно эмпирическими наблюдениями,
  а не математикой?
  В какой ситуации вы сталкивались с отказом таких техник?
  
  Ответ:
  вам нужно понять, что наши теоретические инструменты весьма слабы.
  Иногда у нас появляется хорошая математическая интуиция
  по поводу того, почему определённая техника должна сработать.
  Иногда интуиция изменяет нам.
  В итоге вопросы превращаются в следующие:
  насколько хорошо мой метод сработает на этой конкретной задаче,
  и насколько велик набор задач, на котором он хорошо работает?
  
  - Вопросы и ответы с исследователем нейросетей Яном Лекуном
  
  Однажды на конференции по основам квантовой механики,
  я заметил то, что мне показалось забавной речевой привычкой:
  по окончанию доклада вопросы аудитории часто начинались с фразы:
  <Мне очень импонирует ваша точка зрения, но...>.
  Квантовые основы - не совсем моя обычная область,
  и я обратил внимание на такой стиль задавания вопросов потому,
  что на других научных конференциях я практически не встречался с тем,
  чтобы спрашивающий выказывал симпатию к точке зрения докладчика.
  В то время я решил, что преобладание таких вопросов говорило о том,
  что прогресса в квантовых основах было достигнуто довольно мало,
  и люди просто только начинали набирать обороты.
  Позднее я понял, что эта оценка была слишком жёсткой.
  Докладчики боролись с одними из самых сложных проблем,
  с которыми только сталкивались человеческие умы.
  Естественно, что прогресс шёл медленно!
  Однако всё равно существовала ценность в том,
  чтобы услышать новости о мышлении людей, касающемся этой области,
  даже если у них не было практически ничего нового.
  
  В данной книге вы могли заметить <нервный тик>,
  сходный с фразой <мне весьма импонирует>.
  Чтобы объяснить, что мы имеем,
  я часто прибегал к словам вроде <эвристически> или <грубо говоря>,
  за которыми следовало объяснение того или иного явления.
  Эти истории правдоподобны,
  но эмпирические свидетельства часто были весьма поверхностны.
  Если вы изучите исследовательскую литературу,
  то увидите, что истории подобного толка появляются
  во многих исследовательских работах, посвящённых нейросетям,
  часто в компании малого количества поддерживающих их свидетельств.
  Как нам относиться к таким историям?
  
  Во многих областях науки
  - особенно там, где рассматриваются простые явления -
  можно найти очень строгие и надёжные свидетельства весьма общим гипотезам.
  Но в НС есть огромное количество параметров и гиперпараметров,
  и существуют чрезвычайно сложные взаимоотношения между ними.
  В таких невероятно сложных системах неимоверно сложно делать
  надёжные общие заявления.
  Понимание НС во всех их полноте, как квантовые основы,
  испытывает пределы человеческого разума.
  Часто нам приходится обходиться свидетельствами в пользу или против
  нескольких определённых частных случаев общего заявления.
  В итоге эти заявления иногда требуется менять или отказываться от них,
  поскольку появляются новые свидетельства.
  
  Один из подходов к этой ситуации - считать,
  что любая эвристическая история про НС подразумевает некий вызов.
  К примеру, рассмотрим процитированное мною объяснение того,
  почему работает исключение (dropout) из работы 2012 года:
  <Эта техника уменьшает сложную совместную адаптацию нейронов,
  поскольку нейрон не может полагаться на присутствие определённых соседей.
  В итоге ему приходиться обучаться более надёжным признакам,
  которые могут быть полезными в совместной работе
  со многими различными случайными подмножествами нейронов>.
  Богатое и провокационное заявление,
  на базе которого можно построить целую исследовательскую программу,
  в которой нужно будет выяснять,
  в чём оно правдиво, где ошибается, а что требует уточнений и изменений.
  И сейчас действительно существует целая индустрия исследователей,
  изучающих исключение (и множество его вариантов),
  пытающихся понять, как оно работает, и какие ограничения имеет.
  Так и со многими другими эвристическими подходами,
  которые мы обсуждали.
  Каждый из них - не только потенциальное объяснение,
  но и вызов к исследованию и более детальному пониманию.
  
  Конечно, ни у одного человека не хватит времени исследовать
  все эти эвристические объяснения достаточно глубоко.
  У всего сообщества исследователей НС уйдут десятилетия на то,
  чтобы разработать реально мощную теорию обучения НС,
  основанную на доказательствах.
  Значит ли это, что стоит отвергать эвристические объяснения,
  как нестрогие и не имеющие достаточно доказательств?
  Нет!
  Нам нужна такая эвристика, которая будет вдохновлять наше мышление.
  Это похоже на эпоху великих географических открытий:
  ранние исследователи часто действовали (и совершали открытия)
  на основе верований, ошибавшихся серьёзнейшим образом.
  Позднее мы исправляли эти заблуждения, пополняя свои географические знания.
  Когда вы плохо что-то понимаете
  - как понимали исследователи географию, и как сегодня мы понимаем НС -
  важнее смело изучать неизвестное,
  чем быть скрупулёзно правым на каждом шагу ваших рассуждений.
  Поэтому вы должны рассматривать эти истории как полезную инструкцию
  к тому, как размышлять о НС,
  поддерживая здоровую осведомлённость об их ограничениях,
  и тщательно отслеживая надёжность свидетельств в каждом случае.
  Иначе говоря, хорошие истории нужны нам для мотивации и вдохновения,
  а скрупулёзные тщательные расследования
  - для того, чтобы открывать реальные факты.
  
  ........
  
  //// Из комментариев.
  
  evorios
  23 июл 2019 в 00:50
  
  Нужна обученная нейросеть,
  которая сможет подбирать гиперпараметры
  для 100 самых популярных моделей нейросетей.
  На вход можно оставить только субъективную оценку наблюдателя
  о промежуточных результатах поиска (помимо параметров обучаемой сети).
  Вот тогда заживём! =)
  
  ........
  
  //// Конец цитирования.
  
  На мой взгляд это был один из самых полезных разделов в части понимания того,
  "насколько все запущено" в области машинного обучения нейросетей,
  и насколько жизненно необходимы исследовательские работы,
  и практические, и теоретические, для лучшего понимания что же происходит
  с нейросетями в процессе обучения.
  
  К сожалению, если судить по тенденциям в области ML & DS,
  пожелания автора о крайней необходимости такой работы, похоже,
  остались без особого внимания.
  Сейчас даже рекомендации, что нужно самостоятельно подбирать эти гиперпараметры,
  чтобы в первую очередь лучше понимать особенности разрабатываемой модели,
  выглядят как "ветхозаветные" и крайне "немодные".
  Сейчас подбор гиперпараметров рекомендуется делать автоматически,
  используя самые разные стратегии и алгоритмы оптимизации,
  через соответствующие фреймворки, например, такой:
  
  "Это мы юзаем: библиотека Optuna в Python для оптимизации гиперпараметров".
  Автор: badcasedaily1 (artem)
  https://habr.com/ru/companies/otus/articles/801463/.
  27 мар 2024 в 20:45
  
  "Оптимизация гиперпараметров за 5 секунд?".
  Автор: The-Founder-1
  https://habr.com/ru/articles/807605/.
  14 апр 2024 в 16:15
  
  \\\ Традиционный подход к оптимизации гиперпараметров включает в себя
  \\\ grid search и random search,
  \\\ иногда они могут быть неэффективными и времязатратными,
  \\\ особенно когда пространство гиперпараметров велико.
  
  .....
  
  \\\ Математика предоставляет нам один механизм предугадывания.
  \\\ Если есть данные уже после перебора парочки комбинаций
  \\\ - они могут дать информацию о том,
  \\\ куда лучше двигаться в последующем переборе,
  \\\ какую часть сетки выбрать и получить оптимальные наборы гиперпараметров быстрее.
  \\\ Вот тут то и нам поможет байесовский способ оптимизации.
  
  \\\ Достаточно предрассчитывать степень неопределенности
  \\\ и предполагаемой структуры зависимости
  \\\ между гиперпараметрами и "целевой" функцией,
  \\\ чтобы приблизиться к нужным значениям.
  
  ......
  
  \\\ Для начала строится априорная вероятностная модель,
  \\\ где описывается первоначальное представление
  \\\ о связи между гиперпараметрами и целевой функцией.
  \\\ Чем больше данных об оценках целевой функции мы получаем,
  \\\ тем лучше наше знание о пространстве гиперпараметров
  \\\ и его зависимости от целевой функции.
  
  \\\ Грубо говоря, байесовский метод оптимизации
  \\\ - модернизированный рандомный поиск.
  
  .....
  
  \\\ Optuna решает проблему оптимизации гиперпараметров,
  \\\ предоставляя легковесный фреймворк
  \\\ для автоматизации поиска оптимальных гиперпараметров.
  \\\ Она использует алгоритмы, такие как TPE, CMA-ES,
  \\\ и даже поддерживает пользовательские алгоритмы.
  
  Очевидно, что эпоха нейросетей подбирающих параметры обучения
  для других нейросетей уже явно "не за горами".
  И вопрос даже не в том, насколько это улучшит качество машинного обучения
  - что-то и где-то явно улучшится и точно упростится.
  А в том, приблизит ли такое "нейросетевое благолепие в квадрате"
  к самому интересному во всей этой теме,
  пониманию того, как обучается и как работает нейросеть на самом деле.
  
  //// Хотя вопрос разработки нейросети, точнее нейросетевого агента,
  //// решающего задачу исследования результатов обучения нейросети,
  //// и на основе этого выстраивающий новую улучшенную тактику/стратегию
  //// обучения изучаемой нейросети, а в перспективе и изменения ее структуры,
  //// меня весьма заинтересовал.
  //// Очень достойная задача для темы "обучения с подкреплением",
  //// это не в "арканоида играть" - тут "думать надо".
  
  
  =========
  
  20.04.2024 19:52
  
  Магия аппроксимации любой функции нейросетью.
  В оглавление.
  
  Считается общеизвестным и строго математически доказанным фактом,
  что нейросеть, даже с одним скрытым слоем, способна аппроксимировать
  любую мыслимую функцию.
  Спорить с математикой просто так "в лоб", безусловно, занятие безнадежное,
  но есть у этой "аксиомы нейронауки" некие, обычно умолчиваемые, "мелкие детали",
  на которые имеет смысл обратить более пристальное внимание.
  Вот с таким прицелом стоит рассмотреть следующею главу прорабатываемого "талмуда":
  
  "Нейросети и глубокое обучение, глава 4:
  визуальное доказательство того, что нейросети способны вычислить любую функцию".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/461659/.
  29 июл 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap4.html
  
  //// Начало цитирования.
  
  ......
  
  Один из наиболее потрясающих фактов, связанных с нейросетями,
  заключается в том, что они могут вычислить вообще любую функцию.
  То есть, допустим, некто даёт вам какую-то сложную и извилистую функцию f(x):
  
  ......
  
  И вне зависимости от этой функции гарантированно существует такая нейросеть,
  что для любого входа x значение f(x)
  (или некая близкая к нему аппроксимация)
  будет являться выходом этой сети, то есть:
  
  ......
  
  Это работает, даже если это функция многих переменных f=f(x1,:,xm),
  и со многими значениями.
  К примеру, вот сеть, вычисляющая функцию с m=3 входами и n=2 выходами:
  
  ......
  
  Этот результат говорит о том, что у нейросетей
  есть определённая универсальность.
  Неважно, какую функцию мы хотим вычислить,
  мы знаем, что существует нейросеть, способная сделать это.
  
  Более того, теорема универсальности выполняется,
  даже если мы ограничим сети единственным слоем
  между входящими и выходящими нейронами
  - т.н. одним скрытым слоем.
  Так что даже сети с очень простой архитектурой
  могут быть чрезвычайно мощными.
  
  Теорема универсальности хорошо знакома людям, использующим нейросети.
  Но хотя это так, понимание этого факта не так широко распространено.
  А большинство объяснений этого слишком технически сложные.
  К примеру, одна из первых работ, доказывающих этот результат,
  http://www.dartmouth.edu/~gvc/Cybenko_MCSS.pdf
  использовала теорему Хана - Банаха,
  теорему представлений Риса и немного анализа Фурье.
  Если вы математик, вам несложно разобраться в этих доказательствах,
  но большинству людей это не так-то просто.
  А жаль, поскольку базовые причины универсальности просты и прекрасны.
  
  В данной главе я даю простое и по большей части визуальное объяснение
  теоремы универсальности.
  Мы шаг за шагом пройдём по лежащим в её основе идеям.
  Вы поймёте, почему нейросети действительно могут вычислить любую функцию.
  Вы поймёте некоторые ограничения этого результата.
  //// А вот это, пожалуй, самое важное.
  //// "Дьявол кроется в деталях". Например, "проклятье переобучения".
  И поймёте, как результат связан с глубокими НС.
  
  Чтобы следить за материалом этой главы,
  не обязательно читать предыдущие.
  Он структурирован в виде самостоятельного эссе.
  Если у вас есть самое базовое представление о НС,
  вы должны суметь понять объяснения.
  Но я буду иногда давать ссылки на предыдущие материалы,
  чтобы помочь заполнить пробелы в знаниях.
  
  Теоремы универсальности часто встречаются в информатике,
  так, что иногда мы даже забываем, насколько они потрясающие.
  Но стоит напоминать себе:
  возможность вычислить любую произвольную функцию поистине удивительна.
  //// "Теоретическая" возможность не равна "практической".
  Практически любой процесс, который вы можете себе представить,
  можно свести к вычислению функции.
  Рассмотрим задачу поиска названия музыкальной композиции
  на основе краткого отрывка.
  Это можно считать вычислением функции.
  Или рассмотрим задачу перевода китайского текста на английский.
  И это можно считать вычислением функции
  (на самом деле, многих функций, поскольку существует
  множество приемлемых вариантов переводов одного текста).
  Или рассмотрим задачу генерации описания сюжета фильма
  и качества актёрской игры на основе файла mp4.
  Это тоже можно рассматривать, как вычисление некоей функции
  (здесь тоже верна ремарка, сделанная по поводу вариантов перевода текста).
  Универсальность означает,
  что в принципе,
  НС могут выполнять все эти задачи, и множество других.
  
  Конечно, только из того, что мы знаем, что существуют НС,
  способные, допустим, переводить с китайского на английский,
  не следует, что у нас есть хорошие техники для создания
  или даже распознавания такой сети.
  Это ограничение также применимо к традиционным теоремам универсальности
  для таких моделей, как Булевы схемы.
  Но, как мы уже видели в этой книге,
  у НС есть мощные алгоритмы для выучивания функций.
  Комбинация алгоритмов обучения и универсальности
  - смесь привлекательная.
  //// Точнее "завлекательная", пока не столкнешься с необходимостью
  //// обеспечить точность "шесть девяток".
  Пока что в книге мы концентрировались на обучающих алгоритмах.
  В данной главе мы сконцентрируемся на универсальности
  и на том, что она означает.
  
  Два подвоха
  
  До того, как объяснить, почему теорема универсальности верна,
  я хочу упомянуть два подвоха,
  содержащихся в неформальном заявлении
  <нейросеть может вычислить любую функцию>.
  
  Во-первых, это не значит,
  что сеть можно использовать для точного подсчёта любой функции.
  Мы лишь можем получить настолько хорошее приближение,
  насколько нам нужно.
  //// В реальности ПОКА все достигнутые "приближения" ограничиваются,
  //// максимум, "тремя девятками". А чаще всего вообще "одной девяткой",
  //// а "вторая девятка" требует колоссальных усилий и десятков неудачных попыток.
  Увеличивая количество скрытых нейронов, мы улучшаем аппроксимацию.
  К примеру, ранее я иллюстрировал сеть, вычисляющую некую функцию f(x)
  с использованием трёх скрытых нейронов.
  Для большинства функций при помощи трёх нейронов
  можно будет получить только низкокачественное приближение.
  Увеличив количество скрытых нейронов (допустим, до пяти),
  мы обычно можем получить улучшенное приближение:
  
  .......
  
  И ещё улучшить ситуацию, увеличивая количество скрытых нейронов и далее.
  
  Чтобы уточнить это утверждение, допустим, нам дали функцию f(x),
  которую мы хотим вычислить с некоей нужной точностью ?>0.
  Есть гарантия, что при использовании достаточного количества скрытых нейронов,
  мы всегда сможем найти НС, выход которой g(x)
  удовлетворяет уравнению |g(x)?f(x)|  Иначе говоря, аппроксимация будет достигнута с нужной точностью
  для любого возможного входного значения.
  //// Проблема в том, что нейросети используют в подавляющем большинстве случаев,
  //// когда "требуемая функция" НЕИЗВЕСТНА, а есть только некоторые ее реализации,
  //// в виде КОНЕЧНОГО набора примеров,
  //// причем без гарантии того, что в этих примерах все "чисто",
  //// т.е. тет некоторого "шума" или случайных "выбросов" или "артефактов".
  
  Второй подвох состоит в том, что функции,
  которые можно аппроксимировать описанным способом,
  принадлежат к непрерывному классу.
  Если функция прерывается,
  то есть, делает внезапные резкие скачки,
  то в общем случае её будет невозможно аппроксимировать при помощи НС.
  //// И это не совсем так. И даже совсем не так.
  //// Как раз разрывность нейросеть может обеспечить,
  //// но вот получить требуемую разрывность методом обратного распространения ошибки
  //// через градиентный спуск, не важно, стандартный, или усложненный,
  //// задачка весьма нетривиальная.
  И это неудивительно, поскольку наши НС вычисляют
  непрерывные функции от входных данных.
  Однако, даже если функция, которую нам очень нужно вычислить, разрывная,
  часто оказывается достаточно непрерывной аппроксимации.
  Если это так, то мы можем использовать НС.
  На практике это ограничение обычно не является важным.
  //// А вот это не факт, так как истинное представление искомой функции
  //// нам неизвестно, и когда поведение обученной нейросети отличается
  //// от наших ожиданий понять причины этого очень трудно, если вообще возможно.
  //// И тогда начинаются "старые песни о главном", то бишь, о "переобучении".
  
  В итоге, более точным утверждением теоремы универсальности будет то,
  что НС с одним скрытым слоем можно использовать
  для аппроксимации любой непрерывной функции с любой желаемой точностью.
  В данной главе мы докажем чуть менее строгую версию этой теоремы,
  используя два скрытых слоя вместо одного.
  В задачах я кратко опишу как это объяснение можно,
  с небольшими изменениями,
  адаптировать к доказательству, использующему только один скрытый слой.
  //// А какая практическая надобность есть в сетях с одним скрытым слоем?
  
  Универсальность с одним входным и одним выходным значением
  
  Чтобы понять, почему теорема универсальности истинна,
  начнём с понимания того, как создать НС,
  аппроксимирующую функцию только с одним входным и одним выходным значением:
  
  ......
  
  Оказывается, что это - суть задачи универсальности.
  Как только мы поймём этот особый случай,
  будет довольно легко расширить его на функции
  со многими входными и выходными значениями.
  
  Чтобы создать понимание того,
  как сконструировать сеть для подсчёта f, начнём с сети,
  содержащей единственный скрытый слой с двумя скрытыми нейронами,
  и с выходным слоем, содержащим один выходной нейрон:
  
  .......
  
  Чтобы представить, как работают компоненты сети,
  сконцентрируемся на верхнем скрытом нейроне.
  На диаграмме в оригинале статьи можно интерактивно менять вес мышью,
  кликнув на , и сразу же увидеть,
  как меняется функция, вычисляемая верхним скрытым нейроном:
  
  .......
  
  Как мы узнали ранее в книге, скрытый нейрон подсчитывает ?(wx+b),
  где ?(z) ? 1/(1+e?z) - сигмоида.
  Пока что мы довольно часто использовали эту алгебраическую форму.
  Однако для доказательства универсальности будет лучше,
  если мы полностью проигнорируем эту алгебру,
  и вместо этого будем манипулировать и наблюдать за формой на графике.
  Это не только поможет лучше почувствовать, что происходит,
  но и даст нам доказательство универсальности,
  применимое к другим функциям активации, кроме сигмоиды.
  
  Строго говоря, избранный мною визуальный подход
  традиционно не считается доказательством.
  Но я считаю, что визуальный подход даёт больше понимания
  истинности итогового результата, чем традиционное доказательство.
  А, конечно, подобное понимание и есть реальная цель доказательства.
  В предлагаемом мною доказательстве изредка будут попадаться пробелы;
  я буду давать разумное, но не всегда строгое визуальное доказательство.
  Если это беспокоит вас, то считайте своей задачей заполнить эти пробелы.
  Однако не теряйте из виду главной цели:
  понять, почему теорема универсальности верна.
  
  Чтобы начать с этим доказательством,
  кликните в оригинальной диаграмме на смещение b и проведите мышью вправо,
  чтобы увеличить его.
  Вы увидите, что с увеличением смещения график двигается влево,
  но не меняет форму.
  
  Затем протяните его влево, чтобы уменьшить смещение.
  Вы увидите, что график двигается вправо, не меняя форму.
  
  Уменьшите вес до 2-3.
  Вы увидите, что с уменьшением веса кривая распрямляется.
  Чтобы кривая не убегала с графика, возможно, придётся подправить смещение.
  
  Наконец, увеличьте вес до значений более 100.
  Кривая будет становиться всё круче, и в итоге приблизится к ступеньке.
  Попробуйте подрегулировать смещение так,
  чтобы её угол находился в районе точки x=0,3.
  На видео ниже показано, что должно получиться:
  
  ......
  
  Мы можем очень сильно упростить наш анализ,
  увеличив вес так, чтобы выход реально был хорошей аппроксимацией
  ступенчатой функции.
  Ниже я построил выход верхнего скрытого нейрона для веса w=999.
  Это статичное изображение:
  
  ......
  
  Со ступенчатыми функциями работать немного проще, чем с типичными сигмоидами.
  Причина в том, что в выходном слое складываются вклады от всех скрытых нейронов.
  Сумму кучки ступенчатых функций анализировать легко,
  а вот рассуждать о том, что происходит при сложении кучи кривых в виде сигмоиды
  - сложнее.
  //// Но именно это нужно понять, чтобы основные идеи этой главы
  //// можно было приложить к пониманию рельных машинного обучения нейросетей.
  //// К сожалению, это важное замечание автора теряется в общем объеме материала,
  //// и дальше, особенно в выводах автор к нему не возвращается.
  Поэтому будет гораздо проще предположить,
  что наши скрытые нейроны выдаёт ступенчатые функции.
  Точнее, мы делаем это, фиксируя вес w на некоем очень большом значении,
  а потом назначая положение ступеньки через смещение.
  Конечно, работа с выходом, как со ступенчатой функцией
  - это приближение, но очень хорошее,
  и пока что мы будем относиться к функции,
  как к истинно ступенчатой.
  Позднее я вернусь к обсуждению влияния отклонений от этого приближения.
  //// Это весьма интересный момент доказательства "всемогущества".
  //// С одной стороны, он опирается на свойство нелинейности функции активации,
  //// что, вроде как, соответствует практике конструирования нейросетей.
  //// А с другой, НЕ соответствует практике обучения нейросетей,
  //// особенно с применением так рекламируемых "техник регуляризации",
  //// которые как раз такой способ использования "нелинейности" функций активаций
  //// принудительно существенно ограничивают.
  //// Это первое, но не последнее замечание, по некоей "нереальности"
  //// данного подхода к интерпретации "всемогущества" нейросетей.
  //// Точнее, некоторого несоответствия описываемого подхода
  //// к реальным процессам, происходящим при обучении нейросетей
  //// "аппроксимации любой мыслимой функции".
  
  На каком значении x находится ступенька?
  Иначе говоря, как положение ступеньки зависит от веса и смещения?
  
  Для ответа на вопрос попытайтесь изменить вес и смещение
  в интерактивной диаграмме.
  Можете ли вы понять, как положение ступеньки зависит от w и b?
  Попрактиковавшись немного, вы сможете убедить себя,
  что её положение пропорционально b и обратно пропорционально w.
  
  На самом деле, ступенька находится на отметке s=-b/w,
  как будет видно, если подстроить вес и смещение к следующим значениям:
  
  .......
  
  Наши жизни сильно упростятся, если мы будем описывать скрытые нейроны
  единственным параметром, s,
  то есть, положением ступеньки, s=-b/w.
  На следующей интерактивной диаграмме можно менять уже просто s:
  
  .......
  
  Как отмечено выше, мы специально назначили весу w на входе
  очень большое значение
  - достаточно большое, чтобы ступенчатая функция стала хорошим приближением.
  И мы легко можем превратить таким образом параметризованный нейрон
  обратно к обычной форме,
  выбрав смещение b=-ws.
  
  Пока что мы концентрировались на выходе только верхнего скрытого нейрона.
  Давайте посмотрим на поведение всей сети.
  Предположим, что скрытые нейроны вычисляют ступенчатые функции,
  заданные параметрами ступенек s1 (верхний нейрон) и s2 (нижний нейрон).
  Их соответствующими выходными весами будут w1 и w2.
  Вот наша сеть:
  
  .......
  
  Справа строится график взвешенного выхода w1a1 + w2a2 скрытого слоя.
  Здесь a1 и a2 - выходы верхнего и нижнего скрытых нейронов, соответственно.
  Они обозначаются через ,
  поскольку их часто называют активациями нейронов.
  
  Кстати, отметим, что выход всей сети равен \sigma(w1a1 + w2a2 + b),
  где b - смещение выходного нейрона.
  Это, очевидно, не то же самое, что взвешенный выход скрытого слоя,
  график которого мы строим.
  Но пока мы сконцентрируемся на взвешенном выходе скрытого слоя,
  и только позднее подумаем, как он связан с выходом всей сети.
  
  Попробуйте на интерактивной диаграмме в оригинале статьи
  увеличивать и уменьшать ступеньку s1 верхнего скрытого нейрона.
  Посмотрите, как это меняет взвешенный выход скрытого слоя.
  Особенно полезно понять, что происходит, когда s1 превышает s2.
  Вы увидите, что график в этих случаях меняет форму,
  поскольку мы переходим от ситуации,
  в которой верхний скрытый нейрон активируется первым,
  к ситуации, в которой нижний скрытый нейрон активируется первым.
  
  Сходным образом попробуйте манипулировать ступенькой s2
  у нижнего скрытого нейрона,
  и посмотрите, как это меняет общий выход скрытых нейронов.
  
  Попробуйте уменьшать и увеличивать выходные веса.
  Заметьте, как это масштабирует вклад от соответствующих скрытых нейронов.
  Что будет, если один из весов сравняется с 0?
  
  Наконец, попробуйте выставить w1 в 0,8, а w2 в -0,8.
  Получится функция <выступа>, с началом в точке s1, концом в точке s2,
  и высотой 0,8.
  К примеру, взвешенный выход может выглядеть так:
  
  ......
  
  Конечно, выступ можно масштабировать до любой высоты.
  Давайте использовать один параметр, h, обозначающий высоту.
  Также для упрощения я избавлюсь от обозначений и .
  
  .......
  
  Попробуйте увеличивать и уменьшать значение h,
  чтобы посмотреть, как меняется высота выступа.
  Попробуйте сделать h отрицательным.
  Попробуйте менять точки ступенек, чтобы понаблюдать,
  как это меняет форму выступа.
  
  Вы увидите, что мы используем наши нейроны не просто, как графические примитивы,
  но и как более привычные программистам единицы
  - нечто вроде инструкции if-then-else в программировании:
  
  if вход >= начало ступеньки:
   добавить 1 к взвешенному выходу
  else:
   добавить 0 к взвешенному выходу
  
  По большей части я буду придерживаться графических обозначений.
  Однако иногда вам будет полезно переключаться на представление if-then-else
  и размышлять о происходящем в этих терминах.
  
  Мы можем использовать наш трюк с появлением выступа,
  склеив две части скрытых нейронов вместе в одной сети:
  
  .......
  
  Здесь я опустил веса, просто записав значения h для каждой пары скрытых нейронов.
  Попробуйте поиграть с обоими значениями h, и понаблюдать,
  как это меняет график.
  Подвигайте выступы, меняя точки ступенек.
  
  В более общем случае эту идею можно использовать
  для получения любого желаемого количества пиков любой высоты.
  В частности, мы можем разделить интервал [0,1]
  на большое количество (N) подынтервалов,
  и использовать N пар скрытых нейронов для получения пиков любой нужной высоты.
  Посмотрим, как это работает для N=5.
  Это уже довольно много нейронов, поэтому я немного ужму представления.
  Извините за сложную диаграмму
  - я бы мог спрятать сложность за дополнительными абстракциями,
  но мне кажется, что стоит немного помучаться со сложностью,
  чтобы лучше почувствовать то, как работают нейросети.
  //// К сожалению, эта иллюстрация может служить для объяснения того,
  //// КАК МОГУТ работать нейросети для обеспечения "всемогущества".
  //// Но далеко не факт, что они самом деле в основном ТАК работают
  //// для аппроксимации НЕмонотонных функций, а, может даже и линейных функций.
  //// Ниже постараюсь это проиллюстрировать,
  //// а в данном месте хочу обратить на такую особенность реализации
  //// в таком подходе - это необходимость целенаправленной и согласованной
  //// подгонки параметров СВЯЗАННОЙ ПАРЫ нейронов,
  //// в то время как при обучении "методом обратного распространения ошибки"
  //// настройка параметров нейронов выполняется НЕЗАВИСИМО.
  //// Это второй и, на мой взгляд, самый важный аргумент в "несоответствии"
  //// указанного подхода в объяснении того,
  //// как реально осуществляется нейросетью аппроксимация произвольной функции.
  //// Т.е. нейросеть действительно МОЖЕТ так работать,
  //// но вот обучить ее параметры для такого режима работы
  //// "обратным распространением ошибки" в общем случае совершенно нереально.
  
  .......
  
  Вы видите, что у нас есть пять пар скрытых нейронов.
  Точки ступенек соответствующих пар располагаются
  на значениях 0,1/5, затем 1/5,2/5, и так далее, вплоть до 4/5,5/5.
  Эти значения фиксированы - мы получаем пять выступов равной ширины на графике.
  
  У каждой пары нейронов есть связанное с нею значение h.
  Помните, что у выходных связей нейронов есть веса h и -h.
  В оригинале статьи на диаграмме можно кликнуть на значения h
  и подвигать их влево-вправо.
  С изменением высоты меняется и график.
  Изменяя выходные веса, мы конструируем итоговую функцию!
  
  На диаграмме можно ещё кликнуть по графику,
  и потаскать высоту ступеньки вверх или вниз.
  При изменении её высоты вы видите,
  как изменяется высота соответствующего h.
  Соответствующим образом меняются выходные веса +h и -h.
  Иначе говоря, мы напрямую манипулируем функцией,
  график которой показан справа,
  и видим эти изменения в значениях h слева.
  Можно ещё зажать клавишу мыши на одном из выступов,
  а потом провести мышью влево или вправо,
  и выступы будут подстраиваться под текущую высоту.
  
  Настало время справиться с задачей.
  
  Вспомним функцию, которую я нарисовал в самом начале главы:
  
  ........
  
  Тогда я не упоминал об этом, но на самом деле она выглядит так:
  
  $ f(x) = 0.2+0.4 x^2+0.3x \sin(15 x) + 0.05 \cos(50 x) \tag{113} $
  
  ......
  
  Она строится для значений x от 0 до 1,
  а значения по оси y варьируются от 0 до 1.
  
  Очевидно, что эта функция нетривиальная.
  И вы должны придумать, как подсчитать её с использованием нейросетей.
  
  В наших нейросетях выше мы анализировали
  взвешенную комбинацию ?jwjaj выхода скрытых нейронов.
  Мы знаем, как получить значительный контроль над этой величиной.
  Но, как я отметил ранее, эта величина не равна выходу сети.
  Выход сети - это ?(?jwjaj + b), где b - смещение выходного нейрона.
  Можем ли мы получить контроль непосредственно над выходом сети?
  
  Решение - разработать такую нейросеть,
  у которой взвешенный выход скрытого слоя задаётся уравнением ??1?f(x),
  где ??1 - обратная функция ?.
  То есть, мы хотим, чтобы взвешенный выход скрытого слоя был таким:
  
  .......
  
  Если это получится, тогда выход всей сети будет хорошей аппроксимацией f(x)
  (смещение выходного нейрона я установил в 0).
  
  Тогда ваша задача - разработать НС, аппроксимирующую целевую функцию,
  показанную выше.
  Чтобы лучше понять происходящее, рекомендую вам решить эту задачу дважды.
  В первый раз в оригинале статьи кликните на график,
  и напрямую подстройте высоты разных выступов.
  Вам довольно легко будет получить хорошее приближение к целевой функции.
  Степень приближения оценивается средним отклонением,
   разницей между целевой функцией и той функцией, которую подсчитывает сеть.
  Ваша задача - привести среднее отклонение к минимальному значению.
  Задача считается выполненной, когда среднее отклонение не превышает 0,40.
  
  .......
  
  Достигнув успеха, нажмите кнопку Reset,
  которая случайным образом поменяет выступы.
  Второй раз не трогайте график, а изменяйте величины h с левой стороны диаграммы,
  пытаясь привести среднее отклонение к величине 0,40 или менее.
  
  И вот, вы нашли все элементы, необходимые для того,
  чтобы сеть приблизительно вычисляла функцию f(x)!
  Аппроксимация получилась грубой,
  но мы легко можем улучшить результат,
  просто увеличив количество пар скрытых нейронов,
  что увеличит количество выступов.
  
  В частности, легко превратить все найденные данные обратно
  в стандартный вид с параметризацией, используемый для НС.
  Позвольте быстро напомнить, как это работает.
  
  У первого слоя все веса имеют большое постоянное значение, к примеру, w=1000.
  
  Смещения скрытых нейронов вычисляются через b=-ws.
  Так что, к примеру, для второго скрытого нейрона s=0,2
  превращается в b=-1000*0,2=-200.
  
  Последний слой весов определяется значениями h.
  Так что, к примеру, значение, выбранное вами для первого h, h= -0,2,
  означает, что выходные веса двух верхних скрытых нейронов
  равны -0,2 и 0,2 соответственно. И так далее, для всего слоя выходных весов.
  
  Наконец, смещение выходного нейрона равно 0.
  
  И это всё: у нас получилось полное описание НС,
  неплохо вычисляющей изначальную целевую функцию.
  И мы понимаем, как улучшить качество аппроксимации,
  улучшая количество скрытых нейронов.
  
  Кроме того, в нашей оригинальной целевой функции
  f(x)=0,2+0,4x2+0,3sin(15x)+0,05cos(50x) нет ничего особенного.
  Подобную процедуру можно было бы использовать
  для любой непрерывной функции на отрезках от [0,1] до [0,1].
  По сути, мы используем нашу однослойную НС
  для построения справочной таблицы по функции.
  И мы можем взять эту идею за основу,
  чтобы получить обобщённое доказательство универсальности.
  
  Функция от многих параметров
  
  Расширим наши результаты на случай множества входящих переменных.
  Звучит сложно, но все нужные нам идеи можно понять
  уже для случая всего с двумя входящими переменными.
  Поэтому рассмотрим случай с двумя входящими переменными.
  
  Начнём с рассмотрения того, что будет, когда у нейрона есть два входа:
  
  ........
  
  У нас есть входы x и y, с соответствующими весами w1 и w2 и смещением b нейрона.
  Установим вес w2 в 0 и поиграемся с первым, w1, и смещением b,
  чтобы посмотреть, как они влияют на выход нейрона:
  
  .......
  
  Как видим, при w2=0 вход y не влияет на выход нейрона.
  Всё происходит так, будто x - единственный вход.
  
  Учитывая это, что, как вы думаете, произойдёт,
  когда мы увеличим вес w1 до w1=100, а w2 оставим 0?
  Если это сразу вам непонятно,
  подумайте немного над этим вопросом.
  Потом посмотрите следующее видео, где показано, что произойдёт:
  
  ......
  
  Как и ранее, с увеличением входного веса выход приближается к форме ступеньки.
  Разница в том, что наша ступенчатая функция теперь расположена
  в трёх измерениях.
  Как и раньше, мы можем передвигать местоположение ступеньки, изменяя смещение.
  Угол будет находиться в точке sx=-b/w1.
  
  Давайте переделаем диаграмму, чтобы параметром было местоположение ступеньки:
  
  ......
  
  Мы предполагаем, что входящий вес у x имеет большое значение
  - я использовал w1=1000 - и вес w2=0.
  Число на нейроне - это положение ступеньки,
  а x над ним напоминает, что мы передвигаем ступеньку по оси x.
  Естественно, вполне возможно получить ступенчатую функцию по оси y,
  сделав входящий вес для y большим (допустим, w2=1000),
  и вес для x равным 0, w1=0:
  
  .......
  
  Число на нейроне, опять-таки, обозначает положение ступеньки,
  а y над ним напоминает, что мы передвигаем ступеньку по оси y.
  Я бы мог напрямую обозначить веса для x и y,
  но не стал, поскольку это замусорило бы диаграмму.
  Но учтите, что маркер y говорит о том, что вес для y большой, а для x равен 0.
  
  Мы можем использовать только что сконструированные нами ступенчатые функции
  для вычисления функции трёхмерного выступа.
  Для этого мы возьмём два нейрона,
  каждый из которых будет вычислять ступенчатую функцию по оси x.
  Затем мы скомбинируем эти ступенчатые функции с весами h и -h,
  где h - желаемая высота выступа.
  Всё это видно на следующей диаграмме:
  
  .......
  
  Попробуйте поменять величину h.
  Посмотрите, как она связана с весами сети.
  И как она меняет высоту функции выступа справа.
  
  Также попытайтесь изменить точку ступеньки,
  величина которой установлена в 0,30 в верхнем скрытом нейроне.
  Посмотрите, как она меняет форму выступа.
  Что будет, если перенести её за точку 0,70, связанную с нижним скрытым нейроном?
  
  Мы узнали, как построить функцию выступа по оси x.
  Естественно, мы легко можем сделать функцию выступа и по оси y,
  используя две ступенчатые функции по оси y.
   Вспомним, что мы можем сделать это, сделав большие веса на входе y,
  и установив вес 0 на входе x.
  И вот, что получится:
  
  ......
  
  Выглядит почти идентично предыдущей сети!
  Единственное видимое изменение
  - маленькие маркеры y на скрытых нейронах.
  Они напоминают нам о том, что выдают ступенчатые функции для y, а не для x,
  поэтому на входе y вес очень большой, а на входе x - нулевой, а не наоборот.
  Как и раньше, я решил не показывать этого непосредственно,
  чтобы не захламлять рисунок.
  
  Посмотрим, что будет, если мы добавим две функции выступа,
  одну по оси x, другую по оси y, обе высотой h:
  
  ......
  
  Для упрощения диаграммы связи с нулевым весом я опустил.
  Пока что я оставил маленькие маркеры x и y на скрытых нейронах,
  чтобы напомнить, в каких направлениях вычисляются функции выступов.
  Позже мы и от них откажемся, поскольку они подразумеваются входящей переменной.
  
  Попробуйте менять параметр h.
  Как видите, из-за этого меняются выходные веса,
   а также веса обеих функций выступа, x и y.
  
  Созданное нами немного похоже на <функцию башни>:
  
  .......
  
  Если мы можем создать такие функции башен,
  то мы можем использовать их для аппроксимации произвольных функций,
  просто добавляя башни различных высот в разных местах:
  //// И опять эта иллюстрация никак не акцентирует того
  //// что такая многопараметрическое "башнестроение" возможно
  //// только при стратегическом ПЛАНИРОВАНИИ того,
  //// как, в каком направлении, следует менять эти параметры.
  //// В то время при стандартном обучении нейросети
  //// "обратным распространением ошибки" в стохастическом градиентном спуске
  //// такое целенаправленное и согласованное подгонка параметров,
  //// практически, НЕРЕАЛЬНО.
  //// При практическом обучении нейросети параметры "подгоняются" ПО-ДРУГОМУ,
  //// и, как следствие, результирующая картинка
  //// будет кардинально отличаться от "многобашенного" рельефа.
  //// Ниже приведены иллюстрации реального "рельефа решений".
  
  .......
  
  Конечно, мы пока ещё не дошли до создания произвольной функции башни.
  Мы пока сконструировали что-то вроде центральной башни высоты 2h
  с окружающим её плато высоты h.
  
  Но мы можем сделать функцию башни.
  Вспомните, что раньше мы показали,
  как нейроны можно использовать для реализации инструкции if-then-else:
  
   if вход >= порог:
   выход 1
   else:
   выход 0
  
  Это был нейрон с одним входом.
  А нам нужно применить сходную идею к комбинированному выходу скрытых нейронов:
  
   if скомбинированный выход скрытых нейронов >= порог:
   выход 1
   else:
   выход 0
  
  Если мы правильно выберем порог - к примеру, 3h/2,
  втиснутый между высотой плато и высотой центральной башни
  - мы сможем раздавить плато до нуля, и оставить только одну башню.
  
  Представляете, как это сделать?
  Попробуйте поэкспериментировать со следующей сетью.
  Теперь мы строим график выхода всей сети,
  а не просто взвешенный выход скрытого слоя.
  Это значит, что мы добавляем член смещения
  к взвешенному выходу от скрытого слоя,
  и применяем сигмоиду.
  Сможете ли вы найти значения для h и b,
  при которых получится башня?
  Если вы застрянете на этом моменте, вот две подсказки:
  (1) чтобы выходящий нейрон продемонстрировал правильное поведение
  в стиле if-then-else,
  нам нужно, чтобы входящие веса (все h или -h) были крупными;
  (2) значение b определяет масштаб порога if-then-else.
  
  .......
  
  С параметрами по умолчанию выход похож
  на расплющенную версию предыдущей диаграммы, с башней и плато.
  Чтобы получить желаемое поведение, нужно увеличить значение h.
  Это даст нам пороговое поведение if-then-else.
  Во-вторых, чтобы правильно задать порог, нужно выбрать b = -3h/2.
  
  Вот как это выглядит для h=10:
  
  .......
  
  Даже для относительно скромных величин h мы получаем неплохую функцию башни.
  И, конечно, мы можем получить сколь угодно красивый результат,
  увеличивая h и дальше, и удерживая смещение на уровне b=-3h/2.
  
  Давайте попробуем склеить вместе две сети,
  чтобы подсчитать две разные функции башен.
  Чтобы соответствующие роли двух подсетей были ясны,
  я поместил их в отдельные прямоугольники:
  каждый из них вычисляет функцию башни при помощи описанной выше техники.
  График справа показывает взвешенный выход второго скрытого слоя,
  то есть, взвешенную комбинацию функций башен.
  //// Но обучение нейросетей идет не по частям/подсетям,
  //// а целиком, и данный сценарий не соответствует реальности.
  //// И если для поставленной автором задачи проиллюстрировать
  //// саму ВОЗМОЖНОСТЬ нейронкой ступеньчатой/"башенной" формы
  //// аппроксимации любой функции, это можно считать приемлемым приемом.
  //// Но вот для объяснения того, как именно нейронки обучаются и реализуют
  //// аппроксимацию любой функцию данный подход вряд ли подойдет.
  //// Т.е. моя основная претензия к этому материалу в том,
  //// что это различие недостаточно четко акцентировано,
  //// и по ходу материала у читателя может сложиться впечатление,
  //// что именно так нейросети и работают при аппроксимации "любой функции".
  
  ......
  
  В частности, видно, что изменяя веса в последнем слое,
  можно менять высоту выходных башен.
  
  Та же идея позволяет вычислять сколько угодно башен.
  Мы можем сделать их сколь угодно тонкими и высокими.
  В итоге мы гарантируем,
  что взвешенный выход второго скрытого слоя аппроксимирует
  любую нужную функцию двух переменных:
  
  ......
  
  В частности, заставив взвешенный выход второго скрытого слоя
  хорошо аппроксимировать ??1?f,
  мы гарантируем, что выход нашей сети будет
  хорошей аппроксимацией желаемой функции f.
  
  А что же насчёт функций многих переменных?
  
  Попробуем взять три переменных, x1,x2,x3.
  Следующую сеть можно использовать для подсчёта функции башни
  в четырёх измерениях?
  
  .......
  
  Здесь x1,x2,x3 обозначают вход сети. s1, t1 и так далее
  - точки ступенек для нейронов -
  то есть, все веса в первом слое большие,
  а смещения назначены так, чтобы точки ступенек равнялись s1, t1, s2,...
  Веса во втором слое чередуются, +h,-h,
  где h - некое очень большое число.
  Выходное смещение равно -5h/2.
  
  Сеть вычисляет функцию, равную 1, при выполнении трёх условий:
  x1 находится между s1 и t1;
  x2 находится между s2 и t2;
  x3 находится между s3 и t3.
  Сеть равна 0 во всех других местах.
  Это такая башня, у которой 1 - небольшой участок пространства входа,
  и 0 - всё остальное.
  
  Склеивая множество таких сетей,
  мы можем получить сколько угодно башен,
  и аппроксимировать произвольную функцию трёх переменных.
  Та же идея работает в m измерений.
  Меняется только выходное смещение (-m+1/2)h,
  чтобы правильно втиснуть нужные значения и убрать плато.
  
  Хорошо, теперь мы знаем, как использовать НС
  для аппроксимации вещественной функции многих переменных.
  Что насчёт векторных функций f(x1,..,xm) ? Rn?
  Конечно, такую функцию можно рассматривать,
  просто как n отдельных вещественных функций f1(x1,:,xm), f2(x1,:,xm),
  и так далее.
  А потом мы просто склеиваем все сети вместе.
  Так что с этим легко разобраться.
  
  Задача
  
  Мы увидели, как использовать нейросети с двумя скрытыми слоями
  для аппроксимации произвольной функции.
  Можете ли вы доказать, что это возможно делать с одним скрытым слоем?
  Подсказка - попробуйте работать с всего двумя выходными переменными,
  и показать, что:
  (a) возможно получить функции ступенек не только по осям x или y,
  но и в произвольном направлении;
  (b) складывая множество конструкций с шага (a),
  возможно аппроксимировать функцию круглой, а не прямоугольной башни;
  c используя круглые башни, возможно аппроксимировать произвольную функцию.
  Шаг c будет проще сделать, используя материал,
  представленный в этой главе немного ниже.
  
  Выход за рамки сигмоидных нейронов
  
  Мы доказали, что сеть, состоящая из сигмоидных нейронов,
  может вычислить любую функцию.
  Вспомним, что в сигмоидном нейроне входы x1,x2,...
  превращаются на выходе в ?(?jwjxj + b),
  где wj - веса, b - смещение, ? - сигмоида.
  
  .......
  
  Что, если мы рассмотрим другой тип нейрона,
  использующий другую функцию активации, s(z):
  
  .......
  
  То есть, мы предположим, что если у нейрона на входе будет x1,x2,...
  веса w1,w2,.. и смещение b,
  то на выходе будет s(?jwjxj + b).
  
  Мы можем использовать эту функцию активации для получения ступенчатой,
  точно так же, как в случае с сигмоидой.
  Попробуйте (в оригинале статьи) на диаграмме задрать вес до, допустим, w=100:
  
  .....
  
  Как и в случае с сигмоидой, из-за этого функция активации сжимается,
  и в итоге превращается в очень хорошую аппроксимацию ступенчатой функции.
  Попробуйте поменять смещение,
  и вы увидите, что мы можем изменить местоположение ступеньки на любое.
  Поэтому мы можем использовать всё те же трюки, что и ранее,
  для вычисления любой желаемой функции.
  
  Какие свойства должны быть у s(z),
  чтобы это сработало?
  Нам нужно предположить, что s(z) хорошо определена при z->-oo и z->oo.
  Эти пределы - это два значения, принимаемых нашей ступенчатой функцией.
  Нам также нужно предположить, что эти пределы отличаются.
  Если бы они не отличались, ступеньки бы не получилось,
  был бы просто плоский график!
  Но если функция активации s(z) удовлетворяет этим свойствам,
  основанные на ней нейроны универсально подходят для вычислений.
  
  Задачи
  
  Ранее в книге мы познакомились с нейроном другого типа
  - выпрямленным линейным нейроном,
  или выпрямленной линейной единицей [rectified linear unit, ReLU].
  Поясните, почему такие нейроны не удовлетворяют условиям,
  необходимым для универсальности.
  Найдите доказательство универсальности, показывающее,
  что ReLU универсально подходят для вычислений.
  //// Не нашел. Значит мало, что понял.
  
  Допустим, мы рассматриваем линейные нейроны, с функцией активации s(z)=z.
  Поясните, почему линейные нейроны не удовлетворяют условиям универсальности.
  Покажите, что такие нейроны нельзя использовать для универсальных вычислений.
  
  Исправляем ступенчатую функцию
  
  Покамест, мы предполагали, что наши нейроны выдают точные ступенчатые функции.
  Это неплохое приближение, но лишь приближение.
  На самом деле существует узкий промежуток отказа,
  показанный на следующем графике,
  где функции ведут себя совсем не так, как ступенчатая:
  
  .......
  
  В этом промежутке отказа данное мною объяснение универсальности не работает.
  //// Тут есть и еще один интересный момент,
  //// возможно связанный с проблемой "переобучения".
  //// При наличии такого рода "узких промежутков", задача обучения нейросети
  //// становится "немонотонной" и, даже, "стохастической",
  //// т.к. устранить такие "промежутки" стандартной техникой обучения,
  //// практически нереально, т.к. это требует обеспечения
  //// на порядок более сложной целенаправленно согласованности
  //// изменения параметров нейронов.
  
  Отказ не такой уж страшный.
  Задавая достаточно большие входные веса,
  мы можем делать эти промежутки сколь угодно малыми.
  Мы можем сделать их гораздо меньшими, чем на графике, невидимыми глазу.
  //// Но они все равно будут и обязательно проявят себя,
  //// как минимум, в "adversarial attacks".
  //// Или при задаче получить точность выше "одной девятки".
  Так что, возможно, нам не стоит волноваться из-за этой проблемы.
  //// "Вода дырочку найдет".
  
  Тем не менее, хотелось бы иметь некий способ её решения.
  
  Оказывается, её легко решить.
  Давайте посмотрим на это решение для вычисляющих функции НС
  со всего одним входом и выходом.
  Те же идеи сработают и для решения проблемы
  с большим количеством входов и выходов.
  
  В частности, допустим, мы хотим,
  чтобы наша сеть вычислила некую функцию f.
  Как и раньше, мы пытаемся сделать это,
  проектируя сеть так, чтобы взвешенный выход скрытого слоя нейронов был ??1?f(x):
  
  ......
  
  Если мы будем делать это, используя описанную выше технику,
  мы заставим скрытые нейроны выдать последовательность функций выступов:
  
  ......
  
  Я, конечно, преувеличил размер промежутков отказа,
  чтобы их было легче увидеть.
  Должно быть ясно, что если мы сложим все эти функции выступов,
  то получим достаточно хорошую аппроксимацию ??1?f(x)
  везде, кроме промежутков отказа.
  
  Но, допустим, что вместо использования только что описанной аппроксимации,
  мы используем набор скрытых нейронов для вычисления аппроксимации
  половины нашей изначальной целевой функции, то есть, ??1?f(x)/2.
  Конечно, это будет выглядеть,
  просто как масштабированная версия последнего графика:
  
  .......
  
  И, допустим, мы заставим ещё один набор скрытых нейронов
  вычислять приближение к ??1?f(x)/2,
  однако у него основания выступов будут сдвинуты на половину их ширины:
  
  ........
  
  Теперь у нас есть два разных приближения для ??1?f(x)/2.
  Если мы сложим две этих аппроксимации,
  то получим общее приближение к ??1?f(x).
  У этого общего приближения всё равно будут неточности
  в небольших промежутках.
  Но проблема будет меньше, чем раньше
  - ведь точки, попадающие в промежутки отказа первой аппроксимации,
  не попадут в промежутки отказа второй аппроксимации.
  Поэтому аппроксимация в этих промежутках окажется примерно в 2 раза лучше.
  //// Вот тут уже не понял. Похоже, или устал,
  //// или это объяснение попало в "зазор"/"промежуток" понимания
  //// моей личной "межушной" нейросети.
  //// В любом случае, вероятность такого согласованного обучения
  //// нескольких пар нейронов стохастическим градиеннтным спуском,
  //// да еще и с регуляризацией, представляется совершенно невероятной.
  
  Мы можем улучшить ситуацию, добавив большое количество, M,
  накладывающихся аппроксимаций функции ??1?f(x)/M.
  Если все промежутки отказа у них будут достаточно узкими,
  любая тока будет находиться лишь в одном из них.
  Если использовать достаточно большое количество накладывающихся аппроксимаций M,
  в итоге получится прекрасное общее приближение.
  
  Заключение
  
  Рассмотренное здесь объяснение универсальности
  определённо нельзя назвать практическим описанием того,
  как подсчитывать функции при помощи нейросетей!
  //// Вот это главное в этом материале,
  //// но кто на такие "восклицательные знаки" обращает внимание?
  В этом смысле оно больше похоже на доказательство
  универсальности логических вентилей NAND и прочего.
  Поэтому я в основном пытался сделать так,
  чтобы эта конструкция была ясной,
  и ей было просто следовать, не оптимизируя её детали.
  Однако попытки оптимизировать эту конструкцию могут стать для вас
  интересным и поучительным упражнением.
  
  Хотя полученный результат нельзя напрямую использовать для создания НС,
  //// Именно потому, что данный результат возможен только
  //// при целенаправленном "подборе параметров",
  //// но никак не методами "машинного обучения".
  //// Вот такой ремарки не хватает в этом материале.
  он важен, поскольку он снимает вопрос вычислимости
  какой-либо определённой функции при помощи НС.
  Ответ на такой вопрос всегда будет положительным.
  Поэтому правильно спрашивать: не вычислима ли какая-либо функция,
  а каков правильный способ её вычисления.
  //// И вопрос: как ДОСТИГНУТЬ этого способа?
  
  Разработанная нами универсальная конструкция использует
  всего два скрытых слоя для вычисления произвольной функции.
  Как мы обсуждали, возможно получить тот же результат
  при помощи единственного скрытого слоя.
  Учитывая это, вы можете задуматься,
  зачем вообще нам нужны глубокие сети,
  то есть, сети с большим количеством скрытых слоёв.
  Не можем ли мы просто заменить эти сети на неглубокие,
  имеющие один скрытый слой?
  
  Хотя, в принципе, это возможно,
  существуют хорошие практические причины для использования глубоких нейросетей.
  Как описано в главе 1, у глубоких НС есть иерархическая структура,
  позволяющая им хорошо адаптироваться для изучения иерархических знаний,
  которые оказываются полезными для решения реальных проблем.
  Более конкретно, при решении таких задач, как распознавание образов,
  полезно бывает использовать систему,
  понимающую не только отдельные пиксели,
  но и всё более сложные концепции:
  от границ до простых геометрических фигур,
  и далее, вплоть до сложных сцен с участием нескольких объектов.
  В более поздних главах мы увидим свидетельства,
  говорящие в пользу того, что глубокие НС смогут лучше неглубоких
  справиться с изучением подобных иерархий знания.
  Подытоживая:
  универсальность говорит нам, что НС могут подсчитать любую функцию;
  эмпирические свидетельства говорят о том,
  что глубокие НС лучше адаптированы к изучениям функций,
  полезных для решения многих задач реального мира.
  
  .........
  
  //// Из комментариев.
  
  mst_72
  29 июл 2019 в 10:43
  
  Человек на полном серьезе написал,
  что механизм аппроксимации (нейросеть)
  позволяет аппроксимировать (приблизительно вычислить) аппроксимируемую функцию?
  
  Гениально:
  С нетерпением жду статьи про ряды
  
  trofimovep
  29 июл 2019 в 11:47
  
  Если я правильно помню,
  это упрощенная идея доказательства доказательство теоремы Колмогорова-Арнольда,
  о представимости функции от нескольких переменных функцией одной переменной
  
  MarlboroMan
  29 июл 2019 в 12:01
  
  ОК, пусть вычислит md5()
  
  usdglander
  29 июл 2019 в 16:46
  
  Да не вопрос!
  У вас же есть память для хранения 2^128 нейронов в скрытом слое? :)
  
  Kilorad
  30 июл 2019 в 12:02
  
  И ещё датасет нужен соответствующий) Каждая точка
  
  pavlushk0
  29 июл 2019 в 12:42
  
  Всё-таки вычислить или апроксимировать?
  Это вроде сильно не одно и тоже.
  И речь наверно о любых "вычислимых" функциях.
  
  SLY_G
  29 июл 2019 в 16:49
  
  Во-первых, это не значит, что сеть можно использовать
  для точного подсчёта любой функции.
  Мы лишь можем получить настолько хорошее приближение,
  насколько нам нужно
  //// А вот с этим не согласен. Если функция неизвестна,
  //// то неизвестно какая должна быть сеть и,
  //// что очень важно обучающий набор примеров,
  //// чтобы получить "нужное приближение".
  
  DesertFlow
  29 июл 2019 в 14:02
  
  Мне больше нравится объяснение,
  что для каждой возможной комбинации входных параметров
  можно все выходы сделать 0, кроме одного,
  и тогда нейросеть превращается в обычную табличную функцию.
  Очевидно, что при бесконечном числе нейронов даже в одном скрытом слое,
  таким образом можно аппроксимировать любую функцию
  с любой необходимой точностью.
  Просто берём нужное значение из нужной ячейки таблицы, и все.
  Ну а многослойность нужна,
  чтобы уменьшить число нейронов для решения задачи.
  //// Хорошее предложение, вот только нужен еще и соответствующий
  //// метод обучения - "обратное распространение" с градиентным спуском
  //// для такого решения не подойдет.
  
  Kilorad
  29 июл 2019 в 16:03
  
  Автор не упомянул (насколько я понял) ещё одно важное ограничение.
  При обучении нейросети мы должны иметь в датасете точки,
  достаточно близкие к той точке, которую мы собрались аппроксимировать.
  А что значит <достаточно близкие>,
  зависит от вида целевой функции и от вида активационной.
  
  Например, если наша целевая функция - это 2^x,
  у нас есть в датасете неограниченное число точек из интервала (0,1),
  а активационная функция - это сигмоида,
  то совершенно не факт, что нейронка правильно апроксимирует точку с x=5.
  
  Spin7ion
  29 июл 2019 в 23:26
  
  Если вы не против, немного перефразирую.
  Для того, чтобы достичь требуемой точности НС на интервале,
  необходимо на этом интервале вычислить целевую функцию
  и обучить сеть по этим вычислениям.
  
  Тут напрашивается и такой вопрос:
  имея возможность вычислить значение некоторой функции
  (может и приблизительно),
  на сколько разумно использовать НС
  и начиная с какого момента НС будет менее производительна,
  чем более традиционные методы?
  
  Deosis
  30 июл 2019 в 07:50
  
  НС разумно использовать,
  когда традиционное вычисление функции очень дорого.
  
  Spin7ion
  30 июл 2019 в 10:27
  
  Это-то как раз понятно,
  но хочется понять до построения НС, что будет дороже.
  
  Приведу пример:
  есть алгебраическое матричное уравнение риккати.
  Решать его в real time необходимо для SDC регуляторов,
  но не очень приятно, а порой и невозможно
  (зависит от размерности системы).
  Аналитического решения этого уравнения нет и решают его апроксимацией.
  
  Так вот вопрос, сумеет ли НС дать прирост в производительности?
  
  Kilorad
  30 июл 2019 в 09:58
  
  Часто бывает, что НС аппроксимирует эмпирическую функцию.
  Например, каков будет результат общевойскового боя при заданных вводных.
  Соответственно, мы можем или выяснить это экспериментально,
  или иметь некую теорию, позволяющую предсказывать результаты сражений.
  Обучение нейросети - это как раз и есть создание теории из опытных данных.
  
  В общем, если у нас есть удовлетворительная матмодель процесса
  - тогда лучше использовать её.
  Если нет - можно или вывести теорию
  (хорошо, но требует кучу человекочасов),
  или обучить нейросеть
  (плохо для интерпретации, зато автоматически и довольно точно)
  
  napa3um
  2 авг 2019 в 05:49
  
  Без модели исследуемого процесса не обойтись и в случае применения нейросетей,
  волшебным образом она модель не построит,
  она всего лишь инструмент для подбора свободных параметров в моделях,
  построенных людьми.
  Итого вариантов два:
  либо построить модель решения,
  либо модель поиска этого решения
  - подбора свободных параметров первой модели.
  Во втором варианте есть возможность воспользоваться нейросетями.
  
  Kilorad
  2 авг 2019 в 13:44
  
  В смысле <волшебным образом не построит модель>?
  Нафиг тогда вообще нужна нейронка?)
  
  Если у меня есть соображения, как должна выглядеть модель,
  я возьму линейную или полиномиальную регрессию,
  или какую-то ещё известного вида.
  Если вообще никаких идей или идеи формализуются очень плохо,
  то у нас есть две около-универсальных модели:
  полносвязная нейросеть и градиентный бустинг.
  И формальные методы, как их тестировать на адекватность
  - кроссвалидация.
  
  Да, есть специализированные нейросети - конволюционная, например,
  но я сейчас про полносвязную однонаправленную.
  
  И насколько я понимаю, параметры ищет градиентный спуск
  (+эволюция для гиперпараметров),
  а нейронка - это продукт его работы.
  
  В общем, я прошу пояснить,
  как тогда в вашем представлении выглядит универсальный ML,
  который строит модели данных без значимых априорных данных,
  и почему полносвязная нейросеть/бустинг деревьев/AIXI
  не подходят под это определение?
  
  napa3um
  4 авг 2019 в 10:02
  
  Универсальный ML пока что никак не выглядит,
  по всем тем причинам, которые вы и описываете.
  Универсального решения любой задачи не существует.
  И полносвязная нейронка тоже <увидит> лишь те решения,
  которые дизайнер фич позволит ей увидеть.
  Всё это, конечно, не мешает случайно натыкаться на решения чужими моделями,
  как и не мешает верить в чудо. :)
  
  Kilorad
  12 авг 2019 в 19:48
  
  Фичи повышают вероятность нахождения определённых решений.
  Но если запустить обучение достаточно надолго,
  и нейронка будет достаточно большая,
  то она сама построит эти фичи.
  На бесконечности построит, то есть недостаток предобработки
  можно компенсировать избытком вычислительных мощностей.
  Так что в пределе нейронка универсальна, разве нет?
  
  Есть другая модель, более теоретическая, но более обоснованно универсальная.
  AIXI. Если конкретнее, то AIXI Monte Carlo.
  Это поиск формул, которые могли бы породить данные,
  в алгоритмически полном пространстве.
  Например, у нас есть датасет Y=f(X),
  и AIXI перебирает множество программ на, скажем, Си,
  и все программы тестирует на то,
  насколько похожий датасет они порождают.
  Эта модель тоже неуниверсальна?
  
  Есть гибридные модели.
  Предобработчик на базе чего-то типа AIXI
  и постобработчик на базе нейросети/бустинга.
  Выполняет работу по дизайну фичей.
  Конечно, она может увидеть не все фичи,
  но человек же тоже не все полезные фичи видит.
  Такая модель неуниверсальна?
  
  А если в качестве предобработки используются верхние слои нейронки
  - то есть у нас сеть глубокая и полносвязная -
  это не сделает её универсальной в том же смысле,
  в котором универсальна человеческая способность искать шаблоны в данных?
  
  napa3um
  19 авг 2019 в 01:57
  
  Все эти ваши фантазии упираются только в одно -

.

  Иначе бы то, о чём вы говорите,
  действительно имело бы практическую ценность :).
  
  Kilorad
  23 авг 2019 в 17:49
  
  Вообще-то все эти модели работают.
  Ну как работают.
  Эволюционный поиск тоже работает.
  Глобальный оптимум не находит, но локальный - запросто.
  Вот и эти модели находят локально-оптимальные решения.
  Было бы странно от них ждать идеальных решений.
  
  Без модели исследуемого процесса не обойтись и в случае применения нейросетей,
  волшебным образом она модель не построит,
  она всего лишь инструмент для подбора свободных параметров в моделях,
  построенных людьми.
  
  Чем эта пачка из нейросетей, бустингов и AIXI
  так уж принципиально отличается от того, как модели строят люди?
  Понятно, что физическая база отличается
  и что элементарные блоки несколько иначе устроены.
  
  Но у меня сложилось впечатление, что вы полагаете,
  что люди могут строить модели каким-то таким образом,
  которым ML строить модели не может.
  Даже если данные и у людей, и у ML одни и те же.
  Даже если под ML подразумеваются любые ML
  из класса нейросетей, бустингов и AIXI,
  а так же любых их комбинаций.
  
  Я правильно понял вашу позицию?
  Если да, то можно поподробнее, так как мне это кажется странным?
  
  napa3um
  23 авг 2019 в 17:55
  
  Я говорю о том, что без проектирования модели задачи
  любой инструмент автоматического подбора параметров
  (будь то подкидывание монетки или нейросеть)
  будет бесполезен.
  Выводы о том, насколько схожи или не схожи нейросетки с биомозгами
  из этого тезиса сделать не получится.
  
  Kilorad
  23 авг 2019 в 18:15
  
  Когда человеческий мозг ищет некоторую закономерность в данных
  - это процесс автоматического подбора параметров?
  
  Он это делает с проектированием модели задачи или без?
  Если модель всё же используется,
  то её изготовление всегда происходит из какой-то другой модели
  или иногда тем самым автоматическим подбором параметров?
  
  napa3um
  23 авг 2019 в 19:03
  
  Ваши вопросы не являются контраргументами к моему тезису,
  вы и дальше можете жонглировать словами сколько угодно :).
  Уверен, что вы поняли мой исходный тезис,
  но пытаетесь <юридически> решить вопрос :).
  
  Kilorad
  23 авг 2019 в 23:19
  
  Ок, хорошо. По моим наблюдениям,
  feature engeneering и грамотный ручной выбор модели
  позволяют решить задачу сильно быстрее,
  чем если бы мы использовали тру-универсальные инструменты вроде AIXI
  или околоуниверсальные вроде ff-нейросетей.
  Тем не менее, <грубая сила> позволяет уделять меньше внимания
  построению моделей.
  Это и грубая сила более полного перебора
  (например, в широком пространстве нейронок,
  а не в узком пространстве линейных моделей),
  и грубая сила бОльшего количества статистики.
  
  Тем не менее иногда встаёт вопрос
  - а как в данной конкретной задаче сделать именно универсальную модель?
  Не то, чтобы мы не могли провести feature engeneering
  - скорее, мы себе не доверяем.
  И считаем свой FE слишком неполным.
  А иногда нам и правда нужна широкая универсальность,
  потому что чёрт его знает, с чем там наш сервис столкнётся в будущем,
  и хорошо бы, чтобы он мог сам как-то это прожевать, без доработок.
  
  Некоторые люди сразу говорят, что широкой универсальности добиться
  (даже задорого)
  нельзя.
  Они обосновывают это вполне правильной математикой
  - NP-полные задачи никто не отменял.
  Но эта логика неприменима к реальным мозгам
  - люди решают очень широкий класс задач,
  особенно если им дать компьютер.
  И возникает вопрос - а если человек может,
  то как это на компе реализовать?
  Если человек может делать FE,
  то может, и ML может?
  (ну пусть не человек, а коллектив людей. Но может же?)
  
  Тут некоторые люди начинают высказывать идеалистические концепции,
  мол, если человек что-то может,
  то не факт, что это принципиально возможно для компьютера.
  
  Другие начинают говорить, что:
  Честно говоря, я не уверен, что понимаю их верно.
  Это моя недоработка, и я сейчас именно её пытаюсь исправить,
  задавая вопросы вам =)
  Но концепция видится следующая:
  ML - это прикладное построение моделей.
  Человек может формализовать в виде датасета лишь малую часть своих знаний,
  ещё у него есть всякие неявные догадки,
  и он их формализует, выбирая класс модели
  (свёрточная ли нейронка или линейная регрессия)
  и FE.
  Нам не нужна механика,
  умеющая из нейронки прямого распространения выточить свёрточную,
  потому что это слишком дорого.
  Да, такая механика возможна.
  Да природа примерно так и поступила.
  Безо всяких априорных данных сделала модель из:
  Из молекул, которые были <под рукой>.
  Довольно тупыми алгоритмами эволюции.
  Но это чересчур дорого, потому непрактично и неинтересно.
  Не могли бы вы поправить меня в данной позиции, если я неправ?
  
  Есть и третья позиция.
  Если человек что-то может, значит, может и ML.
  А чтобы конструкция работала, она должна уметь делать Meta-Learning.
  То есть должна быть какая-то механика такая,
  что после решения одной задачи наша модель меняется,
  и вторую задачу решает уже быстрее,
  если вторая задача похожа на первую.
  Например: Можно взять штук 100 разных топологий нейронок,
  прогнать их на 10к задач и собрать статистику,
  какие топологии работают лучше всего.
  И на новой задаче сначала пробовать наилучшие топологии,
  и весь этот рейтинг постоянно обновлять,
  после каждой новой решённой задачи.
  Я опытным путём проверял Meta-Learning под задачи Feature Engeneering.
  Эксперимент показал,
  что поначалу модель Meta-Learning запарывает задачи,
  но после серии попыток выходит на уровень модели
  с хорошим ручным Feature Engeneering.
  Даже несмотря на то, что в этом автоматизированном FE
  был очень урезанный набор функций,
  и подобрать <истинную> закономерность там было тупо невозможно,
  только апроксимация.
  Всё равно Meta-Learning отработал, как надо.
  
  Практически же Meta-Learning сейчас используется в распознавании изображений
  - есть обученная нейросеть, которая распознаёт всякие разные картинки,
  многие пользователи берут её в качестве отправной точки для своей нейросети.
  Обучение в результате требует меньше времени и статистики
  
  napa3um
  24 авг 2019 в 09:42
  
  <Универсальная модель к задаче>
  - это не такая уж и универсальная модель,
  потому что её каждый раз строит человек к каждой задаче.
  Ок, к каждому классу задач.
  Ок, использует общие подходы построения моделей в схожих задачах.
  НО ДЕЛАЕТ ЭТО ЧЕЛОВЕК.
  Не потому, что он умнее транзисторного процессора,
  а потому, что именно у него, этого человека,
  заключённого в физическую реальность, и возникла ЗАДАЧА :).
  У транзистора личных задач нет.
  
  //// Конец цитирования.
  
  27.04.2024 20:55
  
  Специально привел "многометровый" листинг комментариев практически полностью,
  чтобы показать, что при чтении этого материала, с качественной визуализацией
  мифической ступеньки/"башни", реализуемую парой/ансаблем согласованных нейронов,
  читатель практически гарантированно не может заметить самого главного "слона"
  - то что реальное поведение нейронок при аппроксимации "произвольной функции",
  существенно отличается от описанного.
  Впрочем, как и "проблема промежутков", остающаяся без особого внимания.
  И все споры разворачиваются только о применимости нейронок
  в тех или иных сценариях.
  А не то как они действительно работают,
  обучаясь реазиовывать эту "магическую аппроксимацию".
  
  Чтобы не быть голословным, приведу пару иллюстраций как реально выглядит
  аппроксимация нейронкой предельно простых функций:
  
  kraidiky1. Источник: https://habr.com/ru/articles/219647/  Рис. 7127f2f705bb2bb1aa265ba8a2a0fdda.png
  
  Источник: https://habr.com/ru/articles/219647/ Рис. 7127f2f705bb2bb1aa265ba8a2a0fdda.png
  https://habrastorage.org/r/w1560/getpro/habr/post_images/712/7f2/f70/7127f2f705bb2bb1aa265ba8a2a0fdda.png
  
  И если для предыдущей иллюстрации можно еще сказать,
  что нейронку просто недообучили из-за ограниченного обучающего датасета.
  То вот для следующей иллюстрации "эта отмазка не работает":
  
  kraidiky2. Источник: https://habr.com/ru/articles/219647/ Рис. f15eb201219777217526254c5e9a1558.png
  
  Источник: https://habr.com/ru/articles/219647/ Рис. f15eb201219777217526254c5e9a1558.png
  https://habrastorage.org/r/w1560/getpro/habr/post_images/f15/eb2/012/f15eb201219777217526254c5e9a1558.png
  
  Как видите реальная аппроксимация нейронкой "произвольной функции"
  имеет какие-то общие свойства
  - характерный "фрактальный"/"пилообразный" рисунок -
  существенно отличающийся от ступенчатого/"башенного" типа,
  описанного в данном материале.
  Этот реальный характер аппроксимации нейронок
  тоже имеет в основе "нелинейную функцию активации",
  хотя и реализуется это немного по-другому.
  
  Но разбор этого лучше перенести в другой фрагмент
  - этот и так получился великоват,
  но честное слово, не знаю, где его можно было бы "урезать",
  без утери и общей картинки и деталей
  и, что не менее важно, типичного восприятия такого важного и нужного материала,
  если следовать полностью в русле авторской логики подачи материала.
  Основная претензия к этой логике в том,
  что ВОЗМОЖНОСТЬ использования "нелинейной функции активации"
  не увязана с ПРАКТИКОЙ обучения параметров нейронки.
  И в итоге главное в понимании работы нейросети уходит "на задний план",
  а на передний план снова вылезает "необъяснимая магия нейросетей".
  
  
  =========
  
  01.05.2024 11:45
  
  Попытка неканонической трактовки регуляризации. Часть 2.
  В оглавление.
  
  Чтобы продолжить попытку понять, что и как именно происходит в нейросети
  при использовании методов регуляризации на этапе "компрессии" обучения,
  наверно, стоит напомнить некоторые исходные позиции этой трактовки.
  
  Итак, процесс обучения в этой трактовке рассматривается,
  как процесс, состоящий из нескольких этапов.
  Наверно, лучше всего этот процесс можно охарактеризовать типовой S-образной кривой,
  соответствующей графику развития практически всех технических систем.
  Нейросеть так же является технической системой и, что интересно,
  процесс ее обучения так же похож на такую S-образину.
  Интерес заключается в том, что если механизмы, приводящие к такой зависимости,
  имеют что-то общее с процессами развития привычных технических систем.
  то можно предполагать, что и какие-то выводы/рекомендации могут в чем-то пересекаться.
  
  Типовыми этапами этого процесса можно выделить 4-5 достаточно различных фаз:
  
  1. "Стартовый" - этап инициализации параметров нейросети
  и самые первые 5-10 примеров обучающих примеров.
  
  2. "Инфляция" - этап быстрого начального обучения,
  при котором действует правило 80/20,
  когда 20% обучающих примеров обеспечивает 80% точности работы нейросети.
  
  3. "Компрессия" - этап, когда происходит "перелом" графика обучения
  и достигается точность нейросети порядка 90% - 95%.
  
  4. "Стабилизация" - этап, когда путем очень длительного обучения
  от нейросети пытаются добиться еще пары-тройки "заветных процентов" точности.
  
  5. "Стагнация" или даже "деградация" - этап, когда дальнейшее обучение нейросети,
  несмотря ни на объем датасета, ни время обучения,
  к заметному улучшению качества/точности нейросети не приводит.
  А зачастую только ухудшает ее качество не только на тестовой/валидационной выборке,
  но и на обучающей датасете.
  
  Причины, почему эти этапы стоит рассматривать не "чохом", а по отдельности,
  в том, что на каждом этапе обучения нейросети,
  мне представляется,
  даже если оно ведется по одному и тому же алгоритму и функции стоимости/ошибки,
  происходит немного в разных условиях и с разными "последствиями".
  Соответственно, рекомендации к использованию "механизмов регуляризации",
  оценка влияния этих механизмов на "обобщающие способности" нейросети
  и на "проявление эффекта переобучения" могут/должны быть "несколько" отличающимися.
  
  Второй ключевой момент рассматриваемой трактовки
  - это каким образом обеспечивается нейросетью "аппроксимация"
  требуемой функции обобщения.
  Тут важно понимать, что ни общий вид этой функции, ни какие-то кокретные детали
  ее реализации, в общем случае, неизвестны,
  и вся ставка на магию/математику "обратного распространения ошибок",
  градиентного спуска и "обобщающей способности" нейросети.
  А когда этого оказывается недостаточно,
  то начинаются заклинания о "локальных минимумах", "переобучении",
  большем размере датасета обучающих примеров и масштаба нейросети.
  
  Тут вот еще какой важный момент.
  В большинстве случаев конечный вид "обобщающей функции" не только неизвестен,
  - известны только ДИСКРЕТНЫЕ значения, соответствующие обучающим примерам,
  при том, что большинство нейросетей "аппроксимируют" некую НЕПРЕРЫВНУЮ функцию -
  но непонятно/неизвестно даже, какой должен быть характер поведения этой функции
  МЕЖДУ этими дискретными значениями - ступенчатый, линейный, квадратичный,
  или, вообще какой-то полиномиальный/синусоидальный.
  И, в добавок к этому, еще важно понимать, что напрямую повлиять
  на характер поведения "аппроксимирующей функции" между "дискретами примеров",
  существующие механизмы обучения нейросетей практически не позволяют.
  И это при том, что требуемая "аппроксимирующая функция", в общем случае,
  не только нелинейна, но и не монотонна, а в каких-то местах, наверняка, и разрывная.
  Опять вся надежда на некую "магию обобщения нейросетей".
  
  Рассматриваемая в предыдущем фрагменте иллюстрация того,
  как МОГЛА БЫ БЫТЬ реализована "универсальная обобщающая способность нейросети",
  при всей своей эффектности, мало соответствует реальности обучения нейросетей,
  так как требует определенной целенаправленности дифференциации процесса обучения
  параметров нейросети.
  И при этом еще и входит в противоречие с практикой использования
  механизмов регуляризации и дропаута при обучении нейросети.
  НО. Опираясь на эту иллюстрацию можно подступиться к пониманию того,
  как достигаются при обучении нейросети нелинейность "аппроксимирующей функции",
  и какие при этом возникают проблемы, наподобие, "незначительных промежутков".
  
  Итак, как реально может реализовываться обучение НЕМОНОТОННЫМ зависимостям
  в существующих традиционных нейросетях, построенных на нелинейных функциях активации
  и относительно непрерывном диапазоне значений параметров нейронов?
  Представляется, что для этого необходимо использование нескольких
  - больше одной - связей ведущих к нейрону с разными знаками весов.
  Тогда сумма вкладов этих связей на нелинейной активации нейрона
  и позволяет реализовывать "немонотонное" поведение выхода.
  Т.е. реализуется не какое-то одно большое значение связи,
  как это рассматривается в предыдущем фрагменте для иллюстрации такого поведения,
  а сумма нескольких связей, в сумме обеспечивающих такое поведение.
  Но при этом сами значения этих связей по отдельности все-таки остаются
  внутри какого-то ограниченного диапазона,
  который дополнительно еще и ограничивается функциями регуляризации.
  
  Основное отличие такой реализации от "учебной иллюстрации" в том,
  что эти ансамбли/подсети нейронов и связей не заточены
  под одну конкретную "ступеньку"/"башню" а участвуют сразу
  во многих "строительных элементах" "аппроксимирующей функции".
  И большая часть "магии обучения" нейросетей заключается
  в удачном согласовании этих ансамблей/подсетей между собой.
  
  Тут, собственно, ничего особенно нового не заявляется.
  Вместо пары согласованно настроенных нейронов, обеспечивающих "ступеньку"/"башню",
  причем настроенных специально и целенаправленно,
  рассматривается реализация "ступеньки"/"башни" ансамблями/подсетями
  различных нейронов/связей, которые из-за различных ИЗНАЧАЛЬНЫХ ЗНАКОВ вкладов
  в суммарное значение, обучаются, т.е. корректируются в разных направлениях.
  Представляется, что это достаточно очевидно,
  и, может быть, поэтому в литературе по обучению нейросетей
  этот момент как-то совершенно не рассматривается,
  хотя, на мой взгляд,
  это очень важный момент для понимания всего процесса обучения,
  и, самое главное, характера "рельефа решений".
  То, что он - "рельеф решений" - может/должен быть не какой-то кусочно-непрерывный,
  а, так сказать, "точечно-дырочный"/"игольчатый"/"пилообразный",
  в общем, достаточно далекий от "классических иллюстраций" аппроксимирующих функций.
  
  В первую очередь, этот момент дает понимание важности "стартового" этапа обучения,
  т.е. инициализации и самых первых обучающих примеров.
  На этом этапе, мне представляется, важно обеспечить фиксацию
  максимального разнообразия обучающих примеров,
  но при этом сохранив достаточно равномерное распределение весов
  с различными знаками
  для облегчения последующего обучения остальным примерам на этапе "инфляции",
  и, самое главное, расширению возможности согласования представления этих примеров,
  на этапе "компрессии".
  
  Во-вторых, если использовать "метафору создания скульптуры из куска мрамора",
  то "стартовый" и "инфляционный" этапы обучения нейросети,
  фактически задают границы "глыбы мрамора",
  а на этапе "компрессии" происходит "удаление лишних частей" от этой "глыбы".
  Выглядит это таким образом,
  что сначала задаются "контуры аппроксимирующей функции",
  очень даже возможно, что ближе к "ступенчатой"/"башенной" реализации.
  А затем предварительная "подгонка"/"спрямление" "ступенек"
  к чему-то похожему на "линейную аппроксимацию".
  Грубо говоря. просто ступеньки спрямляются "ломанными",
  в основном, "квазипрямолинейными приближениями",
  из-за того, что параметры нейросети на этогм этапе большей частью находятся,
  так сказать, еще в линейной области их влияния на выходной результат.
  Т.е. аппроксимация неизвестной функции идет
  от даже не столько "ступенчатой", сколько от точечной/дискретной формы
  к "квазилинейному" ее приближению.
  
  На иллюстрациях реального результата обучения нейросети
  на разных этапах обучения, которые приведены в конце предыдущего материала,
  достаточно хорошо видно, что нет ни "ступенчатого", ни "линейного" приближения
  к требуемой функции аппроксимирующего результата работы нейросети.
  Скорее это какой-то дискретно-фрактальный рисунок,
  и о "квазинелинейности" можно говорить только в контексте того,
  в каком направлении корректируются параметры нейросети в процессе обучения.
  А вот проявление результатов этой корректировки имеет
  какой-то "дырчатый" характер.
  И, скорее всего, это те самые "незначащие промежутки",
  о которых в предыдущем материале предлагалось "не сильно беспокоится",
  мол "само рассосется".
  
  Мое мнение прямо противоположное, "само не рассосется",
  а будет стоить значительных усилий на этапе "стабилизации",
  и при этом никогда не может быть гарантированно устранено полностью,
  т.к. это заложено "в самой природе" реализации "аппроксимирующих возможностей"
  традиционных нейросетей.
  Это кстати подтверждается фактом "adversarial attacks",
  которым подвержены практически все нейросети независимо от обучающего датасета
  и функции стоимости/ошибки, подробнее см.:
  "Сенсация от Гугла, о которой стараются не вспоминать",
  Те самые "дырочки" на указанных иллюстрациях это как раз и есть
  области чувствительности к "adversarial attacks".
  Поэтому имеет смысл попытаться разобраться с этим вопросом поподробнее.
  
  Но сначала, еще чуть-чуть соображений о том как идет обучение
  на этапе "стабилизации" обучения.
  Основное отличие этого этапа от этапа "компрессии" в том,
  что его задача уже не столько в том,
  чтобы согласовать решения для различных обучающих примеров,
  сколько попытаться обеспечить "интерполяцию" между этими примерами,
  т.е. выстроить какую-то систему "промежуточных" виртуальных примеров,
  получаемых в результате регуляризации,
  и уже ее согласовать с системой реальных примеров.
  Грубо говоря, заполнить те самые "дырочки в решении",
  о которых говорилось абзацем выше.
  
  Основная проблема на этом этапе в том, что как-то явно указать
  способ аппроксимации "промежуточных значений" при этом фактически нет.
  Поэтому используется все тот же способ задания "аппроксимации функции",
  который использовался до этого, но за счет "регуляризационных добавок"
  к функции стоимости или прямого ограничения на требуемого изменение параметра,
  идет попытка аппроксимации, точнее, согласование текущего состояния нейросети,
  с фактически каким-то синтетическим/аугментированным примером.
  При этом механизм этого "согласования" остается все тем же,
  и фактически это приводит к тому,
  что "рельеф решения" дополняется еще одной "ступенькой"/"башней",
  а точнее "изломом"/"пиком" как-то заполняющем "определенную дырочку",
  но при этом формируя уже другую, но менее заметную дырочку.
  
  Если попытаться представить это в каких привычных формах,
  то это больше похоже не на "сглаживание пиков решения",
  а, наоборот, добавление все новых и новых "пиков"/"гребней"/"изломов",
  в, общем-то, как-то приближающее "аппроксимирующую функцию" к искомой,
  но каким-то не очень привычным/предполагаемым образом,
  делая границу "решающей функции" похожей на фрактальную область.
  "Проклятые промежутки" хоть и по-немногу могут уменьшаться,
  но никогда не исчезают.
  И, соответственно, качество работы нейросети
  не может превысить определенного уровня на тестовой/валидационной выборке.
  
  И все это обычно называют "переобучением".
  Хотя проблема не в том, что нейросеть как-то прилежно выучила
  только обучающие примеры, и "игнорирует тестовые",
  а в том что на этапе "стабилизации",
  т.е. обучения ее аппроксимации вне обучающих примеров,
  оцениваемая именно по тестовой и валидационной выборке.
  методика ее обучения, включая и "механизмы регуляризации",
  не соответствуют требуемому характеру "аппроксимации" искомой функции.
  Напомню, искомая функция неизвестна не только в общем виде,
  но непонятно ее поведение и в локальных областях.
  А характер типовой аппроксимации нейросетью каких-то зависимостей,
  за счет реализации их ансамблями/подсетями,
  имеет такой "дырчато-изломанный" характер.
  
  В итоге разработчикам приходится пенять или на "локальные минимумы",
  или "проклятье переобучения", или размер и качество обучающей выборки
  и размер и архитектуру нейросети
  Либо, сжав зубы, увеличивать обучающие датасеты,
  менять размеры и структуру нейросети,
  и, в любом случае, количество попыток обучения с нуля.
  Либо брать какую-то удачно предобученную сеть
  и пытаться ее дообучить под свою задачу.
  
  В общем, суммируя вышесказанное, на мой взгляд,
  применительно к использованию функциям регуляризации и дропаута,
  настоятельно требуется более осмысленное их применение,
  а то и вовсе какой-то иной подход,
  чем использование "средней температуры по больнице".
  
  Вот как это мне видится сейчас,
  возможно, со временем после более глубокого изучения вопроса что-то поменяется.
  
  На "стартовом" этапе "регуляризация" по факту не нужна и даже вредна,
  так как искажает запоминание "контура решения".
  А вот дропаут как раз, наоборот, имеет смысл использовать по максимуму,
  чтобы обеспечить запоминание этих "контуров" максимально свободно/независимо,
  чтобы повысить разнообразие/потенциал возможных решений
  при "усвоении" основного корпуса обучающих примеров на этапе "инфляции".
  
  На этапе "инфляции" применение регуляризации тоже особого смысла не имеет,
  так как основную нагрузку на данном этапе по предварительному
  согласованию решений на обучающих примерах все-таки выполняет
  градиентный спуск и "обратное распространение ошибок".
  Опасность "локальных минимумов" на этом этапе,
  извините за тавтологию, минимальна,
  так как "разброс" между запомненными на "стартовом" этапе "контурами решения"
  фактически максимален, если начальные примеры были максимально разнообразны,
  и усиленно применялась процедура дропаута.
  
  Фактически, представляется практичным вообще начинать
  не просто со случайной инициализации параметров нейросети,
  а чуть ли не принудительного внедрения в нее "образов" первых обучающих примеров,
  НО в РАЗНЫХ частях нейросети.
  "Но это не точно".
  Надо будет поискать подтверждение/опровержение такому тезису.
  
  Использование дропаута по мере обучения нейросети,
  опять же по моим представлениям,
  должна последовательно уменьшаться.
  //// Вера в "счастливый лотерейный билет", см. например:
  //// "О <Гипотезе Лотерейного Билета>"
  //// Автор: 19blackadder97 (Денис Кузнеделев)
  //// https://habr.com/ru/articles/718748/.
  //// 23 фев 2023 в 14:31
  //// в общем-то, имеет такое же "твердое математическое обоснование",
  //// как и вера "в универсальную аппроксимирующую способность" нейросети.
  Ставка на то, что дропаут на финишных этапах обучения
  снижает "вероятность переобучения" больше похожа на игру в "орлянку",
  хотя при достаточно большом количестве попыток,
  действительно можно улучшить систему, которая будет менее точной
  на обучающей выборке, и более точной, точнее, лучше аппроксимирующей
  на тестовой и валидационной выборке.
  Но учитывая, что одни "промежутки" заменились другими,
  а объем тестовой выборки обычно на порядок меньше обучающей,
  то, если хорошо вдуматься, выигрыш получается достаточно "неоднозначный".
  Т.е. дропаут нужен какой-то более управляемый/прицельный.
  
  А в отношении регуляризации,
  на мой взгляд, совершенно диаметрально противоположные:
  от абсолютного минимума на "стартовом" этапе,
  до максимально сильного на этапе "стабилизации",
  т.к. он больше ориентирован именно на обеспечение "интерполяции"
  между обучающими примерами.
  И опять же хотелось бы иметь более управляемые/прицельные механизмы регуляризации.
  
  Возможно, есть смысл как-то "скрестить" между собой
  механизмы дропаута и регуляризации.
  В котором дропаут больше отвечает за "расширение рамок" аппроксимирующей функции,
  а регуляризация за характер/качество интерполяции между "дискретами" обучающих примеров.
  //// Надо будет взять на заметку это предположение,
  //// при дальнейшем поиске информации по улучшению качества обучения.
  
  Пожалуй, на сегодня Все - "кувшин мыслей показал дно".
  Но тему "трактовки регуляризации" считать закрытой пока рано.
  Главное, что мне хотелось отразить в этом фрагменте,
  что причина "переобучения" в реальном характере реализации нейросетью
  "аппроксимирующей функции" в виде "кусочно-прерывистого рельефа решения",
  в котором из-за реализации немонотонности пересекающимися ансамблями/подсетями
  обязательно присутствует определенные "незначительные промежутки".
  И этот уровень "незначительные промежутки" и является причиной того,
  что обычно называется "переобучением".
  Звучит, конечно, не очень гладко.
  Завтра будет новый день - что-то может получше придумается.
  
  
  =========
  
  27.04.2024 23:20
  
  "Некоторые" сложности глубокого обучения.
  В оглавление.
  
  К этому материалу, наверно, нет никакой необходимости что-либо добавлять/комментировать,
  настолько он четко и ясно иллюстрирует "блеск и нищету"
  главного инструмента сегодняшнего машинного обучения
  - метода обратного распространения ошибки.
  Проблема "исчезающих" и "взрывающихся градиентов
  - это обратная сторона универсальности этого метода
  и его "ахиллесова пята" в плане колоссальных затрат
  на обучение нетривиальных нейросетей:
  
  "Нейросети и глубокое обучение, глава 5:
  почему глубокие нейросети так сложно обучать?"
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/462381/.
  5 авг 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap5.html
  
  //// Начало цитирования.
  
  .......
  
  Почти у всех сетей, с которыми мы работали,
  был единственный скрытый слой нейронов (плюс входной и выходной слои):
  
  Эти простые сети оказались весьма полезными:
  в предыдущих главах мы использовали такие сети
  для классификации рукописных чисел с точностью, превышающей 98%!
  Тем не менее, интуитивно понятно,
  что сети с большим количеством скрытых слоёв будут гораздо более мощными:
  
  Такие сети могут использовать промежуточные слои
  для создания множества уровней абстракции,
  как в случае с нашими булевскими схемами.
  К примеру, в случае распознавания образов,
  нейроны первого слоя могут научиться распознавать грани,
  нейроны второго слоя - более сложные формы,
  допустим, треугольники или прямоугольники, созданные из граней.
  Затем третий слой сможет распознавать ещё более сложные формы. И так далее.
  Вероятно, эти многие слои абстракции дадут глубоким сетям
  убедительное преимущество в решении задач по распознаванию
  сложных закономерностей.
  Более того, как и в случае со схемами,
  существуют теоретические результаты, подтверждающие,
  что глубокие сети по сути своей имеют больше возможностей, чем неглубокие.
  
  Как нам обучать подобные глубокие нейросети (ГНС)?
  В данной главе мы попробуем обучить ГНС используя нашу рабочую лошадку
  среди обучающих алгоритмов - стохастический градиентный спуск
  с обратным распространением.
  Однако мы столкнёмся с проблемой - наши ГНС не будут работать сильно лучше
  (если вообще превзойдут),
  чем неглубокие.
  
  Эта неудача кажется странной в свете дискуссии, приведённой выше.
  Но вместо того, чтобы махнуть на ГНС рукой,
  мы углубимся в проблему и попытаемся понять,
  почему ГНС тяжело обучать.
  Когда мы поближе познакомимся с вопросом, мы обнаружим,
  что разные слои в ГНС обучаются с крайне разными скоростями.
  В частности, когда последние слои сети обучаются хорошо,
  первые часто застревают во время обучения,
  и почти ничему не обучаются.
  И дело не в простом невезении.
  Мы обнаружим фундаментальные причины для замедления обучения,
  которые связаны с использованием техник обучения на основе градиента.
  
  Зарывшись в эту проблему поглубже, мы узнаем,
  что может происходит и обратное явление:
  ранние слои могут обучаться хорошо, а более поздние - застревать.
  На самом деле, мы обнаружим внутреннюю нестабильность,
  связанную с обучением градиентным спуском в глубоких многослойных НС.
  И из-за этой нестабильности либо ранние, либо поздние слои
  часто застревают при обучении.
  
  Всё это звучит довольно неприятно.
  Но погрузившись в эти трудности,
  мы можем начать разрабатывать идеи о том,
  что нужно сделать для эффективного обучения ГНС.
  Поэтому эти исследования станут хорошей подготовкой к следующей главе,
  где мы будем использовать глубокое обучение
  для подхода к задачам распознавания изображений.
  
  Проблема исчезающего градиента
  
  Так что же идёт не так, когда мы пытаемся обучить глубокую сеть?
  
  Чтобы ответить на этот вопрос, вернёмся к сети,
  содержащей всего один скрытый слой.
  Как обычно, мы будем использовать задачу классификации цифр MNIST
  в качестве песочницы для обучения и экспериментов.
  
  .......
  
  У такой сети есть 784 нейрона во входном слое,
  соответствующие 28*28=784 пикселям входного изображения.
  Мы используем 30 скрытых нейронов и 10 выходных,
  соответствующих десяти возможным вариантам классификации цифр MNIST
  ('0', '1', '2', ..., '9').
  
  Попробуем обучать нашу сеть в течение 30 целых эпох
  с использованием мини-пакетов из 10 обучающих примеров за раз,
  скорость обучения ?=0,1 и параметр регуляризации ?=5,0.
  Во время обучения мы будем отслеживать точность классификации
  через validation_data:
  
  ......
  
  Мы получим точность классификации в 96,48%
  (или около того - при разных запусках цифры будут варьироваться),
  сравнимую с нашими ранними результатами с похожими настройками.
  
  Давайте добавим ещё один скрытый слой, также содержащий 30 нейронов,
  и попытаемся обучить сеть с теми же гиперпараметрами:
  
  ......
  
  Точность классификации улучшается до 96,90%.
  Это вдохновляет - небольшое увеличение глубины помогает.
  Давайте добавим ещё один скрытый слой из 30 нейронов:
  
  ......
  
  Это никак не помогло.
  Результат даже упал до 96,57%,
  значения, близкого к первоначальной неглубокой сети.
  А если мы добавим ещё один скрытый слой:
  
  ......
  
  Тогда точность классификации опять упадёт, уже до 96,53%.
  Статистически это падение, вероятно, незначительно,
  однако и ничего хорошего в этом нет.
  
  Такое поведение кажется странным.
  Интуитивно кажется, что дополнительные скрытые слои
  должны помочь сети обучиться более сложным функциям классификации,
  и лучше справиться с задачей.
  Уж конечно результат не должен ухудшаться,
  ведь в худшем случае дополнительные слои просто не будут ничего делать.
  Однако этого не происходит.
  
  Так что же происходит?
  Давайте предположим, что дополнительные скрытые слои могут помочь в принципе,
  и что проблема в том, что наш обучающий алгоритм
  не находит правильных значений для весов и смещений.
  Нам хотелось бы понять, что не так с нашим алгоритмом,
  и как его улучшить.
  
  Чтобы понять, что пошло не так, давайте визуализируем процесс обучения сети.
  Ниже я построил часть сети [784,30,30,10], в которой есть два скрытых слоя,
  в каждом из которых по 30 скрытых нейронов.
  На диаграмме у каждого нейрона есть полоска,
  обозначающая скорость изменения в процессе обучения сети.
  Большая полоска значит, что веса и смещения нейрона меняются быстро,
  а маленькая - что они меняются медленно.
  Точнее, полоска обозначает градиент ?C/?b нейрона,
  то есть, скорость изменения стоимости по отношению к смещению.
  В главе 2 мы увидели, что эта величина градиента
  контролирует не только скорость изменения смещения в процессе обучения,
  но и скорость изменения входных весов нейрона.
  Не волнуйтесь, если вы не можете вспомнить эти детали:
  надо просто иметь в виду, что эти полоски обозначают,
  насколько быстро меняются веса и смещения нейронов в процессе обучения сети.
  
  Для упрощения диаграммы я нарисовал
  только шесть верхних нейронов в двух скрытых слоях.
  Я опустил входящие нейроны, поскольку у них нет весов или смещений.
  Я опустил и выходные нейроны, поскольку мы сравниваем два слоя,
  и имеет смысл сравнивать слои с одинаковым количеством нейронов.
  Диаграмма построена при помощи программы generate_gradient.py
  в самом начале обучения,
  то есть, сразу после того, как сеть была инициализирована.
  
  .....
  
  Сеть была инициализирована случайно,
  поэтому такое разнообразие в скорости обучения нейронов неудивительно.
  Однако сразу же бросается в глаза,
  что во втором скрытом слое полоски в основном гораздо больше, чем в первом.
  В итоге нейроны во втором слое будут учиться гораздо быстрее, чем в первом.
  Совпадение ли это, или нейроны во втором слое,
  вероятно, в общем будут обучаться быстрее нейронов в первом?
  
  Чтобы узнать точно, хорошо будет иметь общий способ сравнения
  скорости обучения в первом и втором скрытых слоях.
  Для этого давайте обозначим градиент как ?lj = ?C/?blj,
  то есть, как градиент нейрона ?j в слое ?l.
  Во второй главе мы называли это <ошибкой>,
  но здесь я будут неформально называть это <градиентом>.
  Неформально - поскольку в эту величину не входят явно
  частные производные стоимости по весам, ?C/?w.
  Градиент ?1 можно представлять себе как вектор,
  чьи элементы определяют, насколько быстро обучается первый скрытый слой,
  а ?2 - как вектор, чьи элементы определяют,
  насколько быстро обучается второй скрытый слой.
  Длины этих векторов мы используем,
  как приблизительные оценки скорости обучения слоёв.
  То есть, к примеру, длина || ?1 || измеряет скорость обучения
  первого скрытого слоя,
  а длина || ?2 || измеряет скорость обучения второго скрытого слоя.
  
  С такими определениями и с той же конфигурацией,
  что указана выше, мы обнаружим, что || ?1 || = 0,07,
  а || ?2 || = 0,31.
  Это подтверждает наши подозрения:
  нейроны во втором скрытом слое обучаются гораздо быстрее,
  чем нейроны в первом скрытом слое.
  
  Что будет, если мы добавим больше скрытых слоёв?
  С тремя скрытыми слоями в сети [784,30,30,30,10]
  соответствующие скорости обучения составят 0,012, 0,060 и 0,283.
  Опять первые скрытые слои обучаются гораздо медленнее последних.
  Добавим ещё один скрытый слой с 30 нейронами.
  В данном случае соответствующие скорости обучения составят
  0,003, 0,017, 0,070 и 0,285.
  Закономерность сохраняется:
  ранние слои обучаются медленнее поздних.
  
  Мы изучали скорость обучения в самом начале
  - сразу после инициализации сети.
  Как же меняется эта скорость по мере обучения?
  Давайте вернёмся и посмотрим на сеть с двумя скрытыми слоями.
  Скорость обучения меняется в ней так:
  
  .......
  
  Для получения этих результатов я использовал пакетный градиентный спуск
  с 1000 обучающих изображений и обучение в течение 500 эпох.
  Это немного отличается от наших обычных процедур
  - я не использовал мини-пакеты и взял всего 1000 обучающих изображений,
  вместо полного набора из 50 000 штук.
  Я не пытаюсь хитрить и обманывать вас,
  но оказывается, что использование стохастического градиентного спуска
  с мини-пакетами привносит в результаты гораздо больше шума
  (но если усреднять шум, то результаты получаются похожими).
  Используя выбранные мною параметры легко сгладить результаты,
  чтобы мы могли увидеть, что происходит.
  
  В любом случае, как видим, два слоя начинают обучение
  с двух очень разных скоростей (что нам уже известно).
  Затем скорость обоих слоёв очень быстро падает,
  после чего происходит отскок.
  //// Интересно почему? Что изменилось в сети, чтобы проявилось такое поведение?
  Однако всё это время первый скрытый слой обучается гораздо медленнее второго.
  
  Что насчёт более сложных сетей?
  Вот результаты похожего эксперимента, но уже с сетью с тремя скрытыми слоями
  [784,30,30,30,10]:
  
  .......
  
  И снова первые скрытые слои обучаются гораздо медленнее последних.
  Наконец, попробуем добавить четвёртый скрытый слой (сеть
  [784,30,30,30,30,10]),
  и посмотрим, что произойдёт при её обучении:
  
  .......
  
  И снова первые скрытые слои обучаются гораздо медленнее последних.
  В данном случае первый скрытый слой обучается
  примерно в 100 раз медленнее последнего.
  Неудивительно, что у нас были такие проблемы с обучением этих сетей!
  
  Мы провели важное наблюдение:
  по крайней мере, в некоторых ГНС градиент уменьшается
  при движении в обратную сторону по скрытым слоям.
  То есть, нейроны в первых слоях обучаются гораздо медленнее нейронов в последних.
  И хотя мы наблюдали этот эффект всего в одной сети,
  существуют фундаментальные причины того,
  почему это происходит во многих НС.
  Это явление известно под названием <проблемы исчезающего градиента>
  (см. работы 1, 2).
  http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7321
  http://www.idsia.ch/~juergen/SeppHochreiter1991ThesisAdvisorSchmidhuber.pdf
  
  Почему возникает проблема исчезающего градиента?
  Есть ли способы её избежать?
  Как нам быть с ней при обучении ГНС?
  На самом деле вскоре мы узнаем,
  что она не является неизбежной,
  хотя альтернатива ей и не выглядит очень уж привлекательное:
  иногда в первых слоях градиент оказывается гораздо больше!
  Это уже проблема взрывного роста градиента,
  и в ней не больше хорошего, чем в проблеме исчезающего градиента.
  В целом оказывается, что градиент в ГНС нестабилен,
  и склонен либо к взрывному росту,
  либо к исчезновению в первых слоях.
  Эта нестабильность является фундаментальной проблемой
  для градиентного обучения ГНС.
  Это то, что нам нужно понять,
  и по возможности как-то решить.
  
  Одна из реакций на исчезающий (или нестабильный) градиент
  - подумать, а является ли это на самом деле серьёзной проблемой?
  Ненадолго отвлечёмся от НС,
  и представим, что мы пытаемся численным образом
  минимизировать функцию f(x) от одного переменного.
  Разве не было бы здорово, если бы производная f?(x) была малой?
  Не означало бы это, что мы уже близки к экстремуму?
  И точно так же, не означает ли небольшой градиент в первых слоях ГНС,
  что нам уже не нужно сильно подстраивать веса и смещения?
  
  Конечно же, нет.
  Вспомним, что мы случайным образом инициализировали веса и смещения сети.
  Крайне маловероятно, что наши изначальные веса и смешения
  хорошо справятся с тем, чего мы хотим от нашей сети.
  В качестве конкретного примера рассмотрим
  первый слой весов в сети [784,30,30,30,10],
  классифицирующей цифры MNIST.
  Случайная инициализация означает,
  что первый слой выбрасывает большую часть информации о входящем изображении.
  Даже если бы более поздние слои были тщательно обучены,
  им бы было чрезвычайно сложно определять входящее сообщение,
  просто из-за недостатка информации.
  Поэтому совершенно невозможно представить,
  что первому слою просто не нужно обучаться.
  Если мы собираемся обучать ГНС,
  нам надо понять, как решать проблему исчезающего градиента.
  
  Что вызывает проблему исчезающего градиента?
  Нестабильные градиенты в ГНС
  
  Чтобы понять, как появляется проблема исчезающего градиента,
  рассмотрим простейшую НС:
  всего с одним нейроном в каждом слое.
  Вот сеть с тремя скрытыми слоями:
  
  ........
  
  Здесь w1, w2,... - это веса,
  b1, b2,... - смещения,
  С - некая функция стоимости.
  Просто для напоминания скажу, что выход aj с нейрона ?j равен ?(zj),
  где ? - обычная сигмоидная функция активации,
  а zj = wjaj?1+bj - взвешенный вход нейрона.
  Функцию стоимости я изобразил в конце,
  чтобы подчеркнуть, что стоимость является функцией от выхода сети, a4:
  если реальный выход близок к желаемому,
  тогда стоимость будет маленькой,
  а если далёк - то большой.
  
  Изучим градиент ?C/?b1, связанный с первым скрытым нейроном.
  Найдём выражение для ?C/?b1
  и, изучив его, поймём, почему возникает проблема исчезающего градиента.
  
  Начнём с демонстрации выражения для ?C/?b1.
  Выглядит неприступно,
  но на самом деле структура его проста,
  и я скоро опишу её.
  Вот это выражение (пока игнорируйте саму сеть и отметьте,
  что ?? - просто производная от функции ?):
  
  ......
  
  Структура выражения такова:
  для каждого нейрона в сети имеется член умножения ??(zj),
  для каждого веса имеется wj,
  и ещё есть последний член, ?C/?a4,
  соответствующий функции стоимости.
  Заметьте, что я разместил соответствующие члены
  над соответствующими частями сети.
  Поэтому сама сеть является мнемоническим правилом для выражения.
  
  Можете принять это выражение на веру и пропустить его обсуждение
  прямо до того места, где объясняется,
  как оно связано с проблемой исчезающего градиента.
  В этом нет ничего плохого, поскольку это выражение представляет собой
  особый случай из нашего обсуждения обратного распространения.
  Однако объяснить его верность легко,
  поэтому для вас будет достаточно интересно
  (а, возможно, и поучительно) изучить это объяснение.
  
  Представьте, что мы внесли небольшое изменение ?b1 в смещение b1.
  Это отправит серию каскадных изменений по всей остальной сети.
  Сначала это заставит измениться выход первого скрытого нейрона ?a1.
  Это, в свою очередь, заставить измениться ?z2
  во взвешенном входе на второй скрытый нейрон.
  Затем произойдёт изменение ?a2 в выходе второго скрытого нейрона.
  И так далее, вплоть до изменения ?C в стоимости выхода.
  Получится, что:
  
  $ \frac{\partial C}{\partial b_1} \approx \frac{\Delta C}{\Delta b_1} \tag{114} $
  
  Это говорит о том, что мы можем вывести выражение для градиента ?C/?b1,
  тщательно отслеживая влияние каждого шага в этом каскаде.
  
  Для этого подумаем, как ?b1 заставляет меняться
  выход a1 первого скрытого нейрона.
  Имеем a1 = ?(z1) = ?(w1a0+b1), поэтому
  
  $ \Delta a_1 \approx \frac{\partial \sigma(w_1 a_0+b_1)}{\partial b_1} \Delta b_1 \tag{115} $
  
  $ = \sigma'(z_1) \Delta b_1 \tag{116} $
  
  Член ??(z1) должен выглядеть знакомым:
  это первый член нашего выражения для градиента ?C/?b1.
  Интуитивно понятно, что он превращает изменение смещения ?b1
  в изменение ?a1 выходной активации.
  Изменение ?a1 в свою очередь вызывает изменение
  взвешенного входа z2 = w2a1+b2 второго скрытого нейрона:
  
  $ \Delta z_2 \approx \frac{\partial z_2}{\partial a_1} \Delta a_1 \tag{117} $
  
  $ = w_2 \Delta a_1 \tag{118} $
  
  Комбинируя выражения для ?z2 и ?a1,
  мы видим, как изменение смещения b1 распространяется вдоль сети
  и влияет на z2:
  
  $ \Delta z_2 \approx \sigma'(z_1) w_2 \Delta b_1 \tag{119} $
  
  И это тоже должно быть знакомо:
  это два первых члена в нашем заявленном выражении для градиента ?C/?b1.
  
  Так можно продолжать и далее,
  отслеживая, как изменения распространяются по остальной сети.
  На каждом нейроне мы подбираем член ??(zj),
  и через каждый вес мы подбираем член wj.
  В итоге получается выражение,
  связывающее конечное изменение ?C функции стоимости
  с начальным изменением ?b1 смещения:
  
  $ \Delta C \approx \sigma'(z_1) w_2 \sigma'(z_2) \ldots \sigma'(z_4) \frac{\partial C}{\partial a_4} \Delta b_1 \tag{120} $
  
  Разделив его на ?b1, мы действительно получим нужное выражение для градиента:
  
  $ \frac{\partial C}{\partial b_1} = \sigma'(z_1) w_2 \sigma'(z_2) \ldots \sigma'(z_4) \frac{\partial C}{\partial a_4} \tag{121} $
  
  Почему возникает проблема исчезающего градиента?
  
  Чтобы понять, почему возникает проблема исчезающего градиента,
  давайте подробно распишем всё наше выражение для градиента:
  
  $ \frac{\partial C}{\partial b_1} = \sigma'(z_1) \ w_2 \sigma'(z_2) \ w_3 \sigma'(z_3) \, w_4 \sigma'(z_4) \ \frac{\partial C}{\partial a_4} \tag{122} $
  
  Кроме последнего члена, это выражение есть произведение членов вида wj??(zj).
  Чтобы понять, как ведёт себя каждый из них, посмотрим на график функции ??:
  
  .....
  
  График достигает максимума в точке ??(0)=1/4.
  Если мы используем стандартный подход к инициализации весов сети,
  то мы выбираем веса с использованием распределения Гаусса,
  то есть, среднеквадратичным нулём и стандартным отклонением 1.
  Поэтому обычно веса будут удовлетворять неравенству |wj|<1.
  Сопоставив все эти наблюдения,
  увидим, что члены wj??(zj) обычно будут удовлетворять неравенству
  |wj??(zj)|<1/4.
  А если мы возьмём произведение множества таких членов,
  то оно будет экспоненциально уменьшаться:
  чем больше членов, тем меньше произведение.
  Начинает походить на возможную разгадку проблемы исчезающего градиента.
  
  Чтобы записать это более точно,
  сравним выражение для ?C/?b1 с выражением градиента
  относительно следующего смещения, допустим, ?C/?b3.
  Конечно, мы не записывали подробное выражение для ?C/?b3,
  но оно следует тем же закономерностям, что описаны выше для ?C/?b1.
  И вот сравнение двух выражений:
  
  ........
  
  У них есть несколько общих членов.
  Однако в градиент ?C/?b1 входит два дополнительных члена,
  каждый из которых имеет вид wj??(zj).
  Как мы видели, такие члены обычно не превышают 1/4.
  Поэтому градиент ?C/?b1 обычно будет в 16 (или больше) раз меньше, чем ?C/?b3.
  И это основная причина возникновения проблемы исчезающего градиента.
  
  Конечно, это не точное, а неформальное доказательство возникновения проблемы.
  Существуют несколько оговорок.
  В частности, можно заинтересоваться тем,
  будут ли во время обучения расти веса wj.
  Если это произойдёт, члены wj??(zj) в произведении
  уже не будут удовлетворять неравенству |wj??(zj)|<1/4.
  И если они окажутся достаточно большими, больше 1,
  то у нас уже не будет проблемы исчезающего градиента.
  Вместо этого градиент будет экспоненциально расти
  при обратном движении через слои.
  И вместо проблемы исчезающего градиента
  мы получим проблему взрывного роста градиента.
  
  Проблема взрывного роста градиента
  
  Давайте посмотрим на конкретный пример возникновения взрывного градиента.
  Пример будет несколько искусственным:
  я подстрою параметры сети так,
  чтобы гарантировать возникновение взрывного роста.
  Но хотя пример и искусственный, его плюс в том,
  что он чётко демонстрирует:
  взрывной рост градиента является не гипотетической возможностью,
  а может реально случиться.
  
  Для взрывного роста градиента нужно сделать два шага.
  Сначала мы выберем большие веса во всей сети,
  допустим, w1=w2=w3=w4=100.
  Потом мы выберем такие смещения,
  чтобы члены ??(zj) были не слишком маленькими.
  И это довольно легко сделать:
  нам нужно лишь выбрать такие смещения,
  чтобы взвешенный вход каждого нейрона был zj=0 (и тогда ??(zj)=1/4).
  Поэтому, к примеру, нам нужно, чтобы z1=w1a0+b1=0.
  Этого можно достичь, назначив b1=?100?a0.
  Ту же идею можно использовать и для выбора остальных смещений.
  В итоге мы увидим, что все члены wj??(zj) окажутся равными 100?14=25.
  И тогда у нас получится взрывной рост градиента.
  
  Проблема нестабильного градиента
  
  Фундаментальная проблема заключается не в проблеме исчезающего градиента
  или взрывном росте градиента.
  Она в том, что градиент в первых слоях является
  произведением членов из всех остальных слоёв.
  И когда слоёв много, ситуация по сути становится нестабильной.
  И единственный способ, которым все слои смогут обучаться
  с примерно одной скоростью
  - это выбрать такие члены произведения,
  которые будут балансировать друг друга.
  И при отсутствии некоего механизма или причины для такой балансировки
  маловероятно, что это произойдёт случайно.
  Короче говоря, реальная проблема в том,
  что НС страдают от проблемы нестабильного градиента.
  И в итоге, если мы будем использовать стандартные обучающие техники
  на основе градиента,
  разные слои сети будут обучаться с ужасно разными скоростями.
  
  .......
  
  Преобладание проблемы исчезающего градиента
  
  Мы видели, что градиент может исчезать или расти взрывными темпами
  в первых слоях глубокой сети.
  На самом деле при использовании сигмоидных нейронов
  градиент обычно будет исчезать.
  Чтобы понять, почему, снова рассмотрим выражение |w??(z)|.
  Чтобы избежать проблемы исчезающего градиента,
  нам нужно, чтобы |w??(z)|?1.
  Вы можете решить, что этого легко достичь при очень больших значениях w.
  Однако на самом деле это не так просто.
  Причина в том, что член ??(z) тоже зависит от w: ??(z)=??(wa+b),
  где a - это входная активация.
  И если мы сделаем w большим,
  нам надо постараться, чтобы параллельно не сделать ??(wa+b) маленьким.
  А это оказывается серьёзным ограничением.
  Причина в том, что когда мы делаем w большим,
  мы делаем wa+b очень большим.
  Если посмотреть на график ??, видно, что это приводит нас
  к <крыльям> функции ??,
  где она принимает очень малые значения.
  И единственный способ избежать этого
  - удерживать входящую активацию в достаточно узком диапазоне значений.
  Иногда это происходит случайно.
  Но чаще этого не происходит.
  Поэтому в общем случае у нас возникает проблема исчезающего градиента.
  
  Задачи
  
  ......
  
  Нестабильность градиентов в более сложных сетях
  
  Мы изучали игрушечные сети всего лишь с одним нейроном в каждом скрытом слое.
  Что насчёт более сложных глубоких сетей,
  у которых в каждом скрытом слое есть много нейронов?
  
  ........
  
  На самом деле, в таких сетях происходит примерно то же самое.
  Ранее в главе про обратное распространение мы видели,
  что градиент в слое ?l сети с L слоями задаётся, как:
  
  $ \delta^l = \Sigma'(z^l) (w^{l+1})^T \Sigma'(z^{l+1}) (w^{l+2})^T \ldots \Sigma'(z^L) \nabla_a C \tag{124} $
  
  Здесь ??(zl) - диагональная матрица,
  чьи элементы - это значения ??(z) для взвешенных входов слоя ?l.
  wl - это матрицы весов для разных слоёв.
  А ?aC - вектор частных производных C по выходным активациям.
  
  Это выражение гораздо сложнее случая с одним нейроном.
  И всё же, если приглядеться, его суть окажется весьма похожей,
  с кучей пар вида (wj)T??(zj).
  Более того, у матриц ??(zj) по диагонали стоят небольшие значения,
  не больше 1/4.
  Если весовые матрицы wj будут не слишком крупными,
  каждый дополнительный член (wj)T ??(zl) склонен уменьшать градиентный вектор,
  что ведёт к исчезающему градиенту.
  В общем случае, большее количество членов перемножения
  ведёт к нестабильному градиенту,
  как в нашем предыдущем примере.
  На практике эмпирически обычно в сигмоидных сетях
  градиенты в первых слоях исчезают экспоненциально быстро.
  В итоге в этих слоях замедляется обучение.
  И замедление не является случайностью или неудобством:
  это фундаментальное следствие избранного нами подхода к обучению.
  
  Другие препятствия на пути к глубокому обучению
  
  В этой главе я сконцентрировался на исчезающих градиентах
  - и более общем случае нестабильных градиентов -
  в качестве препятствия на пути к глубокому обучению.
  На самом деле, нестабильные градиенты
  - всего лишь одно препятствие для развития ГО,
  пусть и важное, и фундаментальное.
  Значительная часть текущих исследований пытается лучше понять проблемы,
  которые могут возникнуть при обучении ГО.
  Я не буду подробно описывать все эти работы,
  однако хочу кратенько упомянуть парочку работ,
  чтобы дать вам представление о некоторых вопросах, задаваемых людьми.
  
  В качестве первого примера в работе 2010 года
  http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf
  было найдено свидетельство тому,
  что использование сигмоидных функций активации может привести
  к проблемам с обучением НС.
  В частности, было обнаружено свидетельство того,
  что использование сигмоид приведёт к тому,
  что активации последнего скрытого слоя будут во время обучения
  насыщаться в районе 0,
  что будет серьёзно замедлять обучение.
  Было предложено несколько альтернативных функций активации,
  не страдающих так сильно от проблемы насыщения
  (см. также ещё одну работу с обсуждением).
  http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
  
  В качестве первого примера в работе 2013 года
  http://www.cs.toronto.edu/~hinton/absps/momentum.pdf
  изучалось влияние на ГО как случайной инициализации весов,
  так и график импульсов в стохастическом градиентном спуске на основе импульса.
  В обоих случаях хороший выбор значительно влиял на возможность обучать ГНС.
  
  Эти примеры говорят о том, что вопрос <Почему ГНС так сложно обучать?>
  очень сложный.
  В данной главе мы сконцентрировались на нестабильностях,
  связанных с градиентным обучением ГНС.
  Результаты двух предыдущих параграфов говорят о том,
  что роль играет ещё и выбор функции активации,
  способ инициализации весов
  и даже детали реализации обучения на основе градиентного спуска.
  И, естественно, важными будут выбор архитектуры сети и других гиперпараметров.
  Поэтому множество факторов может сыграть роль
  в затруднении обучения глубоких сетей,
  и вопрос понимания этих факторов является объектом текущих исследований.
  Но всё это кажется довольно мрачным и внушает пессимизм.
  Однако есть и хорошие новости
  - в следующей главе мы обернём всё в нашу пользу,
  и разработаем несколько подходов в ГО,
  которые до некоторой степени смогут преодолеть или обойти все эти проблемы.
  
  //// Конец цитирования.
  
  Еще раз хочется подчеркнуть главный тезис данного материала,
  что "исчезающие" и "взрывающиеся градиенты",
  как проявление НЕСТАБИЛЬНОСТИ обучения обратным распространением ошибки
  через "мгновенные" значения градиентов
  - "это фундаментальное следствие избранного нами подхода к обучению".
  И, соответственно, кардинальное решение этой проблемы,
  скорее всего, лежит не в области "технических ухищрений" или "примочек",
  а переосмыслении самих основ ПОДХОДА к "обратному распространению",
  как бы еретическим это не казалось/звучало.
  Но почему бы не попробовать и здесь по-изобрести нечто "велосипедообразное"?
  
  
  =========
  
  12.05.2024 16:10
  
  Пример глубокого обучения сверточной нейросети.
  В оглавление.
  
  Данный материал, весьма объемный, даже после очень значительного "урезания",
  можно рассматривать двояко:
  с одной стороны, это очень качественное введение
  в классическую структуру сверточных нейросетей (СНС),
  с другой стороны, это очень наглядная иллюстрация того,
  что "непонятки", отмеченные при рассмотрении классических перцептронных сетей,
  никуда не исчезают в нейроструктурах другого типа.
  И постоянно проявляются при анализе результатов любого глубокого обучения,
  основанном на методе обратного распространения ошибки:
  
  "Нейросети и глубокое обучение: онлайн-учебник, глава 6, ч.1:
  глубокое обучение".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/463171/.
  12 авг 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap6.html
  
  //// Начало цитирования.
  
  В прошлой главе мы узнали, что глубокие нейронные сети (ГНС)
  часто тяжелее обучать, чем неглубокие.
  И это плохо, поскольку у нас есть все основания полагать,
  что если бы мы могли обучить ГНС,
  они бы гораздо лучше справлялись с задачами.
  //// Вот эти основания, как ни странно, в четкой формулировке
  //// мне не приходилось встречать.
  //// Только какие-то аналогии и предположения и наблюдения о том,
  //// что более глубокие структуры имеют больший потенциал и качество работы,
  //// но именно "теорехтического" обоснования не видел.
  //// Вот только сейчас это заметил.
  Но хотя новости из предыдущей главы и разочаровывают, нас это не остановит.
  В этой главе мы выработаем техники,
  которые сможем использовать для обучения глубоких сетей
  и применения их на практике.
  Мы также посмотрим на ситуацию шире,
  кратко познакомимся с недавним прогрессом в использовании ГНС
  для распознавания изображений, речи и для других применений.
  
  ......
  
  Основная часть главы -
  введение в один из наиболее популярных типов глубоких сетей:
  глубокие свёрточные сети (ГСС).
  Мы поработаем с подробным примером использования свёрточной сети,
  с кодом и прочим, для решения задачи классификации рукописных цифр
  из набора данных MNIST:
  
  ......
  
  Начнём мы наш обзор свёрточных сетей с неглубоких сетей,
  которые мы использовали для решения этой задачи ранее в книге.
  В несколько этапов мы будем создавать всё более мощные сети.
  По пути мы будем знакомиться с многими мощными технологиями:
  свёртками, пулингом [pooling],
  использованием GPU для серьёзного увеличения объёма обучения
  по сравнению с тем, что делали неглубокие сети,
  алгоритмическим расширением обучающих данных
  (для уменьшения переобучения),
  использованием технологии исключения [dropout]
  (также для уменьшения переобучения),
  использованием ансамблей сетей, и прочим.
  В результате мы придём к системе, способности которой находятся
  почти на человеческом уровне.
  Из 10 000 проверочных изображений MNIST
  - которые система не видела во время обучения -
  она сумеет правильно распознать 9967.
  
  ......
  
  Введение в свёрточные нейросети
  
  В предыдущих главах мы научили наши нейросети
  довольно неплохо распознавать изображения рукописных цифр:
  
  ......
  
  Мы сделали это, используя сети,
  в которых соседние слои были полностью соединены друг с другом.
  То есть, каждый нейрон сети был связан с каждым нейроном соседнего слоя:
  
  .......
  
  В частности, мы закодировали интенсивность каждого пикселя изображения
  в виде значения для соответствующего нейрона входного слоя.
  Для изображений размером 28х28 пикселей это означает,
  что у сети будет 784 (=28?28) входящих нейрона.
  Затем мы обучали веса и смещения сети так,
  чтобы на выходе сеть (была такая надежда)
  правильно идентифицировала входящее изображение:
  '0', '1', '2', ..., '8', or '9'.
  
  Наши ранние сети работают достаточно неплохо:
  мы достигли точности классификации выше 98%,
  используя обучающие и проверочные данные из набора рукописных цифр MNIST.
  Но если оценить эту ситуацию теперь,
  то покажется странным использовать сеть с полностью связанными слоями
  для классификации изображений.
  Дело в том, что такая сеть не принимает во внимание
  пространственную структуру изображений.
  К примеру, она совершенно одинаково относится как к пикселям,
  расположенным далеко друг от друга, так и к соседним пикселям.
  Предполагается, что выводы о таких концепциях пространственной структуры
  должны быть сделаны на основе изучения обучающих данных.
  Но что, если вместо того, чтобы начинать структуру сети с чистого листа,
  мы будем использовать архитектуру,
  пытающуюся воспользоваться пространственной структурой?
  В данном разделе я опишу свёрточные нейронные сети (СНС).
  Они используют специальную архитектуру,
  особенно подходящую для классификации изображений.
  Благодаря использованию такой архитектуры, СНС обучаются быстрее.
  А это помогает нам обучать более глубокие и многослойные сети,
  которые хорошо справляются с классификацией изображений.
  Сегодня глубокие СНС или некий близкий к ним вариант
  используются в большинстве случаев распознавания изображений.
  
  Истоки СНС уходят в 1970-е.
  Но стартовой работой, с которой началось их современное распространение,
  стал труд 1998 года "Градиентное обучение для распознавания документов".
  Лекун сделал интересное замечание касательно терминологии, используемой в СНС:
  <Связь таких моделей, как свёрточные сети, с нейробиологией весьма поверхностна.
  Поэтому я называю их свёрточными сетями, а не свёрточными нейросетями,
  и поэтому мы называем их узлы элементами, а не нейронами>.
  Но, несмотря на это, СНС используют множество идей из мира НС,
  которые мы уже изучили:
  обратное распространение, градиентный спуск, регуляризация,
  нелинейные функции активации, и т.д.
  Поэтому мы будем следовать общепринятому соглашению
  и считать их разновидностью НС.
  Я буду называть их как сетями, так и нейросетями,
  а их узлы - как нейронами, так и элементами.
  
  СНС используют три базовых идеи:
  локальные рецептивные поля, общие веса и пулинг.
  Давайте рассмотрим эти идеи по очереди.
  
  Локальные рецептивные поля
  
  В полносвязных слоях сетей входные слои обозначались
  вертикальными линиями нейронов.
  В СНС удобнее представлять входной слой в виде квадрата из нейронов с размерностью 28х28,
  значения которых соответствуют интенсивностям пикселей изображения 28х28:
  
  .......
  
  Как обычно, мы связываем входящие пиксели со слоем скрытых нейронов.
  Однако мы не будем связывать каждый пиксель с каждым скрытым нейроном.
  Связи мы организуем в небольших, локализованных участках входящего изображения.
  
  Точнее говоря, каждый нейрон первого скрытого слоя
  будет связан с небольшим участком входящих нейронов,
  к примеру, региона 5х5, соответствующего 25 входящим пикселям.
  Так что, для некоего скрытого нейрона связь может выглядеть так:
  
  ......
  
  Этот участок входящего изображения называется
  локальным рецептивным полем для этого скрытого нейрона.
  Это небольшое окошко, глядящее на входящие пиксели.
  Каждая связь обучается своему весу.
  Также скрытый нейрон изучает общее смещение.
  Можно считать, что этот конкретный нейрон обучается анализировать
  своё определённое локальное рецептивное поле.
  
  Затем мы перемещаем локальное рецептивное поле по всему входящему изображению.
  Для каждого локального рецептивного поля существует
  свой скрытый нейрон в первом скрытом слое.
  Для более конкретной иллюстрации начнём
  с локального рецептивного поля в левом верхнем углу:
  
  ........
  
  Сдвинем локальное рецептивное поле на один пиксель вправо (на один нейрон),
  чтобы связать его со вторым скрытым нейроном:
  
  .......
  
  Таким образом, мы построим первый скрытый слой.
  Отметьте, что если наше входящее изображение имеет размеры 28х28,
  а размеры локального рецептивного поля составляют 5х5,
  тогда в скрытом слое будет 24х24 нейрона.
  Это оттого, что мы можем сдвинуть локальное рецептивное поле
  только на 23 нейрона вправо (или вниз),
  а потом столкнёмся с правой (или нижней) стороной входящего изображения.
  
  В данном примере локальные рецептивные поля двигаются по одному пикселю за раз.
  Но иногда используется другой размер шага.
  К примеру, мы могли бы сдвигать локальное рецептивное поле на 2 пикселя в сторону,
  и в этом случае можно говорить о размере шага 2.
  В данной главе мы в основном будем использовать шаг 1,
  но стоит знать, что иногда проходят эксперименты с шагами другого размера.
  С размером шага можно поэкспериментировать, как и с другими гиперпараметрами.
  Можно также изменять и размер локального рецептивного поля,
  однако обычно оказывается,
  что больший размер локального рецептивного поля лучше работает на изображениях,
  значительно больших, чем 28х28 пикселей.
  
  Общие веса и смещения
  
  Я упомянул, что у каждого скрытого нейрона есть смещение и 5х5 весов,
  связанных с его локальным рецептивным полем.
  Но я не упомянул, что мы будем использовать одинаковые веса и смещения
  для всех 24х24 скрытых нейронов.
  Иначе говоря, для скрытого нейрона j,k выход будет равен:
  
  $ \sigma\left(b + \sum_{l=0}^4 \sum_{m=0}^4 w_{l,m} a_{j+l, k+m} \right) \tag{125} $
  
  Здесь ? - функция активации, возможно, сигмоида из прошлых глав.
  b - общее значение смещения.
  wl,m - массив общих весов 5х5.
  И, наконец, ax,y обозначает входную активацию в позиции x,y.
  
  Это значит, что все нейроны в первом скрытом слое
  обнаруживают один и тот же признак,
  просто находящийся в разных частях изображения.
  Признак, обнаруживаемый скрытым нейроном
  - это некая входящая последовательность,
  приводящая к активации нейрона:
  возможно, край изображения, или некая форма.
  Чтобы понять, почему это имеет смысл,
  допустим, что наши веса и смещение таковы,
  что скрытый нейрон может распознать,
  предположим, вертикальную грань в определённом локальном рецептивном поле.
  Эта способность, вероятно, окажется полезной и в других местах изображения.
  Поэтому полезно применять один и тот же детектор признаков
  по всей площади изображения.
  Говоря более абстрактно,
  СНС хорошо приспособлены к трансляционной инвариантности изображений:
  передвиньте изображение, к примеру, кота, немного в сторону,
  и оно всё равно останется изображением кота.
  Правда, изображения из задачи классификации цифр MNIST
  все отцентрованы и нормализованы по размеру.
  Поэтому у MNIST меньше трансляционной инвариантности,
  чем у случайных картинок.
  И всё же, такие признаки, как грани и углы,
  вероятно, окажутся полезными по всей поверхности входящего изображения.
  
  По этой причине иногда мы называем сопоставление входящего слоя и скрытого слоя
  картой признаков.
  Веса, определяющие карту признаков, мы называем общими весами.
  А смещение, определяющее карту признаков - общим смещением.
  Часто говорят, что общие веса и смещение определяют ядро [kernel] или фильтр.
  Но в литературе люди иногда используют эти термины немного по другому поводу,
  и поэтому я не буду сильно углубляться в терминологию;
  лучше давайте посмотрим на несколько конкретных примеров.
  
  Описанная мною структура сети способна распознать
  только локализованный признак одного вида.
  Чтобы распознавать изображения, нам понадобится больше карт признаков.
  Поэтому законченный свёрточный слой состоит
  из нескольких различных карт признаков:
  
  .......
  
  В примере показано 3 карты признаков.
  Каждая карта определяется набором из общих весов 5х5 и одним общим смещением.
  В итоге такая сеть может распознать три разных типа признаков,
  и каждый признак она сможет найти в любой части изображения.
  
  Три карты признаков я нарисовал для простоты.
  На практике же СНС могут использовать больше
  (возможно, гораздо больше) карт признаков.
  Одна из ранних СНС, LeNet-5, использовала 6 карт признаков,
  каждая из которых была связана с рецептивным полем 5х5,
  для распознавания цифр MNIST.
  Поэтому приведённый выше пример очень похож на LeNet-5.
  В примерах, которые мы будем самостоятельно разрабатывать далее,
  мы будем использовать свёрточные слои, содержащие по 20 и 40 карт признаков.
  Давайте быстренько посмотрим на те признаки, что мы изучим:
  
  ........
  
  Эти 20 изображений соответствуют 20 различным картам признаков
  (фильтрам, или ядрам).
  Каждая карта представляется изображением 5х5,
  соответствующим 5х5 весам локального рецептивного поля.
  Белые пиксели означают малый (обычно, более отрицательный) вес,
  и на соответствующие им пиксели карта признаков реагирует меньше.
  Тёмные пиксели означают больший вес,
  и на соответствующие им пиксели карта признаков реагирует больше.
  Очень грубо говоря, эти изображения демонстрируют те признаки,
  на которые реагирует свёрточный слой.
  
  Какие выводы можно сделать на основе этих карт признаков?
  Пространственные структуры здесь, очевидно, появились не случайным образом
  - у многих признаков видно явные светлые и тёмные участки.
  Это говорит о том, что наша сеть действительно обучается чему-то,
  связанному с пространственными структурами.
  Однако кроме этого достаточно сложно понять, что это за признаки.
  Мы явно не изучаем, допустим, фильтры Габора,
  которые использовались во многих традиционных подходах к распознаванию образов.
  На самом деле сейчас проводится большая работа,
  связанная с тем, чтобы лучше понять, какие именно признаки изучают СНС.
  Если вам это интересно, рекомендую начать с работы 2013 года.
  http://arxiv.org/abs/1311.2901
  
  Большое преимущество общих весов и смещений состоит в том,
  что это кардинально уменьшает количество параметров, имеющихся у СНС.
  Для каждой карты признаков нам понадобится 5?5=25 общих весов
  и одно общее смещение.
  Поэтому для каждой карты признаков требуется 26 параметров.
  Если у нас имеется 20 карт признаков,
  то всего у нас будет 20*26=520 параметров, определяющих свёрточный слой.
  Для сравнения, предположим, что у нас есть
  полносвязный первый слой с 28*28=784 входящими нейронами
  и относительно скромные 30 скрытых нейронов
  - такую схему мы использовали ранее во множестве примеров.
  Получается 784*30 весов, плюс 30 смещений, итого 23 550 параметров.
  Иначе говоря, у полносвязного слоя будет более чем 40 раз больше параметров,
  чем у свёрточного.
  
  Конечно, мы не можем напрямую сравнивать количество параметров,
  поскольку эти две модели различаются кардинальным образом.
  Но интуитивно кажется,
  что использование трансляционной инвариантности свёрточным слоем
  уменьшает количество параметров, необходимых для достижения эффективности,
  сравнимой с таковой у полносвязной модели.
  А это, в свою очередь, приведёт к ускорению обучения свёрточной модели,
  и в итоге поможет нам создать более глубокие сети при помощи свёрточных слоёв.
  
  Кстати, название <свёрточные> происходит от операции в уравнении (125),
  которую иногда называют свёрткой.
  Точнее, иногда люди записывают это уравнение, как a1=?(b+w?a0),
  где a1 обозначает набор выходных активаций одной карты признаков,
  a0 - набор входных активаций, а * называется операцией свёртки.
  Мы не будем глубоко зарываться в математику свёрток,
  поэтому вам не нужно особенно беспокоиться по поводу этой связи.
  Но просто стоит знать, откуда взялось название.
  
  Пулинговые слои
  
  Кроме описанных свёрточных слоёв в СНС есть ещё и пулинговые слои.
  Они обычно используются сразу после свёрточных.
  Они занимаются тем, что упрощают информацию с выхода свёрточного слоя.
  
  Здесь я использую фразу <карта признаков> не в значении функции,
  вычисляемой свёрточным слоем,
  а для обозначения активации выхода скрытых нейронов слоя.
  Такое вольное использование терминов часто встречается
  в исследовательской литературе.
  
  Пулинговый слой принимает выход каждой карты признаков свёрточного слоя
  и готовит сжатую карту признаков.
  К примеру, каждый элемент пулингового слоя может просуммировать участок
  из, допустим, 2х2 нейронов предыдущего слоя.
  Конкретный пример: одна распространённая процедура пулинга известна,
  как макс-пулинг.
  В макс-пулинге элемент пулинга просто выдаёт максимальную активацию
  из участка 2х2, как показано на диаграмме:
  
  .......
  
  Поскольку выход нейронов свёрточного слоя даёт 24х24 значения,
  после пулинга мы получим 12х12 нейронов.
  
  Как упомянуто выше, свёрточный слой обычно подразумевает нечто большее,
  чем единственная карта признаков.
  Мы применяем макс-пулинг к каждой карте признаков по отдельности.
  Так что, если у нас есть три карты признаков,
  комбинированные свёрточные и макс-пулинговые слои будут выглядеть так:
  
  .....
  
  Макс-пулинг можно представить себе, как способ сети спросить,
  есть ли данный признак в каком-либо месте изображения.
  А затем она отбрасывает информацию о его точном расположении.
  Интуитивно понятно, что когда признак найден,
  то его точное расположение уже не так важно,
  как его примерное расположение относительно других признаков.
  Преимущество состоит в том,
  что количество признаков, полученных при помощи пулинга,
  оказывается гораздо меньшим,
  и это помогает уменьшить количество параметров, требуемых в следующих слоях.
  
  Макс-пулинг - не единственная технология пулинга.
  Ещё один распространённый подход известен, как L2-пулинг.
  В нём вместо того, чтобы взять максимальную активацию региона нейронов 2х2,
  мы берём квадратный корень из суммы квадратов активаций региона 2х2.
  Детали подходов отличаются, но интуитивно он похож на макс-пулинг:
  L2-пулинг - это способ сжатия информации со свёрточного слоя.
  На практике часто используются обе технологии.
  Иногда люди используют другие типы пулинга.
  Если вы изо всех сил стараетесь оптимизировать качество работы сети,
  вы можете использовать подтверждающие данные для сравнения
  нескольких разных подходов к пулингу,
  и выбрать наилучший.
  Но мы не будем беспокоиться насчёт настолько подробной оптимизации.
  
  Суммируя
  
  Теперь мы можем свести всю информацию вместе и получить полноценную СНС.
  Она похожа на недавно рассмотренную нами архитектуру,
  однако у неё есть дополнительный слой из 10 выходных нейронов,
  соответствующих 10 возможным значениям цифр MNIST ('0', '1', '2',..):
  
  .......
  
  Сеть начинает с 28х28 входных нейронов,
  используемых для кодирования интенсивности пикселей изображения MNIST.
  После этого идёт свёрточный слой,
  использующий локальные рецептивные поля 5х5 и 3 карты признаков.
  В итоге получается слой из 3х24х24 скрытых нейронов признаков.
  Следующий шаг - слой макс-пулинга, применяемый к участкам 2х2,
  на каждой из трёх карт признаков.
  В итоге получается слой из 3х12х12 скрытых нейронов признаков.
  
  Последний слой связей в сети полносвязный.
  То есть, он связывает каждый нейрон слоя макс-пулинга
  с каждым из 10 выходных нейронов.
  Такую полносвязную архитектуру мы использовали ранее.
  Обратите внимание, что на диаграмме выше
  я для простоты использовал одну стрелочку, не показывая всех связей.
  Вы легко можете представить себе их все.
  
  Такая свёрточная архитектура сильно отличается от тех,
  что мы использовали ранее.
  Однако общая картина схожа:
  сеть, состоящая из множества простых элементов,
  чьё поведение определяется весами и смещениями.
  Цель остаётся той же:
  использовать обучающие данные для обучения сети весам и смещениям,
  чтобы сеть хорошо классифицировала входящие цифры.
  
  В частности, как и в предыдущих главах,
  мы будем обучать нашу сеть при помощи стохастического градиентного спуска
  и обратного распространения.
  Процедура идёт практически так же, как и раньше.
  Однако нам нужно внести несколько изменений в процедуру обратного распространения.
  Дело в том, что наши производные для обратного распространения
  предназначались для сети с полностью связанными слоями.
  К счастью, изменить производные для свёрточных и макс-пулинговых слоёв
  весьма просто.
  Если вам хочется разобраться в деталях,
  приглашаю вас попробовать решить следующую задачу.
  Предупрежу, что на неё уйдёт достаточно много времени,
  если только вы не разобрались досконально
  в ранних вопросах дифференцирования обратного распространения.
  
  Задача
  
  Обратное распространение в свёрточной сети.
  Главными уравнениями обратного распространения в сети
  с полностью связанными слоями будут (BP1)-(BP4).
  Допустим, наша сеть содержит свёрточный слой, слой макс-пулинга
  и полностью связанный выходной слой, как в описанной выше сети.
  Как нужно изменить уравнения обратного распространения?
  //// Опять я не могу сообразить, как решить эту задачу.
  //// Наверно, опять придется консультироваться у Copilot.
  
  > Copilot 21:12
  
  > Алгоритм обратного распространения ошибки (Backpropagation)
  > для сверточных нейросетей (CNN) отличается от того,
  > который используется в полносвязных сетях
  > (Fully Connected Networks, FCN).
  > Основное отличие заключается в способе распространения градиентов
  > и обновления весов.
  
  > В сверточных слоях, вместо обычных нейронов,
  > используются сверточные фильтры,
  > которые применяются к входным данным для выявления определенных признаков.
  > При обратном распространении ошибки в CNN,
  > градиенты ошибки распространяются обратно через сеть,
  > и веса сверточных фильтров обновляются таким образом,
  > чтобы минимизировать ошибку.
  
  > Для сверточных слоев, градиент ошибки для каждого фильтра вычисляется
  > с использованием операции свертки,
  > а не простого умножения матриц, как в FCN.
  > Это означает, что градиенты распространяются обратно через слои
  > таким образом, что каждый элемент карты признаков
  > получает вклад от всех пикселей входного изображения,
  > которые были "затронуты" этим фильтром во время прямого прохода.
  
  > Кроме того, поскольку один и тот же фильтр применяется ко всему изображению,
  > обновление весов в сверточном слое также включает в себя
  > суммирование градиентов по всем позициям,
  > где фильтр был применен.
  > Это приводит к тому, что веса фильтра обновляются на основе информации,
  > полученной со всего изображения,
  > а не только с одного нейрона, как в FCN.
  
  > В результате, обратное распространение в CNN
  > учитывает пространственную структуру данных,
  > что позволяет эффективно обучать сеть на задачах,
  > связанных с изображениями и другими видами данных,
  > имеющими пространственную структуру.
  > Это одна из причин, почему CNN так хорошо работают
  > для задач компьютерного зрения.
  
  Свёрточные нейронные сети на практике
  
  Мы обсудили идеи, лежащие в основе СНС.
  Давайте посмотрим, как они работают на практике, реализовав некоторые СНС,
  и применив их к задаче классификации цифр MNIST.
  
  ......
  
  
  Чтобы получить базовые результаты для сравнения,
  начнём с неглубокой архитектуры с одним скрытым слоем,
  содержащим 100 скрытых нейронов.
  Мы будем обучаться 60 эпох, использовать скорость обучения ?=0,1,
  размер мини-пакета 10,
  и будем учиться без регуляризации.
  
  В данном разделе я задаю конкретное количество эпох обучения.
  Я делаю это для ясности в процессе обучения.
  На практике полезно использовать ранние остановки,
  отслеживая точность подтверждающего набора, и останавливать обучение,
  когда мы убеждаемся в том, что точность подтверждения перестаёт улучшаться:
  
  ......
  
  Наилучшая точность классификации составила 97,80%.
  Это точность классификации test_data, оценённая по обучающей эпохе,
  в которой мы получили наилучшую точность классификации данных из validation_data.
  Использование подтверждающих данных для принятия решения об оценке точности
  помогает избежать переобучения.
  Далее мы так и будем поступать.
  Ваши результаты могут немного отличаться,
  поскольку веса и смещения сети инициализируются случайным образом.
  
  Точность в 97,80% довольно близка к точности в 98,04%, полученной в главе 3,
  с использованием сходной архитектуры сети и гиперпараметров обучения.
  В частности, в обоих примерах используются неглубокие сети с одним скрытым слоем,
  содержащим 100 скрытых нейронов.
  Обе сети обучаются 60 эпох с размером мини-пакета 10 и скоростью обучения ?=0,1.
  
  Однако в более ранней сети имелись два отличия.
  Во-первых, мы проводили регуляризацию, чтобы помочь уменьшить влияние переобучения.
  Регуляризация текущей сети улучшает точность, но очень ненамного,
  поэтому мы пока не будем думать об этом.
  Во-вторых, хотя последний слой ранней сети использовал сигмоидные активации
  и функцию стоимости с перекрёстной энтропией,
  текущая сеть использует последний слой с softmax,
  и логарифмическую функцию правдоподобия в качестве функции стоимости.
  Как описано в главе 3, это не крупное изменение.
  Я перешёл с одного на другое не по какой-то глубокой причине
  - в основном потому, что softmax и логарифмическая функция правдоподобия
  чаще используется в современных сетях для классификации изображений.
  
  Можем ли мы улучшить результаты, используя более глубокую архитектуру сети?
  
  Начнём со вставки свёрточного слоя, в самом начале сети.
  Мы будем использовать локальное рецептивное поле 5х5, шаг длиной 1 и 20 карт признаков.
  Мы также вставим слой макс-пулинга,
  комбинирующий признаки при помощи окон пулинга 2х2.
  Так что общая архитектура сети будет выглядеть похоже на ту,
  что мы обсуждали в предыдущем разделе,
  но с дополнительным полносвязным слоем:
  
  .......
  
  В этой архитектуре свёрточный и пулинговый слой
  обучаются локальной пространственной структуре,
  содержащейся во входящей обучающей картинке,
  а последний, полносвязный слой обучается уже на более абстрактном уровне,
  интегрируя глобальную информацию со всего изображения.
  Это часто применяющаяся схема в СНС.
  
  Давайте обучим такую сеть, и посмотрим, как она себя поведёт.
  
  ........
  
  Мы получаем точность в 98,78%,
  что значительно выше любого из предыдущих результатов.
  Мы уменьшили ошибку больше, чем на треть - великолепный результат.
  
  Описывая структуру сети, я считал свёрточные и пулинговые слои единым слоем.
  Рассматривать их, как отдельные слои, или как единый слой
  - вопрос предпочтений.
  
  ......
  
  Упражнение
  
  Какую точность классификации мы получим, если опустим полносвязный слой,
  и будем использовать только свёрточный/пулинговый слой и слой softmax?
  Помогает ли включение полносвязного слоя?
  
  Можем ли мы улучшить результат в 98,78%?
  
  Попробуем вставить второй свёрточный/пулинговый слой.
  Мы вставим его между существующим свёрточным/пулинговым
  и полносвязным скрытым слоями.
  Мы снова используем локальное рецептивное поле 5х5 и пул по участкам 2х2.
  Посмотрим, что случится, когда мы обучим сеть
  с примерно такими же гиперпараметрами, что и ранее:
  
  ......
  
  И вновь у нас улучшение: теперь мы получаем точность в 99,06%!
  
  На текущий момент возникает два естественных вопроса.
  Первый: а что вообще означает применение второго свёрточного/пулингового слоя?
  Вы можете считать, что у второго свёрточного/пулингового слоя на вход приходят
  <изображения> размером 12х12,
  чьи <пиксели> представляют наличие (или отсутствие)
  определенных локализованных признаков в изначальной входящей картинке.
  То есть, можно считать, что на вход этому слою приходит
  некий вариант изначальной входящей картинки.
  Это будет более абстрактная и сжатая версия,
  но у неё всё равно есть достаточно пространственной структуры,
  поэтому имеет смысл использовать для её обработки
  второй свёрточно/пулинговый слой.
  
  Приятная точка зрения, но она порождает второй вопрос.
  На выходе с предыдущего слоя получается 20 отдельных КП,
  поэтому на второй свёрточно/пулинговый слой приходит 20х12х12 групп входных данных.
  Получается, что у нас есть как бы 20 отдельных изображений,
  входящих на свёрточно/пулинговый слой, а не одно изображение,
  как это было в случае с первым свёрточно/пулинговым слоем.
  Как же нейроны из второго свёрточно/пулингового слоя
  должны реагировать на множество этих входящих изображений?
  На самом деле мы просто позволим каждому нейрону этого слоя
  обучаться на основе всех 20х5х5 входящих в его локальное рецептивное поле нейронов.
  Говоря менее формальным языком,
  у детекторов признаков во втором свёрточно/пулинговом слое
  будет доступ ко всем признакам первого слоя,
  но только в рамках их конкретных локальных рецептивных полей.
  
  Кстати, такая проблема возникла бы и у первого слоя,
  если бы изображения были цветными.
  В данном случае у нас было бы 3 входных признака на каждый пиксель,
  соответствующих красному, зелёному и синему каналам оригинальной картинки.
  И мы бы тогда тоже дали детекторам признаков доступ ко всей цветовой информации,
  но только в рамках их локального рецептивного поля.
  
  Задача
  
  Использование функции активации в виде гиперболического тангенса.
  Ранее в этой книге я уже несколько раз упоминал свидетельства в пользу того,
  что функция tanh, гиперболический тангенс,
  может лучше подойти на роль функции активации, чем сигмоида.
  Мы ничего с этим не делали, поскольку у нас и с сигмоидой был хороший прогресс.
  Но давайте попробуем провести несколько экспериментов с tanh
  в качестве функции активации.
  Попробуйте обучить сеть с танг-активацией со свёрточными и полносвязными слоями
  (вы можете передать activation_fn=tanh как параметр
  классам ConvPoolLayer и FullyConnectedLayer).
  Начните с тех же гиперпараметров, что были у сигмоидной сети,
  но обучайте сеть 20 эпох, а не 60.
  Как ведёт себя сеть?
  Что будет, если продолжить до 60-й эпохи?
  Попробуйте построить график точности подтверждения работы по эпохам
  для тангенса и сигмоиды, вплоть до 60-й эпохи.
  Если ваши результаты будут похожими на мои,
  вы обнаружите, что сеть на основе тангенса обучается чуть быстрее,
  но итоговая точность обеих сетей одинаковая.
  Можете объяснить, почему так происходит?
  //// А кто может? Может быть итоговая точность
  //// ВООБЩЕ от функции активации мало зависит,
  //// а зависит от чего-то совсем иного.
  //// Например, от метода обучения?
  Можно ли достичь той же скорости обучения при помощи сигмоиды
  - например, изменив скорость обучения или через масштабирование
  (вспомните, что ?(z)=(1+tanh(z/2))/2)?
  Попробуйте пять-шесть разных гиперпараметров или архитектур сети,
  поищите, где тангенс может опережать сигмоиду.
  Отмечу, что эта задача открытая.
  //// Т.е. другие исследователи или проигнорировали эту задачу,
  //// или, скорее всего, получили неоднозначные результаты.
  //// Причем, уже на достаточно большом промежутке времени.
  //// И о чем это может говорить?
  Лично я не нашёл каких-то серьёзных преимуществ в переходе на тангенс,
  хотя я не проводил всеобъемлющих экспериментов,
  и, возможно, вы их найдёте.
  В любом случае, скоро мы найдём преимущество
  в переходе на выпрямленную линейную функцию активации,
  поэтому больше не будем углубляться в вопрос с гиперболическим тангенсом.
  //// Т.е. эксперименты с "тангенсом" это просто иллюстрация того,
  //// что некие "ключевые элементы" архитектуры, могут и не быть "ключевыми"?
  
  Использование выпрямленных линейных элементов
  
  Разработанная нами на текущий момент сеть является одним из вариантов сетей,
  использованных в плодотворной работе 1998 года,
  в которой была впервые представлена задача MNIST - сети под названием LeNet-5.
  Это хорошая основа для дальнейших экспериментов,
  для улучшения понимания вопроса и интуиции.
  В частности, существует множество способов,
  которыми мы можем изменять нашу сеть в поисках способов улучшения результатов.
  
  Вначале давайте поменяем наши нейроны так,
  чтобы вместо использования сигмоидной функции активации
  мы могли использовать выпрямленные линейные элементы (ReLU).
  То есть, мы будем использовать функцию активации вида f(z) ? max(0,z).
  Мы будем обучать сеть 60 эпох, со скоростью ?=0,03.
  Я также обнаружил, что немного удобнее использовать регуляризацию L2
  с параметром регуляризации ?=0.1:
  
  .......
  
  Я получил точность классификации в 99,23%.
  Скромное улучшение по сравнению с результатами сигмоиды (99,06%).
  Однако во всех моих экспериментах я обнаруживал,
  что сети, основанные на ReLU, с завидным постоянством опережали сети,
  основанные на сигмоидной функции активации.
  Судя по всему, в переходе на ReLU для решения данной задачи
  существуют реальные преимущества.
  
  Из-за чего функция активации ReLU работает лучше,
  чем сигмоида или гиперболический тангенс?
  В настоящий момент мы не особенно хорошо понимаем это.
  //// Чем мне нравится этот автор - тем, что он не стесняется
  //// признать ограниченность уровня существующих знаний в "нейронауках",
  //// о чем другие авторы "почему-то" даже забывают упомянуть.
  Обычно говорят о том, что функция max(0,z) не насыщается при больших z,
  в отличие от сигмоидных нейронов,
  и это помогает ReLU-нейронам продолжать обучение.
  Не спорю,
  но такое оправдание нельзя назвать всеобъемлющим,
  это просто некое наблюдение
  (напомню, что насыщение мы обсуждали в главе 2).
  
  ReLU начали активно использовать в последние несколько лет.
  Их взяли на вооружение по эмпирическим причинам:
  некоторые люди попробовали ReLU,
  часто просто на основании предчувствий или эвристических аргументов.
  //// Как много такой "интуиции" в "нейронауках".
  Они получили хорошие результаты, и практика распространилась.
  В идеальном мире у нас была бы теория, говорящая нам о том,
  для каких приложений какие функции активации подойдут лучше.
  Но пока что нам ещё предстоит долгий путь до такой ситуации.
  Я вовсе не удивлюсь, если дальнейшие улучшения работы сетей
  можно будет получить, выбрав какую-нибудь
  ещё более подходящую функцию активации.
  Также я ожидаю, что в ближайшие десятилетия будет выработана
  хорошая теория функций активации.
  Но сегодня нам приходится полагаться на плохо изученные эмпирические правила
  и опыт.
  
  Расширение обучающих данных
  
  Ещё один способ, который, возможно, может помочь нам улучшить результаты
  - это алгоритмически расширить обучающие данные.
  Простейший способ расширения обучающих данных
  - сдвиг каждой обучающей картинки на один пиксель, вверх, вниз, вправо или влево.
  Это можно сделать, запустив программу expand_mnist.py.
  
  $ python expand_mnist.py
  
  Запуск программы превращает 50 000 обучающих изображений MNIST
  в расширенный набор из 250 000 обучающих изображений.
  Затем мы можем использовать эти обучающие изображения для обучения сети.
  Мы будем использовать ту же сеть, что и ранее, с ReLU.
  В моих первых экспериментах я уменьшал количество эпох обучения
  - это имело смысл, ведь у нас есть в 5 раз больше обучающих данных.
  Однако расширение набора данных значительно уменьшило эффект переобучения.
  Поэтому, проведя несколько экспериментов, я вернулся к количеству эпох 60.
  В любом случае, давайте обучать:
  
  .......
  
  Используя расширенные обучающие данные, я получил точность в 99.37%.
  Такое почти тривиальное изменение даёт значительное улучшение
  в точности классификации.
  И, как мы обсуждали ранее, алгоритмическое расширение данных можно развивать
  и далее.
  Просто, чтобы напомнить вам:
  в 2003 году Симард, Штейнкраус и Платт улучшили точность работы своей сети
  до 99,6%.
  Их сеть была похожа на нашу, они использовали два свёрточно/пулинговых слоя,
  за которым следовал полносвязный слой со 100 нейронами.
  Детали их архитектуры различались
  - у них не было возможности использовать преимущество ReLU,
  к примеру - однако ключом к улучшению качества работы
  было расширение обучающих данных.
  Они достигли этого поворотом, переносом и искажением обучающих изображений MNIST.
  Также они разработали процесс <эластичного искажения>,
  эмулируя случайные колебания мускулов руки при письме.
  Скомбинировав все эти процессы,
  они значительно увеличили эффективный объём их базы обучающих данных,
  и за счёт этого достигли точности в 99,6%.
  
  Задача
  
  Идея свёрточных слоёв состоит в том,
  чтобы работать вне зависимости от местоположения на изображении.
  Но тогда может показаться странным, что наша сеть лучше обучается,
  когда мы просто сдвигаем входные изображения.
  Можете ли вы объяснить, почему на самом деле это вполне разумно?
  //// У меня каких-то обоснованных идей в русле изложенной трактовки
  //// работы сверточных слоев как-то не появилось. А у Вас?
  
  Добавление дополнительного полносвязного слоя
  
  А можно ли ещё улучшить ситуацию?
  Одна из возможностей - использовать точно такую же процедуру,
  однако при этом увеличить размер полносвязного слоя.
  Я запускал программу с 300 и с 1000 нейронов,
  и получал результаты в 99,46% and 99,43% соответственно.
  Это интересно, но не особенно убедительно превосходит предыдущий результат (99,37%).
  
  Что насчёт добавления дополнительного полносвязного слоя?
  Давайте попробуем добавить дополнительный полносвязный слой,
  чтобы у нас было два скрытых полносвязных слоя по 100 нейронов:
  
  ........
  
  Таким образом я достиг точности проверки в 99,43%.
  Расширенная сеть снова не сильно улучшила показатели.
  Проведя похожие эксперименты с полносвязными слоями на 300 и 100 нейронов,
  я получил точность в 99,48% и 99,47%.
  Вдохновляющее, но не похоже на реальный выигрыш.
  
  Что происходит?
  Неужели расширенные или дополнительные полносвязные слои
  не помогают в решении задачи MNIST?
  Или же наша сеть может достичь лучшего,
  но мы развиваем её не в ту сторону?
  Может быть, мы могли, например,
  использовать более жёсткую регуляризацию для уменьшения переобучения.
  Одна из возможностей - техника исключения [dropout], упомянутая в главе 3.
  Вспомним, что базовая идея исключения
  - удалить случайным образом отдельные активации при обучении сети.
  В итоге модель становится более устойчивой к потере отдельных свидетельств,
  и поэтому менее вероятно, что она будет полагаться
  на какие-то мелкие нестандартные особенности обучающих данных.
  Давайте попробуем применить исключение к последнему полносвязному слою:
  
  ......
  
  Используя такой подход, мы достигаем точности в 99,60%,
  что значительно лучше предыдущих, особенно нашей базовой оценки
  - сети со 100 скрытыми нейронами, дающей точность в 99,37%.
  //// Жалко, что в данном месте автор не провел достаточно глубокое изучение
  //// этого результата, ограничившись простой констатацией,
  //// что что-то "почему-то" улучшилось.
  
  Тут стоит отметить два изменения.
  
  Во-первых, я уменьшил количество эпох обучения до 40:
  исключение уменьшает переобучение, и мы учимся быстрее.
  
  Во-вторых, в полносвязных скрытых слоях содержится 1000 нейронов, а не 100,
  как раньше. Конечно, исключение, по сути,
  устраняет многие нейроны во время обучения,
  поэтому стоит ожидать некоего расширения.
  На самом деле, я проводил эксперименты с 300 и 1000 нейронов,
  и получил чуть более качественное подтверждение в случае с 1000 нейронов.
  
  Использование ансамбля сетей
  
  Лёгкий способ улучшить эффективность - создать несколько нейросетей,
  а потом заставить их голосовать за лучшую классификацию.
  Допустим, к примеру, что мы обучили 5 разных НС
  с использованием вышеуказанного рецепта,
  и каждая из них достигла точности, близкой к 99,6%.
  И хотя все сети покажут сходную точность,
  у них могут быть разные ошибки из-за разной случайной инициализации.
  Разумно предположить, что если 5 НС проголосуют,
  их общая классификация будет лучше, чем у любой сети в отдельности.
  //// А вот это не факт. Так как они все обучались, в принципе,
  //// на одном датасете, да и структуры, возможно, имеют похожие,
  //// то "разумно предположить", что и ошибки этого ансамбля
  //// будут сильно скоррелированы.
  
  Звучит слишком хорошо, чтобы быть правдой,
  но сборка подобных ансамблей - распространённый трюк как для НС,
  так и для других техник МО.
  И он на самом деле даёт улучшение эффективности:
  мы получаем точность в 99,67%.
  Иначе говоря, наш ансамбль сетей правильно классифицирует
  все 10 000 проверочных изображений, за исключением 33.
  //// Т.е. за уменьшение ошибки, в лучшем случае на четверть
  //// заплатили пятикратным увеличением как размера системы,
  //// так и временем ее обучения и требуемых вычислительных ресурсов.
  //// И "трех девяток" все равно не добились.
  //// Т.е. "ансамбль" в данном случае явно не совсем удачно "сыгран".
  
  Оставшиеся ошибки показаны ниже.
  Метка в правом верхнем углу - правильная классификация согласно данным MNIST,
  а в правом нижнем - метка, полученная ансамблем сетей:
  
  ......
  
  Стоит подробнее остановиться на изображениях.
  Первые две цифры, 6 и 5 - реальные ошибки нашего ансамбля.
  Однако их можно понять, такую ошибку мог сделать и человек.
  Эта 6 реально очень похожа на 0, а 5 очень похожа на 3.
  Третья картинка, якобы 8, действительно больше похожа на 9.
  Я встаю на сторону ансамбля сетей:
  думаю, что он справился с работой лучше, чем человек, написавший эту цифру.
  С другой стороны, четвёртое изображение, 6,
  реально неправильно классифицирована сетями.
  //// И это, реально, серьезная проблема,
  //// так как "обобщающая способность" нейросети не смогла "подняться"
  //// до ИДЕИ обобщенной цифры и, по факту,
  //// способна опознать просто нечто "усредненное".
  
  И так далее. В большинстве случаев решение сети выглядит правдоподобным,
  а в некоторых случаях они лучше классифицировали цифру,
  чем человек её написал.
  В целом наши сети демонстрируют исключительную эффективность,
  особенно если вспомнить, что они правильно классифицировали 9967 изображений,
  которые мы здесь не приводим.
  В таком контексте несколько явных ошибок можно понять.
  Даже осторожный человек иногда ошибается.
  Поэтому я могу ожидать лучшего результата
  только от чрезвычайно аккуратного и методичного человека.
  Наша сеть приближается к эффективности человека.
  
  Почему мы применили исключение только к полносвязным слоям
  
  Если внимательно посмотреть на приведённый выше код,
  вы увидите, что исключение мы применили только к полносвязным слоям сети,
  но не к свёрточным.
  В принципе можно применить схожую процедуру и к свёрточным слоям.
  Но в этом нет нужды:
  у свёрточных слоёв есть значительное встроенное сопротивление к переобучению.
  Всё потому, что общие веса заставляют свёрточные фильтры
  обучаться по всей картинке сразу.
  //// Это интересное замечание в том плане,
  //// что если его продумывать дальше,
  //// то, наверно, можно сформулировать какие-то не совсем тривиальные
  //// рекомендации по применению дропаута.
  //// Или даже дать какие-то подсказки по корректировке всего метода обучения.
  В итоге они с меньшей вероятностью споткнуться о какие-то локальные искажения
  в обучающих данных.
  Поэтому нет особой нужды применять к ним другие регуляризаторы,
  типа исключения.
  
  Двигаемся дальше
  
  Можно улучшить эффективность решения задачи MNIST ещё больше.
  Родриго Бененсон собрал информативную табличку,
  где показан прогресс сквозь года, и приведены ссылки на работы.
  Многие из работ используют ГСС примерно так же, как их использовали мы.
  Если вы пороетесь в работах, вы найдёте много интересных техник,
  и вам может понравиться реализовывать какие-то из них.
  В таком случае разумно будет начать их реализацию с простой сети,
  которую можно быстро обучать,
  и это поможет вам быстрее начать понимать происходящее.
  
  По большей части я не буду пытаться обозревать недавние работы.
  Но не могу удержаться от одного исключения.
  Речь идёт об одной работе 2010 года.
  Мне нравится в ней её простота.
  Сеть - многослойная, и использует только полносвязные слои (без свёрток).
  В наиболее успешной их сети есть скрытые слои,
  содержащие 2500, 2000, 1500, 1000 и 500 нейронов соответственно.
  Они использовали схожие идеи для расширения обучающих данных.
  Но кроме этого, они применили ещё несколько трюков,
  включая отсутствие свёрточных слоёв:
  это была простейшая, ванильная сеть,
   которую при должном терпении и наличии подходящих компьютерных мощностей
  могли обучить ещё в 1980-х (если бы тогда существовал набор MNIST).
  Они достигли точности классификации в 99,65%,
  //// Т.е. точность в "три девятки" пока реально мало достижима
  //// при самых различных ухищрениях при обучении и масштабах сети.
  что примерно совпадает с нашей.
  Главное в их работе - использование очень крупной и глубокой сети,
  и использование GPU для ускорения обучения.
  Это позволило им обучаться множество эпох.
  Они также воспользовались большой длиной промежутков обучения,
  и постепенно уменьшали скорость обучения с 10-3 до 10-6.
  Пытаться достичь подобных результатов с такой архитектурой, как у них
  - интересное упражнение.
  
  Почему у нас получается обучаться?
  
  В предыдущей главе мы увидели фундаментальные препятствия
  обучению глубоких многослойных НС.
  В частности, мы видели, что градиент становится очень нестабильным:
  при продвижении от выходного слоя к предыдущим градиент склонен
  либо к исчезновению (проблема исчезающего градиента)
  или к взрывному росту (проблема взрывного роста градиента).
  Поскольку градиент - это сигнал, используемый нами для обучения,
  это порождает проблемы.
  
  Как нам удалось их избежать?
  
  Ответ, естественно, такой:
  нам не удалось их избежать.
  Вместо этого мы сделали несколько вещей, позволившие нам продолжать работу,
  несмотря на это.
  В частности:
  
  (1) использование свёрточных слоёв
  сильно уменьшает количество содержащихся в них параметров,
  сильно облегчая проблему обучения;
  
  (2) использование более эффективных техник регуляризации
  (исключения и свёрточных слоёв);
  
  (3) использование ReLU вместо сигмоидных нейронов для ускорения обучения
  - эмпирически до 3-5 раз;
  
  (4) использование GPU и возможность обучаться в течение долгого времени.
  В частности, в последних экспериментах мы обучались 40 эпох,
  используя набор данных, в 5 раз больший, чем стандартные обучающие данные MNIST.
  Ранее в книге мы в основном обучались 30 эпох,
  используя стандартные обучающие данные.
  Комбинация факторов (3) и (4) даёт такой эффект,
  будто бы мы обучались в 30 раз дольше, чем ранее.
  
  Вы, наверное, скажете
  <И это всё? Это всё, что нужно для обучения глубоких нейросетей?
  А из-за чего тогда сыр-бор загорелся?>
  
  Мы, конечно, использовали и другие идеи:
  
  достаточно большие наборы данных
  (чтобы помочь избежать переобучения);
  
  правильная функция стоимости
  (чтобы избежать замедления обучения);
  
  хорошая инициализация весов
  (также во избежание замедления обучения из-за насыщения нейронов);
  
  алгоритмическое расширение набора обучающих данных.
  
  Мы обсудили эти и другие идеи в предыдущих главах,
  и обычно у нас была возможность повторно использовать их
  с небольшими примечаниями и в этой главе.
  
  По всему видно, что это довольно простой набор идей.
  Простой, однако, способный на многое при использовании в комплексе.
  Оказалось, что начать работу с глубоким обучением было довольно легко!
  
  Ну а насколько же глубоки эти сети?
  
  Если считать свёрточно/пулинговые слои за один,
  то в нашей итоговой архитектуре есть 4 скрытых слоя.
  Заслуживает ли такая сеть звания глубокой?
  Естественно, ведь 4 скрытых слоя - это куда как больше, чем в неглубоких сетях,
  изучавшихся нами ранее.
  У большей части сетей было по одному скрытому слою, иногда - 2.
  С другой стороны, в современных передовых сетях
  иногда есть десятки скрытых слоёв.
  Иногда я встречал людей, считавших, что чем глубже сеть, тем лучше,
  и что если вы не используете достаточно большое количество скрытых слоёв,
  значит, на самом деле вы не занимаетесь глубоким обучением.
  Я так не считаю,
  в частности потому, что такой подход превращает определение глубокого обучения
  в процедуру, зависящую от сиюминутных результатов.
  Реальным прорывом в этой области была идея о практичности выхода
  за пределы сетей с одним-двумя скрытыми слоями,
  преобладавших в середине 2000-х.
  Это был реальный прорыв,
  открывший область исследований с более выразительными моделями.
  Ну а конкретное количество слоёв не представляет фундаментального интереса.
  Использование глубоких сетей - это инструмент для достижения других целей,
  например, улучшения точности классификации.
  
  Процедурный вопрос
  
  В данном разделе мы плавно перешли от неглубоких сетей с одним скрытым слоем
  до многослойных свёрточных сетей.
  Всё казалось так легко!
  Мы внесли изменение, и получили улучшение.
  Если вы начнёте экспериментировать,
  то гарантирую,
  что обычно всё будет идти не так гладко.
  Я представил вам причёсанный рассказ, опуская множество экспериментов,
  в том числе и неудачных.
  Надеюсь, что этот причёсанный рассказ поможет вам яснее понять базовые идеи.
  Но он рискует передать неполное впечатление.
  Получение хорошей, рабочей сети требует множества проб и ошибок,
  перемежаемых разочарованиями.
  На практике стоит ожидать огромного количества экспериментов.
  Для ускорения процесса вам может помочь информация из главы 3
  по поводу выбора гиперпараметров сети,
  а также, возможно, упомянутая там дополнительная литература.
  
  Код для наших свёрточных сетей
  
  .......
  
  Менее очевидно, как инициализировать веса и смещения в слое softmax
  - этого мы не обсуждали.
  Мы упоминали, что для сигмоидных слоёв веса нужно инициализировать
  соответствующим образом параметризированные нормальные случайные распределения.
  Но этот эвристический аргумент относился к сигмоидным нейронам
  (и, с небольшими поправками, к танг-нейронам).
  Однако нет особых причин для того, чтобы этот аргумент был применим к softmax-слоям.
  Поэтому нет каких-то причин, чтобы априори применять такую инициализацию снова.
  Вместо этого я инициализирую все веса и смещения в 0.
  Вариант спонтанный, но на практике работает неплохо.
  //// Очередная "интуитивная алхимия".
  
  ........
  
  //// Из комментариев.
  
  art_leo
  13 авг 2019 в 15:25
  
  Сколько не читал статей про СНС,
  так и ни разу не попалось полное объяснение работы этой СНС
  (или не там искал),
  а именно прохождения сигнала (прямого) на более глубоких слоях.
  Везде объяснение ограничивается только первым слоем
  и красивые картинки как выход слоя 1 попадает на вход слоя 2,
  выход слоя 2 на вход слоя 3 и т.д.
  
  Структура СНС (утрированно):
  
  1) входное изображение
  
  2) первый свёрточный слой (простые признаки) = 20 шт карт-признаков (например)
  
  3) второй свёрточный слой (сложные признаки) = 20 шт (например)
  
  Каждый фильтр (регистрирующий свой признак) из первого слоя
  на входе имеет входное изображение.
  
  Вопрос - что на входе имеет каждый фильтр из второго слоя?
  
  Если рассуждать по аналогии, то каждый фильтр второго слоя
  должен будет <пробежаться> по всем картам-признаков первого слоя?
  
  Итого получим
  20 фильтров (слой 2) х 20 карт-признаков (выход слоя 1) = 400 карт-признаков
  (выход слоя 2)?
  
  Особого смысла в таких связях скорее всего нет,
  т.к. разные признаки с первого слоя должны все-таки как-то комбинироваться
  в более сложные признаки на втором слое.
  
  Где-то промелькнуло, что (возможно) фильтр со второго слоя
  может иметь на входе сразу все карты-признаков (с первого слоя).
  Но как?
  
  В примере приводилась схема как крест (слой 2, сложный признак)
  собирается из двух отрезков (слой 1, простые признаки).
  
  Кто-то может разъяснить (на пальцах) как оно на самом деле?
  
  Как простые признаки комбинируются в более сложные на более глубоких слоях.
  
  Какую карту признаков первого слоя сканирует каждый фильтр второго слоя?
  
  Или ссылку на объяснение именно этого момента в структуре СНС.
  
  Спасибо!
  
  //// Интересно, что за 5 лет с момента написания этого комментария
  //// так никто и не захотел ответить на такой "элементарный" вопрос.
  
  .......
  
  //// Конец цитирования.
  
  При проработке этого материала меня не покидала мысль,
  что для специализированных структур типа сверточных слоев,
  метод обучения тоже должен быть каким-то специализированным.
  Но "имеем то, что имеем".
  Принципиально разные в работе структуры обучаются одним и тем же методом,
  и, обратите внимание,
  имеют на выходе принципиально мало отличающиеся результаты.
  Как-то это "сильно не афишируется",
  
  Но, может стоит, все-таки, обратить на это внимание?
  Может быть, разные структуры нужно и по-разному обучать?
  Собственно, именно такой видится цель всего этого модуля:
  попытаться найти более эффективные способы обучения нейросетей,
  и одним из естественных направлений такой работы это "специализация".
  Но для этого нужно понимать, чему именно нужно обучать
  те же самые вторые-третьи-четвертые сверточные слои,
  чтобы в них отражалась не "средняя температура по больнице",
  некая обобщенная оценка, сопоставимая с тем,
  что иногда называется "идеей"/"принципом" или, хотя бы, "силуэтом".
  
  
  =========
  
  13.05.2024 17:21
  
  Финальные аккорды учебника по глубокому обучению.
  В оглавление.
  
  Наконец-то добрался до заключительных разделов
  этого весьма качественного учебного "талмуда".
  И хотя большая часть этих глав уже практичесrи не актуальна,
  - за восемь лет с момента его написании в машинном обучении
  прошла целая эпоха и все прежние достижения в этой области многократно улучшены,
  а многие решения/системы уже вообще "пропали с экранов радаров".
  И даже вопрос о возможности реализации реального ИИ
  уже перешел в практическую плоскость.
  
  Но вот что интересно, основные проблемы глубокого обучения,
  честно отмеченные в этом материале, так и не были за это время решены.
  Вот их то я и считаю нужным отметить:
  
  "Нейросети и глубокое обучение: онлайн-учебник, глава 6, ч.2:
  недавний прогресс в распознавании изображений".
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/464039/.
  19 авг 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/chap6.html#recent_progress_in_image_recognition
  
  //// Начало цитирования.
  ......
  
  Этот раздел отличается от остальной части книги.
  В книге я фокусировался на предположительно долгоживущих идеях
  - обратном распространении, регуляризации, свёрточных сетях.
  Я пытался избегать результатов, считающихся модными на момент написания,
  чья долговременная ценность представлялась сомнительной.
  В науке подобные результаты чаще всего оказываются однодневками,
  быстро исчезают и не оказывают долговременного влияния.
  
  ........
  
  Другие задачи
  
  .......
  
  Возможно, я создал у вас впечатление парада победных
  и вдохновляющих результатов.
  Конечно, самые интересные отчёты касаются фундаментальных вещей,
  нам пока непонятных.
  К примеру, в работе 2013 года было показано,
  http://arxiv.org/abs/1312.6199
  что у НС имеются, по сути, слепые пятна.
  Посмотрите на изображения ниже.
  Слева - изображение из ImageNet,
  которое сеть исследователей классифицировала правильно.
  Справа - немного изменённое изображение
  (в середине показаны различия),
  которое сеть уже не смогла правильно распознать.
  И авторы обнаружили, что подобные <состязательные> изменения
  можно подобрать для любого изображения из базы,
  а не только для избранных.
  
  .......
  
  Неприятный результат.
  В работе использовалась сеть на основе того же кода, что и сеть KSH
  - то есть, именно такая сеть, которую всё больше используют.
  И хотя такие НС вычисляют, в принципе, непрерывные функции,
  подобные результаты говорят о том, что они,
  вероятно,
  вычисляют почти дискретные функции.
  Что хуже, они оказываются дискретными таким образом,
  что нарушают наше интуитивное представление о разумном поведении.
  Это проблема.
  Кроме того, пока не очень ясно,
  что именно приводит к дискретности,
  в чём заключается проблема:
  в функции потерь?
  В том, какие функции активации использовать?
  В архитектуре сети?
  В чём-то другом?
  Мы не знаем.
  //// И самое печальное, что неудачные попытки это как-то объяснить,
  //// опять свелись к "мантрам о переобучении".
  //// Возможно, это действительно какой-то "артефакт магии обучения",
  //// например, те самые "незначащие промежутки",
  //// но тогда тем более это принципиально важно понять,
  //// а проблему просто "тихо замели под ковер",
  //// так как она "бросает тень" на весь "теоретический фундамент нейронаук".
  
  Но эти результаты не настолько уж плохи, как кажется.
  Хотя подобные состязательные изменения довольно распространены,
  их вряд ли получится встретить на практике.
  Как указано в работе:
  
  \\\ Существование состязательных негативов
  \\\ противоречит способности сети достигать высоких показателей обобщаемости.
  \\\ Ведь если бы сеть умела хорошо обобщать,
  \\\ как бы её можно было обмануть такими состязательными негативами,
  \\\ неотличимыми от обычных примеров?
  \\\ Объяснение заключается в том,
  \\\ что набор состязательных негативов имеет чрезвычайно малую вероятность,
  \\\ и потому не наблюдается
  \\\ (или почти не наблюдается)
  \\\ в обучающем наборе данных,
  \\\ однако он обладает большой плотностью
  \\\ (примерно как рациональные числа),
  \\\ и потому его можно найти практически для любого случая.
  
  //// В реальной практике никто ни от чего не застрахован.
  //// "Вода дырочку найдет".
  
  Тем не менее, неприятно, что мы так плохо понимаем работу НС,
  что этот результат был обнаружен совсем недавно.
  Конечно, главным преимуществом таких результатов будет то,
  что они стимулировали появление последующих работ по этой теме.
  В недавней работе 2014 года показано,
  http://arxiv.org/abs/1412.1897
  что для обученной сети возможно создать изображения,
  которые для человека будут выглядеть, как белый шум,
  а сеть будет классифицировать их в известные категории
  с большой долей уверенности.
  Это ещё одна демонстрация того,
  что нам ещё многое предстоит понять в работе НС
  и в их использовании для распознавания изображений.
  //// Но только ли на "изображениях" возможны такие эффекты?
  //// Что гарантирует то, что те же большие языковые модели
  //// застрахованы от подобного? Ведь их методы обучения и структуры моделей
  //// мало чем отличаются от тех, которые подвержены таким "asversial attacks".
  
  ......
  
  Но, несмотря на вдохновение,
  недостаточно лишь наблюдать за улучшениями в выполнении тестов на скорость
  или даже задач реального мира.
  Существуют фундаментальные явления,
  суть которых мы до сих пор понимаем плохо,
  к примеру, существование состязательных изображений.
  И пока такие фундаментальные проблемы ещё открываются
  (не говоря уже о том, чтобы решать их),
  преждевременно было бы говорить о приближении
  к решению задачи распознавания изображений.
  Но в то же время такие проблемы являются прекрасными стимулами
  к дальнейшей работе.
  //// Что-то за прошедшее время этих "дальнейших работ" как-то не заметно.
  
  Другие подходы к глубоким нейросетям
  
  ......
  
  Рекуррентные нейросети (РНС)
  
  В сетях с прямым распространением, которые мы использовали,
  существует один вход,
  полностью определяющий активацию всех нейронов в последующих слоях.
  Это очень статичная картина:
  всё в сети фиксировано, и имеет замороженный, кристаллический характер.
  Но, допустим, мы разрешим элементам сети меняться динамически.
  К примеру, поведение скрытых нейронов может определяться
  не только активациями в предыдущих слоях,
  но и активациями, случившимися ранее во времени.
  Активацию нейрона может частично определять его же более ранняя активация.
  В сетях с прямым распространениям такого однозначно не происходит.
  Или, возможно, активации скрытых и выходных нейронов
  будут определяться не только текущими входными данными в сеть,
  но и предыдущими.
  
  Нейросети с такого типа поведением, меняющимся во времени,
  известны, как рекуррентные нейросети, или РНС.
  
  ........
  
  Я немного рассказал о том, на что способны РНС,
  но не объяснил, как они работают.
  Возможно, вы не удивитесь, узнав,
  что многие идеи из мира сетей с прямым распространением
  можно использовать и в РНС.
  В частности, мы можем обучить РНС,
  модифицировав в лоб градиентный спуск и обратное распространение.
  Также пригодятся и многие другие идеи,
  используемые в сетях прямого распространения,
  от техник регуляризации до свёрток и функций активации и стоимости.
  Также многие идеи, разработанные нами в рамках книги,
  можно адаптировать для использования в РНС.
  
  Модули долгой краткосрочной памяти (ДКП)
  
  Одна из проблем РНС в том, что ранние модели было очень сложно обучать,
  сложнее, чем даже ГНС.
  Причина содержалась в проблем нестабильного градиента,
  которую мы обсуждали в главе 5.
  Вспомним, что обычным проявлением этой проблемы было то,
  что градиент всё время уменьшается при распространении через слои
  в обратную сторону.
  Это чрезвычайно замедляет обучение ранних слоёв.
  В РНС эта проблема становится ещё хуже,
  поскольку градиенты распространяются не только в обратную сторону по слоям,
  но и в обратную сторону по времени.
  Если сеть работает довольно долго,
  градиент может стать чрезвычайно нестабильным
  и на его основе будет очень тяжело обучаться.
  К счастью, в РНС можно включить идею,
  известную, как модули долгой краткосрочной памяти (ДКП).
  Впервые этим модули представили Хохрейтер и Шмидгубер в 1997 году,
  http://dx.doi.org/10.1162/neco.1997.9.8.1735
  специально для того, чтобы помочь решить проблему нестабильного градиента.
  ДКП облегчают получение хороших результатов при обучении РНС,
  и многие недавние работы (включая и те, на которые я уже проставил ссылки)
  используют ДКП или сходные идеи.
  
  Глубокие сети доверия, генеративные модели и машины Больцмана
  
  ......
  
  Учитывая все эти привлекательные моменты ГСД
  как моделей для глубокого обучения,
  почему же их популярность пошла на спад?
  Частично из-за того, что другие модели,
  например, прямого распространения и рекуррентные сети,
  достигли потрясающих результатов,
  в частности, прорывов в областях распознавания изображений и речи.
  Неудивительно, что эти модели удостоились такого внимания,
  и весьма заслуженного.
  Однако из этого следует неприятный вывод.
  Рынок идей часто работает по схеме <победитель получает всё>,
  и практически всё внимание уходит на то,
  что сейчас в данной области наиболее модно.
  Людям может оказаться чрезвычайно сложно работать
  над непопулярными в настоящее время идеями,
  даже если очевидно, что те могут представлять долгосрочный интерес.
  Моё личное мнение - ГСД и другие генеративные модели
  заслуживают большего внимания, чем получают.
  Не удивлюсь, если ГСД или сходная модель когда-нибудь
  обгонит сегодняшние популярные модели.
  
  ......
  
  Другие идеи
  
  ......
  
  Будущее нейросетей
  
  Интерфейсы на основе намерений пользователя
  
  В старой шутке нетерпеливый профессор говорит запутавшемуся студенту:
  <Не слушайте мои слова, слушайте, что я имею в виду>.
  Исторически компьютеры часто не понимали, подобно запутавшемуся студенту,
  что имеет в виду пользователь.
  Однако ситуация меняется.
  
  ......
  
  Машинное обучение, наука о данных и непорочный круг инноваций
  
  ........
  
  
  Роль нейросетей и глубокого обучения
  
  Я описывал МО общими словами,
  как способ создания новых возможностей для развития технологий.
  Какова же будет конкретная роль НС и ГО во всём этом?
  
  Для ответа на вопрос полезно обратиться к истории.
  В 1980-х наблюдалось активное радостное оживление и оптимизм,
  связанный с нейросетями, особенно после популяризации обратного распространения.
  Но оживление спало, и в 1990-х эстафетную палочку МО передали другим технологиям,
  к примеру, методу опорных векторов.
  Сегодня НС снова на коне, устанавливают всяческие рекорды,
  и обгоняют многих соперников в различных проблемах.
  Но кто гарантирует, что завтра не будет разработан новый подход,
  который снова затмит собою НС?
  Или, возможно, прогресс в области НС начнёт буксовать,
  и ничто не придёт им на смену?
  
  Поэтому гораздо проще размышлять о будущем МО в целом, чем конкретно о НС.
  Часть проблемы в том, что мы очень плохо понимаем НС.
  Почему НС так хорошо умеют обобщать информацию?
  Каким образом они так хорошо избегают переобучения,
  учитывая огромное количество параметров?
  Почему стохастический градиентный спуск так хорошо работает?
  Насколько хорошо сработают НС при масштабировании наборов данных?
  К примеру, если мы расширим базу ImageNet в 10 раз,
  от этого эффективность работы НС улучшится больше или меньше,
  чем эффективность других технологий МО?
  Всё это простые, фундаментальные вопросы.
  И пока что мы очень плохо понимаем ответы на эти вопросы.
  В связи с этим сложно сказать, какую роль НС сыграют в будущем МО.
  
  Сделаю одно предсказание:
  думаю, что ГО никуда не денется.
  Возможность изучать иерархии концепций,
  строить разные слои абстракций,
  судя по всему, фундаментальны для познавания мира.
  Это не значит, что сети ГО завтрашнего дня
  не будут радикально отличаться от сегодняшних.
  Мы можем столкнуться с серьёзными изменениями составляющих их частей,
  архитектур или алгоритмов обучения.
  Эти изменения могут оказаться достаточно драматичными
  для того, чтобы мы перестали считать получившиеся системы нейросетями.
  Однако они всё равно будут заниматься ГО.
  
  Приведут ли НС и ГО в скором времени к появлению искусственного интеллекта?
  
  ........
  
  Для подробного ответа на такой вопрос потребовалась бы отдельная книга.
  Вместо этого позвольте мне предложить вам одно наблюдение,
  основанное на законе Конвея:
  
  \\\ Организации, проектирующие системы, ограничены дизайном,
  \\\ копирующим структуру коммуникаций в этой организации.
  
  .......
  
  Закон Конвея применим к разработке и созданию систем в случаях,
  когда мы с самого начала представляем себе,
  из каких составных частей будет состоять продукт, и как их сделать.
  Его нельзя применять напрямую к разработке ИИ,
  поскольку ИИ такой задачей (пока) не является:
  мы не знаем, из каких частей он состоит.
  Мы даже не уверены, какие базовые вопросы можно задавать.
  Иначе говоря, в данный момент ИИ является больше проблемой науки, чем инженеров.
  
  ......
  
  Такое развитие событий часто повторялось
  во многих установившихся научных дисциплинах:
  не только в медицине, но и в физике, математике, химии, и других.
  Области рождаются монолитными,
  имея в запасе лишь несколько глубоких идей.
  Первые эксперты способны охватить их все.
  Но с течением времени монолитность меняется.
  Мы открываем множество новых глубоких идей,
  и их становится слишком много для того,
  чтобы кто-то сумел по-настоящему овладеть ими всеми.
  В итоге социальная структура области реорганизуется
  и делится,
  концентрируясь вокруг этих идей.
  Вместо монолита у нас возникают поля, делящиеся на поля, делящиеся на поля,
  - сложная, рекурсивная социальная структура,
  ссылающаяся сама на себя,
  чья организация отражает связи между самыми глубокими идеями.
  Вот так структура наших знаний формирует социальную организацию науки.
  Однако эта социальная форма в свою очередь ограничивает и помогает
  определить то, что мы можем обнаружить.
  Это и есть научный аналог закона Конвея.
  
  Но какое отношение всё это имеет к глубокому обучению или ИИ?
  
  Ну, с ранних дней разработки ИИ идут споры о том,
  что всё пойдёт либо <не слишком сложно, благодаря имеющемуся у нас сверхоружию>,
  либо <сверхоружия будет недостаточно>.
  Глубокое обучение - последний из примеров сверхоружия,
  который использовался в виденных мною спорах.
  В ранних версиях таких споров использовалась логика,
  или Prolog, или экспертные системы, или какая-то ещё технология,
  которая тогда была самой мощной.
  Проблема таких споров в том, что они не дают вам возможности сказать точно,
  насколько мощным будет любой из кандидатов на сверхоружие.
  Конечно, мы только что целую главу потратили на рассмотрение свидетельств того,
  что ГО может решать чрезвычайно сложные задачи.
  Оно определённо выглядит очень интересно и многообещающе.
  Но так было и с такими системами, как Prolog, или Eurisko,
  или с экспертными системами.
  Поэтому лишь тот факт, что набор идей выглядит многообещающе,
  ничего особенного не означает.
  Откуда нам знать, что ГО на самом деле отличается от этих ранних идей?
  Есть ли способ измерить, насколько мощным и многообещающим является набор идей?
  Из закона Конвея следует, что в качестве грубой и эвристической метрики
  мы можем использовать сложность социальной структуры,
  связанной с этими идеями.
  
  Поэтому у нас возникает два вопроса.
  Во-первых, насколько мощным является набор идей, связанный с ГО,
  согласно этой метрике социальной сложности?
  Во-вторых, насколько мощная теория нам нужна,
  чтобы создать ИИ общего назначения?
  
  По первому вопросу:
  когда мы сегодня смотрим на ГО, это поле выглядит интересным
  и быстро развивающимся, но относительно монолитным.
  В нём есть несколько глубоких идей,
  и проводится несколько основных конференций,
  причем некоторые из них сильно пересекаются.
  Работа за работой используют один и тот же набор идей:
  стохастический градиентный спуск (или его близкий аналог)
  для оптимизации функции стоимости.
  Прекрасно, что эти идеи настолько успешны.
  Что чего мы пока не наблюдаем,
  так это большого количества хорошо развитых более мелких областей,
  каждая из которых исследовала бы свой набор глубоких идей,
  что двигало бы ГО во многих направлениях.
  Поэтому, согласно метрике социальной сложности,
  глубокое обучение, простите за каламбур,
  пока остаётся весьма неглубокой областью исследований.
  Один человек всё ещё способен овладеть большинством глубоких идей из этой области.
  
  По второму вопросу:
  насколько сложный и мощный набор идей понадобится для создания ИИ?
  Естественно, ответом будет:
  никто точно не знает.
  Но в послесловии к книге я изучил некоторые из существующих свидетельств по этому вопросу.
  Я заключил, что даже по оптимистичным оценкам,
  для создания ИИ потребуется много, очень много глубоких идей.
  По закону Конвея, для того, чтобы дойти до этой точки,
  мы должны увидеть появление множества взаимосвязанных дисциплин,
  со сложной и неожиданной структурой,
  отражающей структуру наших глубочайших идей.
  Мы пока не наблюдаем такой сложной социальной структуры
  при использовании НС и ГО.
  Поэтому, я считаю, что мы, по крайней мере,
  находимся в нескольких десятилетиях от использования ГО
  для разработки ИИ общего назначения.
  
  .......
  
  Я могу честно сказать:
  думаю, что пока ещё судить рано.
  Как в старом анекдоте:
  если спросить учёного, сколько нам ещё нужно ждать какого-либо открытия,
  и он скажет <10 лет> (или больше),
  то на самом деле он имеет в виду <понятия не имею>.
  До появления ИИ, как и в случае с контролируемым ядерным синтезом
  и некоторыми другими технологиями,
  уже более 60 лет остаётся <10 лет>.
  С другой стороны, что у нас точно есть в области ГО
  - так это эффективная технология,
  пределы возможностей которой мы пока не обнаружили,
  и множество открытых фундаментальных задач.
  И это открывает потрясающие творческие возможности.
  
  ........
  
  ///// Конец цитирования.
  
  Мое мнение в отношении глубокого обучения нейросетей полностью аналогично.
  Доказавшая свою эффективность технология, вряд уже просто так "канет в небытие",
  даже не смотря на свою текущую "теоретическую непрозрачность" и "детские болезни".
  Причем, многие "болячки" это явное следствие "теоретических недоработок".
  Но в условиях нашего "лучшего из миров" стремление по-быстрее получить
  какой-то легко "монетизируемый" результат,
  отодвигает "фундаментальные" вопросы на второй план, и
  "развитие идет не по спирали,
  а вкривь и вкось, наперерез..."
  
  И главным призом в этой поистине безумной гонке все новых и новых разработок
  и исследований в области "нейронаук"
  считается не "понимание", а создание ИИ,
  которое само и ответит на все наши вопросы о Мирозданье:
  
  "Нейросети и глубокое обучение: онлайн-учебник, послесловие:
  существует ли простой алгоритм для создания интеллекта?"
  Автор: SLY_G (Вячеслав Голованов)
  https://habr.com/ru/articles/464735/.
  26 авг 2019 в 10:00
  
  Автор оригинала: Michael Nielsen
  http://neuralnetworksanddeeplearning.com/sai.html
  
  //// Начало цитирования.
  
  В данной книге мы фокусировались на основных деталях устройства нейросетей:
  как они работают, как их можно использовать
  в задачах распознавания последовательностей.
  Этот материал возможно непосредственно применять на практике.
  Но, конечно, одна из причин интереса к НС
  - надежда, что когда-нибудь они смогут выйти
  за пределы простого распознавания последовательностей.
  Возможно, их, или какие-то другие подходы на основе цифровых компьютеров,
  в итоге можно будет применять для создания думающих машин,
  способных поспорить с человеческим интеллектом или превзойти его?
  
  .......
  
  Вместо этого я хочу изучить другой вопрос:
  существует ли простой набор принципов,
  которые можно использовать для объяснения такого явления,
  как интеллект?
  В частности, более конкретно,
  существует ли простой алгоритм для создания интеллекта?
  
  Идея существования поистине простого алгоритма
  для создания интеллекта довольно смелая.
  Она, вероятно, звучит слишком оптимистично для того,
  чтобы быть правдой.
  У многих людей есть стойкое интуитивное ощущение того,
  что у интеллекта есть значительная сложность,
  которую невозможно упростить.
  Они так впечатлены потрясающим разнообразием и гибкостью человеческой мысли,
  что делают вывод о невозможности существования простого алгоритма
  для создания интеллекта.
  Но, несмотря на эту интуицию,
  не думаю, что стоит делать поспешные выводы по этому вопросу.
  История науки заполнена примерами того,
  как явление, изначально казавшееся чрезвычайно сложным,
  позднее было объяснено простым,
  но мощным набором идей.
  
  .......
  
  Я предубеждён в пользу существования простого алгоритма для интеллекта.
  В основном эта идея, несмотря на неубедительные аргументы, приведённые выше,
  нравится мне потому, что она оптимистична.
  В деле научных исследований неоправданный оптимизм
  обычно оказывается более продуктивным, чем обоснованный пессимизм,
  поскольку у оптимиста достаёт смелости пытаться пробовать что-то новое.
  Это путь к открытиям, даже если вы открываете не то,
  на что надеялись изначально.
  Пессимист может оказаться более <правым> в узком смысле,
  но откроет меньше, чем оптимист.
  
  Эта точка зрения резко контрастирует с тем,
  как мы обычно оцениваем идеи,
  пытаясь понять, правильные они или неверные.
  Это разумная стратегия при работе с повседневными
  или небольшими исследованиями.
  Однако, возможно, оценивать таким способом большие и смелые идеи,
  определяющие целую программу исследований,
  будет неверно.
  Иногда по поводу правильности идеи у нас есть
  лишь слабые свидетельства.
  Мы можем смиренно отказаться следовать ей,
  и всё своё время потратить на тщательное изучение
  доступных свидетельств,
  пытаясь понять, какие из них правдивы.
  Или мы можем просто принять,
  что пока никто точно не знает,
  и активно поработать над развитием большой и смелой идеи,
  понимая, что, хотя у нас нет гарантий успеха,
  только таким образом мы можем расширять границы нашего понимания.
  
  Учитывая всё это, в наиболее оптимистичном его виде,
  я всё же не верю, что мы когда-нибудь найдём простой алгоритм для интеллекта.
  Точнее говоря, я не верю, что мы когда-нибудь найдём возможность
  написать на python (или на C, или на Lisp, или на чём-то ещё)
  очень короткую программу
  - допустим, вплоть до тысячи строк кода -
  реализующую искусственный интеллект.
  И я не думаю, что мы когда-нибудь найдём очень просто описываемую нейросеть,
  способную реализовать ИИ.
  Но я верю, что стоит действовать так,
  будто мы можем найти такую программу или сеть.
  Таков путь к идеям, и идя по нему,
  мы можем однажды понять достаточно для того,
  чтобы написать более длинную программу,
  или создать более сложную сеть, демонстрирующую интеллект.
  Поэтому стоит действовать так,
  будто существует чрезвычайно простой алгоритм для интеллекта.
  
  В 1980-х выдающегося математика и специалиста по информатике Джека Шварца
  пригласили на дебаты между сторонниками и скептиками ИИ.
  Дебаты вышли из-под контроля,
  сторонники начали делать чрезмерные заявления по поводу потрясающих вещей,
  которые уже вот-вот появятся,
  а скептики лишь усиливали свой пессимизм,
  заявляя, что ИИ просто невозможно создать.
  Шварц присутствовал вне дебатов, и молчал, когда дискуссия накалялась.
  Во время затишья его попросили высказаться
  и описать свои мысли по поводу обсуждаемой темы.
  Он сказал:
  <Что ж, до некоторых из этих идей, возможно, случится
  ещё сто нобелевских премий>.
  По-моему, это идеальный ответ.
  Ключ к ИИ - это простые и мощные идеи,
  и мы можем, и должны оптимистично искать их.
  Но нам потребуется множество подобных идей,
  и нам ещё предстоит ещё очень долгий путь!
  
  .........
  
  //// Из комментариев.
  
  Mistx
  26 авг 2019 в 15:32
  
  Интеллект - процесс минимизации разницы(ошибки)
  между желаемым и действительным (ожиданием и реальностью)
  с помощью сетевой аппроксимации.
  Чем глубже сеть и меньше относительная ошибка ей генерируемая,
  тем интеллектуальнее субъект.
  Иными словами интеллект - просто интерактивная модель мира(кривое зеркало).
  ИМХО.
  
  ......
  
  ichael_v89
  26 авг 2019 в 18:12
  
  \\\ Вместо этого я хочу изучить другой вопрос:
  \\\ существует ли простой набор принципов,
  \\\ которые можно использовать для объяснения такого явления, как интеллект?
  
  Я одно время интересовался искусственным интеллектом,
  думал о том, по каким принципам может работать естественный.
  Один из принципов, который кажется мне довольно вероятным, следующий.
  
  Информация пробивает себе дорогу.
  Это значит, что если в некоторой области некоторого слоя нейронов
  есть некоторый паттерн с высоким уровнем сигнала,
  в следующем слое должен быть нейрон (или группа нейронов),
  который на него реагирует.
  Если все нейроны реагируют на другие паттерны,
  и соответственно дают низкий уровень сигнала,
  создается новый нейрон, который обучается распознавать этот паттерн.
  Граница проходит около 1/2.
  Это нечто вроде теоремы Котельникова для информации.
  Таким образом непрерывная аналоговая информация
  раскладывается по дискретным информационным элементам.
  
  Возможно спайки это биологический механизм такого распространения.
  Постоянные электрические импульсы как бы требуют, чтобы их кто-то принимал.
  
  У меня нет доказательств, это просто эмпирическое наблюдение,
  результат размышлений о том, как оно может быть устроено,
  чтобы работало так, как оно работает.
  
  Для примера можно привести ориентационные колонки
  (на изображении ссылка на статью).
  http://web.eecs.umich.edu/~honglak/icml09-ConvolutionalDeepBeliefNetworks.pdf
  Когда одна группа при обучении не распознает
  во входном паттерне свой наклон
  (сигнал меньше половины от стабильного),
  его учится распознавать соседняя с ней группа.
  Поэтому ориентация меняется плавно, а не вразброс.
  
  А это первый слой, который получился в результате обучения нейросети
  (Figure 2 в середине статьи).
  Статья не моя конечно, приведена просто чтобы отметить сходство в результатах.
  
  VDG
  28 авг 2019 в 00:11
  
  \\\ Если все нейроны реагируют на другие паттерны,
  \\\ и соответственно дают низкий уровень сигнала, создается новый нейрон,
  \\\ который обучается распознавать этот паттерн.
  
  Тоже приходила подобная идея (и частично её реализовал),
  а недавно выяснил, что ей лет 40 уже, называется:
  <нейроподобные растущие сети> (Ященко, Виталий Александрович).
  К сожалению, за все эти десятилетия там никакого развития.
  В общем виде эта идея в разных её представлениях существует у Анохина (коги)
  и Редозубова (кластеры).
  
  maagalex (Алекс Липкович)
  28 авг 2019 в 00:37
  
  Мне очень понравилось начало:
  ибо я сам задавался тем же вопросом,
  и со временем таки нашел для себя ответ на него...
  Ждал, что вот-вот будет озвучен тот красивый и универсальный метод,
  позволяющий различать запахи, слова, образы...
  
  Но нет: опять нейронные сети и все эти танцы с бубном и обучениями...
  
  Нууу кто первый?.. Это на самом деле очень просто... и очень красиво...
  
  //// Но и сам автора этого поста так и не решился высказать
  //// эту "простую и красивую" методику.
  //// Наверно, время еще не пришло.
  
  VDG
  28 авг 2019 в 14:37
  
  Красивой философии много, а реальных ответов нет ни у кого.
  И вероятнее всего, никто не стал бы ею вот так свободно делиться.
  
  .......
  
  //// Конец цитирования.
  
  Наблюдая со стороны над тем, что сейчас происходит в "нейронауках",
  с одной стороны, конечно дух захватывает от масштаба и скорости
  происходящих нововведений и перемен.
  Тут даже подходящих эпитетов подобрать сложно.
  Многие тысячи компаний, коллективов, исследований, докладов, моделей,
  миллиарды инвестиций и пользователей, триллионы обучаемых параметров,
  петабайты датасетов...
  И все "в едином порыве" к "заветному ИИ-граалю".
  
  А с другой стороны, все это уже было, может не в таких масштабах,
  но точно было. И называлось "квантовой революцией".
  Точно также недостаток глубокой теории в лихорадке научного поиска
  заменялся эвристическими правилами/постулатами.
  В итоге получилась такая эффективная "квантовая физика",
  понять которую уже никто не в состоянии,
  просто "по определению" самих ее создателей это просто "расчетные формулы".
  
  Очень бы не хотелось бы, чтобы результатом всех этих прорывных работ
  в машинном обучении стала бы максима:
  "Заткнись и обучай".
  
  На этом можно, пожалуй, поставить точку в это очень продолжительном
  "глубоком погружении" в глубокое обучение на основе каких-то
  систематизированных и достаточно простых для понимания материалах.
  Дальше придется пускаться в "свободное плавание"
  в поисках ПОНИМАНИЯ,
  что и как именно происходит в процессе обучения нейросетей.
  И есть ощущение, что это будет увлекательным "интеллектуальным приключением".
  
  19 мая 2024 года Андрей Павлович Митасов, Минск, РБ, Порт приписки Земля.
  
  
  =========
  
  26.05.2024 10:42
  
  Информация к размышлению:
  или материалы к следующей части данного модуля.
   Иллюстрация реального уровня понимания работы нейронок и регуляризации.
   Обучение нейросетей с помощью "дистилляции" знаний.
   Пример обучения нейросети "от входа к выходу".
   Самообучение и обратное распространение влияния.
  
  
  =========
  
  22.05.2024 15:55
  
  Иллюстрация реального уровня понимания работы нейронок и регуляризации.
  В оглавление.
  
  Просто нельзя пройти мимо "кристально чистой иллюстрации" того,
  какой в настоящее время "достигнут" уровень понимания работы нейронок
  и методов их обучения, в частности широко разрекламированной регуляризации:
  
  "Большие языковые модели гораздо линейнее, чем мы думали".
  Автор: Razant (Anton Razzhigaev) https://habr.com/ru/companies/airi/articles/816125/. 22 мая 2024 в 12:47
  
  //// Начало цитирования.
  
  Хабр, привет! Это снова Антон Разжигаев,
  аспирант Сколтеха и научный сотрудник лаборатории FusionBrain в Институте AIRI,
  где мы продолжаем углубляться в изучение языковых моделей.
  В прошлый раз мы выяснили,
  https://habr.com/ru/companies/airi/articles/804515/
  что эмбеддинги трансформеров-декодеров сильно анизотропны.
  //// Разбор этой статьи можно посмотреть здесь:
  //// "Анизотропия и внутренняя размерность "пространства эмбеддингов".
  На этот раз я бы хотел рассказать об их удивительной линейности,
  ведь нашу статью про обнаруженный эффект
  ("Your Transformer is Secretly Linear")
  https://arxiv.org/abs/2405.12250
  несколько дней назад приняли на международную конференцию ACL!
  
  Линейность считается свойством самых слабых моделей,
  ведь они могут решать только простейшие задачи,
  для которых зачастую и ML-то особо не нужен (см. картинку ниже).
  Поэтому принято считать, что НЕлинейность
  - это краеугольный камень сложных вычислений
  и преобразований внутри больших нейронных сетей,
  и, в особенности, трансформеров.
  
  Рис. Справа пример задачи, которую линейные модели решить не могут.
  
  Однако в нашей последней работе, мы обнаружили,
  что для больших языковых моделей (LLM) декодеров это совсем не так!
  Информация от слоя к слою практически
  не испытывает нелинейных преобразований,
  а каждый отдельный блок трансформера можно заменить
  всего лишь на один линейный слой без потери качества!
  Правда звучит интригующе?
  Ниже я коротко расскажу про наши главные выводы.
  
  Как вообще оценить линейность отдельного слоя модели?
  
  Для оценки линейности отдельных слоев модели мы использовали метод,
  который можно назвать обобщением Procrustes Similarity.
  Это звучит сложно, но суть проще чем кажется:
  мы берём два набора векторов (выходы двух последовательных слоев),
  центрируем их (чтобы убрать смещение)
  и нормализуем.
  Затем мы ищем такое линейное преобразование,
  которое минимизирует MSE между этими двумя наборами векторов.
  Если среднюю ошибку такой аппроксимации вычесть из 1,
  то получим коэффициент линейности
  (1 - наивысшая линейность, 0 - полное отсутствие линейности).
  
  На графике ниже видно, что линейность всех LLM близка к 100%.
  Исключением являются только первый и последний слои,
  а также самая крошечная модель Pythia-70M.
  
  Рис. Степень линейности каждого слоя во всевозможных LLM.
  
  Что происходит с линейностью во время претрейна и дообучения?
  
  Мы взяли все открытые языковые модели
  с опубликованными промежуточными весами
  и посмотрели, как менялась линейность,
  усреднённая по слоям от чекпоинта к чекпоинту.
  
  Похоже, что по мере изначального обучения,
  у всех этих моделей линейность постепенно падала
  (то есть их нелинейные свойства проявлялись всё сильнее).
  При этом во время дообучения на любых задачах линейность всегда растёт,
  вне зависимости от типа задачи или модели.
  //// Это вроде как понятно, но это для всей модели целиком.
  //// И вроде бы логично предполагать, что эта суммарная нелинейность,
  //// как результат сложения из нелинейностей отдельных слоев,
  //// распределена по этим слоям более-менее равномерно.
  //// А оказывается, что это не так.
  
  Рис. Средняя линейность (без учёта residual) по мере обучения моделей.
  //// Вот не понял причем здесь ремарка "без учёта residual".
  //// Что собственно измеряется?
  
  Рис. Прирост линейности после файнтюнинга.
  
  Мы предполагаем, что это связано с уменьшением обобщающей способности,
  то есть рост линейности - это то, что приводит к катастрофическому забыванию.
  Грубо говоря, модель постепенно откидывает старые знания,
  которые не пригодились во время файнтюнинга (RLHF не исключение).
  //// Обратите внимание, "мы предполагаем".
  //// Т.е. что это за процесс и к чему он приводит, по факту, загадка.
  
  Регуляризация, усиливающая нелинейность
  
  Раз линейность - это плохо,
  //// Что не доказано, а только "предполагается".
  то, может быть, её можно как-то контролировать при помощи регуляризации?
  Мы попытались повлиять на степень линейности архитектуры Mistral
  во время претрейна, испробовали кучу разных вариантов,
  и ни один из них не работал
  - языковая модель почему-то сопротивлялась
  и старалась оставаться максимально линейной.
  //// Т.е. это какое-то ВНУТРЕННЕЕ свойство/тренд при обучении нейросетей,
  //// и совсем необязательно, что это что-то плохое.
  //// Непонятное, немного загадочное и при этом работающее.
  //// А здесь, не разобравшись сразу, пытаются его "помножить на ноль".
  
  Но в какой-то момент мы случайно перепутали знак в регуляризационном лоссе,
  и всё заработало!
  Почему-то к уменьшению линейности привёл именно тот лосс,
  который <стягивал> эмбеддинги с последовательных слоёв друг к другу
  при помощи косинуса,
  то есть нам помогла случайная ошибка.
  //// Именно так и происходят настоящие открытия
  //// - вопреки теоретическим фундаментальным аксиомам.
  //// Потому как нет незыблемых аксиом, а есть просто стабильные условия.
  //// Изменятся условия, и многие аксиомы могут "поменять знак".
  
  На первый взгляд, такая регуляризация
  наоборот должна учить модель <ничего не делать> на каждом отдельном слое,
  однако языковая модель отреагировала абсолютно противоположным образом.
  При этом с ростом нелинейных свойств её слоёв подросли и метрики,
  модель стала лучше решать некоторые задачи,
  писать более качественный текст,
  а её эмбеддинги стали более экспрессивными
  (то есть полезнее для downstream задач).
  
  Рис. Эффект косинусной регуляризации на среднюю линейность (без учёта residual).
  //// Вообще-то отличие "во-втором знаке" вряд ли можно считать чем-то существенным,
  //// но для оценки тенденции, наверно, можно.
  
  Рис. Косинусная регуляризация приводит к увеличению экспрессивности эмбеддингов.
  То есть растёт точность linear probing.
  
  Рис. Результаты валидации через GPT-4 на Tiny-Stories.
  Модель с косинусной реугуляризацией генерирует
  более связный и качественный текст.
  
  Линейный прунинг
  
  Один из первых вопросов, возникших у нас в голове
  - если отдельные слои LLM на 99% линейны,
  то почему бы просто не заменить их на один-единственный nn.Linear(),
  выкинув при этом весь этэншн, feed-forward и тп?
  
  Да, оказалось, что так можно!
  При этом точность модели и её качество практически не падают,
  но подменить таким образом можно только небольшое количество слоёв (~15%),
  а дальше ошибка линейной аппроксимации накапливается,
  и качество начинает ухудшаться.
  //// Т.е. "щепотка нелинейности" зачем-то все-таки нужна.
  //// Вопрос: какая и где именно?
  //// И самый важный вопрос: почему?
  
  Рис. Перплексия для OPT-1.3B на WikiText
  при выкидывании части слоёв из модели,
  при линейной замене слоёв и при последующем дообучении
  всех новых линейных слоёв одновременно.
  
  Рис. Перплексия для Llama-2-7B на WikiText
  при выкидывании части слоёв из модели,
  при линейной замене слоёв
  и при последующем дообучении всех новых линейных слоёв одновременно
  
  Заключение
  
  Обнаруженный эффект кажется очень контринтуитивным,
  он противоречит многим нашим представлениям о глубоком обучении.
  Откуда такая сильная линейность
  в, казалось бы, одной из самых мощных и изученных архитектур?
  Мы точно не знаем,
  но предполагаем,
  что это связано с режимом триггеринга фичей.
  //// Как обычно, вместо объяснения на пальцах введение нового "спецтермина".
  //// Именно это лучше всего характеризует уровень теоретических знаний в нейронаках.
  То есть нелинейные свойства <вспыхивают> очень редко,
  //// Когда именно?
  а на большинстве входных токенов модель работает в около-линейном режиме.
  Что-то похожее было обнаружено в статье Deja Vu,
  https://proceedings.mlr.press/v202/liu23am.html
  где изучали мёртвые нейроны в языковых моделях.
  
  .......
  
  //// Из комментариев.
  
  ValeriyPushkarev
  2 часа назад
  
  \\\ Мы предполагаем, что это связано с уменьшением обобщающей способности,
  \\\ то есть рост линейности - это то, что приводит
  \\\ к катастрофическому забыванию.
  \\\ Грубо говоря, модель постепенно откидывает старые знания,
  \\\ которые не пригодились во время файнтюнинга (RLHF не исключение).
  
  Ого, да все DeepLearning было придумано чтобы 100+ слоев
  хотя-бы обучить (пусть и на манер хеш-таблицы) :).
  
  И тут оказывается у нас не сверхоптимальное сжатие всего интернета
  в 2b параметрах
  (и вся нелинейная магия только в 70M моделях? )))
  
  ACL - могёте xD
  //// Загадочный, для меня, мем.
  
  ........
  
  //// Конец цитирования.
  
  Ну, что можно хорошего сказать после такой иллюстрации
  "теоретически выверенного научного поиска"?
  Линейность слоев трансформера пока трогать не будем,
  тут нужно еще поглубже покопаться,
  и, может быть, найти "хорошую дебютную идею".
  
  А в отношении регуляризации уже точно можно сказать,
  что "твори, выдумывай, пробуй".
  Т.е. не надо ограничивать себя официально признанными "рамками"/трактовками
  этого интересного подхода к трансформации функции стоимости/лоса.
  Все равно существующие трактовки работы регуляризации,
  как минимум, не полны, а иногда и "принципиально не верны".
  И нужно просто "поменять знак".
  Хотя бы "прикола ради".
  
  
  =========
  
  01.06.2024 11:29
  
  Обучение нейросетей с помощью "дистилляции" знаний.
  В оглавление.
  
  Разбирая материал, по разработке очень специализированной нейрсети, см.:
  "Сеанс поэтапной "дистилляции",
  поразился возможности сжать результирующую сеть практически на два порядка
  в размерах и скорости инференса.
  Все предыдущие материалы по "дистилляции" говорили о существенно меньших цифрах,
  - порядка 20-50% - и поэтому особого внимания не привлекали.
  А вот после этого материала стало понятно,
  что анализ работы метода "дистилляции" может очень многое подсказать,
  вообще, об особенностях обучения нейронок,
  которые незаметны с другого ракурса рассмотрения.
  
  Поэтому считаю нужным познакомиться с достаточно фундаментальной работой
  по этой теме, хотя в ней, на мой взгляд, избыточное количество "математики",
  но таков уж подход и мировоззрение автора:
  
  "Учебник по машинному обучению
  7.2. Дистилляция знаний"
  Автор: Вадим Шиянов
  https://education.yandex.ru/handbook/ml/article/distillyaciya-znanij.
  
  Практически все формулы из данного материала заменены многоточием,
  по ряду причин, главная из которых - попытка сконцентрироваться на "понимании",
  происходящих при дистилляции процессов.
  А формулы, на мой взгляд, в данном случае создают иллюзию,
  что в основе эффективности "дистилляции" лежит какой-то "математический трюк".
  
  //// Начало цитирования.
  
  Введение
  
  В данном параграфе вы познакомитесь с продвинутой техникой машинного обучения,
  получившей название дистилляции знаний.
  Дистилляция знаний (knowledge distillation)
  - это способ обучения в первую очередь нейросетевых моделей машинного обучения,
  направленный на передачу знаний от модели-учителя к модели-ученику.
  
  Рис. 1. https://arxiv.org/abs/2006.05525
  
  Слишком абстрактное определение?
  Соглашусь, но в последние годы дистилляция знаний
  как поле исследований сильно разрослась и стала включать в себя
  множество новых и, возможно, даже неожиданных сценариев применения.
  Так, авторы статьи 2020 года утверждают,
  https://arxiv.org/abs/2006.00555
  что смогли добиться примерной инвариантности выходов полносвязной сети
  к сдвигу входа-картинки с помощью дистилляции в неё знаний из сверточной сети.
  //// Надо будет почитать.
  Таким образом получается,
  что дистилляция знаний может применяться для того,
  чтобы передавать так называемые inductive biases от одной сети к другой.
  Схожие доводы встречаются и в статьях безумно популярного
  на момент написания данного параграфа направления трансформеров
  для компьютерного зрения.
  Так, использование дистилляции знаний оказалась важным компонентом
  https://arxiv.org/abs/2012.12877
  для получения хорошего качества предсказания на ImageNet от ViT
  без использования дополнительных данных.
  Впоследствии данный подход использовался и в других трансформерах
  для компьютерного зрения,
  например, в LeViT.
  https://arxiv.org/abs/2104.01136
  
  Тем не менее, среди всего разнообразия применений дистилляции знаний
  наиболее ярко выделяется одно - сжатие моделей.
  
  Сжатие моделей
  
  Задача сжатия моделей проистекает из следующего наблюдения.
  Неоднократно было замечено,
  что в широком диапазоне практически значимых задач машинного обучения
  точность предсказания модели существенно зависит от её размера.
  При этом зачастую данная зависимость выглядит достаточно тривиально:
  последовательное увеличение размеров модели позволяет
  последовательно улучшать точность её предсказаний.
  Однако такой безграничный рост приводит к ряду проблем,
  связанных с практическим применением итоговых моделей.
  Сюда относятся рост времени обучения больших моделей
  и повышенные аппетиты таких моделей к размерам и качеству обучающей выборки.
  Кроме того, большие модели нередко требуют
  более дорогостоящего вычислительного оборудования для эффективного применения,
  особенно если мы говорим об обработке большого количества запросов в сжатые сроки.
  А для некоторых сценариев, таких как предсказание в реальном времени
  и/или на мобильных устройствах,
  применение большой модели может оказаться вовсе невозможным.
  
  Данные проблемы породили каждая свою ветвь исследований.
  Так в последние годы де-факто стандартным способом обучения
  даже относительно компактных моделей стало использование
  mixed-precision training,
  которое позволяет ускорить обучение более или менее любых сетей
  на современных графических процессорах,
  при этом практически без потерь в итоговом качестве.
  Для борьбы с недостатком обучающих данных была предложена
  целая плеяда методов self-supervised pretraining,
  и новые появляются до сих пор.
  Сжатие моделей же концентрируется на решении проблем,
  связанных с этапом применения уже обученных моделей.
  
  Как можно догадаться из названия,
  задача сжатия моделей заключается в том,
  чтобы взять большую модель, и сжать её
  в как можно более компактную модель
  при этом по возможности минимально пожертвовав качеством предсказания.
  Исторически задачу сжатия моделей пытались решать множеством разных способов.
  Классическим примером здесь может служить прунинг,
  где модель обучается специальным образом
  (например, с использованием L2 регуляризации)
  так, чтобы часть весов в итоге можно было занулить
  и исключить из итоговой модели.
  Однако методы данного семейства, как правило, страдают
  от двух основных проблем.
  Во-первых, простое удаление части весов каждого из слоев
  обычно показывает лишь незначительное ускорение
  в применении итоговой модели
  за исключением случаев использования специализированной аппаратуры.
  Во-вторых, наивный прунинг нередко приводит
  к существенной просадке в качестве предсказания сжатой модели,
  причём соотношение степени сжатия и качества итоговой модели
  едва ли возможно контролировать.
  //// И предсказывать, а это самое важное.
  Чтобы обойти данные ограничения,
  и была предложена техника дистилляции знаний.
  
  Хинтоновская дистилляция знаний
  
  Формулировка
  
  Первой статьёй, в которой можно встретить дистилляцию знаний в современном виде
  является статья Хинтона и др. 2014 года.
  https://arxiv.org/abs/1503.02531
  В данной статье авторы рассматривают задачу классификации картинок
  и предлагают использовать предсказания большой заранее обученной модели-учителя
  в качестве новой, т.н. мягкой, разметки,
  которую будет пытаться повторить компактный ученик.
  Конкретнее, авторы предлагают использовать дивергенцию Кульбака-Лейблера
  между предсказаниями учителя и ученика
  в качестве дополнительного слагаемого к стандартной функции потерь
  - кросс-энтропии между предсказанием ученика и жёсткой разметкой:
  
  .......
  
  Здесь через ? обозначена функция потерь для дистилляции знаний.
  Под ?, подразумевается число объектов,
  а под ? - классов, представленных в обучающей выборке.
  Через ? обозначена жёсткая разметка:
  
  ......
  
  Через ? обозначены вероятности классов, предсказанные моделью-учеником,
  а через ? - моделью-учителем.
  Коэффициент ? позволяет настраивать баланс между решением исходной задачи
  и повторением предсказаний учителя.
  
  В последнем переходе учтено, что логарифм частного
  раскладывается в разность логарифмов,
  после чего один из членов можно исключить,
  поскольку он не зависит от оптимизируемых значений.
  В дальнейшем для упрощения выкладок под ? будет подразумеваться
  именно последнее выражение.
  
  Мотивация
  
  Свой выбор функции потерь авторы мотивируют следующим образом.
  Широко известным фактом является то,
  что при классификации картинок на достаточно больших и разнообразных датасетах
  большие нейронные сети стабильно показывают лучшие результаты
  по сравнению с компактными.
  Однако также хорошо известно,
  что даже сравнительно небольшие нейронные сети
  способны приближать очень широкий спектр функций.
  В таком случае можно предположить,
  что проблема обучения компактных сетей заключается не в том,
  что компактная модель не способна приблизить ту же функцию, что и большая,
  а в том, что компактная модель не способна
  самостоятельно выучить данную функцию из исходных данных.
  //// Вот это, на мой взгляд, ключ к пониманию не только "дистилляции",
  //// но и вообще многих "непоняток" в машинном обучении.
  //// Осталось разобраться, почему большие модели более способны к обучению,
  //// чем компактные.
  В таком случае потенциально мы можем подтолкнуть компактную модель
  к выучиванию более информативного представления
  путем модификации функции потерь.
  Как этого добиться?
  Давайте возьмем заведомо более информативное представление,
  выученное большой моделью-учителем,
  и добавим в функцию потерь слагаемое,
  которое будет учить модель-ученика повторять его.
  В случае решения задачи классификации KL-дивергенция
  является именно таким слагаемым.
  //// Но, наверняка, это не единственный способ "подтолкнуть компактную модель"
  //// к более сложным "представлениям".
  
  Есть и другой способ взглянуть на хинтоновскую дистилляцию знаний.
  Минимизация ? отличается от стандартного обучения,
  тем, что мы дополнительно минимизируем расстояние
  между предсказаниями ученика и учителя.
  От стандартной разметки такая целевая переменная отличается
  наличием так называемых теневых знаний (dark knowledge),
  которые состоят из вероятностей принадлежности объекта ко всем классам,
  помимо истинного.
  //// Скорее это какие-то "кОмплексные знания",
  //// но "кто первым встал - того и тапки".
  //// Пусть это называется "теневые знания",
  //// в смысле, что это больше "тень" от объемного предмета,
  //// чем то "что находится в тени".
  Благодаря теневым знаниям модели-ученику во время обучения
  доступна дополнительная информация
  о взаимоотношениях между представленными в обучающей выборке классами,
  а также схожести отдельных объектов и классов.
  //// Скорее, на мой взгляд, это лучше называть
  //// "прокладкой более оптимального маршрута обучения",
  //// который ученик сам по себе выстроить не в состоянии.
  //// Это еще раз может подчеркнуть, что у компактных моделей,
  //// при стандартном обучении методом "обратного распространения ошибок"
  //// есть какие-то, пока не выявленные, проблемы с обучением сложным зависимостям.
  Чтобы проверить данную гипотезу,
  авторы проводят следующий эксперимент.
  Сначала они обучают модель-учителя классифицировать картинки на датасете MNIST.
  После этого авторы обучают компактную модель-ученика
  с помощью ранее полученного учителя на тех же данных,
  но опуская при этом все картинки цифры 3.
  После этого авторы показывают,
  что, если исправить коэффициент сдвига для данного класса
  в последнем слое сети-ученика с помощью небольшой валидационной выборки,
  //// Не понял. Придется смотреть в оригинал.
  сеть способна верно определить 98.6 картинок тройки,
  несмотря на то, что во время обучения она не видела ни одного примера.
  Также косвенным подтверждением данной гипотезы можно считать
  и тот факт, что при использовании довольно популярной сейчас
  техники сглаживания разметки (label smoothing),
  https://arxiv.org/abs/1906.02629
  эффективность дистилляции знаний заметно падает.
  Именно теневые знания на данный момент являются де-факто
  стандартным объяснением эффекта Хинтоновской дистилляции знаний.
  
  Использование температуры при подсчете KL-дивергенции
  
  В качестве дополнительной эвристики
  авторы также предлагают перед взятием KL-дивергенции
  сглаживать распределения учителя и ученика с помощью температуры ?,
  то есть вместо ? и ? считать KL-дивергенцию между ? и ?,
  где:
  
  ......
  
  Здесь с помощью ? обозначены логиты классов,
  предсказанные моделью-учеником.
  Формула для ? выглядит аналогично.
  
  Зачем нужна температура?
  Давайте рассмотрим формулу дополнительного слагаемого функции потерь.
  Для простоты выкладок я ограничусь функцией потерь
  для единственного объекта под номером ?, а также опущу постоянный множитель ?,
  который также не существенен для данного повествования.
  
  ......
  
  Вспомним, что коэффициенты ? приходят из предобученной модели-учителя,
  а значит являются константными с точки зрения процесса оптимизации.
  В таком случае несложно видеть, что мы имеем дело
  с чем-то очень близким к стандартной кросс-энтропийной функции потерь,
  но таргет ? - это уже не one-hot закодированные номера классов,
  а что-то более интересное.
  В таком случае компоненты предсказания ученика, которые отвечают классам,
  оценённым учителем, как наиболее вероятные,
  получат большие веса и сформируют каркас итоговой функции потерь.
  В то же время все прочие компоненты получат околонулевые коэффициенты
  и влияния на функцию потерь практически не окажут.
  В какой-то степени эффект от этого может быть позитивным.
  Действительно, так как для преобразования предсказания нейронной сети
  в распределение вероятностей мы используем ?,
  итоговая модель не может предсказать строго нулевую вероятность.
  Поэтому типичное предсказание обученной сети
  содержит в себе множество практически нулевых значений.
  При этом порядок между данными значениями определяется в первую очередь
  не похожестью объекта на представителей данных классов,
  а конкретным исходом стохастического процесса обучения данной модели.
  В таком случае нам вовсе не хотелось бы вынуждать ученика
  воспроизводить данный порядок,
  если ценой тому будет ухудшение точности предсказания истинного класса.
  
  С другой стороны, нейронные сети являются зачастую
  излишне уверенными в себе классификаторами:
  их предсказание часто содержит ярко выраженный максимум,
  вероятность которого близка к единице даже в тех случаях,
  когда модели стоило бы усомниться.
  К сожалению, для нас это значит, что при дистилляции знаний из такой модели
  мы рискуем попасть в ситуацию, что итоговые веса ? настолько малы для всех классов,
  кроме истинного,
  что наше дополнительное слагаемое по сути повторяет стандартную кросс энтропию
  и не способно внести хоть сколь-нибудь заметный вклад в обучение модели-ученика.
  Этот эффект можно нивелировать путем сглаживания предсказания учителя
  таким образом, чтобы сделать распределение ? ближе к равномерному,
  для чего, собственно и используется температура.
  
  В таком случае функция потерь задается следующим образом:
  
  .......
  
  Но в данную формулу незаметно закралась одна неприятная деталь.
  Давайте рассмотрим градиент второго слагаемого в скобках.
  Как и в прошлый раз, для простоты выкладок я ограничусь случаем
  единственного объекта под номером i и опущу константный множитель ?:
  
  .......
  
  Здесь легко узнается формула кросс-энтропийной функции потерь,
  градиент которой по логитам считается следующим образом:
  
  ......
  
  Доказательство формулы для градиента кросс-энтропийной функции потерь.
  
  ......
  
  Можно видеть, что при изменении температуры ?
  баланс между слагаемыми функции потерь
  (качеством решения задачи и качеством повторения предсказания учителя)
  нарушается.
  Действительно, если раньше мы настраивали его
  путём выбора подходящего коэффициента ?,
  то теперь мы приходим к тому,
  что при изменении температуры коэффициент ? необходимо также менять:
  иначе при взятии градиента одно слагаемое функции потерь
  будет разделено на ?, а другое останется неизменным.
  Разумным кажется ввести множитель ? в формулу для ? явным образом.
  Однако прежде, чем мы сделаем это,
  давайте ещё раз внимательно посмотрим на получившийся градиент:
  
  ........
  
  где через ? обозначены логиты, предсказанные моделью-учителем.
  
  Давайте теперь устремим ? к бесконечности.
  Раскладывая экспоненты в ряд Тейлора до первого слагаемого, получаем:
  
  .......
  
  Вспомним теперь, что результат применения преобразования ?
  не зависит от сдвига на константу,
  поэтому на выходе из нейронной сети мы можем вычитать из логитов
  среднее значение таким образом, чтобы ?.
  В таком случае, предыдущая формула упрощается до:
  
  ........
  
  
  Из этой формулы следует два вывода.
  Во-первых, можно видеть, что для соблюдения баланса второе слагаемое в ?
  правильнее будет домножить не на ?, а на ?.
  Во-вторых, в данной формуле можно узнать градиент квадратичной функции потерь
  между векторами логитов.
  То есть при стремлении температуры ? к бесконечности
  градиент второго слагаемого в ? стремится
  к градиенту квадрата нормы разности между логитами модели-ученика
  и модели-учителя.
  Таким образом, мы приходим к финальной версии функции потерь:
  
  ........
  
  Описанная выше статья произвела настоящий фурор в 2014 году.
  Дистилляция знаний путем минимизации KL-дивергенции
  между предсказаниями ученика и учителя
  хорошо зарекомендовала себя на практике
  и породила целый ряд исследований,
  направленных на использование и усовершенствование предложенного подхода.
  Вместе с методом прижилось и понятие теневых знаний,
  и его довольно часто можно встретить в статьях,
  посвящённых данной тематике.
  Кроме того, зародилась традиция изучения дистилляции знаний
  на примере задачи классификации картинок.
  Дальше по ходу параграфа мы ещё не раз столкнёмся с тем,
  что авторы различных методов часто прилагают результаты экспериментов
  на таких датасетах, как CIFAR-10, CIFAR-100, ImageNet и т.д.
  Тем не менее, сети для работы с данными других модальностей тоже дистиллируют,
  и начнем мы с разбора статьи,
  которая использует предложенный метод
  для решения задачи языкового моделирования (language modelling).
  
  DistilBERT как пример хинтоновской дистилляции
  
  Одним из наиболее выдающихся примеров применения Хинтоновской дистилляции
  можно считать модель DistilBERT, которая сохраняет 97% качества модели BERT
  https://arxiv.org/abs/1910.01108
  (согласно бенчмарку GLUE) используя при этом на 40% меньше параметров
  и требуя на 60% меньше времени при применении.
  При этом столь выдающийся результат авторы получают,
  используя хинтоновский подход практически без изменений.
  
  По аналогии с тем, как это делалось для модели-учителя
  (в роли которого выступает BERT),
  авторы обучают свою модель решать задачу маскированного языкового моделирования.
  В дополнение к хинтоновской функции потерь использовалось
  ещё косинусное расстояние между итоговыми векторными представлениями токенов,
  полученными с помощью ученика и учителя;
  таким образом, разворачивая представлений ученика в сторону направлений,
  задаваемых представлениями модели-учителя.
  //// Ну, использование дополнительного "косинусного расстояния",
  //// вряд ли, можно считать "практически без изменений".
  //// Интересно было бы понять какое влияние вносит такое "без изменений".
  
  Ещё одной интересной деталью в данной статье является
  способ инициализации модели-ученика.
  Действительно, в качестве архитектуры для своей сети,
  авторы решили переиспользовать архитектуру самого BERT-а,
  но с уменьшенным вдвое для ускорения числом слоёв.
  Авторы замечают, что большинство операций,
  которые используются в трансформерах,
  уже достаточно хорошо оптимизированы во всех популярных библиотеках,
  поэтому изменение размера внутренних представлений
  оказывает существенно меньшее влияние на итоговое время применения сети,
  нежели изменение количества слоев.
  Поэтому в статья фокусировалась на сжатии модели именно в глубину,
  оставляя ширину неизменной.
  
  Поскольку веса слоёв модели-ученика имеют при таком подходе
  такие же размерности, что и веса слоёв модели-учителя,
  последние можно использовать при инициализации.
  Ровно так авторы и поступают,
  копируя веса каждого второго слоя исходной модели для инициализации DistilBERT.
  Может показаться, что умная инициализация не критична
  и наихудшим следствием использования более примитивной стратегии
  будет всего лишь увеличение времени, требуемого для обучения модели-ученика.
  Но авторы провели ablation study и выяснили,
  что обучение без умной инициализации приводит
  к потере почти 4.8% процентных пункта итоговой метрики
  (обученная без неё модель сохраняет лишь 92.2% качества модели-учителя).
  //// Еще один довод в пользу того, что этап инициализации
  //// пока одно из самых темных мест в машинном обучении нейросетей.
  //// И, по-видимому, не менее важным является еще этап самого начального обучения,
  //// о котором пока вообще нигде не упоминается.
  Для сравнения исключение из функции потерь кросс-энтропии
  между предсказанием ученика и истинной разметки приводит к потере лишь
  0.4 процентных пункта итоговой метрики,
  а исключение KL-дивергенции приводит к потере 3.8 процентных пункта.
  //// Интересные цифры, ну ведь правда же.
  //// Все "математические изыски" оказываются менее эффективными
  //// по сравнению с какой-то "осмысленной" инициализацией.
  //// И это, опять же, косвенно подтверждает мысль,
  //// что важнее всего "маршрут обучения",
  //// который существенно зависит от "стартовой позиции",
  //// а не конкретная формула "функции потерь".
  
  Интересно, что двумя годами позднее вышла независимая статья,
  https://arxiv.org/abs/2106.05945
  авторы которой показали,
  что хинтоновская дистилляция является очень сложной оптимизационной задачей
  со множеством локальных минимумов,
  которые сильно усложняют поиск глобального.
  Поскольку данная статья была написана независимо другими авторами,
  конкретный пример DistilBERT там не изучается,
  однако в целом авторы приходят к выводу,
  что умная инициализация может быть
  ключевым элементом
  для успеха дистилляции знаний.
  //// Приятно, что не один я такой, кто тоже обратил на это внимание.
  
  Дополнительные источники знаний для дистилляции
  
  Несмотря на широкий успех хинтоновского подхода,
  дистилляция знаний им не ограничивается.
  Одним из наиболее очевидных направлений улучшения предложенного метода
  является использование дополнительных способов передачи знаний
  от модели-учителя к модели-ученику.
  Действительно, в хинтоновской постановке
  единственным каналом передачи знаний являются выходы
  с последнего слоя модели-учителя.
  Однако в случае нейронных сетей это отнюдь не единственный
  доступный нам источник информации.
  Например, можно использовать веса модели-учителя для умной инициализации,
  как при обучении DistilBERT.
  К сожалению, поскольку дистилляция знаний практически всегда
  сопряжена со сжатием модели,
  не всегда получается непосредственно использовать веса учителя,
  и в каждом отдельном случае
  приходится изобретать специализированные трюки.
  По этой причине DistilBERT является единственной
  известной автору этого параграфа моделью,
  в которой удалось добиться улучшения результатов
  благодаря использованию весов модели-учителя для умной инициализации.
  
  Тем не менее, в нейронных сетях можно найти и другие источники информации.
  Хинтоновская дистилляция использует только выходы с последнего слоя сети.
  Почему бы нам дополнительно не использовать выходы промежуточных слоев?
  И действительно, исследования показывают,
  https://arxiv.org/abs/1412.6550
  что использование выходов промежуточных слоев
  позволяет улучшить результаты дистилляции знаний.
  
  Для получения прироста качества авторы предлагают выбрать
  один или несколько промежуточных слоев модели-учителя,
  сопоставить каждому из них промежуточный слой модели-ученика,
  после чего использовать квадрат нормы разности выходов
  итоговых пар слоев в качестве дополнительного слагаемого
  к хинтоновской функции потерь.
  //// Вот опять вся ставка на "завернутость" функции потерь.
  //// Именно это мне и не нравится в существующем "математическом обосновании"
  //// машинного обучения.
  //// Все "математические усилия" направлены на обосновании "оптимальности"
  //// или "обоснованности" в каком-то смысле этой самой "функции потерь".
  //// И на этом вся "математика" быстро заканчивается,
  //// так как оценить предполагаемый результат в каждом конкретном случае
  //// оказывается невозможно.
  //// А практика еще и показывает, что "теоретически обоснованные" ухищрения
  //// работают как-то не так, а то и вовсе не работают.
  //// А работают какие-то примитивные/наивные и "полушаманские" методы.
  
  К сожалению, несмотря на кажущуюся прямолинейность данного подхода,
  здесь возникают две сложности.
  
  Во-первых, мы явным образом предполагаем наличие заранее выбранных пар слоев,
  оставляя за бортом вопрос о том,
  каким образом их собственно стоит выбирать.
  Поскольку дополнительные слагаемые функции потерь
  по сути обучают модель-ученика повторять
  промежуточные представления модели-учителя,
  разумным кажется сохранять порядок слоев:
  слои из середины модели-учителя сопоставлять со слоями
  из середины модели-ученика,
  а слои, находящиеся ближе к концу модели-учителя,
  - со слоями, находящимися ближе к концу модели-ученика.
  В частности, авторы оригинальной статьи
  просто берут средний слой в каждой из моделей
  и используют их в качестве своей единственной пары,
  однако это в большей степени связано с тем,
  что статья была написана в 2014 году
  и рассматривала достаточно маленькие по современным меркам модели.
  Более свежие статьи, как правило, работают с более глубокими сетями,
  а потому используют большее количество пар слоев.
  Так, авторы следующей работы
  https://arxiv.org/abs/1612.03928
  рассматривают глубокие сверточные сети с промежуточными связями
  (residual connections)
  и предлагают разбивать каждую из моделей на группы блоков
  с промежуточной связью таким образом,
  чтобы итоговое количество групп совпало.
  Пример такой разбивки можно видеть на картинке ниже.
  Здесь к каждой группе относится по 3 блока в модели-учителе
  и по 2 блока в модели-ученике.
  После этого выходы каждой такой группы можно сопоставить друг другу
  и использовать для дистилляции знаний.
  
  Рис. 2. https://arxiv.org/abs/1612.03928
  
  После того, как пары слоев были выбраны,
  перед нами может возникнуть и второе препятствие:
  что, если выходы выбранных слоев различаются по размерам?
  Такая ситуация запросто может случиться,
  ведь мы хотим, чтобы модель-ученик была поменьше,
  а одним из способов сжатия является как раз уменьшение количества нейронов
  в полносвязных слоях.
  В таком случае авторы оригинальной статьи предлагают использовать
  дополнительное преобразование,
  например, линейный слой,
  чтобы придать выходам модели-ученика нужные размеры.
  Такие слои обучаются совместно с моделью-учеником,
  а после исключаются из сети при применении.
  В более поздних работах встречаются и другие,
  более продвинутые преобразования.
  
  Несмотря на кажущуюся интуитивность дистилляции промежуточных выходов,
  практическое применение данного метода,
  к сожалению, осложняется необходимостью выбора целого ряда гиперпараметров.
  Скажем, оптимальные тактики выбора пар слоев для дистилляции
  или дополнительных преобразований для выравнивания размерностей выходов
  до сих пор являются предметами активных исследований,
  точно так же, как и функции потерь для оптимизации.
  
  Иерархия методов дистилляции знаний
  
  Выше мы рассмотрели два подхода к дистилляции знаний:
  хинтоновскую дистилляцию и дистилляцию промежуточных представлений.
  Как мы уже упоминали ранее,
  в последние годы область применения дистилляции знаний сильно разрослась,
  и новые методы появляются день ото дня.
  Это породило довольно естественное желание
  систематизировать предложенные методы в некоторую иерархию.
  Мы рассмотрим классификацию методов по:
  
  режиму дистиляции,
  
  области применения.
  
  Режимы дистилляции знаний
  
  Различные подходы к дистилляции знаний принято делить
  по так называемым режимам.
  Выделяют три основных режима дистилляции знаний:
  offline, online и self дистилляция.
  
  Offline дистилляция знаний
  
  Все рассмотренные выше статьи так или иначе следуют некоторой общей схеме:
  в качестве учителя используется большая заранее обученная модель,
  знания из которой дистиллируются в ученика,
  в то время как сам учитель остается неизменным.
  Дистилляция в таком режиме получила название offline дистилляции знаний.
  
  Но что делать, если большой предобученный учитель для вашей задачи не доступен?
  Что если модель-учитель не помещается на доступную нам видеокарту,
  из-за чего обучение или вовсе невозможно,
  или требует в десятки раз больше времени,
  по сравнению с обучением желаемой модели-ученика?
  Что, если набор данных, описывающий вашу задачу, невелик,
  и большая модель может переобучиться на нём,
  делая дистилляцию знаний как минимум неэффективной,
  а возможно и вредной для итогового качества ученика?
  
  Online дистилляция знаний
  
  В качестве альтернативы авторы этой статьи
  https://arxiv.org/abs/1706.00384
  предлагают брать в качестве учителя модель такой же архитектуры,
  что и ученик,
  и обучать обе модели одновременно.
  То есть вместо одной модели мы случайно инициализируем две,
  после чего на каждом шаге обучения для каждой из моделей
  мы минимизируем ?, где в качестве учителя выступает другая модель.
  В таком случае в начале обучения градиент дистилляционного члена
  не будет иметь какого-то чёткого направления,
  а обучение обеих моделей будет происходить преимущественно
  за счет минимизации обычной функции потерь.
  На поздних же этапах обучения в дело включится и KL-дивергенция,
  что позволит дополнительно повысить качество каждой из моделей.
  
  Рис. 3. https://arxiv.org/abs/1706.00384
  
  Почему данный подход работает?
  Широко известно, что в ряде задач ансамблирование
  нескольких одинаковых нейронных сетей,
  одинаково обученных на одних и тех же данных,
  но из разных случайных инициализаций,
  дает прирост в итоговой метрике.
  Этот факт подталкивает нас к выводу о том,
  что в зависимости от инициализации одна и та же нейронная сеть
  вычленяет из данных разные закономерности.
  //// Может быть, это все-таки имеет смысл как-то по другому называть.
  //// Например, имеют разный "рельеф решения".
  //// Мне "почему-то" кажется, что в такой формулировке этот процесс
  //// может быть не только более понятным, но и более "управляемым".
  Опираясь на данный вывод, авторы вышеупомянутой статьи
  утверждают, что в предложенной постановке
  каждая из моделей в процессе обучения
  может воспользоваться информацией,
  которая иначе была бы доступна только модели,
  стартовавшей из другой инициализации.
  
  Авторы проводят ряд экспериментов с моделями разных размеров,
  обучая их на датасетах CIFAR-100 и Market-1501,
  и показывают, что использование даже одной дополнительной модели
  позволяет добиться заметного улучшения
  в качестве предсказаний обучаемой модели.
  //// Ну, ведь интересно то как.
  Так на датасете CIFAR-100 совместное обучение ансамбля из двух моделей
  практически во всех экспериментах дает прирост в 1-2 процентных пункта
  к итоговой точности предсказания,
  причем метод позволяет достигнуть положительного эффекта
  даже для самой большой из рассмотренных моделей
  при её совместном обучении с самой малой моделью.
  Кроме того, авторы проводят ряд экспериментов,
  в которых сравнивают offline дистилляцию большей модели в меньшую
  с их совместным обучением
  и показывают, что предложенный метод позволяет добиться лучших результатов.
  //// А если попробовать не две, а больше моделей разной архитектуры?
  
  Online-постановка естественным образом обобщается
  на случай большего числа моделей в обучаемом ансамбле.
  В таком случае в качестве дистилляционного слагаемого
  авторы предлагают минимизировать среднее значение KL-дивергенций от текущей модели
  до предсказаний каждой из других моделей в ансамбле,
  поскольку минимизация KL-дивергенции до усредненных вероятностей
  приводит к худшему результату.
  При этом авторы в своих экспериментах показывают,
  что увеличение числа моделей в ансамбле
  приводит к улучшению результатов обучения.
  Кроме того авторы отмечают,
  что для ускорения обучения можно достаточно эффективно
  использовать несколько видеокарт,
  поскольку на каждом шаге между устройствами передавать необходимо
  только результаты предсказания.
  
  Самодистилляция
  
  В качестве отдельного режима дистилляции знаний
  принято выделять также самодистилляцию (self distillation),
  при которой учитель и ученик являются одной и той же моделью.
  //// А это просто крайне интересно,
  //// так как потенциально может быть трансформирован в новую методику обучения.
  Самодистилляция включает в себя две основные группы методов.
  
  Первая группа методов направлена на использование информации,
  которая накапливается в модели во время обучения,
  для дополнительного улучшения качества предсказаний той же самой модели.
  Методы данной группы являются как бы продолжением
  идей online дистилляции знаний,
  поскольку учитель и ученик обучаются одновременно.
  Хороший пример метода из данной группы можно найти в этой статье,
  https://arxiv.org/abs/1905.08094
  где авторы пытаются заставить представления менее глубоких слоев
  быть эквивалентными представлениям более глубоких слоев.
  А именно, авторы предлагают разделить сеть на несколько частей (4 в статье)
  и после каждой такой части добавить небольшую предсказательную голову.
  Все такие головы обучаются путем минимизации суммы трёх слагаемых:
  
  кросс-энтропии с истинной разметкой,
  
  KL-дивергенции с предсказаниями полной сети,
  
  квадратичной функции потерь между промежуточными представлениями данной головы
  и выходом последней части сети.
  
  Рис. 4. https://arxiv.org/abs/1905.08094
  
  //// Тут надо хорошо подумать, что собственно такое обучение обеспечивает?
  //// Как это отражается в конечном состоянии этих частей?
  //// Обеспечивает это дополнительную линеаризацию свойств сети,
  //// или, наоборот, дополнительную нелинейность.
  //// Опять, наверно, придется пытаться расшифровать оригинал.
  //// Но скорее всего там будет опять трехэтажные формулы "функций потерь"
  //// и пара-тройка невразумительных результирующих графиков.
  //// Таков уж стандарт этих публикаций.
  
  Таким образом авторы добиваются от ResNet50 81.04% точности предсказания
  на тестовой выборке CIFAR-100 с минимальным замедлением обучения.
  Для сравнения, стандартное обучение такой же сети позволяет добиться
  лишь 77.68% точности предсказания,
  а дистилляция из ResNet152
  (которая, в свою очередь, показывает точность предсказания в 79.21%)
  позволяет улучшить данный показатель лишь до 79.31%.
  При этом обучение в предложенном режиме занимает 5.87 часов
  (обычное обучение занимает 4.03 часа),
  а дистилляция из ResNet152 занимает уже 12.31 часов
  без учета обучения модели учителя (что требует дополнительных 14.67 часов).
  
  Вторая группа методов по сути заключается
  в offline дистилляции из обученной модели в новую модель такой же архитектуры.
  То есть мы выбираем некоторую архитектуру нейронной сети,
  обучаем одну модель стандартным образом,
  а затем обучаем точно такую же модель из новой случайной инициализации
  с использованием хинтоновской дистилляции из ранее обученной модели.
  Стоит заметить, что с хинтоновской точки зрения
  данное действие едва ли способно улучшить итоговое качество модели.
  Действительно, будучи точно такой же моделью,
  ученик обладает идентичной способностью к обучению,
  а значит учитель едва ли может предоставить ему
  какую-либо дополнительную информацию во время обучения.
  //// Кроме изменения "маршрута обучения",
  //// а это может быть принципиально важно/полезно.
  Поэтому такая самодистилляция изначально была предложена
  как метод изучения процесса хинтоновской дистилляции знаний,
  поскольку в такой постановке у задачи минимизации KL-дивергенции
  гарантированно есть глобальный минимум,
  причем мы даже знаем точку, в которой он достигается.
  В частности именно с помощью данного метода авторы ранее упомянутой статьи
  https://arxiv.org/abs/2106.05945
  демонстрируют, что хинтоновская дистилляция знаний
  является сложной оптимизационной задачей.
  
  Тем удивительнее, что авторы этой статьи 2018 года обнаружили,
  https://arxiv.org/abs/1805.04770
  что самодистилляция в предложенной выше постановке
  позволяет получить прирост в обобщающей способности итоговой модели.
  Так, авторы проводят ряд экспериментов с моделями DenseNet и Wide-ResNet
  на датасете CIFAR-100 и показывают, например,
  что самодистилляция DenseNet-112-33 позволяет повысить точность предсказания
  на тестовой выборке с 81.75 до 83.05.
  //// Ну, вот Вам реальная цифра эффективности влияния на "маршрут обучения",
  //// по сравнению с добавлением дополнительных членов в "функцию потерь".
  
  Вопрос об источнике прироста качества в данном случае
  до сих пор является в значительной степени открытым.
  Авторы статьи приписывают данный эффект
  комбинации умного сглаживания разметки
  и внесения в обучение информации о взаимоотношении классов в датасете.
  Но на взгляд автора этого параграфа
  эксперименты, которые предъявляют в статье
  в качестве доказательства этих гипотез,
  едва ли можно назвать убедительными.
  Возможно, здесь в очередной раз проявляется то,
  что одинаковые модели могут вычленять из одних и тех же данных
  разные закономерности
  в зависимости от случайной инициализации,
  и дистилляция одной такой модели в другую
  позволяет ученику увидеть ранее недоступные ему связи.
  //// А это уже демонстрация применения "бритвенного прибора монаха из Оккама" -
  //// зачем искать новые объяснения, если есть старые объяснения,
  //// "доказавшие свою эффективность и понятность".
  Также хочется обратить внимание на интересную статью, вышедшую в 2020 году,
  https://arxiv.org/abs/2002.05715
  в которой показывается, что в случае обучения с L2-регуляризацией
  предложенная выше самодистилляция производит неявный отбор признаков.
  
  Ну, и, раз мы проходили мимо самодистилляции,
  здесь никак нельзя не упомянуть статью 2019 года
  https://arxiv.org/abs/1911.04252
  которая в течении практически года держала почетный статус SOTA на датасете ImageNet.
  Её авторы предлагают подход, который во многом очень близок к описанному выше.
  А именно они обучают модель на исходном наборе данных,
  после чего используют ее для разметки новых данных,
  взятых в данном случае из стороннего обширного набора данных JFT-300M
  (закрытый набор данных, который нередко упоминается в статьях от Google).
  После этого авторы отбрасывают картинки,
  для которых модель дает неуверенные предсказания,
  чтобы избежать out-of-domain данных.
  Кроме того, они выравнивают размеры классов,
  чтобы избежать связанных с этим спецэффектов
  (согласно авторам статьи, модели меньшего размера показали себя
  более чувствительными к данной оптимизации).
  Таким образом, авторы получают большое количество
  дополнительных шумно размеченных данных,
  на котором, совместно с основным набором, они обучают новую модель.
  Эту модель, в свою очередь, можно использовать
  для получения новой разметки для дополнительных данных,
  с помощью которых обучается следующая модель,
  и такие итерации можно продолжать произвольное количество раз.
  В качестве разметки авторы предлагают использовать мягкую разметку,
  задаваемую моделью-учителем,
  но и бинаризованная разметка показывает схожие результаты на in-domain данных.
  Ключевой деталью здесь является то,
  что предсказание на новых данных производится без аугментаций,
  в то время как ученик учится воспроизводить разметку
  уже с высоким уровнем аугментации данных,
  а также с применением других техник регуляризации,
  таких как dropout и stochastic depth.
  Авторы утверждают,
  что ученик обучается лучше переносить свои знания на новые данные.
  Предложенный метод позволил авторам добиться от модели EfficientNet-L2
  точности предсказания в 88.4% на тестовом наборе данных ImageNet,
  существенно улучшив результат исходной модели в 85.5% и обновив мировой рекорд.
  
  Области применения дистилляции знаний
  
  Сжатие генеративных состязательных сетей
  
  Подавляющее большинство рассмотренных выше статей, так или иначе,
  ограничиваются задачей классификации картинок.
  Такой выбор, хоть и не является случайным,
  всё же несет больше исторический, нежели практический характер.
  На самом деле, многие предложенные выше методы
  достаточно тривиально могут быть обобщены и на другие задачи машинного обучения.
  Например, метод дистилляции промежуточных представлений по сути
  вовсе никак не зависит от природы итоговых выходов модели,
  а потому может использоваться при сжатии практически любой модели.
  В частности данный метод может быть использован
  для сжатия генеративных состязательных сетей.
  Так авторы довольно популярной статьи в данной области
  https://arxiv.org/abs/2003.08936
  демонстрируют 9 - 10- и даже 20-кратное ускорение
  для ряда популярных pix2pix генеративных сетей,
  при этом не теряя в качестве генерации.
  
  Как уже упоминалось ранее, авторы используют дистилляцию
  промежуточных представлений:
  модель-ученик учится минимизировать L2-расстояние
  между своим промежуточным представлением
  и промежуточным представлением модели-учителя.
  Но, так как данные представления имеют различное количество каналов
  (ученик выучивает более сжатое представление)
  авторы используют дополнительную свертку 1х1 над представлением ученика
  для сопоставления тензоров друг с другом.
  
  Помимо дистилляции промежуточных представлений,
  авторы также пользуются наличием модели-учителя для того,
  чтобы получить парную картинку в случае обучения на неспаренных данных
  (как это происходит, например, в CycleGAN).
  Парная картинка используется для минимизации L1 нормы разности
  с предсказанием модели.
  Кроме того, авторы во время обучения минимизируют
  и стандартную для генеративных состязательных сетей функцию потерь,
  при этом для модели-ученика используется такой же дискриминатор,
  что и для модели-учителя,
  что позволяет авторам инициализировать веса
  с помощью весов оригинального дискриминатора.
  
  Таким образом, авторы предлагают следующий рецепт
  для сжатия генеративных состязательных сетей.
  Сначала необходимо обучить модель-учителя.
  После этого нужно сконструировать сжатый генератор-ученика,
  скопировать (вместе с весами) дискриминатор
  и обучить получившуюся систему с помощью минимизации
  взвешенной суммы трех функций потерь:
  
  Стандартной функции потерь генеративных состязательных сетей.
  
  L1-расстояния между предсказанием генератора и парной картинки.
  При этом если в данных парной картинки нет,
  вместо неё используется результат генерации моделью-учителем.
  
  L2-расстояния между промежуточными представлениями двух генераторов.
  
  Данный метод хорошо себя зарекомендовал на практике
  и получил широкое распространение в своей нише.
  
  Дистилляция знаний при квантизации моделей
  
  Еще одним интересным применением дистилляции знаний
  является улучшение результатов квантизации моделей.
  Техника квантизации нейронных сетей заключается в том,
  чтобы перевести часть весов или даже всю сеть из полной точности
  (как правило, float32) во float8 или даже float4.
  Помимо очевидной экономии памяти,
  такое представление нередко позволяет использовать
  специальные ядра современных графических ускорителей
  или специальные регистры процессоров
  для достижения существенного ускорения при применении квантизованных моделей.
  К сожалению, бесплатный сыр бывает только в мышеловке.
  Сжатое представление на то и называется сжатым,
  что является менее богатым, нежели полная точность.
  Поэтому большинство весов сети приходится изменять при сжатии,
  чтобы они попали на более грубую сетку.
  Разумеется изменения каждого отдельного веса может показаться незначительным,
  однако когда все веса сети незначительно изменяются,
  итоговый результат подсчетов может оказаться вовсе неузнаваемым.
  Чтобы смягчить данный эффект,
  модель принято доучивать после квантизации.
  И вот здесь на помощь приходит дистилляция знаний:
  например, из сети полной точности в квантизованного ученика.
  Ровно к такой схеме приходят авторы данной статьи.
  https://arxiv.org/abs/1711.05852
  Итоговая схема выглядит следующим образом:
  мы обучаем сеть в полной точности,
  квантизуем ее веса
  и доучиваем ее в квантизованном виде
  с использованием дистилляции знаний из сети в полной точности.
  
  Дистилляция знаний за пределами сжатия моделей
  
  Хочется отметить, что сжатие моделей является хоть и основным,
  но все же не единственным применением дистилляции знаний.
  Так, раньше в этом параграфе уже упоминалась самодистилляция,
  которая позволяет получать прирост в обобщающей способности обучаемой модели
  без использования моделей большего размера.
  
  Самодистилляцией, однако, примеры применения дистилляции знаний
  без сжатия модели не ограничиваются.
  Так, в 2020 году был предложен метод BYOL предобучения без учителя,
  https://arxiv.org/abs/2006.07733
  основанный на дистилляции знаний.
  
  Метод BYOL направлен на предобучение моделей компьютерного зрения
  и основан на идее так называемого контрастивного предобучения
  (contrastive pretraining).
  Суть методов данного семейства заключается в том,
  чтобы обучать модель выдавать схожие представления
  для различных аугментаций одной и той же картинки.
  Действительно, случайные патчи, вырезанные из фотографии автомобиля,
  скорее всего также являются фотографиями автомобиля.
  При этом, если в наших данных присутствует
  достаточное количество фотографий различных автомобилей,
  мы можем надеяться на то, что модель выучит
  некоторое общее понимание концепта автомобиля
  даже несмотря на то, что мы можем вовсе не знать,
  на каких конкретно картинках автомобили присутствовали,
  а на каких - нет.
  
  Однако если мы хотим добиться от такой модели осмысленных представлений
  сначала нам необходимо преодолеть проблему коллапса представлений.
  Действительно, у предложенной выше задачи есть тривиальное решение,
  в котором выход обучаемой сети не зависит от ее входа.
  В таком случае представления для произвольных аугментаций любой картинки
  будут совпадать, то есть функция потерь окажется нулевой.
  Тем не менее, сами представления при этом окажутся совершенно бесполезными.
  Поэтому различные методы контрастивного обучения
  отличаются в первую очередь как раз способами борьбы
  с проблемой коллапса представлений.
  Так, авторы метода BYOL часто сравнивают свои результаты
  с довольно свежим на момент написания статьи методом SimCLR,
  https://arxiv.org/abs/2002.05709
  в котором предлагается обучать модель одновременно минимизируя расстояния
  между парами представлений для различных аугментаций одной картинки
  и максимизируя раccтояния между представлениями для различных картинок.
  При этом, для повышения эффективности такого обучения,
  во время генерации батча данных
  авторы сначала выбирают некоторое количество картинок из набора данных,
  затем для каждой картинки производят две различные случайные аугментации,
  после чего полученные картинки используются для создания одной позитивной пары,
  расстояние между представлениями которой будет минимизироваться,
  а также для создания множества негативных пар с аугментациями других картинок в батче,
  расстояния между представлениями которых будут максимизироваться.
  
  Авторы BYOL подвергают данный подход критике,
  показывая, что для эффективного обучения SimCLR требует большого размера батча,
  а также довольно агрессивных аугментаций.
  В противном же случае качество обучаемых представлений заметно падает.
  Авторы BYOL объясняют данный эффект тем,
  что сам подход использования негативных пар является субоптимальным,
  поскольку требует аккуратного выбора негативных примеров.
  Поэтому свой метод авторы конструируют таким образом,
  чтобы модель обучалась только на позитивных парах картинок.
  
  В таком случае
  каким образом авторам удается решить проблему коллапса представлений?
  Для этого, вместо минимизации расстояния между представлениями обучаемой сети
  для двух аугментаций одной картинки,
  авторы обучают свою модель минимизировать расстояние
  между представлением обучаемой (online) сети для одной аугментации
  и представлением для второй аугментации,
  которое задается уже другой, целевой (target) сетью.
  То есть в некотором смысле здесь происходит
  дистилляция знаний из целевой сети в обучаемую.
  //// Вот не понял этой техники. Тут смущает терминология "целевая".
  //// Никак не могу к этой терминологии привыкнуть/приспособиться.
  
  Последней важной деталью является природа целевой сети.
  Авторы BYOL замечают,
  что даже использование произвольно инициализированной сети
  в качестве целевой для предложенного выше метода обучения
  приводит к выучиванию обучаемой моделью осмысленных представлений.
  Подробнее, линейный классификатор, обученный
  на основе выученных таким образом представлений картинок
  из набора данных ImageNet показывает 18.8 тестовой точности предсказания,
  в то время как использование представлений задаваемых самой целевой сетью
  позволяет добиться лишь 1.4 точности.
  Мотивированные данным наблюдением,
  авторы предлагают в качестве целевой использовать такую же сеть,
  что и обучаемая. При этом:
  
  градиенты не текут через целевую модель,
  и она не обновляется на шаге градиентного спуска;
  
  обучаемая модель заканчивается дополнительным двухслойным перцептроном,
  который используется для преобразования её финальных представлений
  в представления целевой модели;
  
  веса целевой модели не меняются на шаге градиентного спуска,
  а вместо этого они обновляются между шагами
  с помощью экспоненциального сглаживания весов обучаемой модели:
  
  ......
  
  где, следуя обозначениям из статьи, мы обозначили через ?
  и ? веса целевой и обучаемой моделей соответственно,
  а ? - вещественный параметр.
  
  Рис. 5. https://arxiv.org/abs/2006.07733
  
  Предложенный метод позволяет авторам добиться уже 79.0 тестовой точности
  от линейного классификатора на наборе данных ImageNet,
  заметно превосходя предложенные ранее методы self-supervised предобучения,
  и практически преодолевая разрыв между self-supervised и supervised обучением
  классификаторов на основе ResNet.
  //// Не, не понял этой техники. И лезть в оригинал, похоже, тоже бесполезно.
  
  Стоить заметить, что сценарии применения дистилляции знаний
  отнюдь не ограничиваются выше рассмотренными.
  На данный момент уже существует множество различных подходов и алгоритмов,
  так или иначе связанных с дистилляцией знаний,
  и их количество растет день ото дня.
  Данный параграф не ставит своей целью полный обзор таких методов.
  Вместо этого всем заинтересовавшимся я рекомендую обратить внимание
  на довольно исчерпывающий обзор от 2020 года.
  https://arxiv.org/abs/2006.05525
  Здесь можно найти множество ссылок на актуальные к тому моменту статьи,
  в числе которых присутствует и большинство статей, упомянутых в этом параграфе.
  
  Открытые проблемы
  
  Завершим параграф упоминанием открытых проблем в области дистилляции знаний.
  Действительно, несмотря на впечатляющие результаты,
  дистилляция знаний всё же не является идеальным методом,
  и ряд вопросов до сих пор остаются без ответа.
  Например, с ростом популярности дистилляции знаний выяснилось,
  https://arxiv.org/abs/1910.01348
  что использование учителя с большей обобщающей способностью
  не всегда приводит к улучшению обобщающей способности ученика.
  В какой-то степени данный эффект можно списать на то,
  что компактная модель-ученик упирается в пределы своего качества предсказания,
  и тогда использование более умного учителя
  уже не приносит дополнительной пользы.
  Но это не объясняет,
  почему использование более точной модели в качестве учителя
  может приводить даже к ухудшению итоговой точности модели-ученика.
  //// Любопытный факт.
  В чём причина данного эффекта
  и как выбрать оптимального учителя для фиксированного ученика,
  до сих пор является открытым вопросом.
  
  Кроме того, как уже упоминалось ранее, достоверно известно,
  https://arxiv.org/abs/1805.04770
  что дистилляция знаний из одной сети в точно такую же
  нередко приводит к росту обобщающей способности ученика
  по сравнению со своим учителем.
  С точки зрения хинтоновской теории,
  которая является де-факто стандартным способом объяснения дистилляции знаний,
  это звучит абсурдно.
  //// Это если оперировать только концепцией "теневых знаний",
  //// но наличие "абсурда", это явный маркер того, что нужны новые концепты,
  //// например, "рельеф решения" или "маршрут обучения".
  Модель-ученик гарантированно способна приблизить ту же функцию,
  что и модель-учитель.
  Тем не менее, этого не происходит,
  а модель-ученик выучивает свое собственное представление,
  которое нередко качественно превосходит представление учителя.
  Данный факт уже сложно объяснить
  в парадигме передачи знаний от учителя к ученику,
  потому что здесь ученик оказывается в состоянии получить больше знаний,
  нежели учитель способен передать.
  Несмотря на то, что на данную тему написана уже не одна статья,
  исчерпывающего объяснения пока нет.
  
  Так или иначе, дистилляция знаний неоспоримо работает
  и является основным практическим подходом
  к сжатию нейросетевых моделей на данный момент.
  
  //// Конец цитирования.
  
  Очень качественный материал. Огромное спасибо автору.
  Есть над чем думать дальше.
  Особенно над тем, можно ли развить метод самодистилляции
  в какую-то новую методику обучения нейронок.
  
  
  =========
  
  29.01.2024 18:37
  
  Пример обучения нейросети "от входа к выходу".
  В оглавление.
  
  Существующие подходы в машинном обучении помимо всего прочего,
  страдают от "проклятия масштаба машинного обучения"
  - от необходимости использования все большего и большего датасета
  при увеличении масштабов нейросети, проще говоря от количества нейронов.
  Насколько реально с ним бороться, используя не совсем стандартный
  способ обучения нейросети можно оценить из следующего материала:
  
  "Обучение живых и <биологичная> нейронная сеть".
  Автор: aigame (Андрей Белкин)
  https://habr.com/ru/articles/562908/.
  2 июл 2021 в 12:41
  
  //// Начало цитирования.
  
  ........
  
  Я не утверждаю, что универсальный алгоритм обучения с <чистого листа>
  невозможен,
  просто в живой природе нет этому примеров.
  Поэтому искать такой алгоритм очень сложная задача,
  это практически поиск чего-то в полной темноте.
  Но у нас есть примеры интеллектов животных,
  и интеллекта Человека, понимание их природы - это более лёгкий путь.
  Если понять, как работает человеческий интеллект,
  понять, как он обучается,
  тогда и можно задаваться вопросами о более универсальных алгоритмах.
  //// Наверно, все-таки, на данном этапе лучше искать не какой-то
  //// универсальный, на все случаи жизни и все типы задач, алгоритм,
  //// а просто какой-то иной/иные.
  //// И уже потом, сравнив их эффективность, задаваться поиском универсального.
  
  Кажется, что обучение человека имеет непрерывный характер,
  не имеет явно выделенных стадий,
  его обучение универсально,
  он обучается как на неразмеченных данных,
  так и на примерах сопоставления различных модальностей.
  Для нервной системы практически не имеет значения наличия рядом учителя,
  если человек обучается, к примеру, читая книгу,
  причём замечания, которые делает учитель
  можно также отнести к просто информации аналогичной получаемой из книги.
  //// Интересный момент. Т.е., в принципе, "размеченный датасет"
  //// можно рассматривать двояко,
  //// как просто информацию, которую надо как-то усвоить,
  //// и как информацию с дополнительной оценкой, которую можно/нужно как-то учитывать.
  
  ........
  
  По существу статистическое обучение
  - это процесс подготовки и настройки опорных векторов образов, как якорей.
  //// А почему только "статистического"?
  В машинном обучении уже существует класс нейронных сетей,
  которые в своей работе очень сходны с работой биологических анализаторов
  - это нейронные сети Кохонена,
  автором которой является финский учёный Теуво Калеви Кохонен
  
  <Биологичные> нейронные сети
  
  Такой метод как моделирование помогает понять многие процессы и явления очень глубоко.
  Давайте и мы разберёмся в процессе обучения живых
  на примере модели нейронной сети настроенной
  на распознавание рукописных цифр из стандартного набора MNIST
  (а также fashion-MNIST пентаграммы предметов одежды).
  
  Наша сеть имеет вход в виде массива точек 28*28,
  каждая точка число от 0 до 1 в градации 256.
  Сеть состоит из двух слоёв:
  первый слой условно назовём слой Кохонена,
  второй слой - слой Хебба.
  
  Слой Кохонена представим массивом нейронов 32*32,
  каждый такой нейрон связан со всеми входами сети.
  Каждая такая связь определяется весом,
  вещественным числом от 0 до 1.
  Все веса будем хранить в одном массиве размером 896*896 (32*28=896),
  я использую для этого изображения, для простоты и наглядности,
  поэтому будем называть этот массив картой синаптических связей,
  или картой весов.
  Карту весов изначально заполним случайными значениями.
  Когда на вход сети подаётся образ,
  то определяется уровень активности каждого нейрона слоя Кохонена,
  через близость входного вектора и вектора хранящегося в весах нейрона.
  
  $Ai=?(1 - |Wij - Ij|) / n;$
  
  где Ai - итоговая активность i-го нейрона;
  Wij - j-тый вес i-го нейрона;
  Ij - j-тый элемент входа;
  n - длина векторов.
  
  Таким образом, получается, чем ближе входной вектор
  и вектор, хранящийся в весах,
  тем ближе активность нейрона к 1.
  Слой Кохонена работает по принципу <победитель получает всё>,
  поэтому выбираем нейрон с максимальным значением активности и обучаем его,
  сближая вектор его весов к входному вектору на определённое значение.
  //// Т.е. в данном случае обучение идет от "входа",
  //// так сказать, подгонкой весов под конкретный образ.
  //// Но что мешает сразу задать необходимые коэффициенты, без всякой подгонки?
  //// Зачем нужна процедура "последовательного приближения" к входным образам?
  //// Что при этом происходит, и что при этом достигается?
  //// Без ответов на эти ПРИНЦИПИАЛЬНЫЕ вопросы смысл процедуры "подгонки" теряется.
  //// Просто, одним черным ящиком становится больше.
  Для более быстрого обучения можно выбрать максимальный коэффициент изменения
  (Rate) вектора при обучении,
  тем самым победивший нейрон будет сразу присваивать себе
  значение входного вектора.
  
  И здесь проявляется одна из проблем,
  которая связанна с обучением по принципу <победитель получает всё>.
  В случае если начальные случайные вектора окажутся далеки от векторов примеров,
  то при обучении может возникнуть нейрон-лидер,
  который всегда будет забирать себе победу.
  //// И к чему это приведет? А если все примеры очень похожи друг на друга?
  
  Для устранения этой проблемы есть несколько решений.
  Во-первых, возможно заполнить изначально карту весов
  не случайными значениями,
  а векторами из обучающей выборки.
  Этот способ мне кажется читерским,
  ведь новорождённая система не имеет такой возможности
  как получение образов внешней среды до взаимодействия с ней.
  //// Есть такой "эффект утенка", когда "биологическая" нейросеть
  //// именно так и работает.
  Во-вторых, способ, который используется в самоорганизующихся картах Кохонена,
  это обучать не один победивший нейрон,
  но и его соседние нейроны в меньшей степени по убыванию
  при увеличении расстояния от победителя.
  //// Вот тут проблема с "расстоянием".
  //// Задание его любым способом это точно такое же "читерство".
  Постепенно можно уменьшать радиус действия обучения.
  Этот метод позволяет создавать некие карты образов,
  где можно увидеть плавных переход от одного образа к другому.
  //// А он точно должен быть "плавным"? Чем это определяется?
  
  Пример карты Кохонена на примерах MNIST
  
  Но наша задача не состоит в том,
  чтобы создавать подобные карты с плавными переходами между векторами,
  мы стремимся к специализации нейронов,
  к получению эффекта <бабушкиных нейронов>,
  то есть желательно получить как можно больше разнообразных специфичных векторов.
  //// Специализация нейронов, скорее всего, приведет к "резким переходам".
  //// Либо нужно по-другому строить саму структуру нейросети.
  Мы будем использовать принцип обучения соседей только в начале обучения,
  так как это способствует более быстрому обучению.
  
  В статье <Сравнение мозга с нейронной сетью> я высказывал идею,
  https://habr.com/ru/post/507420/
  о том, что нейрон стремиться к некому балансу в количестве его активаций,
  нежелательно отсутствие активаций, как и избыточная активность.
  Применим эту теорию к практике.
  Каждый нейрон слоя Кохонена будет иметь некий параметр
  вовлеченности в процесс обучения.
  Каждый раз, когда нейрон побеждает,
  этот параметр увеличивается обычно на достаточно высокий уровень,
  а при проигрыше этот параметр будет незначительно снижаться.
  //// Некоторая аналогия с наградами и штрафами из "обучения с подкреплением"
  //// точно напрашивается.
  //// Но интересен сам критерий "вовлеченности в обучение".
  И этот параметр будет влиять на вероятность победы нейрона,
  чем выше вовлеченность в обучение, тем ниже шанс победить.
  //// Это какой-то "костыль" без особого обоснования.
  То есть победа нейрона определяется не только близостью вектора
  на весах нейрона и входного вектора,
  но и тем насколько давно или насколько часто побеждал нейрон.
  Тем самым нейроны в обучение вовлекаются более равномерно по слою.
  //// Т.е. задача стоит "равномерного обучения",
  //// но конечный образ того каким должен быть результат этого обучения
  //// - отсутствует. Так что это опять проходит по разряду "полушаманских практик".
  
  После предъявления сети 2 000 случайных примеров
  мы заполним все веса всех нейронов слоя различными примерами,
  здесь выделяются примеры разных цифр с различным их начертанием.
  Для того, чтобы увидеть результат работы слоя в режиме выполнения,
  делаем следующее:
  во-первых, определяем уровень активности каждого нейрона в слое Кохонена
  по формуле описанной выше,
  во-вторых, определяем максимальные и минимальные значения активности в слое.
  Далее вычисляем для каждого нейрона
  значение отношения к максимальному и минимальному значениям,
  по формуле (факт - min)/(max - min).
  Тем самым минимальное значение приравнивается к 0, а максимальное к 1.
  Уже так мы наглядно видим,
  какие нейроны максимально близки к входному вектору,
  а какие максимально удалены.
  Так как полученные значения находятся в интервале от 0 до 1,
  мы можем сделать эту картину еще острее,
  контрастнее просто возведя это значение в определённую степень
  (у меня в примерах степень 15).
  Так максимумы останутся единицами,
  а значения сильно меньшие единицы станут практически равными нулю.
  Эту операцию назовём эскалацией.
  //// Ну, не знаю. Вряд ли подобные приемы имеют какую-то аналогию
  //// в "биологических сетях". Снова это больше похоже на "полушаманские практики".
  
  Получается если на вход нашего слоя Кохонена подать вектор,
  то на выходе мы получим активность наиболее близкого к входному вектору
  специализированного нейрона.
  Остаётся сопоставить эту активность с требуемым соответствующим классом.
  
  Этим занимается второй слой сети - слой Хебба.
  Слой Хебба имеет 10ть нейронов, по количеству классов,
  карта весов этого слоя имеет размер 32*320,
  то есть все нейроны слоя Кохонена связаны со всеми нейронами слоя Хебба.
  Обучение этого слоя достаточно тривиально:
  при сочетании активности нейронов из слоя Хебба и слоя Кохонена
  связь-вес усиливается,
  при отсутствии сочетания ослабевает.
  При выполнении веса просто суммируются,
  и как в слое Кохонена побеждает только одни нейрон из слоя.
  Победивший нейрон и является ответом сети.
  
  Эти два слоя могут обучаться как совместно, так и по отдельности.
  К примеру, мы можем предъявить 2 000 случайных примеров,
  обучая слой Кохонена и параллельно передавать информацию о классе примера
  на слой Хебба обучая его.
  Для моей реализации в таком режиме достаточно 2 000 примеров
  для результата в районе ?82% качества
  (тест проходит на 10 000 тестовых примерах).
  
  Ещё пример обучения, который ближе к биологическому,
  это когда слой Кохонена обучается на случайных неразмеченных примерах.
  Тем самым формируя базовые образы.
  Затем можно представить сети несколько размеченных примеров от 10 до 1000
  и обучать при этом только слой Хебба.
  
  Сеть была обучена на 2 000 не размеченных примерах
  и достаточно дообучить её на 300 размеченных примеров для качества выше 80%.
  
  Размеченных данных может быть мало относительно полученных опорных образов
  и не все смогут быть задействованы,
  в этом случае хорошим вариантом будет снижение степени при эскалации.
  
  С результатом работы и обучения сети можно ознакомиться в видео,
  озаглавливающим эту статью.
  Приведены примеры обучения на датасете MNIST.
  Возможно, скачать и запустить приложения по ссылкам ниже,
  а также посмотреть и при желании использовать исходный код реализации сети в среде Unity3D.
  
  Исходник:
  github.com/BelkinAndrey/BrainSquared
  
  Download build for Windows: MNIST; Fashion-MNIST
  
  В сравнении
  
  Описанная сеть имеет очень существенный недостаток
  - это низкое качество.
  Качество обучения этой сети всегда будет иметь некий потолок,
  который зависит от общего количества опорных образов
  хранящихся в слое Кохонена,
  чем нейронов этого слоя больше,
  тем возможный уровень качества выше.
  Но с увеличением количества нейронов требуется
  большее количество примеров для их обучения.
  //// Т.е. "проклятье масштаба машинного обучения" не преодолено.
  //// Зависимость - "больше нейронов" требует "большего датасета" - осталась,
  //// хотя направление обучения изменилось на противоположное -
  //// "от входа к выходу".
  //// Т.е. это какое-то "фундаментальное проклятие",
  //// которое требует какого-то принципиально иного подхода.
  
  Обучение по бэкпропу и обучение биологичных сетей:
  
  Обучение сети через обратное распространите ошибки
  позволяет очень точно провести границу между классами,
  чем больше примеров, тем точнее граница.
  Граница между классами при обучении сети Кохонена
  проходит только по границам локусов,
  что и создаёт неточности.
  Поэтому даже при возможности перемещать опорные вектора
  ограничение в их количестве может не дать добиться очень высокого качества.
  
  НО! Описанный тип сети имеет ряд преимуществ,
  которые потенциально делает возможным на основе их в будущем
  создать искусственный интеллект.
  Во-первых, возможность отказаться от бэкпропа.
  Обратное распространение ошибки
  это нечто чуждое биологическим нервным системам,
  пресловутая проблема переноса не решена в рамках нейронной парадигмы
  (да, уже и не нужно).
  Во-вторых, в её основе лежит самообучение,
  аналог статистического обучения,
  тренд к получению эмбеддингов при самообучении
  очень актуален в машинном обучении.
  В-третьих, лёгкость вычислений,
  что очень актуально при растущих ценах на вычислительные ресурсы.
  С этим связан еще один факт:
  Мозг - это не нейронная сеть!
  Мозг - это множество нейронных сетей!!!
  При такой концепции качество сети в 80%
  будет компенсироваться их количеством.
  Представите, что на цифру будет <смотреть> не одна сеть,
  а несколько под разным углом и масштабом,
  а итоговое значение определяется коллегиально.
  И легкость вычислений для таких конфигураций будет играть свою роль.
  
  Для эволюции большую роль играла скорость обучения,
  а не точность.
  //// И уж точно не размер обучающего датасета.
  //// Во многих реальных случаях должно быть достаточно "одной таблэтки".
  Человек не может по фотографии родинки диагностировать опухоль
  с вероятностью 99,8%.
  Точность конёк машин, а не Человека.
  Описанная сеть ближе к биологическим,
  чем нейронные сети, обучаемые на основе бэкпропа.
  
  В заключение
  
  Сети Кохонена известны уже более 40 лет,
  но они не получили за это время таково бурного развития
  как сети обучаемые на основе алгоритмов обратного распространения ошибки.
  Но в том, как обучаются эти сети больше биологического,
  чем в популярных на сегодняшний день методах обучения в машинном обучении.
  На данный момент я работаю над развитием подобных сетей,
  прежде всего над задачей создания <глубоких>, многослойных сетей.
  Подобные модели должны обучаться по принципу <снизу вверх>,
  а не <сверху вниз> как это происходит при обратном распространении ошибки.
  
  Ведь наш мозг и его зрительный анализатор в частности
  способен пассивно наблюдая обучаться
  и создавать высокоуровневые, так называемые, эмбеддинги, фичи,
  причём эти эмбеддинги будут связаны с активностью конкретных нейронов.
  //// А вот с этим можно и поспорить.
  И при этом мозг не использует бэкпроп,
  и при этом ему требуется меньше примеров.
  
  ........
  
  //// Из комментариев.
  
  aigame
  5 июл 2021 в 10:32
  
  При уменьшении слоя Кохонена до 16*16 (такая версия была)
  уменьшается итоговое качество на 10-20%.
  Это связанно с тем, что нейроны этого слоя
  как бы специализируются на определённых эталонах начертания цифры,
  чем меньше таких эталонов
  тем меньше шансов найти подходящий при сравнении со входом.
  Соответственно, чем больше размер слоя Кохонена
  тем выше будет итоговое качество сети,
  но при этом будет требоваться больше примеров для обучения.
  
  .......
  
  //// Конец цитирования.
  
  И хотя автору данного материала не удалось в этом примере
  преодолеть "проклятье масштаба машинного обучения",
  катастрофическую связку "больше нейронов" - "больше датасет",
  но кое-что полезное, он похоже нащупал.
  Изменение направления обучения "от входа к выходу"
  может дать существенную прибавку в скорости всего процесса обучения,
  даже если оно используется только на начальном этапе.
  Фактически это может быть аналогом достаточно умной инициализации нейросети,
  от которой очень многое может зависеть.
  
  А с "проклятие масштаба" вряд ли можно просто так победить,
  если не разобраться, что же собственно происходит
  при обучении нейронов в нейросети.
  
  
  =========
  
  30.01.2024 20:05
  
  Самообучение и обратное распространение влияния.
  В оглавление.
  
  Это фактически продолжение и существенное развитие предыдущего материала
  о возможности реализации самообучения нейросетей на основе
  направления обучения их "от входа к выходу"
  и организации их архитектуры с упором на "нейроны-детекторы":
  
  "Искусственные и биологические нейронные сети".
  Автор: aigame (Андрей Белкин)
  https://habr.com/ru/articles/709350/.
  7 янв 2023 в 11:25
  
  //// Начало цитирования.
  
  Это можно сравнить с поиском Священного грааля,
  поиск алгоритма, по которому работают биологические нейронные сети.
  Конечно многие скажут, что никакого грааля не существует,
  это всё легенды, и в искусственных нейронных сетях уже всё реализовано,
  осталось дождаться развития этой технологии, вычислительных ресурсов и...
  и всё - настоящий искусственный интеллект будет создан.
  А, разбираться в сложном и запутанном органе для этих целей нет необходимости.
  Но, надеюсь есть добрая доля искателей приключений,
  которым будет интересны некоторые рассуждения
  где стоит искать этот "Священный грааль".
  В статье мы проанализируем и сравним работу искусственных нейронных сетей
  с гипотезами о том, как работают биологические нейронные сети,
  и конечно, сопроводим это практическими опытами,
  разберем новую искусственную нейронную сеть,
  которая по своему принципу работы ближе к биологическому аналогу.
  
  Как же работает искусственная нейронная сеть?
  
  Начнём мы с анализа искусственных нейронных сетей.
  Нет, здесь не будет описаний принципов работы сетей,
  лучше о них расскажут другие многочисленные источники,
  здесь мы попытаемся понять некую фундаментальную суть их работы
  в части распознавания образов.
  Это очень наглядно демонстрирует одни простой пример:
  
  .......
  
  Представим сеть состоящую из двух частей энкодера и декодера,
  на вход которой будет подаваться примеры из набора рукописных цифр MNIST
  и на выходе соответственно дублируем вход.
  Обучать её будем классическим методом, обратным распространением ошибки.
  Самая узкая часть сети, самый маленький слой
  расположенный между энкодером и декодером
  будет иметь всего 2 нейрона.
  После обучения получится так, что эти 2 нейрона будут нести в себе
  информацию как, так скажем,
  кодировать образы множества начертаний всех цифр.
  Если по оси x разместить активность одного нейрона,
  а по y активность другого нейрона,
  то на диаграмме можно отметить какие точки соответствуют каждому классу,
  а с помощью декодера воспроизвести начертание цифры соответствующее точкам.
  
  ......
  
  Замечательный интерактивный пример этого можно попробовать здесь
  https://n8python.github.io/mnistLatentSpace/
  
  То, что мы получили, специалисты называют
  Малое Репрезентативное Представление (МРП),
  "малое" - потому, что у нас всего 2 вещественных числа
  отражают вектор из 784 вещественных чисел,
  а "репрезентативное" - оно потому,
  что отражает внутри сети внешний мир,
  то есть зная лишь эти два значения,
  мы можем оценить что в данный момент "видит" сеть,
  какую цифру и даже примерную форму её начертания.
  Можно сказать, что Малое Репрезентативное Представление (МРП)
  это некая модель мира,
  только сети пришлось сделать очень простую модель,
  малую, всего два числа,
  хотя внешний мир более сложен и представляет собой наборы
  из 784 вещественных чисел.
  
  Давайте взглянем подробнее, что из себя представляет
  эта Малое Репрезентативное Представление (МРП),
  мы видим несколько областей которые будут соответствовать
  определённым классам и соседние точки будут соответствовать
  очень близким по начертанию цифрам.
  Получается МРП может помочь существенно упростить
  процесс обучению распознавания.
  Мы можем взять обученный декодер, отбросив энкодер,
  добавить небольшой персептрон и достаточно быстро новую сеть
  научить распознавать рукописные цифры
  (это называется transfer learning, или перенос обучения),
  то есть сначала наша сеть, или её первая конфигурация
  обучалась только на изображениях без связи их с фактическим числом,
  такое вот самообучение (без учителя) для получения МРП,
  а затем следующая конфигурация, используя полученное МРП,
  обучается на сопоставлении изображения и метки цифры,
  обучение с учителем,
  и делает это значительно быстрее,
  чем сеть которая будет обучаться сразу на сопоставлении.
  //// Надо ли это понимать, как рекомендацию на разделение обучения
  //// уже не только по-этапно, но и еще и по подсистемам?
  
  По сути здесь класс цифры определяется некоторыми диапазонами активности двух нейронов.
  Эти диапазоны или области как мы видим на диаграмме,
  можно назвать некими эмбеддингами,
  представительствами классов внутри сети,
  которые сформировались в процессе самообучения.
  //// Т.е. даже двухэлементный эмбеддинг как МРП, может считаться "моделью Мира",
  //// следовательно, и одноэлементный эмбеддинг тоже "проекция" целого мира, см.:
  //// "Простенький" мысленный эксперимент".
  
  Далее мы поговорит о том,
  что из себя представляет Малое Репрезентативное Представление (МРП)
  в биологических сетях, в мозге,
  как в нём представлены эти эмбеддинги,
  но для начала выделим некоторые качества этих сущностей
  для искусственных нейронных сетей.
  Во-первых, в МРП задействован слой целиком,
  все нейроны слоя имеют значение.
  Представим, что мы убрали из сети один из двух нейронов,
  детектировать точно что "видит" сеть по одному нейрону будет проблематично,
  не всегда можно ответить даже на вопрос,
  а видит ли сейчас сеть, например, цифру "5".
  //// И все-таки "и один нейрон в поле (МРН) воин".
  Да, существует прунинг,
  но он возможен только при избыточном количестве нейронов,
  когда можно убрать нейроны без последствий для МРП.
  Во-вторых, чем больше нейронов в слое, задействованном в МРП
  тем сложнее выделить фичи,
  так как каждый нейрон создает свое измерение
  в пространстве представительств классов,
  2 нейрона - 2 измерения, 10 нейронов - 10 измерений:
  и все 10 будут взаимозависимы.
  //// Вот эта "взаимозависимость измерений",
  //// с одной стороны, трудно опровергаемое положение,
  //// а с другой, наиболее часто забываемое в теоретических выкладках.
  //// Ну очень непривычные получаются "пространства" для обычного мышления,
  //// если "измерения" как-то нетривиально "взаимосвязаны".
  //// В итоге или эти измерения принимаются или как "независимые",
  //// и тогда используются всяческие "формулы расстояния",
  //// или как вероятностное распределения, но опять же независимое,
  //// и тогда используются уже другие известные формулы.
  //// А чего-то другого, вроде как, даже не рассматривается.
  В-третьих, очевидная для искусственных сетей вещь,
  все нейроны слоя или даже всей сети,
  при каждом такте обучения вовлечены в него,
  каждый нейрон получит свою корректировку весов.
  
  В отличии от классических искусственных нейронных сетей
  в биологических сетях отражён нейроно-детекторный подход.
  В биологической сети нейрон выступает
  как детектор определённого признака или группы признаков.
  //// Вот не знаю как к этому положению относится.
  //// Вроде как просто все и понятно,
  //// но почему-то душу гложат сомнения, что так все "однозначно".
  //// И очень непросто сформулировать в чем собственно состоят эти "сомнения".
  Можно сказать, что за фичи или эмбеддинги
  здесь отвечают отдельные нейроны.
  Это подтверждается многочисленными экспериментами,
  существует даже шуточное название для этого явления
  - "бабушкины нейроны",
  которое говорит о том, что любому образу в нашем мозге
  будет соответствовать активность определенной клетки,
  не исключено даже наличие такой клетки для образа нашей бабушки.
  Конечно, когда мы говорим "нейрон" в данном случае,
  то подразумевается целая группа активных нейронов.
  Во-первых, прежде чем возбуждение достигнет пресловутого бабушкиного нейрона
  оно пройдет через ряд других нейронов,
  во-вторых, обычно за каким-либо образом стоит активность
  целой группы распределенных по коре нейронов,
  нейронного ансамбля или паттерна активности.
  //// Это одна причина сомнений, но далеко не все, и даже главная.
  
  Формальный нейрон искусственных сетей достаточно хорошо отражает
  принцип работы биологического нейрона,
  веса формального нейрона - отражают размеры порций медиатора
  выделяемые в синаптическую щель при активации синапса,
  а совокупное влияние нейромедиатора приводящие
  к возникновению потенциала действия отражено в пороговой функции
  формального нейрона.
  Всё замечательно, но ...
  
  при картировании первичной зрительной коры
  ("Глаз, мозг, зрение" Хьюбел Дэвид, Торстен Визель)
  фиксируется активность нейронов на определенные раздражители,
  к примеру, различной ориентации линии, отрезки, концы отрезков.
  И дело здесь не в том, что нейроны коры работают по другим принципам,
  дело, скорее, в самой организации этих нейронов.
  
  В общем, можно сказать,
  что формальные нейроны искусственных сетей более эффективно работают
  с информацией чем биологические нейроны,
  например, как мы убедились,
  для кодирования множества начертаний рукописных цифр
  может потребоваться всего два нейрона,
  а при кодировании по нейроно-детекторному принципу
  потребуется минимум 10 нейронов хотя бы закодировать 10-ть классов цифр,
  не говоря уже о различных формах начертаний этих цифр.
  Тогда возникает резонный вопрос:
  зачем вообще пытаться понять этот принцип,
  зачем искать этот Грааль?
  
  Во-первых, работая над созданием модели нейронных сетей
  в которых будет применяться нейроно-детекторный подход
  мы можем больше узнать о принципах на которых работают
  биологические нейронные сети.
  Во-вторых, хоть эволюционный процесс не идеален
  и не всегда приводит к оптимальным решениям,
  но в вопросе сбережения энергии и эффективности работы мозга
  эволюция была успешна.
  При нейроно-детекторном подходе нет необходимости
  активировать все нейроны при обучении и работе модели,
  //// Интересная мысль. Ограничение зоны обучения,
  //// как способ обеспечения энергоэффективности.
  //// Как-то над таким аргументом не задумывался.
  да, для математической модели это не даёт особых преимуществ в эффективности,
  а при реализации такой модели в "железе" может дать существенно.
  В-третьих, представьте насколько удобно использовать нейронную сеть
  состоящую из нейронов-детекторов,
  мы можем оценить о чём "думает" в данный момент сеть
  по активности нейронов,
  мы можем понять как она принимает решения,
  мы можем управлять этим решениями просто активировав нужные нейроны.
  В-четвертых, возможность обучения с одного раза
  (one-shot learning).
  //// Конечно, с точки зрения интерпретируемости, нейросеть чистых детекторов,
  //// наверное, будет более удобна.
  //// Но будет ли она при этом обеспечивать нужное качество
  //// на примерах которым она не обучалось.
  //// Т.е. задачи интерполяции и экстраполяции для такой
  //// для такой чисто "детекторной" нейросети, наверно, будут более трудными.
  
  //// Вот кажется удалось сформулировать основное сомнение
  //// в концепции этих "бабушкиных нейронов".
  //// Т.е. в моем представлении, нейросеть должна использовать нейроны-детекторы
  //// не для собственно детектирования/классификации,
  //// а как основу, опорные точки для интерполяции/экстраполяции.
  Если у Вас есть нейрон-детектор реагирующий на слово "стол"
  и нейрон-детектор реагирующий на изображение стола,
  Вам не составит труда создать между ними связь.
  В пятых, это была бы более стабильная модель в вопросе дообучения,
  переобучения (в хорошем смысле этого слова),
  а также физическом разрушении,
  если повредить нейрон-детектор ответственный за цифру "5",
  оставшиеся нейроны позволяют на хорошем уровне распознавать цифры,
  банально из-за отсутствия тесного взаимодействия уровня активности нейронов при детекции.
  Еще несколько доводов в пользу перспектив таких сетей:
  это гибкость их управления в динамике,
  а значит возможность создавать алгоритмы высокоуровневого управления этих сетей,
  подобно тому как эмоциональные системы управляют памятью
  и реакциями в нервных системах животных и человека.
  Еще есть возможность оценить новизну поступающей информации
  на любом абстрактном уровне на котором работает сеть,
  если в нашей системе существует детектор
  который реагирует на внешний раздражитель,
  и мы можем оценить степень этой реакции,
  а значит оценить близость внешнего раздражителя к внутренней памяти системы,
  что и будет оценкой новизны.
  Если критерии новизны станут важными для управления нейронной сетью
  то, это должно приблизить нас пониманию того
  как создать настоящий искусственный интеллект,
  ведь в поведении человека и животных новизна - это очень важный фактор.
  
  Как кодируют информацию биологические нейронные сети?
  
  Малым Репрезентативным Представлением (МРП) для мозга
  является SDR (Sparse Distributed Representation)
  или Разреженное Распределенное Представление (РРП).
  "Разреженное" - значит, что только небольшое число нейронов
  активны одновременно,
  а "распределенное" - означает, что активность
  эта распределена по ткани равномерно.
  Но к этому термину можно применить и слово "малое",
  так как любое представление в мозге всегда будет иметь
  меньшую размерность чем внешний мир.
  На самом деле разреженность и распределённость
  является лишь результатом работы нейро-детекторного подхода,
  мы на практике увидим, как это происходит.
  
  Многие могут связать понятие SDR с работами Джеффа Хокинса (Jeff Hawkins),
  так как он активно писал о SDR и применял его
  в своей модели Hierarchical Temporal Memory или HTM,
  но SDR это общий экспериментально наблюдаемое явление
  свойственное для нервных систем всех млекопитающих (и насекомых)
  от мышей до человека.
  Автор не разделяет взглядов Джеффа Хокинса относительно HTM,
  по причине невозможности существования HTM-нейрона
  (так как описывает его Джефф)
  который не вписывается в общепринятую нейронную парадигму
  - опять же, по мнению автора.
  
  Попробуем создать искусственную нейронную сеть
  основанную на нейроно-детекторном подходе,
  мы будем руководствоваться и вдохновляться знаниями
  о биологическом мозге и принципах его работы.
  
  Схема и организация сети
  
  Нет инструмента который бы одинаково хорошо работал
  с обычными и разреженными данными одновременно,
  поэтому механизм работы нейронов-детекторов связанных с внешними данными
  и данными возникающими внутри сети будет различаться.
  Первый слой нашей модели будет получать обычный вход,
  в данном случае 784 мерный вектор представляющий собой цифру из набора MNIST,
  и на выходе мы получим разреженность (SDR),
  а все последующие слои будут получать SDR и выдавать SDR.
  По существу, главная задача первого слоя преобразовать данные
  в разреженное представление,
  в обучении этого слоя нет необходимости.
  Перебрав множество вариантов к принципам построения этого слоя
  я пришёл к самому простому и оптимальному варианту,
  применению нескольких ядер свёртки выбранных вручную.
  Шестнадцать ядер размером 5х5.
  
  Выбор ядер определяется распространенностью паттернов в данных
  которые мы будем обрабатывать.
  К примеру, для цифр из MNIST характерны пустые,
  незаполненные пространства,
  то есть почти в каждом примере можно найти не одну область 5х5
  где все пиксели будут равны 0,
  такое ядро разумно внести в наш набор.
  Также цифры выполнены линиями, разной толщины и ориентации,
  что определяет ещё некоторые варианты ядер
  - линии разной направленности.
  Здесь важно, чтобы набор оказался максимально разнообразным.
  //// Опять же есть сомнения в этом положении.
  //// Где критерий, позволяющий разделить "максимальное разнообразие"
  //// от попытки "объять необъятное"?
  
  Как мы знаем для первичной зрительной коры свойственны нейроны-детекторы
  линий различной ориентации,
  каждая колонка фактически настроена на свой раздражитель.
  Хьюбел Дэвид и Торстен Визел в своей работе по картированию
  первичной зрительной коры ввели термин -
  гиперколонка или модуль,
  что представляет собой совокупность всех колонок
  которые имеют общее рецептивное поле,
  к примеру, небольшую область на экране
  где проецируются светящиеся линии различной ориентации.
  То есть в составе модуля (название термина модуль, для меня более приемлем,
  чем гиперколонка, так как нет созвучия с термином колонка,
  поэтому здесь и далее буду применять это название)
  присутствуют все представительства ориентаций линий для обоих глаз
  и это составляет около 1000 колонок.
  
  Рис. Гиперколонка или модуль, иллюстрации из книги
  "Глаз, мозг, зрение" Хьюбел Дэвид
  
  В нашем варианте будет всего 16-ть нейронов-детекторов в модуле
  (да, наш нейрон-детектор эквивалентен одной колонке в коре),
  каждый будет соответствовать своему ядру.
  Каждый модуль будет отвечать за свой фрагмент картинки 5х5,
  причём, как и в коре рецептивные поля колонок обычно пересекаются,
  поэтому мы будем разбивать общую картинку на фрагменты 5х5 шагом 1.
  
  Модульный принцип организации фундаментален для нашей сети,
  как для первого слоя так и для последующих.
  Главная особенность модульного построения это то,
  что победитель в модуле всегда один.
  То есть среди нейронов-детекторов модуля идет конкуренция
  которая будет определять какой нейрон в модуле
  будет иметь приоритеты в активации и обучении.
  Подобно тому как у живых колонок существует латеральное ингибирование
  (боковое торможение),
  за счёт которого колонки со слабой активностью полностью подавляется,
  а за счёт эффекта иррадиации (стремления возбуждения распространится)
  победившие колонки укрепляются в своей активности.
  
  В предыдущих своих работах я описывал опыты с пиксельным шейдером
  https://habr.com/ru/post/526850/
  в котором реализованы латеральное ингибирование и иррадиация,
  которые показывает, что любая изначальная активность
  преобразуется в небольшие точечные распределенные очаги.
  Вот и причина распределённости и разреженности.
  
  .......
  
  В коре нет явных границ модулей,
  но при создании математической модели нейронных сетей
  мы можем её сделать более точной и структурированной,
  в какой-то степени в этом наше преимущество.
  //// Или, наоборот, слабость, так модули с нечеткими границами
  //// неизвестно как реализовывать.
  //// Так что это просто следствие нашего незнания/неумения,
  //// но никак не достижение.
  Поэтому латеральное ингибирование можно заменить правилом:
  в модуле может быть активен только один нейрон-детектор.
  
  Первоначальную активность каждого нейрона в первом слое
  оцениваем по манхэттенскому расстоянию,
  //// Вот и "расстояние подтянулось"
  //// и о взаимосвязанности "измерений" уже и не вспоминается.
  но в конечном итоге, в каждом модуле будем считать активным только один,
  тот который будет иметь максимальную близость со входным вектором в модуле.
  Работа модуля может напомнить принципы работы сети Кохонена,
  наша будущая модель как будто состоит из множества малых сетей Кохонена.
  
  Примеры работы первого слоя.
  Входной вектор 28х28, ядро 5х5 шагом 1, в модуле по 16 нейронов-детекторов,
  в итоге получаем результат 24х24х16,
  которую преобразуем в планарный вид 96х96.
  Этот выход первого слоя представляет собой SDR для любого входного вектора.
  
  ......
  
  Планарность или представление данных в двумерном виде в нашем случае
  очень важна,
  так как последующие слои будут получать данные именно таком виде,
  еще это более наглядно и похоже на то как представлены данные в коре мозга.
  
  Как уже оговаривали ранее,
  главная задача первого слоя - это представление внешних раздражителей в виде SDR.
  Так как количество нейронов в модуле 16,
  то соотношение единиц и нулей в полученном SDR всегда будет 1 к 15-ти,
  для любого входного вектора.
  Наш первый слой не обучается, только преобразует данные.
  
  Так как слой производит обычное преобразование данных,
  то возможно получить и обратное преобразование,
  которое показывает, что трансформация данных происходит
  с некоторой потерей качества,
  но это необходимая жертва,
  так как полученные данные будут абсолютно нормализованы,
  полная сумма полученного вектора будет всегда одинакова,
  независимо от того,
  что подано на вход сети.
  В биологии подобные преобразования происходят уже на уровне сетчатки глаза,
  благодаря on-, off-клеткам, независимо от того,
  что проецируется на сетчатку глаза общая активность нерва
  идущего от глаза будет постоянна.
  //// Тут нужно много думать.
  //// Что-то интересное в таком SDR (1 к 15-ти) представлении, безусловно, есть,
  //// но сразу же соглашаться с этим не хочется.
  
  ......
  
  Нейроны последующих слоев будут получать на вход разреженные вектора.
  Если нейроны первого слоя, можно сказать,
  выделяли признаки из входных данных (палочки, точки, пустоты),
  то нейроны последующих слоев будут генерализировать
  то есть обобщать выделенные признаки.
  
  Неконтролируемое обучение снизу-вверх
  
  Самообучение - это главная подсказка того, где искать наш Священный грааль.
  Можно сказать, что обычно обучение у животных и человека
  в своем большинстве происходит на данных, которые не являются размеченными,
  зачастую эти данные не полные и зашумлены.
  А метки появляются в процессе обучения лишь иногда,
  в форме сопоставления модальностей,
  то есть обучение по разметке,
  контролируемое обучение является лишь вспомогательным,
  так как в основе лежит самообучение.
  
  Если говорить о задаче распознавания образов,
  то по существу нам нужен алгоритм, который позволит
  формировать разнообразный набор нейронов-детекторов,
  которые реагировали бы на явно выраженные представителей своих классов.
  Ранее в своих изысканиях я использовал алгоритм сетей Кохонена и его вариации,
  но он плохо работает с разреженным представлением,
  что не позволило мне создать многослойный вариант сети.
  Да и нейрон этой сети свою активность определяет по манхэттенской близости,
  но я склонялся к более простой версии нейрона,
  как простого сумматора.
  
  И решать задачу классификации на простых сумматорах оказалась очень просто.
  Меня заинтересовала статья,
  https://www.frontiersin.org/articles/10.3389/fncom.2015.00099/full
  которая рассказывала о успешной кластеризации MNIST с помощью спайковых сетей,
  решение было для меня очень большим,
  https://github.com/peter-u-diehl/stdp-mnist
  громоздким и сложным.
  
  Поэтому я попытался реализовать механику этой кластеризации
  без чего-либо лишнего,
  результат уместился буквально в несколько строк кода (ссылка на Google colab).
  https://colab.research.google.com/drive/1Mjx-ULP8oQKCw_Pf6uMS9s7-qIbbtAHZ?usp=sharing
  
  ......
  
  Веса сети после 10 000 примеров MNIST
  
  В примере выше веса нейронов,
  которых в слое 256 (16x16).
  За такт сети во всём слое может обучаться только один,
  самый активный нейрон.
  
  Обучение происходит по очень простой формуле:
  
  map[:, winner] += rate * (inp - 0.5)
  
  к весам победителя прибавляем
  произведение коэффициента ставки обучения (rate=0.2)
  и разности вход минус 0.5.
  Почему именно 0.5?
  - Это банально среднее значение от диапазона входа,
  он является вещественным числом от 0 до 1.
  Назовём это число - целевая интенсивность.
  
  Целевая интенсивность позволяет провести границу между слабым и сильным входом.
  По сути эта формула приводит к ослаблению слабых входов и усилению сильных.
  И чем слабее вход, тем мы сильнее уменьшаем связанный с ним вес и наоборот.
  Конечно, в связи с этим для этого алгоритма подойдут не все данные,
  там, где число в векторе не означает только интенсивность,
  а несёт более сложную информацию вероятнее всего
  лучше применять сети Кохонена,
  но для MNIST это работает достаточно хорошо.
  Также этот алгоритм имеет явное преимущество,
  здесь практически отсутствует проблема "суперпобедителя" или лидера.
  Суть её в том, что выделяется один нейрон который побеждает чаще всего
  и часто забирает себе всё обучение.
  Благодаря обучению соседей в сетях Кохонена
  эта проблема не проявляется явно.
  Дело в том, что при использовании вышеописанного алгоритма
  если стартовая сумма весов достаточно большая,
  то чем больше обучается нейрон, тем меньше уровень его активации на входной вектор,
  по сравнению с менее обученными нейронами,
  тем самым у менее обученных нейронов будет больше шансов на победу.
  //// Вопрос: "а зачем это, по большому счету, надо"?
  Это имеет ключевое значение в начале обучения,
  когда нейрон только приобретает свою специализацию.
  Поэтому логичнее всего было сделать значение всех весов при инициализации сети
  равными единице.
  
  При рождении мозг имеет максимальное число нейронов
  и в первые дни и недели разворачиваются максимальное число синаптических связей.
  Далее в процессе роста и обучения происходит общая деградация
  и утрата синаптических связей,
  а также потеря нервных клеток.
  Этот процесс называется прунинг
  и особо большие его масштабы для человеческого мозга проходят
  к первым трем годам после рождения.
  //// Но при этом объем мозга растет. Вопрос: что же увеличивается,
  //// если происходит и "утрата синаптических связей" и "потеря нервных клеток"?
  
  Прунинг позволяет более точно специализироваться нейронам,
  и это можно сравнить с тем,
  что происходит в нашем алгоритме кластеризации,
  изначально все веса равны 1,
  то в процессе обучения лишнее сводится к нулю.
  
  Но у этого алгоритма есть недостаток,
  это стремление к наименьшей сумме весов,
  при все большем обучении уровень активации будет снижаться,
  также будет снижаться и сумма весов,
  и для победы нейроны будут специализироваться на примеры с всё меньшей суммой.
  
  .......
  
  Рис. Веса сети после 10 эпох на всех 60 000 примерах
  
  Для устранения этой проблемы напрашивается решение
  о нормализации входного вектора,
  причем приведение суммы входного вектора к константе.
  И лучшее для этого решение это SDR.
  
  Но, на самом деле простое сочетание этого алгоритма и SDR
  не решает проблемы снижения общей суммы весов,
  хотя разнообразие классов будет сохранятся.
  Необходимо привнести в алгоритм еще большей стабильности.
  
  Общая идея работы биологического нейрона заключается в том,
  что он укрепляет в регулярно повторяющиеся связи,
  а редко используемые связи деградируют и теряются,
  формируются некие устойчивые пути распространения нервных сигналов.
  Для реализации этого необходимо вести некую статистику для каждого синапса,
  насколько часто и эффективно он используется.
  Поэтому помимо карты весов у нас будет карта "температурного следа"
  или trace,
  значение этой карты будут в диапазоне от 0 до 1.
  Каждый раз, когда оба нейрона будут активны соединяющий
  их синапс будет прибавлять к trace +0,3,
  но при других тактах сети значение trace будет постепенно убывать на -0,001.
  Таким образом синапсы которые будут регулярно эффективно использоваться
  будут иметь высокий trace близкий к 1,
  напротив, для синапсов которые практически не используется
  trace будет равным нулю или близким к нулю значению.
  Этот показатель будет оказывать прямое действие на значение веса синапса,
  так как часто используемые синапсы следует усиливать.
  Окончательная формула для полученного алгоритма имеет следующий вид:
  
  map[winner,:] = (1 - rate)*map[winner,:] + rate*(inp - 0.5) + trace[winner,:]*rate
  
  Помимо известной формулы,
  здесь при победе веса нейрона увеличиваются на произведение trace и rate
  тем самым часто используемый синапс усиливается,
  в противовес этому происходит регулярная деградация синапсов,
  их веса уменьшаются по модулю (1 - rate)*map[winner,:].
  Так как постоянный рост в биологических клетках невозможен,
  всегда есть некий ограниченный ресурс,
  поэтому существует гетеросинаптическая конкуренция.
  Также веса ограничены в диапазоне от -1 до 1,
  где -1 - это максимально сильный ингибирующий синапс,
  а 1 - это максимально сильный побудительный синапс.
  //// Интересная техника.
  //// Можно попытаться е как-то трансформировать в "обучаемый дропаут"
  
  Описанный алгоритм достаточно прост и позволяет производить самообучение сети
  даже организованной во множество иерархических слоёв.
  
  Далее давайте рассмотрим конкретную конфигурацию многослойной сети для примера.
  
  Для рассматриваемого варианта сети модули следующего слоя
  также будет содержать по 16 нейронов-детекторов,
  у которых будет иметься общее рецептивное поле.
  Рецептивное поле нейрона будет иметь размер 20х20,
  что составляет 25 (5х5) модулей предыдущего слоя.
  Рецептивные поля модулей будут пересекаться с шагом в 4.
  Итого следующий слой будет содержать 400 (20х20) модулей по 16 нейронов,
  всего 6 400 (80х80) нейронов.
  Напомню первый слой составляет 96х96 (9 216) нейронов.
  
  По похожей схеме добавим еще два слоя,
  в первом из них размер модуля будет 16 (4х4) нейронов.
  Третий слой размер рецептивного поля 20х20, шаг 4, итого 64х64 нейронов.
  Четвертый слой - рецептивное поле будет охватывать весь предыдущий слой 64х64,
  но размер модуля мы сделаем 36,
  фактически активность этого слоя будет охарактеризовано
  только одним нейроном из 36,
  чтобы получить четкий выраженный детектор одной цифры.
  И последний пятый, выходной слой будет содержать только 10 нейронов
  по количеству распознаваемых классов.
  Этот слой необходим чтобы сопоставить результат работы предыдущих слоёв
  и метки цифры.
  Этот слой будет иметь только один модуль,
  соответственно возможна активность только одного нейрона из этого слоя.
  Каждый нейрон выходного слоя будет иметь одинаковое рецептивное поле размером 6х6 (=36).
  
  В итоге получается схема: 28х28 (рецепторы)
   96х96 (первый слой, необучаемый, просто преобразует входной сигнал в SDR)
   80х80 (второй слой)
   64х64 (третий слой)
   6х6 (четвертый слой)
   10 (выходной слой).
  Многослойность данной сети выбрана для демонстрации всех аспектов её работы,
  в частности "глубокого обучения",
  для задачи MNIST возможно использовать и более простую конфигурацию.
  
  Выходной слой имеет всего 10 нейронов по количеству распознаваемых классов,
  все нейроны выходного слоя включены в один модуль.
  Это значит, что все нейроны выходного слоя имеют общее рецептивное поле
  равное размеру предыдущего слоя (в данном примере 6х6),
  также может быть активным только один нейрон выходного слоя.
  
  Предпоследний слой состоит из одного модуля,
  в нем будет формироваться при самообучении некое представление,
  каждый из 36 нейронов будет реагировать на свой выбранный тип входного сигнала,
  обучение последнего же слоя происходит
  на сопоставлении полученного представления с меткой класса
  представляемого сети примера.
  Если метка совпала, то увеличиваем вес синапса на rate (0.1),
  а для всех остальных синапсов, которые связаны с другими классами
  вес снижается на тоже значение только деленное на общее количество классов,
  то есть на число меньшее в десять раз.
  
  Итогом, самообучение на 5 000 примерах предъявленных сети по одному разу,
  качество составляет примерно 77%.
  То есть мы явно видим, что самообучение работает
  и происходит выделение классов цифр даже без привязки к метке.
  Но мы можем улучшить этот результат распространив влияние метки класса глубже в слоях.
  //// Любопытная цифра. Близкая к классической формуле "80/20".
  //// Интересно, это случайное совпадение, или за этим стоит что-то большее?
  
  Контролируемое обучение или обратное распространение влияния
  
  Алгоритм обратного распространения ошибки (backpropagation, бэкпроп)
  для коннекционных нейронных сетей
  стал невероятным мощным двигателем машинного обучения,
  благодаря нему искусственные нейронные сети сдали давать потрясающие результаты.
  Но этот алгоритм не сочетается с тем,
  что мы знаем о биологической нервной системе.
  И вопрос не в распространении сигналов назад по сети,
  а в том, что нужно передавать достаточно много информации,
  нужно передавать значение ошибки,
  и пока не известны в биологии механизмы, механики или органеллы
  которые даже бы производили бы оценку этой самой ошибки.
  Существует множество статей которые предлагают
  якобы близкие к биологии варианты бэкпропа,
  но все это, если оценивать со стороны биологии истории про сову и глобус.
  
  С одной стороны, между различными областями коры участвующей
  в иерархической обработки информации,
  как у аналогов слоёв в искусственных нейронных сетях,
  есть обратные связи и их иногда насчитывают в несколько раз больше,
  чем прямых связей.
  Происходит постоянная циркуляция возбуждения между участками коры
  - реверберация.
  Но каких-то сложных вычислений при этом не производится.
  Вычисления производятся на органелле
  - мембрана и алгоритм этих вычислений определён моделью Ходжкина - Хаксли,
  всё, в этой системе знаний нет места бэкпропу и вычислений ошибок.
  
  И, всё таки, нейрон находящийся на низком уровне иерархии
  имеющий ограниченное рецептивное поле
  какой бы у него не был хороший алгоритм самообучения
  эффективно обучаться не может без высокоуровнего дирижера,
  без подсказок исходящей от общей поставленной задачи или цели.
  
  Модульная организация сети и SDR позволяет нам применить
  алгоритм обратного распространения влияния или backpreference.
  //// Интересная формулировка.
  Нейроны в модуле конкурируют между собой,
  так как в модуле может быть только один победитель,
  какой именно нейрон победит определяют восходящие связи и их веса,
  но возможно благодаря нисходящим связям
  дать некоторым нейронам в этой борьбе преимущество.
  Возможно взять любой нейрон последнего слоя
  и оценить активность каких нейронов предыдущего слоя
  вероятнее всего приведут этот нейрон к победе,
  и далее так можно спускаться на более нижние уровни.
  
  Зная метку класса, мы можем выбрать нейроны последнего слоя
  которые наиболее релевантны этой метке,
  далее двигаясь вниз от слоя к слою
  обозначать те нейроны, которые в конце концов
  дадут преимущество нужным нейронам последнего слоя,
  затем этим нейронам дадим преимущество в победе
  //// Причем это можно сделать разными способами,
  //// в том числе и давая некоторые преимущества в процессе САМОобучения.
  добавив некоторое значение к итоговой сумме их активации.
  //// Ну это, наверно, все-таки слишком грубое вмешательство
  //// в процесс именно самообучения. Или нет?
  Получается мы лишь немного вмешиваемся в процесс самообучения,
  направляя его в более подходящее русло.
  Мы можем регулировать то на сколько контролируемое обучение
  будет оказывать влияние на неконтролируемое.
  Разумно если контролируемое обучение будет сильнее действовать
  на последних слоях,
  а самообучение будет действовать больше на первых слоях
  которые ближе ко входу к рецепторам.
  
  ........
  
  В нашем примере есть три обучаемых слоя,
  на последний, третий из них контролируемое обучение
  действует с коэффициентом 1,
  что говорит 100% выиграет тот нейрон, который получит преференции.
  Для второго слоя коэффициент составляет 0.5,
  и на первом только 0.1, здесь большее преимущество у самообучения.
  
  Это очень гибкое сочетания контролируемого и неконтролируемого обучения,
  можно в любой момент полностью отключить контроль
  и дать самообучению управлять,
  а когда появится необходимые метки добавить в обучение контроля.
  Это очень похоже на то как работает и учится биологический мозг.
  
  В начале обучения, когда выходной слой еще не определил
  корреляцию нейронов последнего слоя и меток класса,
  контролируемого обучения вообще не происходит,
  только за счет самообучения формируются слабые соотношения,
  которые затем подхватываются контролируемым самообучением и укрепляются.
  
  Результат с применением контролируемого обучения
  на 5 000 примерах, предъявленных сети по одному разу,
  качество составляет примерно 93%.
  Конечно алгоритм по метрикам качества уступает коннекционным нейронным сетям с бэкпропом,
  но это очень достойный результат учитывая,
  что в алгоритме нет никаких методов сходимости и вычисления ошибки.
  Увеличение размерности сети,
  а значить её потенциальной ёмкости при тех же параметрах тренировки
  может немного улучшить результат по качеству.
  
  ........
  
  Интерпретируемость искусственной нейронной сети
  на базе нейро-детекорного подхода
  
  Вопрос интерпретируемости сети очень важен,
  не достаточно взять модель обучить её на большом количестве данных
  и полностью довериться ей,
  особенно если речь идет о жизни и здоровье людей.
  Необходимо хорошо понимать почему эта модель принимает те или иные решения,
  должна быть возможность предсказать её действия на любой внешний стимул.
  В это нейронным сетям, основанным на нейро-детекторном подходе не будет равных.
  
  Мы уже затрагивали тему интерпретируемости говоря
  о малом репрезентативном представлении,
  в примере где латентное пространство имеет всего два измерения
  как в случае двух нейронов между энкодером и декодером,
  в этом примере мы легко можем интерпретировать результата обучения,
  но только одного самого узкого слоя.
  Но, например, в задачах распознавания лиц,
  латентное пространство достаточно большое и имеет, например,
  18 параметров, представить в наглядном и читабельном виде
  18-мерное измерение и сопоставить с образами лиц
  будет достаточно сложно, не говоря уже о других слоях сети.
  
  Для сетей на базе нейро-детекторного подхода легко интерпретировать результаты,
  возможно провести обратное преобразования
  и получить значения активности рецептивного поля
  которая вероятнее всего приведет к активности конкретного нейрона,
  причем это можно сделать для любого нейрона любого слоя.
  Фактически алгоритм обратного распространения влияния
  и производит обратные преобразования,
  мы просто применим его для интерпретации результатов обучения.
  
  Возможность интерпретировать результаты обучения сети
  нужны не только для большего доверия сети,
  но и для возможности исключать недопустимые действия в её работе,
  корректируя работу сети, прямо изменяя её веса,
  блокируя работу конкретных нейронов,
  а не пересматривать содержание датасета
  или применять дополнительные алгоритмы.
  
  Рис. Обратный анализ по выходному слою (3-му обучаемому)
  
  Рис. Обратный анализ по скрытому слою (2-му обучаемому)
  
  Рис. Обратный анализ по скрытому слою (1-му обучаемому)
  
  Локальный минимум коннекционных сетей с бэкпропом
  
  Искусственные нейронные сети
  и в частности алгоритм обратного распространения ошибки
  одно из величайших открытий Человека,
  который еще во многом поспособствует развитию прогресса.
  Этот совершенный математический инструмент
  может преобразовать данные в функцию,
  но в вопросе создания общего искусственного интеллекта
  или интеллекта человеческого уровня развитие сетей
  как математического инструмента
  не приведёт к желаемому результату.
  Не имеет смысла стремиться превзойти бэкпроп в метриках качества.
  Изучение нейробиологии, нейропсихологии и физиологии нервной системы
  дает представление о принципах, на которых основаны когнитивные функции,
  но эти принципы никак не согласуются с механизмами работы
  классических искусственных сетей.
  Поэтому я долго искал "Священный Грааль" алгоритм нейронной сети
  соответствующий парадигме работы сети биологического мозга,
  и следующий этап исследований будет направлен
  на применение знаний управления сетью
  на основе нейро-детекторного подхода с помощью
  эмоциональных механизмов
  и воплощению механизмов обучения с подкреплением на базе этой сети.
  
  Если представить задачу создания искусственного интеллекта общего назначения
  в виде пространства решений,
  то с коннекционными сетями мы находимся в неком локальном минимуме,
  нельзя не отметить величайшие достижения, полученные моделями,
  основанные на данном алгоритме.
  Но есть альтернатива, которая только зарождается,
  которая пока не имеет ярких и значимых результатов,
  и в перспективе, кто знает,
  с развитием даст возможность решить задачу создания искусственного интеллекта.
  
  .......
  
  //// Конец цитирования.
  
  07.06.2024 11:03
  
  Почти за полгода с момента первого прочтения этой статьи,
  идеи заложенные в ней постоянно всплывают в памяти
  при продумывании "собственных велосипедов".
  Понятно, что в соревновании с существующими хорошо развившимися
  классическими нейросетями "модельки" с таким нестандартным подходом
  шансов практически не имеют.
  НО ...
  
  Если во главу угла поставить энергоэффективность как процесса обучения,
  так и инференса,
  - а это сейчас называют чуть ли не главной проблемой ИИ-моделей -
  то у этого направления исследований есть определенные перспективы.
  
  Самообучаемость нейросетей, хотя бы, до уровня 80% за одну эпоху обучения
  очень даже неплохой рубеж, который можно рассматривать как критерий
  оценки и архитектурных и алгоритмических решений,
  обеспечивающих такую результативность.
  "Обратное контролируемое влияние" вполне стоит рассматривать,
  как интересный прототип обратной связи при обучении.
  
  И отдельный вопрос - это стыковка этих методов
  с классическим "обратным распространением ошибки".
  Все-таки, отказываться от работающих методов никто не предлагает,
  вопрос в том, как и где их использовать.
  А для этого нужно понимание как работает нейросеть,
  и не всегда "биологические аналоги" могут помочь в этом деле,
  а иногда и просто могут увести в другую сторону.
  Ведь не факт, что "биологические аналоги" и ИИ-модели
  работают по одному и тому же принципу.
  
  
  =========
  
  Тральщик Наставник. Модель Kandinsky 2.1 нарисовала:  1aebf897258045c5b9ec97627a35993c_00000
  
  Тральщик Наставник. Модель Kandinsky 3.0 нарисовала:  751029a1bece46f4b70b8a955584c33c_res_00000_image
  
  Тральщик Наставник. Модель Kandinsky 3.0 нарисовала:  7c3c1468865a4bee87e601a110307d82_res_00000_image
  
  Тральщик Наставник. Модель Kandinsky 3.1 нарисовала:  b7661267d91f468f87deba1f33727005_res_00000_image
  
  Тральщик Наставник. Модель Kandinsky 3.1 нарисовала:  9767fc6d-0445-466d-ae7b-405ab4533a57
  Flag Counter
  Free counters!
  
 Ваша оценка:

Связаться с программистом сайта.

Новые книги авторов СИ, вышедшие из печати:
О.Болдырева "Крадуш. Чужие души" М.Николаев "Вторжение на Землю"

Как попасть в этoт список

Кожевенное мастерство | Сайт "Художники" | Доска об'явлений "Книги"