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

Если вы не читали предыдущую запись блога Word2Vec о Гарри Поттере, в которой рассказывалось о веб-сайте и алгоритме w2v, сделайте это сейчас.

Вот мой код.

Цели этого проекта:

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

Архитектура

На этой диаграмме показаны все файлы, которые я создал для запуска моего приложения w2v. Вот краткое описание, но я более подробно объясню всю настройку в этом посте.

Файлы интерфейса:

  • HTML стартовая страница (3 КБ) - код для оформления www.zareenfarooqui.com/w2v
  • Файлы журнала сервера Apache (различаются) - файлы прямого доступа из cPanel

Файлы MacBook:

  • .pem (2 КБ) - файл аутентификации для безопасного входа в мой EC2

Файлы сети доставки контента:

  • Bootstrap CSS (121 КБ) - файл CSS для загрузки Twitter
  • Bootstrap JS (37 КБ) - файл Twitter Bootstrap JS

Файлы AWS:

  • 7 книг HP (6,6 МБ) - текстовый корпус
  • Код бутылки (4 КБ) - код для веб-фреймворка
  • gensim model (3 КБ) - код для создания модели w2v
  • keyerror.tpl (3 КБ) - шаблон ошибки для отображения слов не в корпусе
  • results.tpl (4 КБ) - успешный шаблон с w2v результатами 7 наиболее похожих слов
  • Файлы SQLite3 db (различаются) - таблицы user_words и saved_words
  • Файл журнала сервера Bottle (различается) - файлы журнала, автоматически генерируемые из среды Bottle.
  • файл журнала приложения w2v (различается) - пользовательское ведение журнала

В архитектуре приложения w2v есть два основных компонента:

  • Внешний интерфейс: то, что хранится в браузере пользователя, включая дизайн веб-сайта, HTML, CSS, JavaScript и библиотеку Bootstrap.
  • Back-end: все на сервере EC2, включая код Python, веб-сервер Bottle, библиотеку gensim и базу данных SQLite3.

Я запустил сервер t2.micro EC2 с помощью Консоли управления AWS для размещения своего веб-приложения. Этот тип инстанса поставляется с 1 виртуальным ЦП, 1 ГБ ОЗУ и стоит 0,013 доллара в час для работы в центре обработки данных в Орегоне (так что он стоит ~ 10 долларов в месяц). Я выбрал Red Hat 7.2 Amazon Machine Image (AMI) на сервере, потому что Red Hat - один из самых популярных дистрибутивов Linux, которые организации используют в производственной среде.

Я размещаю свое приложение на виртуальной машине, а не на своем ноутбуке, поэтому я могу запускать свой веб-сайт 24/7 (мой ноутбук не обязательно должен быть включен), и его легко масштабировать вверх или вниз. Поэтому вместо того, чтобы покупать больше ноутбуков по мере того, как мое приложение будет использовать все больше людей, я могу заплатить за более крупные или просто дополнительные виртуальные серверы EC2 за небольшую часть стоимости. Если бы мой объем снизился, я бы просто перестал работать и платить за ненужные серверы, не имея громоздкого оборудования для обслуживания.

Прежде чем я смог начать писать код для внешнего и внутреннего интерфейсов веб-приложения, мне нужно было подготовить серверную среду EC2.

Подготовка сервера EC2

После запуска сервера EC2 мне нужно было создать идеальную рабочую среду. Я загрузил ключ безопасности .pem из консоли AWS и использовал его для SSH на сервере с помощью терминала в OS X:

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

Далее я установил и настроил необходимые инструменты и библиотеки:

  • Отключен брандмауэр Redhat 7 на сервере EC2.
  • Открыты необходимые порты в группе безопасности Amazon
  • Установлен PIP, чтобы я мог легко установить дополнительные пакеты Python
  • Установлен FTP-сервер (VSFTPD), чтобы я мог перемещать файлы между моим ноутбуком и сервером EC2, я использую FileZilla на своем локальном компьютере
  • Установлен сервер Jupyter Notebook (версия 4.1.0) для использования интерфейса записной книжки в моем браузере для запуска кода Python на сервере.
  • Установлена ​​библиотека gensim с открытым исходным кодом (версия 0.12.4) для построения и оценки моделей w2v.
  • Установлен Bottle как мой микро-фреймворк для Python
  • Установил SQLite3 в качестве движка реляционной базы данных

