Нейросети на пальцах

Нейросети на пальцах

Дмитрий Жмудь

БАЗА

Прежде всего нужно прочесть вот эту божественную статью:

https://vas3k.ru/blog/machine_learning/

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

Дальше, поймите, что нейронки — это в общем-то обычный ML, только мы избавляемся от главной проблемы: выделения признаков. Вместо этого обретаем ряд новых)) но более общего плана, поэтому нейронки по идее универсальней.

Если совсем на пальцах, то если вы научились делать несколько магических строчек в классическом ML:

Писал почти по памяти, но чот как-то так

То вы без особого труда нафигачите и аналогичные строчки на pytorch. Только это сразу +100500 к модности и хайповости, deep learning и вот это всё. И в общем-то необязательно как следует понимать чо там под капотом. Тем более что до конца вы всё равно не поймёте. Сраная магия.

Берёте короч железяку с видяхой, или что-то облачное с ней же, ставите туда Торч (либо Tensorflow, но если вам пофиг, то я рекомендую Торч), старательно игнорируете все сложные слова, заучивайте какой тип нейронок хорош для каких задач и будет вам счастье.

В любой непонятной задаче — допиливайте ДАННЫЕ. Данные, а не модель. Данные куда важнее модели. Хотя совсем говно в роли модели тоже брать не стоит, берите что-то, что сейчас на хайпе или недавно на нём было. Да, это так работает.

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


А если подробнее?

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

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

Ну короч я накатал вводную для людей совсем без выш мат образования, хватит ли её — хз. Дальше собсно мои конспекты осени 2021 про нейроночки.

Базовые вещи

Развёрнуто про перцептроны (базовая нейронка) и обратное распространение ошибки.

Это относится и к большинству остальных типов нейронок.

Обратное распространение ошибки суть просто последовательное вычисление компонент градиента для градиентного спуска.

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

ReLU = Rectified Linear Unit: простейшая вещь со сложным названием:

f(x) = max(0, x).

Т.е. просто отбрасываем отрицательные значения. 

Применяется вместо сигмоиды, и даёт лучшие результаты.

"Глубокое обучение" — это просто любая нейронка из более чем 3 слоёв.

(Это наиболее распространённое теоретическое разделение. С точки зрения практики вообще пофиг называть ли сеть "глубокой".)

Смысл разделения такой: нейронка уже из 3 слоёв может аппроксимировать любую НЕПРЕРЫВНУЮ функцию.

А нейронка из более чем 3 слоёв (ограниченной ширины, но неограниченной глубины) аппроксимирует уже вообще любую [интегрируемую по Лебегу] функцию! Если кто слабый в математике досюда дочитал: интегрируемая по Лебегу = любая, встречающаяся в реальности.

На практике > 3 слоёв означает, что нейронка работает даже с отвратительными фичами! Сама их "исправит".

https://en.wikipedia.org/wiki/Deep_learning

Для регуляризации (предотвращения переобучения) можно выбрасывать определённое количество рандомных нейронов. Это стохастический (вероятностный) подход. Насколько он применяется — не знаю.

Отдельные типы нейронок

Простейший тип — кодировщик (автоэнкодер): всего 3 слоя, причём выходы с последнего должны совпадать с входами первого. Для борьбы с переобучением (тривиальным решением) делаем ширину скрытого (внутреннего) слоя строго меньше внешних.


Ключевой тип — рекурентные, т.е. с памятью: см. здесь, раздел "Recurrent Neural Networks". Основной смысл — у них есть не только вход и выход, но и СОСТОЯНИЕ. Это позволяет им аппроксимировать уже не только функции, но и "программы" (алгоритмы). На практике это означает, что, скажем, переводя слово, RNN учитывает его КОНТЕКСТ (предыдущие слова).

В жизни используется конкретный вид рекурентных сетей — LSTM (Long & Short Term Memory). Особенность типа — наличие кратковременной и долговременной памяти, возможность ЗАБЫВАТЬ.

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

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

 — взятию сигмоиды (значения от 0 до 1 => определяем, в какой доли запоминаем или забываем скаляр/компоненту вектора);

 — взятию гиперболического тангенса tanh (значения от -1 до 1 => определяем, насколько увеличивать или уменьшать запомненное значение);

 — сложению и умножению (в т.ч. матричному) чтобы свести всё это воедино и с весовыми коэффициентами;

 — передаче этих данных между слоями.

