MLOps: Streamlit ve Heroku ile Canlıya Çıkmak

6 minute read

Published:

Turkceci
Uygulamaya buradan ulaşabilirsiniz.

Bu çalışmada Stacking ile Kelimelerden Dil Tahmini çalışmasını baz alarak benzeri bir veri seti ile bu çalışmadan daha fazla kelime kullanarak doğrusal ve doğrusal olmayan modeller kullanılarak Türkçe ve İngilizce kelimeler için sınıflama yapıldı. Bu sefer amaç çok daha iyi sonuç veren modeller elde etmek yerine modelleri canlıya almaktı. Nitekim öyle de oldu çünkü model başarımları canlıda çok da iyi görünmüyor.

Problem, veri önişleme, modelleme aşamaları daha önceki çalışma ile (%99) benzer. Bu çalışmada farklı olarak kelimelerin dağılımına bakıp kısmen normal dağılıma yaklaştırıldı, böylece az 3 harf ve en fazla 16 harfli kelimeler için filtreleme yapıldı. Kelimelerin vektörhaline getirilmesi amacıyla bu sefer TF-IDF kullanılmadı sadece CountVectorizer ile kelimeler vektör haline getirildi. Yine aynı şekilde sesli, sesiz ve toplam harf sayısı değişkenlerini eklendi ve n-gram için 1-9 (ortalama harf sayısı) arası tercih edildi.

Kullanılan Modeller:

  • Lojistik Regresyon
  • Ridge Regresyon
  • LightGBM
  • XGBoost
  • Karar Ağacı
  • KNN
  • SGD

Modellere ait sonuçlar %20’lik test setinde şu şekilde;

 F1AccuracyRecallPrecision
LGB0.9270.9690.9140.940
LR0.9240.9680.8990.952
XGB0.9230.9680.9110.936
SGD0.9190.9660.9000.939
DT0.8920.9530.8550.933
Ridge0.8650.9380.7860.961
KNN0.8310.9180.7250.972

Canlıda yapılan denemelerde ise bundan uzak sonuçlar alınıyor. Bahsettiğim gibi amaç streamlit ile arayüzün oluşturulması ve heroku üzerinden de canlıya çıkılması olduğu için bu sefer model başarısını pas geçiyoruz.

Uygulamaya geçmeden önce streamlit’ten de bahsetmek istiyorum. Streamlit özellikle veriye dayalı uygulamalar için hızlıca arayüz oluşturmanızı sağlayan bir Python kütüphanesi. Çok modüler bir yapıya sahip ve title, map, checkbox gibi işinizi inanılmaz kolaylaştıran fonksiyonlara sahip. Dökümanına buradan ulaşabilirsiniz.

Uygulamaya gelecek olursak text_input, select_box, button ve success fonksiyonlarını kullanarak uygulamayı yaratmak mümkün. Geri kalanlar ise tamamen modele ait aşamalar ya da HTML gibi işin önyüz tarafı. Kodu da kısaca anlatmak gerekirse ihtiyacımız olan kütüphaneleri yükledikten sonra modellerin bulunduğu dizini belirtip streamlit’e ait basit ayarları seçiyoruz. Bu ayarlar uygulama adının ne olacağı, uygulamanın sayfadaki konumu gibi değerler. Sonrasında main ile başlayarak öncelikle basit şekildeki önyüzü belirtiyoruz. markdown fonksiyonu bu önyüzün oluşturulmasını sağlıyor. Devamında ise kullanıcıdan alacağımız kelime için text_input ve tahmin yapacak olan model seçimi için select_box bulunuyor. Buna göre seçilen kelime ve model için predictor fonksiyonu belirlenen ve pickle ile çıkarılmış vectorizer‘ı kullanarak sonuç döndürüyor. Sonucun Türkçe veya İngilizce olmasına göre success bize sonucu iletiyor.

import pandas as pd
import numpy as np
from scipy.sparse import hstack, csr_matrix, lil_matrix
import streamlit as st
import pickle
from utils import *
from sklearnwrapper import *
import os, re

path = "model/path"

st.set_page_config(
    page_title="Uygulama Adı",
    page_icon="",
    layout="centered",
    initial_sidebar_state="expanded",
)


