Эта статья состоит из трех частей
Модель НЛП, развертывание с флягой, развертывание в Интернете (Heroku)
Вы можете проверить работающую развернутую модель здесь: http://www.nltkbot.com/
Прежде чем перейти к статье, вам необходимо правильно установить Python в вашей системе, и вам необходимо иметь базовое представление о моделях машинного обучения.
В этой статье рассматривается только часть развертывания модели с помощью flask, а не подробное построение модели. Поэтому, если у вас уже есть рабочая модель, вы можете использовать эту модель для развертывания и можете сразу перейти к части развертывания, или же вы можете использовать приведенный ниже пример модели.
ЧАСТЬ 1) — Модель НЛП
Поскольку построение модели выходит за рамки этой статьи, я просто объясню модель и то, что она делает. Если кому-то нужны наборы данных для дальнейшего улучшения модели, ссылки на github приведены в конце статьи в разделах «Ссылки».
У нас есть очень простая модель, которая была обучена на технических твитах от клиентов о различных технологических фирмах, которые производят и продают мобильные телефоны, компьютеры, ноутбуки и т. д. Задача состоит в том, чтобы определить, имеют ли твиты негативное отношение к таким компаниям или продуктам.
Процесс очистки данных включал удаление всех URL-адресов, знаков препинания, а библиотека NLTK использовалась для токенизации, лемметизации и удаления стоп-слов. Убедитесь, что у вас уже установлена библиотека NLTK, иначе она выдаст ошибки.
import pandas as pd import numpy as np import nltk import string import re import pickle nltk.download('stopwords') nltk.download('wordnet') train_data = pd.read_csv('train.csv') test_data = pd.read_csv('test.csv') data = pd.concat([train_data, test_data], axis=0) df = data.copy() df['label'].value_counts() # Removing URLs def remove_url(text): return re.sub(r"http\S+", "", text) #Removing Punctuations def remove_punct(text): new_text = [] for t in text: if t not in string.punctuation: new_text.append(t) return ''.join(new_text) #Tokenizer from nltk.tokenize import RegexpTokenizer tokenizer = RegexpTokenizer(r'\w+') #Removing Stop words from nltk.corpus import stopwords def remove_sw(text): new_text = [] for t in text: if t not in stopwords.words('english'): new_text.append(t) return new_text #Lemmatizaion from nltk.stem import WordNetLemmatizer lemmatizer = WordNetLemmatizer() def word_lemmatizer(text): new_text = [] for t in text: lem_text = lemmatizer.lemmatize(t) new_text.append(lem_text) return new_text df['tweet'] = df['tweet'].apply(lambda t: remove_url(t)) df['tweet'] = df['tweet'].apply(lambda t: remove_punct(t)) df['tweet'] = df['tweet'].apply(lambda t: tokenizer.tokenize(t.lower())) df['tweet'] = df['tweet'].apply(lambda t: remove_sw(t)) df['tweet'] = df['tweet'].apply(lambda t: word_lemmatizer(t))
Позже текст был векторизован с помощью TfidVectorizer перед отправкой в модель для прогнозирования. Модель LightGbm использовалась для прогнозирования без какой-либо настройки гиперпараметров, как я уже упоминал ранее, построение модели выходит за рамки этой статьи. Наконец, модель и векторизатор должны быть сохранены с помощью pickle, чтобы мы могли позже загрузить эти модели в наше приложение, чтобы предсказать результаты пользовательского ввода.
features_set = df.copy() train_set = features_set.iloc[:len(train_data), :] test_set = features_set.iloc[len(train_data):, :] X = train_set['tweet'] for i in range(0, len(X)): X.iloc[i] = ' '.join(X.iloc[i]) Y = train_set['label'] from sklearn.feature_extraction.text import TfidfVectorizer TfidV = TfidfVectorizer() X = TfidV.fit_transform(X) from sklearn.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.1, random_state = 1234) from lightgbm import LGBMClassifier lgb = LGBMClassifier(scale_pos_weight=3) lgb.fit(X, Y) #lgb.fit(x_train, y_train) y_predict_lgb = lgb.predict(x_test) from sklearn.metrics import confusion_matrix, f1_score cm_lgb = confusion_matrix(y_test, y_predict_lgb) f1_lgb = f1_score(y_test, y_predict_lgb) score_lgb = lgb.score(x_test, y_test) with open('twitter_predictions.pkl', 'wb') as file: pickle.dump(lgb, file) with open('vectorizer.pkl', 'wb') as file: pickle.dump(TfidV, file)
ЧАСТЬ 2) — Развертывание с использованием Flask
Я надеюсь, что у вас есть рабочий файл модели и файл векторизатора, сохраненные с помощью pickle, прежде чем приступить к развертыванию.
Flask — это микрофреймворк для Python, его легко настроить. Перед установкой flask создайте каталог (я назвал его flask_app), в котором вы собираетесь установить приложение flask, и создайте виртуальную среду (я назвал его nlp_env) в этом каталоге и активируйте его, и он должен выглядеть примерно так:
C:\Users\Surya\Documents\flask_app>py -m venv nlp_env C:\Users\Surya\Documents\flask_app>nlp_env\Scripts\activate (nlp_env) C:\Users\Surya\Documents\flask_app>
Теперь мы можем установить flask, для установки flask мы используем pip установщика пакетов python.
(nlp_env) C:\Users\Surya\Documents\flask_app>pip install flask
После завершения установки мы можем пойти и создать наше приложение для фляги. Первый шаг — создать файл в каталоге flask_app и назвать его (я назвал его app.py). Вы можете открыть этот файл в своем любимом текстовом редакторе. Поскольку это ваш основной файл приложения, нам нужно установить переменную среды, которая позволит фляге знать, какой файл искать, когда он хочет запустить
(nlp_env) C:\Users\Surya\Documents\flask_app>set FLASK_APP=app.py
Теперь мы проверим работу знаменитого «Hello World» с нашим фляжным приложением. Откройте текстовый редактор и напишите приведенный ниже код.
import flask app = flask.Flask(__name__) @app.route('/') def index(): return "<h1>Hello World</h1>"
Код довольно прост, мы просто импортировали библиотеку flask и создали экземпляр класса Flask, а __name__ ссылается на имя текущего модуля, в котором мы работаем (здесь это app.py). В следующей строке мы создаем маршрут, за которым следует функция, которая возвращает прямо в браузер.
Пришло время увидеть, как наше приложение flask запущено и работает в браузере, просто введите flask run, и вы должны увидеть приложение, работающее по адресу локального хоста (что-то вроде этого, работающее на http://127.0.0.1:5000/)
(nlp_env) C:\Users\Surya\Documents\flask_app>flask run
Написание html непосредственно в app.py не рекомендуется, и это также выглядит не очень хорошо, поэтому мы создадим отдельную папку в нашем непосредственно и будем ссылаться на нее в нашем app.py. Мы также должны создать отдельную папку для хранения наших сохраненных моделей, которые позже мы будем использовать для прогнозирования. После создания папок ваша структура папок должна выглядеть так, как показано ниже.
Мы обновим наш app.py, чтобы отразить эти изменения. Сначала мы загрузим файлы нашей модели, а затем обновим наш класс Flask с помощью папки с шаблонами. В дополнение к этому мы также обновим нашу маршрутизацию, чтобы принимать запросы GET и POST.
import flask #Use pickle to load in the pre-trained model. with open(f'model/twitter_predictions.pkl', 'rb') as f: model = pickle.load(f) with open(f'model/vectorizer.pkl', 'rb') as f: vectorizer = pickle.load(f) app = flask.Flask(__name__, template_folder='templates') @app.route('/', methods=['GET', 'POST']) def index(): return "<h1>Hello World</h1>"
Наше приложение по-прежнему возвращает «Hello World» с запросом GET. Итак, нам нужно, чтобы наше приложение возвращало правильный html, и для этого мы создадим html-файл (index.html) в папке с нашими шаблонами. Я собираюсь добавить простую html-форму в index.html, которая позволит пользователю ввести текст и отправить его.
<!doctype html> <html> <head> <title>Enter Text</title> </head> <form action="{{ url_for('index') }}" method="POST"> <fieldset> <legend>Enter Review:</legend> <textarea name="tweet" rows="10" cols="80" required></textarea> <br> <br> <input type="submit"> </fieldset> </form>
Когда пользователь вводит текст и отправляет его, наше приложение получает запрос POST с текстом, прикрепленным к «твиту». Нам нужно обновить наш app.py, чтобы обрабатывать этот запрос POST и отображать результат соответствующим образом.
import flask #Use pickle to load in the pre-trained model. with open(f'model/twitter_predictions.pkl', 'rb') as f: model = pickle.load(f) with open(f'model/vectorizer.pkl', 'rb') as f: vectorizer = pickle.load(f) app = flask.Flask(__name__, template_folder='templates') @app.route('/', methods=['GET', 'POST']) def index(): if flask.request.method == 'GET': return(flask.render_template('index.html')) if flask.request.method == 'POST': tweet = flask.request.form['tweet']
Мы получили пользовательский ввод, который нам нужно предсказать из запроса POST, поэтому мы будем использовать нашу ранее загруженную модель для предсказания результатов. Поскольку пользовательский ввод все еще находится в необработанном виде, нам нужно преобразовать его в машиночитаемый вид так же, как мы делали это при построении модели в первой части. Сначала мы преобразуем его в фрейм данных с теми же именами столбцов, которые понимает наша сохраненная модель, а позже все шаги, которые мы использовали при построении модели, будут выполняться в том же порядке. Итак, наш окончательный файл app.py должен выглядеть так, как показано ниже.
import flask import pickle import pandas as pd import numpy as np import nltk import string import re # Use pickle to load in the pre-trained model. with open(f'model/twitter_predictions.pkl', 'rb') as f: model = pickle.load(f) with open(f'model/vectorizer.pkl', 'rb') as f: vectorizer = pickle.load(f) # Removing URLs def remove_url(text): return re.sub(r"http\S+", "", text) #Removing Punctuations def remove_punct(text): new_text = [] for t in text: if t not in string.punctuation: new_text.append(t) return ''.join(new_text) #Tokenizer from nltk.tokenize import RegexpTokenizer tokenizer = RegexpTokenizer(r'\w+') #Removing Stop words from nltk.corpus import stopwords def remove_sw(text): new_text = [] for t in text: if t not in stopwords.words('english'): new_text.append(t) return new_text #Lemmatizaion from nltk.stem import WordNetLemmatizer lemmatizer = WordNetLemmatizer() def word_lemmatizer(text): new_text = [] for t in text: lem_text = lemmatizer.lemmatize(t) new_text.append(lem_text) return new_text app = flask.Flask(__name__, template_folder='templates') @app.route('/', methods=['GET', 'POST']) def index(): if flask.request.method == 'GET': return(flask.render_template('index.html')) if flask.request.method == 'POST': tweet = flask.request.form['tweet'] df = pd.DataFrame([tweet], columns=['tweet']) df['tweet'] = df['tweet'].apply(lambda t: remove_url(t)) df['tweet'] = df['tweet'].apply(lambda t: remove_punct(t)) df['tweet'] = df['tweet'].apply(lambda t: tokenizer.tokenize(t.lower())) df['tweet'] = df['tweet'].apply(lambda t: remove_sw(t)) df['tweet'] = df['tweet'].apply(lambda t: word_lemmatizer(t)) final_text = df['tweet'] final_text.iloc[0] = ' '.join(final_text.iloc[0]) final_text = vectorizer.transform(final_text) prediction = model.predict(final_text) return flask.render_template('index.html', result=prediction, original_input={'Mobile Review':tweet}) if __name__ == '__main__': app.run()
Прогнозируемый результат в app.py сохраняется в переменной результата, которая будет отображать результат в index.html. Мы создадим новый элемент div для отображения результата вместе с пользовательским вводом, когда запрос POST отображает index.html. Элемент div имеет простой оператор if else для проверки типа результата и добавления цвета к результату. Я добавил некоторые стили к html-странице, чтобы она выглядела красиво. Таким образом, наш окончательный HTML-файл будет выглядеть следующим образом:
<!doctype html> <html> <style> form { margin: auto; width: 35%; } .result { margin: auto; width: 35%; border: 1px solid #ccc; } </style> <head> <title>Enter Text</title> </head> <form action="{{ url_for('index') }}" method="POST"> <fieldset> <legend>Enter Mobile Review:</legend> <textarea name="tweet" rows="10" cols="80" required></textarea> <br> <br> <input type="submit"> </fieldset> </form> <br> <div class="result" align="center"> {% if result == 0 %} {% for variable, value in original_input.items() %} <b>{{ variable }}</b> : {{ value }} {% endfor %} <br> <br> <p style="font-size:30px">The Review is:</p> <p style="font-size:40px; color: green;">{{ result }}</p> {% elif result == 1 %} {% for variable, value in original_input.items() %} <b>{{ variable }}</b> : {{ value }} {% endfor %} <br> <br> <p style="font-size:30px">The Review is:</p> <p style="font-size:40px; color: red;">{{ result }}</p> {% endif %} </div> </html>
Теперь введите, запустите flask и посмотрите, как модель ML в браузере запущена и работает и готова предсказывать некоторые твиты. Ура !! вы успешно развернули модель НЛП с флягой на своем локальном компьютере. Вы можете дополнительно добавить стиль и фон в приложение, чтобы оно выглядело более ярким, или вы можете проверить мое приложение на наличие полного шаблона https://github.com/vijjeswarapusuryateja/mobile-review-rating.
ЧАСТЬ 3) — Развертывание в Интернете (Heroku)
Здесь я рассказываю только о развертывании модели НЛП на Heroku, если у вас уже есть учетная запись в Heroku. Если вы не знакомы с Heroku, в Интернете доступно множество источников богатой информации о Heroku. Объяснение процесса регистрации в Heroku не входит в задачу этой статьи. Поэтому вам нужно установить git, Heroku CLI, прежде чем переходить к следующему шагу.
Первый шаг — создать репозиторий git для нашего веб-приложения.
(nlp_env) C:\Users\Surya\Documents\flask_app>git init
Аутентифицируйтесь с помощью Heroku и создайте новое приложение heroku
(nlp_env) C:\Users\Surya\Documents\flask_app>heroku login (nlp_env) C:\Users\Surya\Documents\flask_app>heroku create flask-app-nlp
Чтобы наше приложение успешно работало на Heroku, нам нужно добавить три дополнительных файла.
Создайте файл requirements.txt в каталоге flask_app, и он должен иметь следующее
flask pandas numpy gunicorn lightgbm nltk
Аналогичным образом создайте файл nltk.txt и добавьте следующее
stopwords wordnet pros_cons reuters omw-1.4
Наконец, создайте Procfile в каталоге flask_app и добавьте следующую строку.
web: gunicorn app:app
Ваша окончательная папка flask_app теперь должна выглядеть так:
Добавьте все эти файлы в репозиторий, используя команды git, как показано ниже.
(nlp_env) C:\Users\Surya\Documents\flask_app>git add . (nlp_env) C:\Users\Surya\Documents\flask_app>git commit -m "First commit!"
Установите удаленный пункт назначения для нажатия с git на heroku
(nlp_env) C:\Users\Surya\Documents\flask_app>heroku git:remote -a flask-app-nlp
После выполнения приведенной ниже команды ваше приложение будет подключено к сети. Heroku загрузит файлы вашего приложения, установит необходимые пакеты и запустит приложение.
(nlp_env) C:\Users\Surya\Documents\flask_app>git push heroku master
Вы получите показанный ниже экран, как только все будет отправлено в Heroku.
После завершения загрузки вы можете ввести heroku open и увидеть приложение, работающее в веб-браузере. В качестве альтернативы вы можете посмотреть свое приложение с созданным вами именем http://flask-app-nlp.herokuapp.com. Я уже создал приложение с таким именем в Heroku, поэтому вместо этого используйте другое имя.
(nlp_env) C:\Users\Surya\Documents\flask_app>heroku open
Возможные ошибки!
Если у вас возникнут проблемы с развертыванием heroku, всегда рекомендуется проверять журналы heroku, чтобы устранить проблему. Одно из решений наиболее распространенной проблемы, возникающей при развертывании NLP, связано с библиотекой NLTK, и ее можно исправить, указав соответствующий корпус в файле nltk.txt, который отображается в журналах heroku.
ПОЛЕЗНЫЕ ССЫЛКИ (набор данных, репозиторий Github, развернутая модель)
Ссылки на наборы данных, на которых обучалась модель: https://github.com/vijjeswarapusuryateja/Datasets
Ссылка на код развернутого приложения: https://github.com/vijjeswarapusuryateja/mobile-review-rating
Рабочая развернутая модель: http://www.nltkbot.com/
Портфолио: https://vijjeswarapusuryateja.github.io/