Бывает также двухсторонний LSTM (BiLSTM): когда половина состояния — состояние LSTM по входным данным от начала к концу, а другая половина — состояние LSTM по входным данным от конца к началу.

Подробнее об этом см. ниже про Внимание.

В жизни рекурентные сети (RNN) и LSTM это синонимы, т.к. другие виды рекуррентных не используются. UPD: со времён написания статьи уже и LSTM кажется полностью отправился в разряд deprecated/legacy, будучи вытесненным вариантами Внимания/Трансформера, о которых ниже.

Внимание (Attention)

Внимание (Attention) — механизм нейросетей для перевода текстов.

В переводах модель часто делится на 2 части: encoder и decoder.

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

Decoder отвечает за выдачу результата, каждое следующее состояние вычисляется из предыдыщего и хитрой "выжимки" из Энкодера:

 — для каждого из сохранённых состояний Энкодера вычисляем (напр. скалярным произведением) новое число из него и предыдущего состояния Декодера (их "совместимость");

 — затем нормализуем эти новые числа ("совместимости") с помощью Softmax — получаем вес для каждого из состояний;

 — складывая состояния Энкодера с нововычисленными весами, получаем итоговую "выжимку".

Вот такое создание "выжимки" — и есть собственно Внимание.

Итоговый вход для слоя декодера — конкатенация предыдущего его (декодера) состояния и вот этой "выжимки".

Отличительная особенность Внимания от Памяти — гораздо большая терпимость к вариативности порядка слов в предложении.

Другой плюс (возможно связанный) — гораздо лучше переводит длинные предложения.

И лучше параллелится.

Внимание оказалось настолько крутой штукой, что Google Brain в итоге сделал архитектуру чисто на ней, БЕЗ памяти (не RNN) — Transformer. Тот самый.

Подробнее про Трансформер на Хабре (текстовое продолжение видео по ссылке выше).

Дополнительная информация:

http://jalammar.github.io/illustrated-transformer/

https://en.wikipedia.org/wiki/Transformer_(machine_learning_model)

https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80_(%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%BC%D0%B0%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F)

(статьи на ру и англо вики разные совсем)

Свёрточные нейросети

Свёртка — понятие из обработки изображений. Про свёртку из функана не вспоминаем.

Вход — матрица MxN.

Параметр — ядро свёртки: матрица KxL (т.е. K*L скалярных параметров). Вроде обычно K=L.

Сама свёртка — это поэлементное умножение каждой подматрицы KxL входной матрицы MxN на ядро свёртки.

Всего таких операций (M-K+1)*(N-L+1).

Затем все поэлементные произведения складываются, записываются в матрицу (M-K+1)x(N-L+1) — результат свёртки.


Cвёрточные нейронки (CNN) неплохо описаны на русской вики.

Используются в основном для обработки изображений.

Основной этап — чередование 2 слоёв:

 — на нечётных производится несколько свёрток с разными ядрами — результат каждой сохраняется в отдельном канале;

 — на чётных размерность матриц во всех каналов сокращается: обычно выбор максимума среди соседних нейронов.

Размерность матриц сокращается и на нечётных, и на чётных этапах — но на нечётных умножается количество каналов.

Каждый канал — это как бы выделенный признак. После каждой следующей пары этапов — всё более абстрактный признак.

В конечном счёте получаем кучу каналов с максимально абстрактными признаками; матрицы же сокращаются до предела: вектора или скаляра.

Эти абстрактные признаки кормим обычной нейросетке, и она выдаёт окончательный результат.


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

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

Для каждой задачи и каждого железа ответ будет индивидуален.

Нетипичные нейронки — стохастические

Ограниченная машина Больцмана вообще в 2 слоя (выходы там же где и входы), но взаимодействие слоёв в обе стороны. Слои генерятся каким-то хитрым матстатом, потом вариация на тему обратного распространения ошибки.

Обобщение — глубокие сети доверия (deep belief network, DBN). Делаем сколько угодно слоёв, но каждую пару соседей обучаем как ограниченную машину Больцмана. Начинаем с пары 1-го и 2-го слоёв, затем 2-го и 3-го, и так до предпоследнего и последнего. Это называется "жадное послойное обучение".

https://t.me/shm512_tldr


Report Page