Category: технологии

Category was added automatically. Read all entries about "технологии".

with Cat The Cat

Управление версиями.

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

Например, если мы сливаем ветки сложный-функционал и тесты-сложного-функционала, и при этом у нас робот проверяет сборку и тесты, то, фактически, в процессе доведения слияния до приемлемого состояния мы выполняем 1) работу по созданию функционала, 2) работу по проверке функционала и 3) работу по отслеживанию требований - нам нужен сложный функционал и нам нужны тесты к нему, чтобы формально его проверить.

Получается, что управление требованиями и планирование можно вести в ветках git/mercurial.
with Cat The Cat

Поржать.

https://matloff.wordpress.com/2018/06/20/neural-networks-are-essentially-polynomial-regression/ - нейронки смело уподоблены полиномам, причём полиномы добиваются схожей точности при степени полинома 2. По мнению авторов, поскольку на каждом следующем слое степень полинома перемножаются, это приводит к переобучению.

https://arxiv.org/abs/1611.03530 - современные нейронки свободно учатся на случайных метках в тренировочных данных, достигая нулевой ошибки предсказания на них.
with Cat The Cat

Эксперимент.

А что будет, если мы попробуем приблизить градиент случайными векторами?

(проверяю идеи)

Collapse )

Предел получается в районе обратного корня из 2. Это разумно ожидать. До косинуса, равного половине, мы добираемся за выборку, равную трети от размерности вектора. Четверть - где-то в районе 7%, пятая часть - 4,7%. Снижая скорость приближения, мы можем уменьшить количество вычислений.

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

Мне не нравится градиентный спуск, как его применяют сейчас. Он был придуман, в его современной форме, из-за ограниченности ресурсов (особенно learning rate) и уже довольно давно. У него есть проблемы со значениями и он плохо применим в новых системах (то самое обучение подкреплением). Поэтому я и пытаюсь получить что-то другое. Две вещи, которые мне очень не нравятся, это скорость обучения (learning rate) и обратное распространение ошибок (backpropagation). Обе они подозрительны мне из-за связанной с ними магии - для скорости обучения придумывают вычурные "расписания" (learning rate cosine schedule, например), обратное распространение ошибок требует хитрых приведений (batch normalization, ADAM и тп), чтобы оно обучало более-менее быстро на современных данных.
with Cat The Cat

Случайный поиск.

https://thegradient.pub/why-rl-is-flawed/

Там про "обучение подкреплением", и в процессе рассматриваются методы, отличные от градиентного спуска. Вкратце, случайный поиск вполне себе сравним с градиентным спуском и даже превосходит его.
with Cat The Cat

Про тренировку нейросетей

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

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

Для ССГ необходимо несколько проходов по обучающему набору, со случайной выборкой обучающих примеров. Во время прохода множитель обучения меняется от начального относительного большого значения до конечного относительно малого. Выбор множителя и способа его убывания является ремеслом (тут, с картинками, может работать, а вот тут, со словами - может, но много хуже; cosine learning rate schedule - это вот что такое? кому в голову пришло? и почему cosine, а не tangent или hyperbolic?..).

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

Критикуя, предлагай.

Предложение - тренировать нейросети на всём тренировочном наборе сразу и всегда.

Первое, самое интересное: http://proceedings.mlr.press/v48/taylor16.pdf Смотрите сразу на страницу 8, рисунок 2, правая часть. На нём показаны результаты тренировки на ЦЕРНовском наборе из области физики элементарных частиц высоких энергий для ССГ, который тренируется по части набора, для метода в статье и для метода сопряжённых градиентов. Последние два работают с полным тренировочным набором. Важно в картинке то, что ССГ после полного цикла тренировки с многочисленными проходами по всему набору остановился там, где методы, работающие с полным тренировочным набором, начали.

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

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

Собственно, моя попытка что-то сделать со случайными направлениями это как раз оно - как научиться работать с большими наборами в памяти наилучшим образом и убрать из машинного обучения как можно больше ремесла (нет множителя обучения, нет обусловливания промежуточных слоёв и тп).
with Cat The Cat

Нейросетки - случайные направления.

Возьмём нейросеть с какими-то весами и выберем случайное направление изменения весов.

w=w0+at

Вход функции активации будет иметь вид x=x0+bt, а выход, в общем случае, для дважды дифференцируемых функций активации (ReLU, выйди вон), будет иметь вид y=y0+ct+dt^2.

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

Чем меня привлекает эта идея - нет градиента вообще. Задал направление, прошёлся по корпусу, получил полином, вычислил шаг и выполнил обновление. В рекуррентных автокодерах, например, расстояние между входами и выходами (по которым, обычно, считается градиент) велико, и для кодирующей части его легко потерять.

Вот это я сейчас и пытаюсь состряпать.

PS
ReLU тоже можно прикрутить. Как мне кажется.
with Cat The Cat

Статистика

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

(я смотрел на байты, но для букв тоже более-менее справедливо)

" бит дополнитель" - 16 букв. Пары букв: "\0 " (буквы перед началом кодируем симолов с кодом 0), " б", "би", "ит" и так далее до пары "ль". Префиксов с выбором у нас два - пробел и буква "о". Выбор после пробела требует один бит, после "о" - один бит. Поскольку статистика у нас полная, мы можем удалять увиденные пары, поэтому после первого пробела у нас нет выбора при его втором появлении, то же справедливо и для пар, начинающихся с буквы "о".

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

Увеличение длины побуквенной послледовательности с 2 до 3 ещё сильнее уменьшает необходимость в дополнительной информации для выбора.

Это объясняет неплохие результаты фейсбучного fasttext (вычисление словарных вложений, как суммы вложений для отдельных частей слова) и последнего достижения Kaldi, где рекуррентная сеть с входом в 10 тысяч наиболее частых слов и несколькими тысячами буквенных N-ок позволила получить уменьшение ошибок распознавания (обычно на входе и выходе несколько сотен тысяч слов, закодированных как 1-из-N (one hot)).
with Cat The Cat

Разное.

Побывал в Тайпее, возвращался через Дубай.

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

Два основных впечатления от аэропорта в Дубае - реклама "Маши и Медведя" и очередь в мужской туалет. Авиакомпания Emirates очень приятная.

Тензорфлов - пакость. Ибо 1) Питон и 2) Java, хоть и C++ (фабрики способностей сессий синглтонов).

Про правильный make напишу чуть позже.
with Cat The Cat

Случайные нейросети

Я наткнулся на идею под названием Extreme Learning Machines. Нагуглить её проще простого, а в кратком изложении она звучит так: давайте построим веса для двухслойной "нейросети" следующим образом - веса для аффинного преобразования из входов возьмём случайные, функцию активации возьмём бесконечно дифференцируемой, скрытый слой имеет вид y_i=f(x_ij*w_ij+c_i), а веса для выходов посчитаем через регрессию любым способом и выходы должны иметь вид o_i=\beta_i*y_i. То есть, просто перемножение.

Идея мне понравилась, только я её по-другому использовал (код). Скрытый слой - это случайная проекция R^n->R^h, с функцией активации поверх, а выходной слой учится обычным образом.

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

f(x) = x < 0,5-a ? -1 : x > 0,5+a ? 1 : 0, где a=0,3724.

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

Весов, правда: требуется в 4 раза больше - необходимо увеличить размер скрытого слоя до 120 супротив 32 для обычной полностью тренируемой сети. Разность в точности - 96% у обычной сети и чуть меньше 96% у вот такой вот случайной сети.

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