*Исключительно ради изучения Machine Learning, разумеется. Под немного недовольным взглядом любимой жены.

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

Я решил, что это неплохой способ немного пощупать машинное обучение на новой видеокарте. Останется только объяснить жене, что мне не нужна новая женщина потолще, а я просто тренирую нейросети.


В чем проблема сетей для знакомств


Был такой ресурс — Ashley Madison. Специфичный, с лозунгом «Life is short. Have an affair». Основная аудитория — женатые мужчины, ищущие себе интрижку на стороне. Монетизация тоже веселая — помимо стандартных «потрать баллы, чтобы лайкнуть и написать» они просили $19, чтобы удалить аккаунт пользователя без следов.

В 2015 году сайт закономерно протек и 60 ГБ персональных данных утекли в открытый доступ. Помимо множества разрушенных семей, эта утечка дала очень много интересной информации аналитикам. Я всегда подозревал, что мужчин на сайтах знакомств намного больше, но в этом случае оказалось совсем интересно. Журналистка Annalee Newitz, анализируя утекшие данные обнаружила, что из 5 миллионов пользователей только 12 000 были похожи на настоящие аккаунты девушек и использовались регулярно. Остальные были просто ботами, которые общались с мужчинами посетителями.

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

Особенность Tinder


image
Идеальный брутфорсер в гендерных отношениях

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

Вполне понятно, что платформа подразумевает мало возможностей оценить глубокий внутренний мир человека по полуторасекундному взгляду на фотографию в купальнике или за рулем модного тонированного автомобиля. Поэтому, если вы не выглядите просто божественно на своих фотографиях, вам не остается ничего другого как увеличить свои шансы, переняв r?стратегию у некоторых видов. Проще говоря, будем брутфорсить и брать объемом, чтобы увеличить свои шансы на размножение успех. Так как вам надо иногда отвлекаться на еду и сон, а свайпы ограничены, то вы наверняка предпочтете, чтобы автоматизация выбирала наиболее подходящие под ваши вкусы девушек или мужчин. Рыжих маленького роста или высоких брюнеток — это уже на ваше усмотрение.

Собираем данные


Прежде всего вам нужно очень много данных для нормальной точности. Любой, кто сталкивался с машинным обучением знает, как сложно бывает набрать корректно собранный и размеченный датасет. Теоретически, в качестве источника данных подойдет любой подобный ресурс, будь то Instagram или другие социальные сети. Но лучше всего обучать именно на тех образцах, на которых сеть будет работать в дальнейшем.

За основу возьмем репозиторий TinderAutomation. Фотографии у Tinder всегда общедоступны, но функция «лайков» уже лимитирована. Поэтому надо извлечь все живое в радиусе и тщательно промаркировать. Для начала надо воспользоваться довольно простым скриптом:

from skimage.io import imread, imsave, imshow, show
import matplotlib.pyplot as plt
import pynder
from helpers import get_access_token, get_login_credentials
from io_helper import save_image

email, password, FBID = get_login_credentials()
FBTOKEN = get_access_token(email, password)
session = pynder.Session(facebook_token=FBTOKEN)

while True:
    users = session.nearby_users()
    for user in users:
        photos = user.get_photos()
        print("Fetched user photos..")
        for photo in photos:
            print(photo)
            image = imread(photo)
            imshow(image)
            show()

            input_string = "Write 1 to like. Write 2 to dislike."
            ans = str(input(input_string)).lower()

            if ans == "1":
                save_image(image, photo, True)
            else:
                save_image(image, photo, False)

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

Traceback (most recent call last):
  File "img_scrape.py", line 4, in <module>
    from helpers import get_access_token, get_login_credentials
  File "/home/someone/tmp/TinderAutomation/helpers.py", line 1, in <module>
    import robobrowser
  File "/home/someone/tmp/TinderAutomation/venv/lib/python3.6/site-packages/robobrowser/__init__.py", line 3, in <module>
    from .browser import RoboBrowser
  File "/home/someone/tmp/TinderAutomation/venv/lib/python3.6/site-packages/robobrowser/browser.py", line 8, in <module>
    from werkzeug import cached_property