def main():
    # ona minik tasarımlar yapın
    html_temp = """ 
    <div style ="background-color:#4169e1; padding:1px"> 
    <h1 style ="color:black;text-align:center;">Kelimeden Dil Tahmini</h1> <br> <br>
    </div> 
    <div>
    <p><a href="https://silverstone1903.github.io/posts/2020/07/language-detection-via-words-with-stacking-tr/" target="_blank" rel="noopener">Stacking ile Kelimelerden Dil Tahmini</a> &ccedil;alışması temel alınarak yapılmıştır. %20'si T&uuml;rk&ccedil;e %80'i ise İngilizce'den oluşan kelimeler kullanılarak karakter seviyesinde vekt&ouml;rize edilmiş ve 
    aşağıda bulunan y&ouml;ntemler ile 5 kat CV kullanılarak modeller eğitilmiştir. <a href="http://streamlit.io/" target="_blank" rel="noopener">streamlit</a> 
    ile <a href="heroku.com" target="_blank" rel="noopener">heroku</a> &uuml;zerinde canlıya alınmıştır.</p>
    <p>Kullanılan Modeller;</p>
    <ul>
    <li>Lojistik Regresyon</li>
    <li>Ridge Regresyon</li>
    <li>LightGBM</li>
    <li>XGBoost</li>
    <li>Karar Ağacı</li>
    <li>KNN</li>
    <li>SGD</li>
    </ul>
    <p>&nbsp;</p>
    </div>
    """

    st.markdown(html_temp, unsafe_allow_html=True)
    value = "istatistik"
    word = st.text_input("Tahmin edilecek kelimeyi girin:", value)
    model = st.selectbox(
        "Model Seçin",
        (
            "Lojistik Regresyon",
            "Ridge Regresyon",
            "LightGBM",
            "XGBoost",
            "Karar Ağacı",
            "KNN",
            "SGD"))
    # işte o meşhur yapay zeka (if-else)
    if model == "Lojistik Regresyon":
        model = model_loader(path + "LogisticRegression.p")
    elif model == "LightGBM":
        model = model_loader(path + "LGBMClassifier.p")
    elif model == "Ridge Regresyon":
        model = model_loader(path + "RidgeClassifier.p")
    elif model == "SGD":
        model = model_loader(path + "SGDClassifier.p")
    elif model == "Karar Ağacı":
        model = model_loader(path + "DecisionTreeClassifier.p")
    elif model == "XGBoost":
        model = model_loader(path + "XGBClassifier.p")
    elif model == "KNN":
        model = model_loader(path + "KNeighborsClassifier.p")

    if st.button("Tahmin Et!"):
        p1, p0 = predictor(word, model, path + "vectorizer.p")
        if p1 > 0.5:
            st.success('"{}" %{:.2f} olasılıkla Türkçe'.format(word, 100 * p1))
        elif p0 > 0.5:
            st.success('"{}" %{:.2f} olasılıkla Ingilizce'.format(
                word, 100 * (p0)))

if __name__ == "__main__":
    main()

heroku ile de çalışan streamlit uygulamamızı canlıya alıyoruz. Öncelikle Procfile oluşturuyoruz. Procfile uygulamanın nasıl çalışağını belirten bir dosya.

# Procfile
web: sh setup.sh && streamlit run strapp.py
# setup.sh
mkdir -p ~/.streamlit/
echo "\
[general]\n\
email = \"your-email@domain.com\"\n\
" > ~/.streamlit/credentials.toml
echo "\
[server]\n\
headless = true\n\
enableCORS=false\n\
port = $PORT\n\
" > ~/.streamlit/config.toml

Son olarak uygulamada kullandığımız Python kütüphaneleri için gereken requirements.txt‘yi de oluşturduktan sonra uygulamamız heroku’ya göndermek için hazır. Heroku’da deployment için 3 seçenek mevcut. Bu yöntemler; heroku-cli, Github ve heroku-cli ile container registry (docker). Ben bu işe de çok sevdiğim Github-Actions’ı karıştırmak istediğim için Github’ı tercih ettim.

Gelelim Actions aşamasına. Sıklıkla formata dikkat etmeden kod yazan biri olduğum için bir kontrol aşaması ekledim. Böylece kod Github’a push’landıktan sonra FormattingPy çalışarak kod için PEP8 kod formatı kontrolü yapılıyor, eğer format dışı bir yazım varsa bunu düzeltiyor ve düzeltilmiş halini repo’ya push’luyor. Heroku ise actions çalışması bittikten sonra kod düzeltilmesi de yapıldıysa bundan sonra deployment için yeni versiyonu deploy etmeye başlıyor. İlkel bir CI/CD çalışıyor denebilir. Kodun biraz daha çetrefilli hale gelip Class yapısına geçilmesi ile (şu an def‘ler havada uçuşuyor) Python testleri eklemek de mümkün.

# actions.yaml
name: FormattingPy
on: [push]
   
jobs:
  autoyapf:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
        with:
          ref: $
      - name: autoyapf
        id: autoyapf
        uses: mritunjaysharma394/autoyapf@v2
        with:
          args: --style pep8 --recursive --in-place .
      - name: Check for modified files
        id: git-check
        run: echo ::set-output name=modified::$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi)
      - name: Push changes
        if: steps.git-check.outputs.modified == 'true'
        run: |
          git config --global user.name github-actions
          git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com'
          git remote set-url origin https://x-access-token:$@github.com/$
          git commit -am "Automated autoyapf fixes"
          git push

Son olarak bu yazıyı yazma motivasyonum Vladimir Iglovikov‘un I trained a model. What is next? yazısıydı. Modeli kurdum sonuçları elde ettim tamam o zaman bittiden sonra yapılabilecek pek çok aşama var aslında. Bu nedenle ben de daha önce yaptığım bir çalışmaya geri dönüp bunu nasıl daha da geliştirebilirim sorusuyla başladım. Bazı ara adımları atlasam da blog yazısı kısmına gelebildim.

Kaynaklar