Этот этап проекта включал в себя много поисков в Google, проб и ошибок, установки, отладки и вина.

Front-end веб-разработка

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

Однако в современных веб-приложениях разработчики используют фреймворк или библиотеку более высокого уровня, поэтому им не нужно копировать общие функции интерфейса. Фреймворк Twitter Bootstrap с открытым исходным кодом, пожалуй, самый популярный интерфейсный фреймворк. Он содержит шаблоны дизайна на основе HTML и CSS для типографики, форм, кнопок, таблиц, навигации и других компонентов интерфейса. Используя эти уже предоставленные шаблоны CSS из Twitter, я смог легко и быстро создать профессиональный веб-сайт. Bootstrap также позволяет мне создавать адаптивный веб-сайт, то есть сайт без проблем работает на устройствах с экранами разных размеров - ноутбуках, смартфонах, планшетах и ​​т. Д. Чтобы изучить Bootstrap, я выполнил руководство, приведенное ниже:

Размер моего файла стартовой страницы составляет всего 3 КБ. Однако размер файла CSS Bootstrap составляет 121 КБ, а файла JavaScript - 37 КБ. Если бы моему серверу EC2 пришлось обслуживать эти два дополнительных файла Bootstrap для каждого пользователя, это оказало бы дополнительную нагрузку на сервер. Чтобы снять это бремя, я использую сеть доставки контента (CDN), которая распространяет файлы Bootstrap на многие серверы по всему миру. Теперь, когда пользователи заходят на мой сайт, они загружают два файла Bootstrap с ближайшего физического сервера CDN. Это беспроигрышная ситуация для меня как разработчика и моих пользователей, которым файлы Bootstrap предоставляются быстрее.

Есть две проблемы с использованием CDN: они могут отслеживать IP-адреса пользователей, скачивающих файлы, и я не могу настраивать файлы CSS + JS. Поскольку я не делаю критически важное для безопасности приложение, это не было серьезной проблемой.

Строки 9 и 10 ниже загружают файлы Bootstrap из CDN в браузер пользователя:

Bootstrap обрабатывает форматирование и дизайн веб-сайта, но мне нужен код JavaScript для создания надежного сайта. JavaScript - это язык программирования для Интернета, работающий в браузере. Я написал функции JS, чтобы убедиться, что вводимые пользователем данные соответствуют критериям программы. Во-первых, действительно ли пользователь вводил что-нибудь в текстовое поле? Это обязательное поле, поэтому форма не может быть отправлена, пока это условие не будет выполнено.

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

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

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

В основном это визуальная уловка, чтобы удержать внимание пользователей, пока программа работает в фоновом режиме. Я не вычислял программным способом точное время, необходимое gensim для прохождения слова через мою модель, но я знаю, что это примерно несколько секунд. Я запрограммировал индикатор выполнения, чтобы (надеюсь) никогда не достигать 100%. Вместо этого результаты должны быть представлены пользователю до того, как пользователь их ожидает. В 2006 году Google опубликовал исследование, в котором утверждалось, что задержка в полсекунды привела к снижению трафика и доходов на 20%. Это главное - пользователи предпочитают скорость дополнительной функциональности. Я знал, что было бы неприемлемо ожидать, что пользователи будут ждать несколько секунд, чтобы попробовать каждое слово, и это осознание привело меня к важному решению по функциональности серверной части (см. Раздел базы данных ниже).

Я загрузил код HTML, CSS и JS для начальной страницы своего приложения через NameCheap CPanel. Это сделало www.zareenfarooqui.com/w2v активным сайтом. Однако любая отправка формы на этом этапе приведет к ошибке, поскольку внутренний код еще не развернут.

