/ai-hat

Python Guess the Word Game

Primary LanguageDockerfileMIT LicenseMIT

Игра в шляпу

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

Правила игры

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

Игра проходит следующим образом:

  • Ведущий вытягивает из шляпы слово WORD для команды i и отправляет его сервису команды с помощью REST API.
  • Сервис команды i составляет для ведущего список из N_EXPLAINING_WORDS слов, которые ведущий будет сообщать другим участникам по одному.
  • Отгадывание проходит N_EXPLAINING_WORDS итераций:
    • каждую итерацию j ведущий добавляет новую подсказку - новое слово и отправляет сервисам команд все сказанные на данный момент слова;
    • сервисы других игроков пытаются отгадать загаданное слово WORD, сообщая N_GUESSING_WORDS слов;
    • Как только загаданное слово оказывается в сообщенных ведущему словах, команда получает очки (чем раньше угадала - тем больше, например N_EXPLAINING_WORDS - j);
    • Загадывающая команда получает очки за каждую отгадавшую команду (например, столько же очков).

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

Пример игры

Начнем с примера проведения игры. Для этого откроем ноутбук GuessingWordByWordSequence.ipynb и выполним его целиком. Для примера можно взять данные датасета 20 news groups - их можно загрузить с помощью модуля sklearn.datasets. Они также доступны на kaggle. В качестве примера также подойдет любой достаточно длинный файл с текстом (приблизительно 1 миллиона строк должно быть достаточно).

Данный пример позволяет проводить локальные игры между несколькими игроками в рамках юпитер ноутбука (нужно инициализировать объекты соответствующих классов в ноутбуке), а также тестировать развернутые удаленно сервисы (с помощью класса RemotePlayer).

Как эта игра в шляпу связана с реальной жизнью

"Чеклист" стадий ML-проекта

Существуют разные этапы работы над проектами. Например, можно выделить следующие:

  • этап постановки задачи,
  • этап быстрого прототипирования и уточнения постановки задачи,
  • этап подготовки к продакшену.

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

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

В данном соревновании мы с вами воспользуемся Python, Flask и Docker, чтобы реализовать игрока в шляпу, научить его отвечать на HTTP запросы и, наконец, задеплоить его на удаленном сервере, откуда он будет доступен другим людям.

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

Как создать игрока

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

Важным моментом является наличие timeout запросов к сервису с удаленным игроком. Обратите внимание на реализацию этого в коде.

Как реализовать локального игрока

Обратим внимание на класс LocalFasttextPlayer в ноутбуке GuessingWordByWordSequence.ipynb. Для описания локального игрока необходимо создать подобный класс с обязательным присутствием методов explain и guess, которые принимают на вход те же аргументы и возвращают объект того же типа. Предлагается инициализировать класс обученной моделью и другими необходимыми параметрами, описывающими логику загадывания и отгадывания. По умолчанию предлагается следующий подход:

  1. Имеющийся корпус текстов предобрабатывается - например, удаляются специальные символы, слова приводятся к начальной форме, и так далее;
  2. На текстах обучаются эмбеддинги;
  3. Обученные эмбеддинги используются, чтобы находить ближайшие по косинусному расстоянию слова к загадываемому слову (/explain) и к предлагаемой для отгадывания последовательности слов (/guess);
  4. Поверх найденных ближайших слов реализуется определенная логика - например, убрать из списка однокоренные слова или убрать слишком короткие/бессмысленные слова.

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

Обратим внимание на класс RemotePlayer в ноутбуке GuessingWordByWordSequence.ipynb. Этот класс используется для коммуникации с сервисом, поднимаем на удаленной (или локальной) машине. Сам запускаемый сервис описан в папке docker-flask-app. Содержимое папки:

docker-flask-app
- templates
- Dockerfile
- app.py
- player.py
- requirements.txt

В скрипте app.py создается простое Flask-приложение, отображающее на главной странице гифки с котами и умеющее обрабатывать два типа запросов: /explain и /guess. Запросы к приложению могут выглядеть следующим образом: 127.0.0.1:5000/explain?word=riddle&n_words=10

В скрипте player.py находится класс, описывающий игрока (в примере класс LocalFasttextPlayer).

В requirements.txt перечислен список библиотек, необходимых для работы app.py и player.py

Dockerfile представляет собой файл, задающий параметры сборки докер-образа.

