[Из песочницы] Похоже, с помощью нейронных сетей появился шанс слабый ИИ сделать сильным

4b24cb91534942b3bff3c18a124bed46.jpg

Рост интереса к разработкам в сфере искусственного интеллекта связан не только с увеличением производительности компьютеров, но и с рядом качественных прорывов в машинном обучении. И хотя все планомерно идет к тому, что успех более чем вероятен, и в возможности создания в обозримом будущем сильного ИИ уже мало кто сомневается, одной важной стороне этого процесса уделяется незаслуженно мало внимания.
К построению искусственного интеллекта есть два принципиально разных подхода, назовем их условно алгоритмический и с помощью самообучения. В первом случае надо вручную прописать все правила, по которым действует интеллект, а во втором нужно создать алгоритм, который сам обучится на некотором большом объеме данных, и выделит эти правила самостоятельно. Как мы уже знаем, алгоритмический путь потерпел катастрофическое фиаско. И это печально, потому что этот путь более «правильный». Хотя в нем есть свои недостатки, вроде взрывающихся роботов от логического парадокса (шутка. хотя нет, правда), но зато такой робот никогда не сделает того, на что он не запрограммирован.

Но важно даже не это, а то что это академическая задача. Разобраться, как работает сознание, интеллект, разум. Поражение в этой области это как пощечина нашему собственном интеллекту. Почему же ничего не получилось? В основном, это проблема комбинаторного взрыва. Разум нашего уровня оперирует слишком уж большим количеством понятий и их отношениями. В развитом языке порядка 500 тысяч слов, и еще наверно столько же, а может и больше, чувственных образов, которым пока не дали словесного определения. Итого, интеллект человеческого уровня должен оперировать не менее чем миллионом понятий и их взаимоотношениями. Пусть вас не смущает, что на практике людьми используется порядка 2000–30000 тысяч слов (2000 — это необходимый минимум для свободного общения в другой стране, см. Simplified English, а писатели вроде Шекспира, используют порядка 30 тысяч слов). Просто это обобщенные и наиболее часто используемые слова в тех рутинных вещах и ситуациях, которые мы называем жизнью. А на самом деле развитый мозг оперирует намного большим числом «внутренних» понятий, которые он при желании облекает в эти общие слова. Хотя и 30 тысяч это большое число. Представьте, что ваша собака могла бы различать 30 тысяч слов. Понимать, что обозначает каждое из этих слов и реагировать на каждое по-разному. Определенно, она была бы гораздо умнее. И даже наверняка с ней можно было бы поддерживать беседу.

«Алгоритмический» путь


Известен древний компьютерный эксперимент, когда попытались описать вручную созданными правилами взаимоотношение простых геометрических фигур в виртуальной сцене. «Шар круглый», «куб может сдвинуть другой куб», «шар может катиться», «пирамида может лежать на кубе», и так далее. Оказалось, что при числе объектов в сцене более пяти, вручную описать все их возможные физические взаимодействия очень сложно. А при числе более десяти, уже не представляется возможным. А нам нужно сделать такое ручное описание не менее, чем для миллиона понятий! Комбинаторный взрыв.

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

Еще один наглядный пример — провал автоматических алгоритмических переводчиков. Построить общие правила, полностью описывающие два разных языка, это по сути создать правила, по которым действует разум, который оперирует этими языками. Один человек может знать два языка, поэтому описать общую структуру двух языков (чтобы их можно было конвертировать один в другой), это не то же самое, что описать правила синтаксиса для одного отдельного языка. Создать правила одновременно для двух языков это значит описать их общую структуру, а значит и общую структуру того человека, который ими пользуется. Те, кто занимался созданием баз знаний для таких алгоритмических переводчиков, могут более подробно рассказать, с какими трудностями они столкнулись. Но в целом, трудности сводятся к комбинаторному взрыву, и к тому, что реально используемых в мышлении понятий больше, чем слов. Более того, буквально за год-два язык меняется, некоторые правила устаревают и перевод с их помощью будет восприниматься комично. Опять получится »-Как ты это делаешь? -Всегда правой!» (»-How do you? -All right!»). Последний случай такой попытки создать вручную базу знаний для автоматического переводчика, который приходит на память, это ABBYY Compreno. Прекрасное начинание, много труда, но похоже завершившееся как и предыдущие попытки.

