Herkese Selam,
Machine Learning modellerinin kullanıma açılması ile ilgili opsiyonları bir süredir paylaşıyorum. Bu opsiyonlardan birini bir önceki yazımda paylaşmıştım. Link‘e tıklayarak bu yazıya gidebilirsiniz. Bu yazıda ise farklı bir kullanıma açma senaryosu ile ilgili bir örnek yapmayı planlıyorum. Umarım farkındalık anlamında faydalı bir yazı olur.
Girişi, yukarıda linkini paylaşmış olduğum bir önceki yazımdan alıntı yaparak başlamak istiyorum.
“Hepimizin bildiği üzere Makine Öğrenimi ve uygulamaları günümüzün en trend konularının başında geliyor. Bireysel kullanıcılardan kurumsal büyük organizasyonlara kadar bir çok oyuncu makine öğrenimi uygulamaları geliştirmeye çalışıyor. Bu konu ile ilgili mesai harcayan herkesin bildiği üzere bu projelerin gelişimi standart yazılım geliştirme akışından bir miktar farklı. Çözmek istediğimiz probleme ait modeli önce prototipliyoruz daha sonra belirli bir süre test edip parametrelerini en iyileyerek modelimizi nihai halini almasını sağlıyoruz. Modelimiz oldu dediği noktada da bu modeli kullanıma açma kısımına geçiyor. Tam bu noktada mevcut skill setimizin yanında bir miktar yazılım geliştirme ve veri mühendisliği bilmemiz gerekiyor çünkü standart yazılım geliştirme yöntemleri ile bundan sonraki kısımları halletmemiz gerekiyor. Yazımıza konu olan kısımda tamda bu noktada başlıyor.”
Bu yazıya konu olacak modelimiz bir önceki yazımda kullanmış olduğum modelin bire bir aynısı dolayısıyla bu yazıdaki örneği daha iyi kavrayabilme adına bir önceki yazıdakinin aynısı. Yani daha önce bu blogta paylaşmış olduğum “Doğal Dil İşleme (NLP) ile Sentiment (Duygu) Analizi Tespiti” yazısında paylaşmış olduğum model üzerinden çalışmayı yapacağım ve yine önemle vurgulamak isterimki bu yazının yazılma amacı state of the art bir sentiment analyzer yapmak değil.
“Öncelikle senaryomdan bir miktar bahsedeyim. Bir sentiment analizi modeli geliştirmek istiyorum. Bu modeli imdb, yelp ve amazon’dan toplanmış bir veri seti ile eğitip basit bir sentiment tahmin modeli geliştireceğim. Daha sonra bu modeli bitirdikten sonra bir web sayfası tasarlayıp bu web sayfası üzerinden modeli son kullanıcıların kullanımına açacağım.
Bu yazıya konu olan modeli daha önce paylaşmış olduğum yazımdan daha detaylı anlayabilirsiniz. Ben sadece modeli elde ettiğim kod kısmını bütünlük bozulmasın diye copy paste edeceğim.
import pandas as pd import numpy as np import pickle import sys import os import io import re from sys import path import numpy as np import pickle from sklearn.feature_extraction.text import CountVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelBinarizer import matplotlib.pyplot as plt from string import punctuation, digits from IPython.core.display import display, HTML from nltk.corpus import stopwords from nltk.corpus import stopwords from nltk.tokenize import word_tokenize from nltk.tokenize import RegexpTokenizer
#Amazon Data input_file = "../data/amazon_cells_labelled.txt" amazon = pd.read_csv(input_file,delimiter='\t',header=None) amazon.columns = ['Sentence','Class'] #Yelp Data input_file = "../data/yelp_labelled.txt" yelp = pd.read_csv(input_file,delimiter='\t',header=None) yelp.columns = ['Sentence','Class'] #Imdb Data input_file = "../data/imdb_labelled.txt" imdb = pd.read_csv(input_file,delimiter='\t',header=None) imdb.columns = ['Sentence','Class'] #combine all data sets data = pd.DataFrame() data = pd.concat([amazon, yelp, imdb]) data['index'] = data.index
#Total Count of Each Category pd.set_option('display.width', 4000) pd.set_option('display.max_rows', 1000) distOfDetails = data.groupby(by='Class', as_index=False).agg({'index': pd.Series.nunique}).sort_values(by='index', ascending=False) distOfDetails.columns =['Class', 'COUNT'] print(distOfDetails) #Distribution of All Categories plt.pie(distOfDetails['COUNT'],autopct='%1.0f%%',shadow=True, startangle=360) plt.show()
#Text Preprocessing columns = ['index','Class', 'Sentence'] df_ = pd.DataFrame(columns=columns) #lower string data['Sentence'] = data['Sentence'].str.lower() #remove email adress data['Sentence'] = data['Sentence'].replace('[a-zA-Z0-9-_.]+@[a-zA-Z0-9-_.]+', '', regex=True) #remove IP address data['Sentence'] = data['Sentence'].replace('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}', '', regex=True) #remove punctaitions and special chracters data['Sentence'] = data['Sentence'].str.replace('[^\w\s]','') #remove numbers data['Sentence'] = data['Sentence'].replace('\d', '', regex=True) #remove stop words for index, row in data.iterrows(): word_tokens = word_tokenize(row['Sentence']) filtered_sentence = [w for w in word_tokens if not w in stopwords.words('english')] df_ = df_.append({"index": row['index'], "Class": row['Class'],"Sentence": " ".join(filtered_sentence[0:])}, ignore_index=True) data = df_
from sklearn.metrics import confusion_matrix from sklearn.model_selection import cross_val_score from sklearn.metrics import accuracy_score from sklearn.neural_network import MLPClassifier from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import SGDClassifier #grid search result vectorizer = TfidfVectorizer(analyzer='word',ngram_range=(1,2), max_features=50000,max_df=0.5,use_idf=True, norm='l2') counts = vectorizer.fit_transform(X_train) vocab = vectorizer.vocabulary_ classifier = SGDClassifier(alpha=1e-05,max_iter=50,penalty='elasticnet') targets = y_train classifier = classifier.fit(counts, targets) example_counts = vectorizer.transform(X_test) predictions = classifier.predict(example_counts)
from sklearn.metrics import precision_score from sklearn.metrics import recall_score from sklearn.metrics import classification_report #Model Evaluation acc = accuracy_score(y_test, predictions, normalize=True) hit = precision_score(y_test, predictions, average=None,labels=classes) capture = recall_score(y_test, predictions, average=None,labels=classes) print('Model Accuracy:%.2f'%acc) print(classification_report(y_test, predictions))
Evet modelimizi oluşturduk. Bundan sonra ihtiyacımız olan şey oluşturduğumuz modeli ve modelin vocabulary çıktısını pickle ile kayıt etmek. Daha sonra geliştireceğimiz web sayfasında bu outputları kullanacağız.
### model_save ### pickle.dump(classifier,open("model_sentiment.pkl","wb")) pickle.dump(vocab,open("vocab_sentiment.pkl","wb"))
Modelimiz ile ilgili çıktılarımız diske kayıt edildi. Şimdi bu modele input olarak gönderilecek text’in sentimentini bulup geriye dönecek web sayfasının geliştirmesine başlayabiliriz.
Geliştirmeyi python ile yapacağımdan dolayı python’ın flask kütüphanesini kullanacağım. Flask python ile web tabanlı uygulamalar geliştirmenizi sağlayan bir kütüphane. Bende bu kütüphaneyi kullanarak bir web servis geliştireceğim. Öncelikle geliştirme ortamımıza flask kurulumu yapalım.
pip install -U Flask veya anaconda kullanıcıları için conda install -c anaconda flask
Flask kurulumumuzda tamamlandığına göre şimdi web sayfamızın geliştirmesini yapabiliriz.
Geliştirmeye başlamadan önce kendi localimde kurmuş olduğum dizin yapısını göstermek istiyorum. Böyle bir çalışma için sizinde benzer bir dizin yapısı kurmanızın işe yarayacağını düşünmekteyim. Zaten bu bir web uygulaması olacağı için ana kodu yazdığımız webform.py çalıştığı esnada render edeceği .html dosyasını /templates dizini altında arayacak. Dolayısıyla html sayfanızı geliştirdikten sonra templates dizini altına atmanız gerekecek. Aşağıda başarılı şekilde çalışacak dizin yapısını görebilirsiniz.
Dizin yapımda da göreceğiniz üzere geliştirdiğim ve outputlarını aldığım model çıktılarımı models folder’ının altına taşıdım. Templates dizini altına webform.html dosyamı yaratıp koydum. Aynı şekilde ana dizin altına da webform.py isimli kod dosyamı oluşturup kayıt ettim.
Bu uygulama web sayfası üzerinden kullanıcıya ulaştırılacağı için çok basit bir tasarım la kullanıcının text girişi yapıp sonucu göreceği basit bir html form tasarlıyorum. Bu web sayfası, web teknolojilerinin sunmuş olduğu tüm güncel alt yapılar ile donatılabilir ben sadece olabildiğince basit bir tasarım ile nasıl yapıldığını göstermek istiyorum.
“Not: Form inputunu bir tweet olarak kurguladım. Bunun hiç bir önemi yok :)”
webform.html
<form method="POST"> <br><b>Enter Tweet here...</b></br> <textarea rows="4" cols="50" name="tweet"> </textarea> <br></br> <input type="submit"> <br></br> <h1><b> Result: </b> {{ value }} </h1> </form>
Şimdi yarattığımız formun nasıl bir şey olduğuna bakalım.
Evet görüldüğü üzere tasarımımız çok basit. Şimdi bu formu kullacak ve modelimizi çalıştırıp yukarıdaki sayfadan gönderilen text’in sentimeni bulup geri form’a cevabı döndüren python kodunuz yazalım.
webform.py
Burada dikkat edilmesi gereken üç şey var. Birincisi yazdığımı html kodunun nasıl çağırıldığı. İkincisi model outputlarımızı load edip kullanıma hazır hale getirmek.
Üçüncüsü ise dışarıdan parametre olarak gelecek text’i bir değişken içerisine almak ve dördüncüsü bulunan sonucun web sayfasına geri döndürülmesi. Bu satırları vurgulamak açısından bold yapıyorum.
from flask import Flask, request, render_template, url_for import pickle import time import os from sklearn.feature_extraction.text import TfidfVectorizer import pandas as pd import io import re from sys import path import numpy as np from sklearn.feature_extraction.text import CountVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelBinarizer import matplotlib.pyplot as plt from string import punctuation, digits from flask import Flask, request, render_template, url_for start_time = time.time() app = Flask(__name__) app.config["DEBUG"] = True @app.route('/') def my_form(): return render_template('webform.html') @app.route('/', methods=['POST','GET']) def home(): vec = open("models/model_sentiment.pkl", 'rb') loaded_model = pickle.load(vec) vcb = open("models/vocab_sentiment.pkl", 'rb') loaded_vocab = pickle.load(vcb) txt = request.form['tweet'] examples = txt examples = examples.lower() examples = examples.replace('\n',' ') examples = re.sub(r'[a-zA-Z0-9-_.]+@[a-zA-Z0-9-_.]+', ' ', examples) examples = re.sub(r'@[A-Za-z0-9]+', ' ', examples) examples = re.sub(r'((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}', ' ', examples) examples = re.sub(r'[^\w\s]', ' ', examples) examples = re.sub(r'\d', ' ', examples) examples = re.sub(' +',' ',examples) examples = [examples] from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import TfidfVectorizer count_vect = TfidfVectorizer(analyzer='word',ngram_range=(1,2), max_features=50000,max_df=0.6,use_idf=True, norm='l2',vocabulary=loaded_vocab) x_count = count_vect.fit_transform(examples) predicted = loaded_model.predict(x_count) result='' if predicted[0] == 0: result= 'Negative' elif predicted[0] == 1: result= 'Positive' return render_template('webform.html',value=result)
Evet geliştirmeleri tamamladık. Şimdi yazdığımız webform.py kodunu çalıştıralım.
env FLASK_APP=webform.py flask run
Evet servisimiz ayağa kalktı ve endpoint adresi ekranda bize gösterildi. Şimdi servisi test edelim. Test için ekranda görünen endpointi browsera yazmamız yeterli olacak ve istediğimiz bir input ile testimizi yapacağız.
Evet görüldüğü üzere web sayfamızı yazdığımız python kodu üzerinden ayağa kaldırdık ve machine learning modelini son kullanıcının rahatlıkla kullanabileceği bir hale getirmiş olduk.
Pingback: Machine Learning Uygulamalarının Docker Üzerinden Servis Edilmesi | Emrah METE
Ne güzel bir blog sayfası!