Для модификации сервиса должно быть достаточно переместить код класса своего игрока в player.py, скопировать необходимые для работы файлы в папку docker-flask-app, затем проинициализировать объект класса с использованием нужных файлов в скрипте app.py.

Запуск созданного сервиса

Ниже рассматриваются две возможности запуска данного приложения:

  1. Без использования docker-образа;
  2. С помощью использования докер-образа.

Запускать сервис можно локально, на удаленном сервере и с помощью специализированных платформ для этого - например, heroku или GKE (Google Kubernetes Engine).

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

Без использования docker

При запуске непосредственно flask-приложения локально достаточно выполнить команду python app.py. Проверить работу приложения можно, зайдя в браузере на 127.0.0.1:5000. Если приложение успешно запустилось, вы увидите гифки с котиками.

С использованием docker

Запуск с помощью docker можно произвести следующим образом. Внутри папки docker-flask-app выполните две команды:

  1. Собрать докер-образ, руководствуясь инструкцией в Dockerfile: docker build -t hat_player .
  2. Запустить собранный образ, связав порт 5000 внутри докер-контейнера с портом 5000 на используемом сервере: docker run --rm -it -p 5000:5000 hat_player

При запуске контейнера с docker-образом выполняются команды, описанные в Dockerfile. В частности, внутри нашего докер-образа будет выполнена команда python app.py.

Запуск на удаленном сервере и heroku

Если вы запускаете приложение на удаленном сервере, необходимо, чтобы порт 5000 был открыт для входящий соединений извне. При использовании aws, google cloud, azure или других облачных провайдеров эти параметры есть в панели управления созданным сервером.

Для запуска сервиса в рамках участия в соревновании предлагается воспользоваться сервисом heroku. Запуск с бесплатным аккаунтом обладает следующими особенностями:

  • (+) Запущенный сервис будет существовать на heroku неограниченное время, в отличие от поднятых временно серверов на облачных провайдерах;
  • (+) Поднятый сервис не требует вашего дальнейшего вмешательства а также не зависит от перезагрузок сервера, переустановок пакетов и так далее;
  • (-) Сервис "засыпает" после получаса неиспользования;
  • (-) В месяц доступно около 500 часов для работы запущенных сервисов;
  • (-) На один сервис доступно 512мб RAM.

Приложение на heroku можно запустить с помощью git и с помощью docker-образа.

Запуск на GKE

Чтобы развернуть более требовательное к памяти или вычислениям приложение, можно воспользоваться Google Kubernetes Engine. Для этого достаточно завести аккаунт в Google Cloud (за регистрацию дают 300$, но придется привязать банковскую карту. Не забудьте отвязать вовремя :)

  1. Создать аккаунт в Google Cloud;
  2. Задеплоить докер-образ. Удобно воспользоваться вариантом А и использовать Cloud Shell. Вместо Step 4: Create a container cluster нужно создать кластер с двумя n2-highmem-4 (4vCPUs, 32GB RAM);
  3. Проверить его доступность и мониторить состояние.

Запуск на Google Cloud

Аналогично использованию Google Kubernetes Engine, можно арендовать машинку на Google Cloud. На этой машинке можно запустить приложение на Flask или установить докер и запустить докер-образ. Чтобы сервер был доступен снаружи, потребуется также открыть порты.

Полезные ссылки

Docker image pull/push

Pull

docker pull mnrozhkov/ai-hat:v1

Push

docker tag ai-hat:latest mnrozhkov/ai-hat:v1 docker push mnrozhkov/ai-hat:v1

Fodler Structue

app/ - папка с приложением config/ - конфиги для обучения, приложения и сборки data/ - данные (NOT in GitHub) models/ - здесь лежат обученные модели (NOT in GitHub) notebooks/ - для ноутбуков (NOT in GitHub) src/ - пака с общим кодом для app, обучения и процесинга

Installation

  1. git clone https://github.com/mnrozhkov/ai-hat.git

  2. cd ai-hat

  3. Скопировать файлы

данные в data/ vocabulary/ us-financial-news-articles.txt

модели в models/ ноубуки в notebooks/

GIT_CONFIG_USER_NAME=mnrozhkov GIT_CONFIG_EMAIL=mnrozhkov@gmail.com

Test

Local test

explain: http://0.0.0.0:5000/explain?word=riddle&n_words=10 guess: http://0.0.0.0:5000/guess?word=riddle&n_words=10