Самообучение


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

Здесь совпали сразу несколько факторов:

1. Рост вычислительной мощности. В основном, параллельные вычисления на GPU, что дало возможность даже простым людям с легкостью повторять результаты самых последних научных работ (что ранее было недоступно, по крайней мере, если у вас не было личного суперкомпьютера). Да-да, вы правильно поняли. Для таких замечательных фреймворков, вроде связки TensorFlow + Keras, созданы копии самых современнейших архитектур нейросетей. Все, о чем вы слышали в новостях о нейросетях и их достижениях за последние несколько лет, вы можете повторить на домашнем компьютере. Буквально в течении нескольких минут, необходимых для скачивания этих библиотек. Конечно, гиганты вроде Google могут себе позволить запускать расчет на 1000 компьютерах с GPU с 12 Gb видеопамяти на борту в течении пары недель. Но и обычный настольный игровой компьютер тоже дает сейчас большой простор для маневра.

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

3. Но, главное, появились новые эффективные методы обучения. Так как старыми алгоритмами мы до сих пор не можем добиться ничего вразумительного, даже от новых увеличенных объемов данных. И это говорит само за себя (хоть это и печально, повторюсь).

Если не получается найти выход, выходите через вход


Разумеется, возможны и разные комбинированные методы. Где-то используем самообучение, где-то вручную пишем правила. Именно так и происходит сейчас. Google Assistant, Siri, IBM Watson — все они используют для распознавания речи и картинок машинное обучение (как правило, нейросети), а для общей работы вручную написанные правила. Watson вообще, судя по всему, представляет собой жуткую смесь древних экспертных систем и современных узкоспециализированных модулей по распознаванию. Более того, такой подход сейчас кажется наиболее перспективным. Только с обратным порядком — не мы пишем правила для примитивных распознавалок, а надо создать ИИ нашего уровня, и дать ему доступ ко всей алгоритмической мощи современных компьютеров. И такие ранние попытки уже предпринимаются, например Нейронная машина Тьюринга, где пытаются научить нейросеть пользоваться жестким диском для хранения структурированных данных. С рядом ограничений, но суть именно такова.

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

Так что именно изменилось? Откуда такой хайп по поводу ИИ в последнее время?

Нейронные сети


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

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

23733cfceac84f9ab0c6ee280a237d70.png


А что если теперь отбросить третий (выходной) слой, а средний слой использовать в качестве входного для следующего автоэнкодера?

d61ca118822d443b8e96977a60e6d6af.png


Таким образом можно собирать какое угодное количество слоев в общей суммарной нейросети. И каждый такой слой будет прекрасно обучаться!

Какой в этом физический смысл, помимо решения проблемы исчезающего градиента? Дело в том, что в первом слое (в первом автоэнкодере) будут выделяться какие-то простые признаки. Скажем, вертикальные и горизонтальные линии, если идет речь о распознавании изображений. Второй слой (второй автоэнкодер) на своем входе будет получать уже не исходные пиксели картинки, а только вертикальные и горизонтальные линии. И уже из этих линий выделять признаки более высокого абстрактного уровня: квадраты, круги, многоугольники. Третий слой получит на свой вход эти абстрактные простые фигуры и будет оперировать только ими, выделив из них, скажем, схематичную фигурку человека («палка, палка, огуречик — вот и вышел человечек!»). Все что нам не хватает для полного счастья, это на выходе из такой многослойной-многоэнкодерной сети добавить один-два слоя обычного перцептрона, чтобы классифицировать результат самого последнего автоэнкодера. Разбить человечков по классам или вывести в удобном виде (x, y) координаты фигуры на картинке.

Хорошая новость в том, что наш собственный мозг (по крайней мере, зрение) работает именно таким способом. На самых первых нейронах, связанных с сетчаткой глаза, распознаются только простые линии и градиенты яркости. Примерно такие:

