В нашем недавнем посте мы построили модель с использованием PyCaret для машинного обучения с низким кодом.



Теперь давайте посмотрим, как создать приложение для выполнения логического вывода по модели с помощью Streamlit.

Streamlit — это библиотека Python с открытым исходным кодом, которая позволяет легко создавать красивые настраиваемые веб-приложения для машинного обучения и обработки данных и делиться ими. Всего за несколько минут мы можем создать и развернуть мощные приложения для работы с данными.

Сначала соберем контейнер Streamlit Docker по официальной документации.

Сначала мы создадим локальную папку для Streamlit и создадим этот Dockerfile в папке.

FROM python:3.8-slim
EXPOSE 8501
WORKDIR /app
RUN apt-get update && apt-get install -y \
    build-essential \
    software-properties-common \
    git \
    && rm -rf /var/lib/apt/lists/*
COPY . .
RUN pip3 install -r requirements.txt
ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", 
 "--server.port=8501", "--server.address=0.0.0.0"]

Мы используем образ контейнера на основе Python версии 3.8 (работает на Debian) для создания нашего образа Streamlit. Текущая версия PyCaret 2.3.10 поддерживает до этой версии Python и Python 3.9 в Ubuntu. В этом образе нам также понадобится PyCaret, чтобы убедиться, что мы можем запустить модель, созданную в последнем разделе, с помощью контейнера PyCaret.

Следующая строка в Dockerfile предоставляет уникальный порт 8501, необходимый для запуска Streamlit. Затем мы устанавливаем необходимое программное обеспечение, включая git. Следующая строка копирует локальную папку в виртуальную среду. Затем мы запускаем pip для установки зависимостей, указанных в файле requirements.txt, который мы создадим далее. Последняя строка определяет точку входа для образа контейнера и указывает, что мы хотим запустить конкретное приложение Streamlit, определенное в src/steamlit_app.py.

Давайте определим файл требований для установки зависимостей.

pandas
streamlit
pycaret

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

import streamlit as st
import pandas as pd
from pycaret.classification import *
from pycaret.utils import check_metric
st.subheader('Unseen Data')
data_unseen = pd.read_csv('work/data_unseen_creditml.csv')
st.write(data_unseen.head())
st.subheader('Predictions')
saved_final_rf = load_model('work/CreditML RF Model 2022-Sep-05')
new_prediction = predict_model(saved_final_rf, data=data_unseen)
st.write(new_prediction.head())
metric = check_metric(new_prediction['default'], new_prediction['Label'], metric = 'Accuracy')
st.write('Model accuracy: ', metric)

В качестве последнего шага мы создаем наш контейнер.

docker build -t streamlit .

Теперь мы готовы запустить контейнер Streamlit. Мы монтируем общий том, который мы создали ранее, чтобы обмениваться данными между контейнерами PyCaret и Streamlit.

docker run -d -p 8501:8501 -v shared:/app/work streamlit

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

Теперь предположим, что мы хотим изменить код и перезапустить приложение. Нам придется пересобрать образ контейнера Streamlit. Существует лучший способ. Мы устанавливаем расширения VS Code для Docker, которые позволяют нам управлять контейнерами Docker в VS Code, и Remote Containers, которые позволяют нам подключаться к контейнеру и запускать VS Code для файлов внутри контейнера. Щелкните значок докера на левой панели VS Code после установки расширений. Щелкните правой кнопкой мыши запущенный контейнер Streamlit и выберите Прикрепить код Visual Studio. Это создаст новое окно VSCode и настроит контейнер для удаленного запуска VSCode в контейнере.

Щелкните значок проводника на левой панели, откройте папку и выберите /app, чтобы подключиться к папке контейнера. Мы заметим, что наши файлы доступны в контейнере, включая смонтированный том в папке /work.

Пришло время создать новое приложение Streamlit. Мы называем его credit_check.py и сохраняем в папке work, чтобы сохранить его даже при удалении контейнера. Просто скопируйте код из streamlit_app.py, чтобы посмотреть, как он работает. Затем откройте окно терминала в VSCode, которое подключено к нашему контейнеру. Внутри этого типа streamlit run work/credit_check.py вы заметите, что Терминал распознает это приложение, работающее в удаленном контейнере, где уже запущено другое, поэтому он запускает это новое приложение на другом порту и автоматически перенаправляет его в наш браузер. Умный!

Теперь мы можем вносить изменения в файл credit_check.py, и, сохраняя его, мы можем повторно запускать приложение в нашем браузере без необходимости каждый раз перестраивать контейнер. Вот что мы создадим примерно в 50 строках кода!

Начнем с импорта Streamlit, Pandas и PyCaret.

import streamlit as st
import pandas as pd
from pycaret.classification import *

Затем мы создаем форму для ввода данных нашего кредитного заявителя.

with st.form("my_form"):
    col1, col2 = st.columns(2)
    with col1:
        gender = st.selectbox('Gender', ('Male', 'Female'))
        marital = st.selectbox('Marital status', ('Married', 'Single', 'Other'))
        age = st.slider('Age', 0, 80, 25)
        education = st.selectbox('Education', ('Graduate school', 'University', 'High school', 
            'Others', 'Unknown 1', 'Unknown 2'))
    with col2:
        limit_balance = st.slider('Limit balance', value=30000, min_value=10000, max_value=720000, step=10000)
        clear = st.text_input('Clear', '3,2,2,2,2,3')
        bill = st.text_input('Bill', '26061,25349,27826,27080,30525,29764')        
        pay = st.text_input('Pay', '0,3200,0,3900,0,0')
    submitted = st.form_submit_button("Submit")

Затем мы подготавливаем данные для подачи в нашу модель.

if submitted:
        gender = 1 if gender == 'Male' else 2
        if education == 'Graduate school': education = 1
        elif education == 'University': education = 2
        elif education == 'High school': education = 3
        elif education == 'Others': education = 4
        elif education == 'Unknown 1': education = 5
        elif education == 'Unknown 2': education = 6
        if marital == 'Married': marital = 1
        elif marital == 'Single': marital = 2
        elif marital == 'Other': marital = 3
        df = pd.DataFrame(columns=['LIMIT_BAL', 'SEX', 
            'EDUCATION', 'MARRIAGE', 'AGE', 
            'PAY_1', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6',
            'BILL_AMT1', 'BILL_AMT2', ...
            'PAY_AMT1', 'PAY_AMT2', ...]
        clear_list = [int(x) for x in clear.split(',')]
        bill_list = [int(x) for x in bill.split(',')]
        pay_list = [int(x) for x in pay.split(',')]
        df.loc[0] = [limit_balance, gender, education, marital, age] + 
            clear_list + bill_list + pay_list + [0]

Наконец, мы загружаем модель и запускаем прогноз.

saved_final_rf = load_model('work/CreditML RF Model 2022-Sep-05')
        new_prediction = predict_model(saved_final_rf, data=df)
        score = float(new_prediction.iloc[-1]['Score'])
        prediction = float(new_prediction.iloc[-1]['Label'])
        scol1, scol2 = st.columns(2)
        with scol1:
            st.title('👎 Bad credit' if prediction else '👍 Good credit')
        with scol2:
            st.metric('Accuracy', value=score, delta=round(score-0.8167,4))

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