С 30 ноября по 2 декабря в Москве прошел PicsArt AI hackathon c призовым фондом — 100,000$. Основной задачей было сделать AI решение для обработки фото или видео, которое можно будет использовать в приложение PicsArt. Коллега по работе(на тот момент) Артур Кузин предложил поучаствовать, заинтересовав меня идеей — анонимизация личных фотографий пользователей с сохранением деталей(мимики и т.д). Также Артур позвал Илью Кибардина — студента МФТИ (кому-то же нужно было писать код). Название родилось очень быстро: DeepAnon. Это будет рассказ про наше решение, его деградацию развитие, хакатон, и как не надо подстраиваться под жюри. Было три пути попадания на хакатон. Первый — пройти в топ-50 лидерборда на задаче сегментации лиц — “Datascience гений”. Второй — сразу объединиться в группу до 4-х человек и показать работающий MVP — “бодрая команда”. В последнем варианте было необходимо просто прислать описание своей гениальной идеи. Мы решили не терять время и сразу, за неделю до хакатона, делать MVP. Ну и вообще мы решили, что классные, поэтому всей тимой попали в топ 10 на лидерборде и, соответственно, инземани. Основная идея нашего продукта заключается в следующем: люди бездумно шарят фотографии с собой (иногда не совсем законные) в социальных сетях, о которых они потом могут пожалеть, или за которые их даже могут наказать в будущем. Чтобы обезопасить себя, можно зацензурить свое лицо “квадратиками”, а фон замазывать. Но тогда будет скрыто не только лицо, но и эмоции на нем, а фон будет испорчен. Чтобы сохранить эмоции на лице и объекты на фоне, наше приложение меняет все лица на фотографии, а фон делает мультяшным. А чтобы человека нельзя было узнать по одежде, она заменяется на другую. За неделю нам удалось сделать почти все задуманное. Для каждого этапа использовалась отдельная нейронная сеть (а иногда даже несколько). Сначала на изображении находились все лица и заменялись на одно и то же лицо знаменитости — для этого использовалось решение, похожее на DeepFake. Далее, с помощью сегментации человека, отделяли фон и делали на нем перенос стиля на мультяшный (Рик и Морти). На последнем этапе происходила сегментация разных частей одежды и их изменение — случайное смещение цветов в HSV пространстве, так как перенос стиля не успели перед показом MVP жюри. На каждом этапе возникали свои технические трудности. Например, все реализации DeepFake на гитхабе умели превращать только определенное лицо X в определенное лицо Y. В такой постановке задачи необходимо множество фотографий двух людей. Наиболее простой способ собрать такой набор данных — найти видео выступлений человека, где большую часть времени показывается только он, и, с помощью детекции лиц, нарезать фото. Основной упор в нашей идеи был как раз в том, что можно из любого лица сделать одно и тоже другое лицо Y. Мы попробовали вместо одного лица X использовать множество всевозможных лиц из датасета CelebA, и, к нашему счастью, это завелось. Ниже схема DeepFake, взятая с реализациии, которую мы использовали. Результат был завернут в веб-демо на flask и запущен для показа. Вот так выглядело описание нашего МВП для жюри.  До начала хакатона оставалось несколько дней, и мы успели улучшить изменение одежды. Если до этого это было изменение цветов в HSV, то теперь на каждый тип одежды применялся свой стиль (различных художников). Еще появилась идея, что лучше будет делать изменение лица не в одну знаменитость, а сначала классифицировать по полу, и после этого переносить лица мужчин и женщин по-разному (например, в Навального и Собчак). А в последний момент успели добавить различные уровни анонимизации в веб демо — появилась возможность выбрать, какие элементы анонимизации использовать. На оффлайн часть мы шли с настроем, что это полезный, необычный юзкейс, а не просто вирусные маски на лица. Одно из сообщений в нашем командном чате: В пятницу началась оффлайн часть. Каждой команде был отведен отдельный стол, а в буфете были бесконечные быстрые углеводы печеньки. После официального открытия мы решили не терять время и сразу узнать у жюри, чего они хотят от участников. Пообщавшись с несколькими организаторами неформально, мы почувствовали, что анонимность их не зацепила. Но понравилась идея с сегментацией отдельных частей фотографии и их изменение. Также стало понятно, что от нас хотят чего-то, что можно внедрить в PicsArt. Тем не менее, к вечеру наша команда отправила описание проекта, в котором говорилось об анонимизации, но уже с акцентом на сегментацию и редактирование отдельных частей фото. Описание проекта для жюри на вечер пятницы: По формату хакатона к защите будут допущены те команды, которые хорошо показали себя на технических комиссиях. На комиссиях было живое общение с жюри и технической командой PicsArt, а также демонстрации демо с описанием его работы.  На первой же комиссии в субботу мы не смогли продать жюри анонимизацию, но увидели, что им нравится идея редактирования отдельных предметов на фотографии. Также члены жюри очень воодушевленно приняли идею со сменной прически по нажатию на волосы (оказалось, что они сейчас пытаются сделать что-то похожее). Наша команда не устояла под таким напором (к сожалению) и согласилась изменить видение продукта. Было решено сделать акцент на качественную смену одежды. В демо на главном экране планировалось показывать несколько вариантов исходной фотографии (в идеале, одежда меняется по тапу на экран): Верхняя одежда: Штаны: Обувь: В базовом варианте с волосами было решено сделать трансформацию “лысый — не лысый”. Для этого из датасета знаменитостей CelebA были выбраны лысые и все остальные. На этих двух группах был поставлен учиться CycleGAN, который умеет трансформировать картинки домена A в домен Б, и наоборот (другим примером может быть превращение лошади в зебру). Нам удалось познакомиться с одним из разработчиков PicsArt и немного узнать об их внутренней кухне. Он не очень верил в успех нашего эксперимента с волосами, но накидал ссылок, в какую сторону смотреть. К нашему разочарованию нейронка действительно не научилась добавлять-убавлять волосы. Зато она научилась менять тон кожи (угадайте, почему). Видение продукта менялось после каждого общения с тех комиссией. В планы добавилось улучшение неба и смена стилей отдельных объектов (изначально только одежда): зданий, машин, а также аксессуаров на людях. Фокус уходил с анонимизации все больше. Для итоговой презентации решили придерживаться следующей структуры из 4-х слайдов: Но оказалось, что презентация не нужна. К вечеру субботы всем объявили, что на защите должно быть выступление на 3 минуты без презентации. Со сцены необходимо будет показывать свое демо в режиме реального времени. Организаторы хотят увидеть работающие технологии, а не красивые презентации, и это круто. Сравнивая с другими хакатонами, где выигрывали команды с неработающим демо, такая концепция нам понравилось. Небольшая проблема была лишь в том, что на тот момент наша куча моделей запускалась по отдельности и очень долго. Для показа со сцены была необходима оптимизация. Во время разработки по залу ходили менторы из технической комиссии и смотрели на прогресс. После очередного общения с одним из менторов мы получили фидбек, что лучше бы нам сосредоточиться на чем-то одном, по его мнению, на изменении одежды. PicsArt хочет, чтобы результат был реалистичным и его можно было показать пользователям. На самом деле у разных менторов и членов жюри были разные точки зрения на то, каким должен быть идеальный проект для них.  После того, как изменение волос не завелось CycleGAN-ом, решили попробовать другой подход. Вначале сегментировать волосы, а затем на них применять inpainting. Задача inpainting — восстановить скрытую часть изображения по окружающему контексту. По нашему плану — скрываем волосы, а нейронная сеть будет пытаться восстановить их. Но так как сеть не видела, какие волосы у данного человека, она будет восстанавливать другую прическу. Проблема в том, что даже обученные на лицах людей модели не смогли нормально восстанавливать волосы (если закрасить лишь часть волос, то работает). Основная сложность — огромное разнообразие причесок. Была идея обучить inpainting только на лысых людях, и тогда бы модель, вероятно, научилась менять любую прическу на отсутствие волос. Реализацию нейронной сети мы взяли из этого репозитория. Так как демо нужно будет показывать со сцены в режиме реального времени, пришлось оптимизировать скорость работы пайплайна. Наибольшей прирост скорости дал перенос всех нейронных сетей в память на все время работы приложения. Не обошлось и без трудностей: начиная делать все в docker, но забив по ходу, несколько раз попадали на боль с версиями tensorflow. На самом деле сложно не попасть в такую ситуацию, когда в день пробуешь запустить десяток репозиториев с гитхаба, в каждом из которых используется разная версия tensorflow, обновляя до нужной версии в одном месте — ломаешь в другом. Docker может быть хорошим другом в такой ситуации, но в условиях хакатона хочется каждую минуту тратить на проверку новых гипотез, а не на создание нового образа. Тем не менее, поддаваясь на такое искушение, вы рискуете еще больше времени потратить на отладку кода и попытки понять, какая версия библиотеке в каком месте вам нужна. В воскресенье утром мы определились с финальным видением продукта (пора бы уже): изменение одежды с возможностью улучшения неба. Хотелось максимально сузить задачу, но и делать только изменение одежды казалось слишком мало. Вот так выглядел “дизайн” нашего веб приложения. Изначально хотели добавить адаптивный дизайн, чтобы было удобно смотреть с телефона. Но время поджимало, и наш дизайн свелся к np.vstack(imgs_list).  Перед финальным выступлением хотелось довести фичу с одеждой до законченного состояния. Было добавлено альфа смешивание одежды и фона — исчезли резкие переходы. Оставили только самые реалистичные текстуры — джинса и крокодиловая кожа. За несколько часов до показа удалось запустить сегментацию неба и перенос стиля на него из этого репозитория. Были варианты с превращением неба в апокалиптическое, ядовитое, мультяшное. Но самым подходящим тематике конкурса стало зимнее небо — его применение давало эффект “улучшателя” неба. Оставалось совсем немного времени, когда все компоненты соединились в единое целое и заработали. Мы скачали множество фотографий с социальных сетей и планировали запускать на них приложение, чтобы выбрать самые удачные кейсы (начерепикать). Но оказалось, что наша команда выступает первой, поэтому все было максимально честно — показывали демо на случайных фотографиях.  Артур, выступая на сцене, смог раскрыть нашу идею, а Илья на проекторе демонстрировал наш MVP — на всех фото одежда поменялась, а небо улучшилось. Не все участники смогли справиться с заданием — показывать только свою демку. Искушение добавить несколько красивых слайдов было велико. Из тех решений, которые нам понравились больше всех на защите — превращение видео в комиксы, а также соединение двух фотографий в одну. В итоге, по инсайдерской инфе, наша команда заняла 6-е место в шаге от мани.  Постфактум, мы пришли к общему мнению (ну, кроме того, что 3 из топ 5 команд получили приз незаслуженно), что нужно было проявить стойкость и решительно допиливать первоначальную идею анонимизации. Даже сейчас, мы убеждены в том, что она годная и принесет ценность для ряда пользователей. Занимаясь развитием идеи с анонимизацией все выходные, мы бы, как минимум, получили больше фана.  Если вы никогда не участвовали в хакатонах, обязательно попробуйте — отличная проверка себя и своей команды, шанс реализовать что-то, на что никогда не хватало времени. Ну и конечно, обязательно делайте то, что нравится вам, ведь максимальный каеф от процесса можно получить только угарев по хардкору. Наша команда выложила код финальной демки на GitHub. А также есть отдельный репозиторий, который делает именно анонимизацию. В будущем есть планы по развитию первоначальной версии с анонимизацией: переписать все на PyTorch, обучить на фотографиях с большим разрешением и меньшим количеством шума (фотография только с одним лицом), а также поднять бота в telegram. Для тех, кто уже сейчас хочет попробовать версию, рожденную в самом начале хакатона, в демо режиме запущен бот в telegram(@DbrainDeepAnon -> /start -> /unlock dbraindeepanon). Он работает на сервере Dbrain(наша благодарность), на котором происходило все обучение переноса лиц, поэтому пробуйте пока не выключили. Для работы сервиса используется внутренняя обертка Dbrain — wrappa, которая позволяет легко обернуть docker контейнер и запустить telegram бота. В скором времени wrappa станет доступна в open source. Хочется отметить, что наш труд не был напрасным. Благодаря DeepAnon, один “аноним”, сильно переживающий за приватность своих данных, наконец-то смог вести инстаграм о своей жизни. Он больше не боится, что камеры в городе смогут распознать его лицо по фотографиям из социальных сетей, тем не менее друзья смогут узнать его. Лица всех людей в его инстаграме также подвергаются анонимизации. Ссылки на репозитории, которые мы использовали: https://github.com/shaoanlu/faceswap-GAN
https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix
https://github.com/sacmehta/ESPNet
https://github.com/JiahuiYu/generative_inpainting
https://github.com/NVIDIA/FastPhotoStyle P.S. Также, для фана, я попробовал переобучить сеть по замене лиц на одного из членов ODS. Попробуйте угадать на кого. Сети дали название — TestesteroNet. Machine Learning