38fca1b417884623ae2d952fc95d71e1.png


Это результат работы первого слоя сверточной нейросети, о которых будет ниже

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

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

fcbf4cfc6c0248f9a88e8889627ce5e1.gif


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

Не смотря на свою простоту, идея такого послойного обучения нейросети получила практическую реализацию только в середине 2000-х годов (хотя и до этого пытались предобучать начальные слои в многослойном перцептроне методами без учителя, но не так успешно). Надо понимать, что такой метод обучения глубоких нейронных сетей (и даже не совсем такой, т.к. все начиналось с ограниченных машин Больцмана, но суть та же) это была первая ласточка, известившая о новой нейросетевой революции. С того момента прогресс ушел далеко вперед, сейчас автоэнкодеры и их аналоги в чистом виде практически не используются (их заменили новые методы регуляризации и слои вроде сверточных или реккурентных), а зоопарк архитектур нейросетей разросся до неприличных размеров. Краткую памятку о различных типах современных нейронных сетей можно наглядно посмотреть здесь: Зоопарк архитектур нейронных сетей. Часть 1 и Часть 2. Из двух частей. Краткую. Ага.

Оказалось, что в энкодере внутрениий слой можно делать не меньше, а больше входного. А чтобы сигнал не проходил насквозь без изменений (нам ведь нужно реализовать что-то вроде сжатия, чтобы вычленить признаки), давайте случайно отключать входные нейроны или подмешивать к ним случайные величины, эмулируя случайный шум. Это оказалось даже полезнее, чем чистый автоэнкодер, так как позволяет распознавать зашумленные данные. Вообще, идея случайным образом выключать часть нейронов во время обучения, т.н. dropout (иногда до 50% всей нейросети!) оказалась очень полезной. В некотором роде это приближение к биологическому образцу, так как в живом мозге активность нейронов тоже носит отчасти случайный характер. За подробностями отправлю к замечательной и крайне рекомендуемой к прочтению статье о современных типах нейронных сетей и как мы дошли до такой жизни Как обучается ИИ.

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

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

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

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

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

b14907c11f1a4311a977d07955b957a4.png

На самом деле сверточные сети работают так. Сначала мы решаем, сколько признаков хотим выделить из картинки. Это будет количество плоскостей (второй большой квадрат на картинке, обозначенный feature maps). Например, если мы хотим найти вертикальные линии, горизонтальные и диагональные, нам достаточно 4 плоскостей (т.к. диагональные могут быть двух видов: / и \). После этого решаем, какого размера должен быть фильтр, которым будем проходить по картинке. Это размер маленького черного квадратика, допустим, 3×3 пикселя. И заполняем его какими-нибудь числами, графически кодирующими примитив, который хотим найти. К пример, заполняем четверками по диагонали, чтобы искать наклонную линию \. А потом проходим им как скользящим окном по всей исходной картинке, и перемножаем пиксели на картинке на пиксели в нашем маленьком квадратике-фильтре, и суммируем результат. Получаем одно единственное число, характеризующее насколько картинка под скользящим окном похожа на картинку в фильтре. И записываем это число в плоскость, соответствующую этому фильтру. Картинка ниже лучше объясняет принцип.

216fa69be40e424f9196ab779681a820.png
Иллюстрация с лекции Яндекса

Здесь маленький синий квадратик между плоскостями почти что кодирует диагональную линию \ из левого верхнего угла в правый нижний, если бы у него по диагонали были все четверки (к сожалению, иллюстрация нашлась только такая, с нулем в центре и -4 в нижнем правом углу). Область на исходной картинке немного похожа на такую диагональную линию, так как там есть 1 и 2, которые умножались бы на 4, соответствующие положениям этих 1 и 2. И общая степень похожести была бы 0×4+1×4+2×4=12 (вместо -8 на картинке). А вот если бы на исходной картинке по диагонали тоже были бы четверки, а еще лучше десятки! («летят n самолетов, нет, n мало, пусть будет k. и оба реактивные»). Тогда степень похожести была бы 10×4+10×4+10×4=120. Чем больше число, тем лучше.

