Спринты Data Science

Создание и развертывание проекта Data Science за две недели

Изучите основы обработки естественного языка, Flask и развертывания моделей машинного обучения, создав что-нибудь интересное!

Я кинестетик; Я учусь, делая, строя и ломая вещи. В этой статье я расскажу, как я построил базовую модель машинного обучения для анализа настроений + веб-приложение и развернул ее менее чем за две недели, чтобы изучить три новые технологии: обработку естественного языка (NLP), флэш и инкрементное / непрерывное обучение.

Результаты обучения

Моими основными целями в этом начинании были следующие:

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

Я хотел сделать все это в режиме быстрого построения / обучения с упором на функциональность, а не на эстетику. Некоторые из других тем, которые я изучал и изучал по пути, включают оптимизацию модели, постепенное / постоянное обучение и jQuery. Все записные книжки Jupyter и код, использованные в этой статье, можно найти на моем Github.

Набор данных

Для этого проекта мне нужен был набор данных, который содержал текстовые данные, но уже был помечен и структурирован. Это позволило бы мне сосредоточиться на предварительной обработке, основанной на NLP, при этом не обращая внимания на другие формы подготовки данных. Посмотрев несколько разных вариантов, я остановился на наборе данных yelp reviews reviews, потому что он был предварительно помечен (текстовый обзор и оценка 1–5 звезд), но фактический текст внутри обзоров был беспорядочным и непоследовательным. Вы можете увидеть пример записи из необработанного набора данных JSON ниже:

Для моей модели меня интересовал только текстовый обзор и 1–5 звезд (возможно, в будущем я смогу попробовать сделать что-нибудь забавное с другими атрибутами). Кроме того, чтобы еще больше упростить процесс обучения и придерживаться мышления быстрого развития, я решил изменить метки с оценок 1–5 на положительные (4 или 5 звезд) или отрицательные (1 или 2 звезды), связанные с текстовым обзором. . Я отказался от обзоров с рейтингом 3 звезды, потому что их классификацию было бы трудно проверить. Спустя несколько строк кода у меня были данные внутри фрейма данных pandas, который можно увидеть ниже:

С текстом есть много потенциальных проблем. Некоторые символы, такие как * и \ n, не служат реальной цели для понимания текста, в то время как другие, такие как $ и ! , может помочь понять, что чувствовал рецензент. Кроме того, есть много слов / сленгов, которые может понять человек (8G = 8000 долларов США), но не имеют почти никакого смысла для машины. Все эти и многие другие сценарии будут рассмотрены в следующем разделе.

Конвейер обработки естественного языка

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

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

Для первой итерации моей модели НЛП я решил реализовать простую модель набора слов, используя метод CountVectorizer() sklearn, и обучить ее примерно на 100 000 строках. Я использовал train_test_split() метод sklearn, чтобы разбить данные на блоки обучения и тестирования. Попробовав несколько различных классификаторов, таких как логистическая регрессия, полиномиальный наивный байесовский анализ и машина линейных опорных векторов, я обнаружил, что модель логистической регрессии лучше всего подходит для этих данных. Вот матрица путаницы соответствующих классификаторов:

Забегая вперед, я обнаружил, что модель логистической регрессии не сможет использовать инкрементное обучение позже в проекте, в то время как линейная SVM (на базе sklearn's SGDClassifier()) будет. Компромисс точности был небольшим: логистическая регрессия имела средний показатель F1 93%, в то время как SVM имел средний показатель F1 92%. Таким образом, я решил продолжить линейную SVM, чтобы использовать инкрементное обучение позже в проекте.

Кроме того, я решил заменить CountVectorizer() на HashingVectorizer(), поскольку он использует метод, называемый хешированием, для уменьшения размера модели обработки ввода на ›99%. Единственный серьезный компромисс - это потеря способности смотреть на явные слова в модели (хеширование преобразует все слова в числа), что меня не сильно беспокоило. Подробнее об этой модели вы можете прочитать здесь.

Оптимизация модели

Я сделал несколько вещей, чтобы оптимизировать свою модель. Как видно из приведенной выше матрицы недоразумений, мои данные обучения и тестирования имеют меньшее количество отрицательных отзывов по сравнению с положительными. В результате моя оценка F1 для отрицательной метки составила 82%, а для положительной - 94%. Чтобы уменьшить это несоответствие, мне пришлось сбалансировать свой набор данных, убедившись, что количество записей, соответствующих двум меткам, было сопоставимым. После балансировки набора данных я пропустил такие стоп-слова, как и, а и т. Д. из модели «мешок слов».

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

Нграммы просто относятся к непрерывной группе из n слов, которые встречаются одновременно. Например-

In the sentence "I love data science", the 1-grams would be ["I", "love", "data", "science"]. The 2-grams would be ["I love", "love data", "data science"] and so on.

Из приведенного выше примера вы даже можете понять, почему использование ngram может быть полезным. 2-граммовое «наука о данных», появившееся в предложении, предоставит больше информации, чем просто 1-граммовые «данные» и «наука». Теперь вернемся к оптимизации: я использовал 1,2 грамма для дальнейшего усиления моей модели. Матрицы путаницы до и после этих оптимизаций можно увидеть ниже:

Как видите, это было серьезным улучшением, поскольку исчезли как положительные, так и отрицательные неверные догадки. Окончательная оценка модели в F1 поднялась до 92%, а разница между двумя классами была незначительной. На данный момент модель была готова. Далее, постепенное / постоянное обучение.

Пошаговое обучение

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

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

Если вы подумаете о том, как люди изучают язык, вы быстро увидите, что они учатся постепенно. Каждый раз, когда родитель поправляет ребенка, учитель поправляет ученика или двое друзей поправляют друг друга, имеет место форма постепенного обучения. В этом разделе мы построим аналогичную систему для нашей модели НЛП, чтобы пользователи могли «исправить» ее, когда она допускает ошибку классификации.

Помните, как мы ранее выбрали SGDClassifier () из-за этой функциональности? SGDClassifier имеет встроенный partial_fit() метод, который поможет нам реализовать инкрементное обучение в нескольких строках кода следующим образом:

# Incremental training
# example x
X_instance = cv.transform(["I like this place, but not much"])  
# user determined label
y_instance = ['n']
# max iterations of training until the classifier relearns 
max_iter = 100
# loop for a maximum of max_iter times
# partially fit the classifier over the learning instance
# stop when classifier relearns (or max_iter is reached)
for i in range (0,max_iter):
    clf.partial_fit(X_instance, y_instance)
    if(clf.predict(X_instance) == y_instance):
        break

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

Подведение итогов и часть 2

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

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

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

[1]: Гэн X., Смит-Майлз К. (2009) Постепенное обучение. В: Ли С.З., Джайн А. (ред.) Энциклопедия биометрии. Спрингер, Бостон, Массачусетс