Внутренний стек

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

Веб-фреймворк

Весь back-end код написан на Python с использованием микро-веб-фреймворка Bottle. Я выбрал Bottle вместо Flask или Django, потому что он прост и не имеет других зависимостей, кроме стандартной библиотеки Python. Мне нравится подход Бутылки к одному файлу, потому что это намного проще, чем поддерживать много файлов. Бутылка позволяет мне запрашивать базу данных SQL, а затем отправлять конечному пользователю эти результаты SQL в шаблоне вывода. Если пользователь отправляет слово, которого нет в серии HP, пользователю предоставляется шаблон ошибки, который позволяет пользователю ввести другое слово. Bottle использует функции маршрутизации для обслуживания веб-страниц конечным пользователям. Вот базовый пример Hello World, с которого я начал:

Если у вас установлен Bottle, вы можете запустить этот сценарий и посетить http: // localhost: 8080 / hello и увидеть веб-страницу, которая возвращает Hello World!.

Я использовал уроки по бутылкам ниже:

Я использую пакет daemon Bottle для автоматического запуска моего скрипта 24/7 в фоновом режиме.

Схема базы данных

SQLite3 - это моя СУБД. У меня есть две таблицы: user_words и saved_words.

Приложение My Bottle захватывает слово из внешнего интерфейса, а затем добавляет его в таблицу user_words вместе с меткой времени (часовой пояс по Гринвичу) и IP-адресом пользователя.

Помните, как я объяснял ранее, что модель w2v запускается за несколько секунд, и это был плохой дизайн? Изначально у меня была только таблица user_words, и я запускал модель для каждого отправленного слова. Модель запускается примерно за 3–4 секунды. Говоря языком разработки этого проекта, я был единственным пользователем, поэтому на моем сервере не было нагрузки. В производственной среде может быть много одновременных пользователей, и я беспокоился, что это может привести к сбою моего сайта или замедлению работы, поэтому мне пришлось придумать другую технику. Один из вариантов заключался в том, чтобы запустить модель для каждого слова в корпусе и сохранить результаты в таблице, но это заняло бы более 14 часов и не было эффективным подходом.

Вместо этого я создал новую таблицу, которая автоматически оптимизируется для самых популярных слов:

В таблице saved_words есть два столбца: слово и данные. Изначально эта таблица полностью пуста. Когда пользователь отправляет слово, я проверяю, существует ли это точное слово в столбце word таблицы saved_words. Если нет, моя модель w2v запускает отправленное слово, и к этой таблице добавляется новая строка. Столбец word получает отправленное слово в виде строки, а столбец данных получает маринованные результаты 7 похожих слов из модели w2v. Однако, если отправленное слово уже существует, я извлекаю результаты и передаю их прямо из базы данных. Теперь, когда другой пользователь отправляет то же слово, приложение запускается значительно быстрее, поскольку оно не запускает модель.

Я использовал руководства по SQLite3 ниже:

Gensim Реализация w2v

Чтобы использовать w2v, я изменил свой код HP Text Analysis для извлечения пакета предложений, а не набора слов для каждой книги. Я скормил эти пакеты предложений из 7 книг в общую реализацию word2vec. Я следовал этому руководству, чтобы построить свою модель:

Вот параметры, которые влияют на качество и время работы моделей gensim:

  • Архитектура. Можно выбрать один из двух алгоритмов - непрерывный пакет слов (CBOW) или непрерывный скип-грамм (вариант по умолчанию), CBOW является более быстрым из двух и предсказывает целевое слово с учетом соседних слов. , непрерывная скип-грамма предсказывает соседние слова на основе целевого слова и обычно используется для менее частых слов. Я использую опцию пропуска грамма по умолчанию
  • Алгоритм обучения: иерархический softmax (по умолчанию) или отрицательная выборка, я использую значение по умолчанию
  • Размерность вектора слова: это количество функций (или слов), обычно большее количество функций означает лучшие модели, но более длительное время выполнения. Я использую 10 000 функций.
  • Минимальное количество слов: если слово не встречается в тексте хотя бы такое количество раз, оно будет проигнорировано, поэтому в словарь будут включены только значимые слова, я установил для него значение 30 (если вы введете редкое слово на моем веб-сайте, он может сказать вам, что слово не может быть найдено в серии, потому что оно не повторялось по крайней мере 30 раз)
  • Рабочие потоки: количество параллельных процессов для запуска. 4 считается стандартным значением, поэтому я использую его (установите cython, чтобы запустить более одного воркера).
  • Контекст / размер окна: количество слов до и после данного слова, которое должен учитывать алгоритм, я использую 10
  • Понижение частоты дискретизации часто используемых слов: рекомендуемые значения от 0,00001 до 0,001, я использую 0,001.

Вот документация, которая объясняет эти параметры более подробно. Я прогнал пару моделей с разными параметрами, прежде чем выбрать одну для производства. На создание каждой модели ушло около 15 минут, а затем на выполнение для каждого отправленного слова - 3–4 секунды.

логирование

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

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

В моем nameCheap cPanel также есть файлы журнала необработанного доступа, сгенерированные веб-сервером Apache. Это записи IP-адресов пользователя, даты и времени доступа, переданных байтов, запрошенных файлов, браузера и операционной системы.

Когда я открыл эти файлы журналов, я заметил несколько ботов Google и Baidu. Google и Baidu регулярно загружают всю сеть с помощью этих поисковых роботов и используют эти данные для создания своих поисковых систем. Если я не хочу, чтобы мой веб-сайт сканировался и индексировался этими сайтами, я могу добавить файл robots.txt, предупреждающий их игнорировать мой сайт, но для моего сайта в этом нет необходимости.

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

Что дальше?

Этот проект не является типичным проектом аналитика данных, но мне было любопытно изучить основы разработки полного стека. Теперь я вернусь к анализу с помощью Python, в частности, с использованием Pandas, NumPy и matplotlib.

Я узнал, что ни один программный проект не будет идеальным - всегда есть дополнительные функции, которые я могу добавить, рефакторинг кода, который я могу сделать, и улучшение скорости / безопасности для улучшения взаимодействия с пользователем. Если бы я стремился сделать свои проекты идеальными, я бы никогда их не закончил. Вместо этого сначала я создаю минимально жизнеспособный продукт, который работает, но не выглядит чистым. Затем я начинаю добавлять новые функции, пока не останусь довольна. У меня есть несколько идей, которые можно реализовать, когда я вернусь к этому проекту:

  1. Добавьте больше функций w2v - аналогии слов, поиск противоположности слову, кластеры слов, поиск слова, не принадлежащего к группе
  2. Раскрасьте слова в таблице результатов как визуальный индикатор косинусного сходства; возможно, если косинусное сходство составляет ›.9, сделайте слово зеленым, если оно находится между 0,75 и 0,9, сделайте его желтым, а‹ 0,75 - красным.
  3. Выполните аналитику по таблице user_words - определите, какие слова используются чаще всего, и порекомендуйте их в качестве предлагаемых слов для изучения со стартовой страницы, выясните, в какие дни / время мой сайт наиболее популярен
  4. Используйте Pandas в Jupyter Notebook для анализа файлов журналов из NameCheap и журнала Bottle - узнайте, где находится моя аудитория, посмотрите, сколько уникальных IP-адресов посетили мой сайт в любой момент времени, сколько слов люди вводят в приложение, прежде чем им станет скучно и уход
  5. Используйте более крупный текстовый корпус, такой как Google Книги или Википедия, для создания универсального англоязычного w2v-сайта.
  6. Создайте сайт, на котором пользователи сначала загружают свой собственный текстовый корпус, могут запускать на нем w2v, а затем изучать результаты

Если у вас есть другие функции, которые вы хотели бы увидеть, сообщите мне об этом в комментариях.

Хотите, чтобы я построил для вас нечто подобное? Свяжитесь со мной в LinkedIn.