На самом деле, мы не знаем какие именно графические примитивы мы хотим искать, а главное, какие из них окажутся важными для распознавания, например, морды лица кота на фото. Поэтому мы просто создадим заведомо избыточное количество плоскостей. Каждая из плоскостей составляет как бы карту, на которой отмечены места, где на картинке встречаются наиболее похожие на ее фильтр участки. Как на символ \ в примере выше. Как правило, в сверточных сетях в первом слое используется 100–200 плоскостей, чтобы перекрыть все возможные типы простых примитивов. Еще зависит от размера фильтра, чем он больше по размеру, тем большее разнообразие примитивов может вместить, и тем больше нам надо плоскостей-карт для них. И инициализируем веса принадлежащих им окошек-фильтров случайными числами. Нейросеть сама разберется, какие придать им значения в процессе обучения. Что удивительно, обученные на реальных фотографиях сверточные нейросети в первом слое создают именно такие же примитивы, вроде наклонных линий и пятен разной яркости (см. выше картинку), на которые реагируют нейроны первого слоя у живой кошки. И, надо полагать, у человека тоже.

Какие во всем этом плюсы?

Во-первых, уменьшается число нейронов по сравнению с полносвязным перцептроном, а это экономия памяти и ускорение расчета.

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

В-третьих, сверточные сети позволяют определять не только факт наличия признака на картинке, но и его положение. В каком-то слое лицо человека будет распознано не просто по наличию где-то на фотографии глаз и рта, а по тому, что левый глаз расположен именно выше и левее, правый выше и правее, а рот ниже их обоих и по центру. Тут можно провести аналогию с каскадами Хаара, которые использовались раньше для распознавания лиц в методе Виолы-Джонса. Только сверточные нейронные сети могут распознавать не только графические примитивы вроде горизонтальных/вертикальных полос, но и такие сложные абстрактные понятия как «попугай». Если «попугай» расположен на правом плече абстрактного объекта «человек с деревянной ногой», то с большой вероятностью этот объект «пират». В этом сила сверточных (и других многослойных) нейронных сетей.

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

Все это сделало сверточные сети такими эффективными в задачах распознавания.


Рекуррентные сети

Рекуррентные сети


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

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


GAN

GAN


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

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

Такой подход дает впечатляющие результаты по «творчеству» нейросетей. Это так же используется, чтобы генерировать похожие на настоящие наборы данных, если настоящих данных у нас по каким-то причинам мало. На этом видео можно посмотреть, как GAN учится генерировать кошачьи морды, похожие на настоящие: https://www.youtube.com/watch? v=JRBscukr7ew.

baf769bf3a9b4651bb2c2c7da6b3dc57.jpg

Или человеческие лица

8a40d7acf978402b946b9c5aed1c546c.jpg

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

А вот спальни генерируются куда как лучше (вероятно потому, что мы хуже распознаем несовершенные детали на них):

2eaa82a5791f47209f4171d1131239ab.png

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

К примеру, один случайный набор чисел (входной вектор) сгенерировал мужчину в очках. А другой случайный набор дает мужчину без очков. И третий дает женщину. Мы можем из первого вектора вычесть второй и в разнице получим те числа, которые определяют очки. А потом сложить с третьим набором, который определяет, что будет нарисована женщина. И подадим результат как вектор чисел на вход генерирующей нейросети. И она, тарам-папам!, сгенерирует женщину в очках! и с бородой Это удивительная магия, если не знать что за ней стоит.

4fa49eaf5fc048d7bb86fb990cd4b20b.png

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

94fa738b352f47b499ee4be93a82c918.png
Иллюстрация из работы https://arxiv.org/abs/1702.01983v1

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

Подробнее про генеративные нейронные сети (к которым относится GAN) можно почитать тут: Generative Models.


Обучение с подкреплением

Обучение с подкреплением


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

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


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

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

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

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

© Geektimes