ImportError: cannot import name 'cached_property'

Поэтому, в requirements.txt надо прописать Werkzeug==0.16.1. Тогда взлетит.
Вторая проблема — добыть этот самый токен. Стандартный способ из репозитория у меня не взлетел, но получилось добыть его из консоли разработчика. Для этого переходим по ссылке и выдергиваем ответ на POST-запрос в www.facebook.com/v2.6/dialog/oauth/confirm?dpr=1. Внутри ищем 'access_token'. С первого раза почему-то не получилось, но потом я его нашел и захардкодил в скрипт.

Требования к датасету


Есть несколько ключевых требований к датасетам машинного обучения:

  1. Достаточность
  2. Равномерность
  3. Разнообразие

Достаточность в данном случае требует не меньше 10000 фотографий для построения адекватной модели. Да, это очень много. Собственно поэтому и существуют сервисы вроде Amazon Mechanical Turk, где за определенную плату вы можете перепоручить разметку вашего датасета другим людям. С другой стороны, вы точно хотите, чтобы ваш бот лайкал чудесных луноликих азиаток или не менее прекрасных девушек с индийскими корнями? Все-таки модель должна отражать именно ваш вкус.

С разнообразием проблем особо нет, все фотографии представлены в разнообразных ракурсах и освещении. В очках, платьях, купальниках и лыжных костюмах. Проблема может возникнуть с равномерностью датасета. В идеале, когда мы разметим нашу выборку, она должны состоять из приблизительно равных частей. Если у вас получился «перекошенный» датасет, то его придется разбавлять фотографиями из других источников. Более симпатичных надо будет добавить или наоборот вы определите по результату разметки. У меня получилось что-то в районе 60% симпатичных. То ли я не слишком разборчив, то ли мне просто повезло и вокруг много симпатичных девушек.

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

Обработка данных


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

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

image
Более подробно это описано в мануале к OpenCV

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


Источник

У людей Hue параметр в цвете кожи не привносит значимого вклада в оценку симпатичности.
Поэтому, стоит упросить работу нейросети и оставить только grayscale.

Построение модели


Сразу хочу сказать, что без хорошей видеокарты и CUDA вы скорее всего просто не получите обученную модель в адекватные сроки. Поэтому сразу нацеливайтесь на расчеты в специализированных облаках или с использованием python-CUDA.

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

model = Sequential()
model.add(Convolution2D(32, 3, 3, activation='relu', input_shape=(img_size, img_size, 3)))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Convolution2D(32, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Convolution2D(64, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
          
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))

adam = optimizers.SGD(lr=1e-4, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
              optimizer= adam,
              metrics=['accuracy'])

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

Запускаем бота


image

Спасибо автору репозитория за готовый вариант для быстрой проверки идеи. На самом деле вполне себе работает в базовом варианте и можно, в принципе, запустить на нашем готовом арендованном сервере. Обучать пока не получится, на данный момент мы не предоставляем виртуальные машины с поддержкой CUDA для расчетов, но запустить что-то на 24/7 работу можно без проблем. Бот довольно легковесный, поэтому выгоднее будет взять тариф с оплатой за использованные ресурсы.

Результаты



Наверное я очень симпатичный. И у меня богатый внутренний мир. Получил что-то в районе 13 совпадений в течение часа. Причем, несколько раз девушки писали первыми.
В итоге получались весьма милые диалоги, где я рассказывал, что зашел исключительно поиграть с машинным обучением и разметкой данных. Одна из девушек крайне заинтересовалась, так как сама разработчик. Есть стойкое ощущение, что она в итоге прочитает этот пост на Хабре. Я очень надеюсь, что Оксана сохранит мою анонимность. :-)
*машет лапой и передает привет

Немного про этическую сторону вопроса


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

Вокруг лето. Пора знакомиться.