- Ümit Yılmaz @ylmz-dev
- Büşra Gökmen @newsteps8
Amacımız Türkçe NLP literatüründeki birçok farklı sorunu bir arada çözebilen, eşsiz yaklaşımlar öne süren ve literatürdeki çalışmaların eksiklerini gideren open source bir yazım destekleyicisi/denetleyicisi oluşturmak. Kullanıcıların yazdıkları metinlerdeki yazım yanlışlarını derin öğrenme yaklaşımıyla çözüp aynı zamanda metinlerde anlamsal analizi de gerçekleştirerek bu bağlamda ortaya çıkan yanlışları da fark edip düzeltebilmek.
Literatürde her ne kadar yazım yanlışlarını düzelten birçok kütüphane olsa da bunların hiçbiri anlamsal bağlamda meydana gelen hataları düzeltme kapasitesine sahip değildi. Bu tarz hataların en önemlilerinden olan bağlaç ve ek olan durumlarda ayrı veya bitişik yazılması gereken -da/-de, -ki, ve -mi örnek olarak verilebilir. Çalışmamız tamamıyla eşsiz olup, literatürdeki bütün örneklerinden çok daha iyi bir performans sergilemiştir. Model olarak 1DCNN, GRU, LSTM RNN denenmiş olup en iyi performans veren model olarak 2 layerlı Bidirectional LSTM seçilmiştir, bayesian search optimization tekniği ile parametreleri optimal değerlere ulaştırılmıştır.
Modelin performansının hem resmi hem de resmi olmayan dilde güzel sonuç vermesi ve genelleşmesi adına 3 farklı dataset birleştirilmiştir. Bunlar OPUS Subtitle veriseti, TSCORPUS Wikipedia veriseti ve TSCORPUS gazete verisetidir.
Çalışmamızda 85 milyondan fazla satırda veri işlenmiştir. Ön işleme olarak bitişik olan ekler kelimelerden ayrılmış ve “X” ile yer değiştirilmiştir. Ayrı olan ekler de “X” ile yer değiştirilmiştir. Bu sayede modelin aynı cümlede birden fazla ek olması durumunda da daha doğru sonuçlar vermesi amaçlanmıştır. Ön işleme işleminin ardından ayrı olan ekleri içeren cümleler 0, bitişik olan ekleri içeren cümleler ise 1 ile etiketlenmiştir. Ardından modelin hatalı öğrenmesine karşı 0 ve 1 labellarından fazla sayıda olanlar random undersampling ile azaltılmıştır. Sonuç olarak model hataları değil eklerin nasıl doğru yazılması gerektiğini öğrenmiştir. Oluşturulan verisetlerinin %20’si test %10’u da validation verisi olarak kullanılmıştır. Tüm verisetlerine csv formatında data klasörünün içerisinden ya da aşağıdaki başlıklar altında bulunan drive linklerinden ulaşabilirsiniz.
Modelleri pre_trained_weights klasöründe bulunan weightler ile doğrudan yükleyip test edebilirsiniz. Ya da siz de kendi düzelticinizi kendi verilerinizle veya bizim paylaştığımız veriler ve kendi oluşturduğunuz modeller ile train notebooklarını kullanarak eğitebilirsiniz.
Performans sonuçlarını, karşılaştırmalarını, modeller tarafından ayırt edilen cümle örneklerini ve verisetlerinin drive linklerini aşağıdaki başlıklar altında ayrı ayrı bulabilirsiniz.
Python 3.6+
git clone https://github.com/Fixy-TR/fixy.git
DE-DA, Kİ ve Mİ düzeltmesi için yayınlamış olduğumuz DeepChecker kütüphanesini doğrudan pip ile yükleyebilirsiniz.
kütüphaneyi yüklemek için:
pip install DeepChecker
Kullanabileceğiniz fonksiyonlar ve kullanımları:
Correct fonksiyonları cümlenin doğru halini döndürmektedir. Check fonksiyonları ise cümlenin sigmoid fonksiyonundan gelen değeri ifade eder. 0'a yakın olması ayrı yazılması gerektiğini göstermektedir
from DeepChecker import correct_de, correct_ki, correct_mi, check_de, check_ki, check_mi
print(correct_de("bu yaz bizimkiler de tatile gelecek")) # doğru hali output olarak gelecek
print(check_de("bu yaz bizimkiler de tatile gelecek") # sigmoid değeri output olarak dönecek
Yapılan Çalışmalar | Doğruluk Oranı |
---|---|
Fixy | %87 |
Boğaziçi | %78 |
Google Docs | %34 |
Microsoft Office | %29 |
ITU | %0 |
Libra Office | %0 |
Boğaziçi Universitesi tarafından oluşturulmuş 100 zor cümle ile test edilmiştir. İlgili makale
Kullanılan metodoloji tamamiyle özgündür ve Literatürdeki diğer çalışmalardan farklı bir yaklaşıma dayanmaktadır. Performans sonuçlarındaki fark yaklaşımın doğruluğunu ispatlar niteliktedir.
from google.colab import drive
import pandas as pd
import keras
import pickle
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from sklearn.model_selection import train_test_split
import tensorflow as tf
from keras.layers import Dense, LSTM, Flatten, Embedding, Dropout , Activation, GRU, Flatten, Input, Bidirectional, GlobalMaxPool1D, Convolution1D, TimeDistributed, Bidirectional
from keras.layers.embeddings import Embedding
from keras.models import Model, Sequential
from keras import initializers, regularizers, constraints, optimizers, layers
Kütüphaneleri kurduktan sonra modeli yüklüyoruz ve test ediyoruz.
model.load_weights("/content/Model_deda.h5")
pred = tokenizer.texts_to_sequences(["olsun demek x zor artık"])
maxlen = 7
padded_pred = pad_sequences(pred, maxlen=maxlen)
model.predict(padded_pred)
# 0' yakın çıkması ekin ayrı yazılması gerektiğini gösteriyor.
array([[0.04085088]], dtype=float32)
- Accuracy on Test Data: 92.13%
- ROC AUC on Test Data: 0.921
Confusion Matrix [336706 20522] [ 36227 327591]
class | precision | recall | f1-score | support |
---|---|---|---|---|
0 | 0.9049 | 0.9397 | 0.9219 | 357228 |
1 | 0.9384 | 0.9030 | 0.9204 | 363818 |
Data Oluşturulan 3605229 satır veri içeren etiketli -ki veriseti linki: Data
Kütüphaneleri kurduktan sonra modeli yüklüyoruz ve test ediyoruz.
model.load_weights("/content/Model_ki.h5")
pred = tokenizer.texts_to_sequences(["desem x böyle böyle oldu"])
maxlen = 7
padded_pred = pad_sequences(pred, maxlen=maxlen)
model.predict(padded_pred)
# 0' yakın çıkması ekin ayrı yazılması gerektiğini gösteriyor.
array([[0.00843348]], dtype=float32)
- Accuracy on Test Data: 91.32%
- ROC AUC on Test Data: 0.913
Confusion Matrix [27113 3311] [ 1968 28457]
class | precision | recall | f1-score | support |
---|---|---|---|---|
0 | 0.9323 | 0.8912 | 0.9113 | 30424 |
1 | 0.8958 | 0.9353 | 0.9151 | 30425 |
Oluşturulan 304244 satır veri içeren etiketli -ki veriseti linki: Data
Kütüphaneleri kurduktan sonra modeli yüklüyoruz ve test ediyoruz.
model.load_weights("/content/Model_mi.h5")
pred = tokenizer.texts_to_sequences(["olsun demek x zor artık"])
maxlen = 7
padded_pred = pad_sequences(pred, maxlen=maxlen)
model.predict(padded_pred)
# 0' yakın çıkması ekin ayrı yazılması gerektiğini gösteriyor.
array([[0.04085088]], dtype=float32)
Oluşturulan 9507636 satır veri içeren etiketli -mi veriseti linki: Data
- Accuracy on Test Data: 95.41%
- ROC AUC on Test Data: 0.954
Confusion Matrix [910361 40403] [ 46972 903792]
class | precision | recall | f1-score | support |
---|---|---|---|---|
0 | 0.9509 | 0.9575 | 0.9542 | 950764 |
1 | 0.9572 | 0.9506 | 0.9539 | 950764 |
Literatürde ki ve mi ekleri üzerine yapılmış çalışmaya rastlanamaması projenin özgünlüğünü arttırmaktadır.
Üç katmanlı LSTM nöral ağıyla oluşturduğumuz modeli yaklaşık 260000 tane pozitif ve negatif olarak etiketlenmiş sentiment verisiyle eğittik. Rastgele oluşturduğumuz kelime vektörleri ile birlikte embedding layeri nöral ağımıza ekledik. 10 Epoch ile eğittiğimiz modelden %94.57 accuracy(doğruluk) skoru elde ettik.
import numpy as np
import pandas as pd
from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM, Dropout
from tensorflow.python.keras.preprocessing.text import Tokenizer
from tensorflow.python.keras.preprocessing.sequence import pad_sequences
Kütüphaneleri yükledikten sonra keras ile modeli yüklüyoruz.
from keras.models import load_model
model = load_model('hack_model.h5') # modeli yüklüyoruz
Test inputları oluşturuyoruz.
#test yorumları(inputlar)
text1 = "böyle bir şeyi kabul edemem"
text2 = "tasarımı güzel ancak ürün açılmış tavsiye etmem"
text3 = "bu işten çok sıkıldım artık"
text4 = "kötü yorumlar gözümü korkutmuştu ancak hiçbir sorun yaşamadım teşekkürler"
text5 = "yaptığın işleri hiç beğenmiyorum"
text6 = "tam bir fiyat performans ürünü beğendim"
text7 = "Bu ürünü beğenmedim"
texts = [text1, text2,text3,text4,text5,text6,text7]
Test inputları için tokenize ve padding yapıyoruz
#tokenize
tokens = turkish_tokenizer.texts_to_sequences(texts)
#padding
tokens_pad = pad_sequences(tokens, maxlen=max_tokens)
model bu inputların hangi duyguya yakın olduğunu tahminliyor
for i in model.predict(tokens_pad):
if i < 0.5:
print("negatif")#negatif yorum yapmış
else
print("pozitif")#pozitif yorum yapmış
negative
negative
negative
positive
negative
positive
positive
Oluşturulan 260000 satır veri içeren etiketli pozitif-negatif veriseti linki: Data
Üç katmanlı LSTM nöral ağıyla oluşturduğumuz modeli twitter, newspaper ve wikipediadan aldığımız verinin yaklaşık 2504900 tanesini formal(düzgün) ve informal(düzgün olmayan) olarak etiketledik ve nöral ağımızı eğittik. Rastgele oluşturduğumuz kelime vektörleri ile birlikte embedding layeri nöral ağımıza ekledik. 10 Epoch ile eğittiğimiz modelden % 95.37 accuracy(doğruluk) skoru elde ettik.
import numpy as np
import pandas as pd
from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM, Dropout
from tensorflow.python.keras.preprocessing.text import Tokenizer
from tensorflow.python.keras.preprocessing.sequence import pad_sequences
Kütüphaneleri yükledikten sonra keras ile modeli yüklüyoruz.
from keras.models import load_model
model = load_model('MODEL_FORMAL.h5') # modeli yüklüyoruz
Test inputları oluşturuyoruz.
# test inputları oluşturuyoruz
text1 = "atatürk, bu görevi en uzun süre yürüten kişi olmuştur."
text2="bdjfhdjfhdjkhj"
text3 = "hiç resimde gösterildiği gibi değil..."
text4 = "bir yirminci yüzyıl popüler kültür ikonu haline gelen ressam, resimlerinin yanı sıra inişli çıkışlı özel yaşamı ve politik görüşleri ile tanınır. "
text5 = "fransız halkı önceki döneme göre büyük bir evrim geçirmektedir. halk bilinçlenmektedir ve sarayın, kralın, seçkinlerin denetiminden çıkmaya başlamıştır. şehirlerde yaşayan pek çok burjuva, büyük bir atılım içindedir. kitaplar yaygınlaşmakta, aileler çocuklarını üniversitelere göndererek sağlam bir gelecek kurma yolunu tutarak kültürel seviyeyi yükseltmektedir. bağımsız yayıncıların çıkardıkları gazete, bildiri ve broşürler, kitlesel bilinçlenmeye yol açmaktadır. bu koşullar da toplumsal değişim taleplerinin olgunlaşmasına yol açmıştır."
text6 = "bunu çıkardım söylediklerinden"
text7 = "Bu koşullar da toplumsal değişim taleplerinin olgunlaşmasına yol açmıştır."
text8="bu çok saçma yaa"
text9="bana böyle bir yetki verilmedi."
text10="napıcaz bu işi böyle"
text11="Öncelikle Mercedes-Benz’e olan ilgin için teşekkür ederiz."
text12="Ekibimizle çalışma isteğin için teşekkür ediyor, sağlıklı günler ve kariyerinde başarılar diliyoruz. Farklı etkinlik ve programlarda tekrar bir araya gelmek dileğiyle."
text13="Ben de öyle olduğunu düşünmüyordum ama gittik yine de jzns"
texts = [text1, text2,text3,text4,text5,text6,text7,text8,text9,text10,text11,text12,text13]
Test inputları için tokenize ve padding yapıyoruz
#tokenize
tokens = tokenizer.texts_to_sequences(texts)
#padding
tokens_pad = pad_sequences(tokens, maxlen=max_tokens)
model bu inputların hangi duyguya yakın olduğunu tahminliyor
#test verisini tahminleme
for i in model.predict(tokens_pad):
if i < 0.5:
print("informal")
else:
print("formal")
formal
informal
informal
formal
formal
informal
formal
informal
informal
informal
formal
informal
informal
Oluşturulan 1204900 satır veri içeren etiketli formal veriseti linki: Data Oluşturulan 3934628 satır veri içeren etiketli informal veriseti linki: Data
6 farklı duygu(Fear: Korku,Happy: Sevinç,Sadness: Üzüntü,Disgust: İğrenme-Bıkkınlık,Anger: Öfke,Suprise: Şaşkınlık) ile etiketli 27350 verinin bulunduğu veriseti ile SVM linearSVC,MultinomialNB,LogisticRegression, RandomForestClassifier modellerini eğittik. Modellemeden önce verideki kelimeleri vektörize etmek için tfidf vektörizerı ve türkçe stopword listesini kullandık. Bu modeller arasında en yükse accuracy oranını LinearSVC modeli ile elde ettik.
Model | Accuracy(Doğruluk Oranı) |
---|---|
LinearSVC | 0.80 |
LogisticRegression | 0.79 |
MultinomialNB | 0.78 |
RandomForestClassifier | 0.60 |
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.svm import LinearSVC
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
Kütüphaneleri yükledikten sonra load_model ile modeli yüklüyoruz ve test ediyoruz.
# modeli yükleyip test ediyoruz
tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5, norm='l2', encoding='latin-1', ngram_range=(1, 2), stop_words=myList)
loaded_model = pickle.load(open("emotion_model.pickle", 'rb'))
corpus = [
"İşlerin ters gitmesinden endişe ediyorum",
"çok mutluyum",
"sana çok kızgınım",
"beni şaşırttın",
]
tfidf.fit_transform(df.Entry).toarray()
features = tfidf.transform(corpus).toarray()
result = loaded_model.predict(features)
print(result)
['Fear' 'Happy' 'Anger' 'Suprise']
Bu model için kullandığımız verisetini TREMODATA adresinden istedik. Ayrıca bu verisetinin bulunduğu drive linki: Data
Virtual environment ortamında oluşturduğunuz Flask API yardımı ile modelleri bir arayüzde gösterebilirsiniz. Bunun için gerekli kütüphaneler:
from flask_wtf import FlaskForm
from flask import Flask, request, render_template,redirect
import pickle
import re
from wtforms.validators import DataRequired
import pandas as pd
from os.path import join
app.py dosyasını çalıştırarak modellerinizi ön yüze bağlayabilirsiniz.
Backend kısmında kural tabanlı düzeltici için Zemberek'in Normalization modülünü kullandık. Ayrıca yine backend kısmında metinlerin daha formal halini görebilmek için Zemberek'in Informal Word Analysis modülünü kullandık.
Deep Learning Tabanlı spell-checker modellerinin yazım yanlışını öğrenmesi için düzgün cümle-cümlenin hatalı hali şeklinde veri üretmek gerekebiliyor. Türkçede sıkça yapılan yazım yanlışlarını belirleyerek ve bunları kullanarak düzgün kelimeyi bozan noisy fonksiyonları oluşturduk. Böylece modelleme için kirli veri elde edebiliyoruz. Fonksiyonları Noice_Adder_Functions.ipynb dosyasında bulabilirsiniz.
2364897 satırlık temizlenmiş Türkçe Wikipedia verisetini herhangi bir Türkçe NLP çalışmasında kullanabilirsiniz:) Wikipedia Veriseti