Sentiment analysis by text classification using Deep Learning and CNN

Sentiment analysis by text classification using Deep Learning and CNN

Derin öğrenme ile Cnn modeli kullanarak metin sınıflandırması ve duygu analizi

Bu yapay zeka projesinde, CNN modelini kullanarak sosyal medya mesajları gibi metinlerde yer alan duyguları tespit etmek hedeflenmiştir.

Source Code

GitHub

Dataset

Import Libraries

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import classification_report, confusion_matrix
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.metrics import Precision, Recall
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras import layers
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.preprocessing.sequence import pad_sequences
from keras.utils import to_categorical
from keras.layers import ZeroPadding1D
import pickle

Read and Preprocessing Data

Read Data

train_df = pd.read_csv("dataset/train.txt", delimiter=';', header=None, names=['sentence','label'])
val_df = pd.read_csv("dataset/val.txt", delimiter=';', header=None, names=['sentence','label'])
test_df = pd.read_csv("dataset/test.txt", delimiter=';', header=None, names=['sentence','label'])

train_df.head(10)
 sentencelabel
0aşağılanmış hissetmedimüzgün
1Sadece önemseyen ve uyanık birinin yanında old…üzgün
2paylaşım yapmak için bir dakika ayırıyorum açg…öfke
3Şömineyle ilgili nostaljik hisler yaşıyorum on…sevgi
4huysuz hissediyorumöfke
5son zamanlarda kendimi biraz yük altında hisse…üzgün
6Tavsiye edilen miktarın miligramını veya katın…şaşkın
7Hayat konusunda bir ergen kadar kafam karışık …korku
8Yıllardır Petronas’la birlikteyim Petronas’ın …mutlu
9aşağılanmış hissetmedimben de romantik hissediyorumsevgi
train_df['label'].value_counts() # etiketlerin sayısı
label
mutlu     5361
üzgün     4665
öfke      2160
korku     1937
sevgi     1304
şaşkın     573
Name: count, dtype: int64
label_counts = train_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts)) # renk paleti olşuturulması
sns.set(style="whitegrid") # arka plan rengi
plt.figure(figsize=(6,6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors) # pasta grafiği oluşturulması
plt.title('Eğitim Veri Seti Etiket Dağılımı')
plt.show()

graph

label_counts = test_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts)) # renk paleti olşuturulması
sns.set(style="whitegrid") # arka plan rengi
plt.figure(figsize=(6,6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors) # pasta grafiği oluşturulması
plt.title('Test Veri Seti Etiket Dağılımı')
plt.show()

graph

label_counts = val_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts)) # renk paleti olşuturulması
sns.set(style="whitegrid") # arka plan rengi
plt.figure(figsize=(6,6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors) # pasta grafiği oluşturulması
plt.title('Doğrulama Veri Seti Etiket Dağılımı')
plt.show()

graph

Eğitim veri setindeki veriler dengesiz olduğu için ve veri setini daha dengeli hale getirmeliyim. Bunun için veri setindeki en az etiket sayısına sahip 2 etiket olan sevgi ve şaşkın etiketlerine sahip verileri çıkartacağım.

train_df = train_df[~train_df['label'].str.contains('sevgi')] # sevgi etiketine sahp verilerin çıkartılması
train_df = train_df[~train_df['label'].str.contains('şaşkın')] # şaşkın etiketine sahip verilerin çıkartlılması

Şimdi geriye kalan mutlu, üzgün, öfke ve korku etiketleri hala dengesiz bir şekilde dağılmış durumda. Bu etikerlerin dağılımını olabildiğince birbirine yaklaştırıyorum.

mutlu = train_df[train_df['label'] == 'mutlu'].sample(n=2200, random_state=20) # mutlu etiketine sahip rastgele 2200 veri
uzgun = train_df[train_df['label'] == 'üzgün'].sample(n=2200, random_state=20) # üzgün etiketine sahip rastgele 2200 veri
korku = train_df[train_df['label'] == 'korku'].sample(n=1937, random_state=20)
ofke = train_df[train_df['label'] == 'öfke'].sample(n=2160, random_state=20)

new_train_df = pd.concat([mutlu, uzgun, korku, ofke]) # rastgele seçilen bu verilerin birleştirilmesi

train_df = new_train_df.sample(frac=1, random_state=20).reset_index(drop=True) # birleştirilen verileri karıştırarak train_df yi yeniden oluşturuyorum
train_df.label.value_counts() # etiketlerin sayısı
label
mutlu    2200
üzgün    2200
öfke     2160
korku    1937
Name: count, dtype: int64
label_counts = train_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts))
sns.set(style="whitegrid")
plt.figure(figsize=(6, 6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors)
plt.title('Eğitim Veri Seti Etiket Dağılımı')
plt.show()

graph

Artık eğitim veri seti daha dengeli hale geldi. Bu işlemlerin aynısını test_df ve val_df dataframeleri içinde yapacağım.

val_df.label.value_counts()
label
mutlu     704
üzgün     550
öfke      275
korku     212
sevgi     178
şaşkın     81
Name: count, dtype: int64
# sevgi ve şaşkın etiketlerinin çıkartılması
val_df = val_df[~val_df['label'].str.contains('sevgi')]
val_df = val_df[~val_df['label'].str.contains('şaşkın')]
mutlu = val_df[val_df['label'] == 'mutlu'].sample(n=250, random_state=20)
uzgun = val_df[val_df['label'] == 'üzgün'].sample(n=250, random_state=20)
korku = val_df[val_df['label'] == 'korku'].sample(n=212, random_state=20)
ofke = val_df[val_df['label'] == 'öfke'].sample(n=275, random_state=20)

df_sampled = pd.concat([mutlu, uzgun, korku, ofke])

val_df = df_sampled.sample(frac=1, random_state=20).reset_index(drop=True)
label_counts = val_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts))
sns.set(style="whitegrid")
plt.figure(figsize=(6, 6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors)
plt.title('Doğrulama Veri Seti Etiket Dağılımı')
plt.show()

graph

test_df.label.value_counts()
label
mutlu     698
üzgün     582
öfke      274
korku     224
sevgi     155
şaşkın     67
Name: count, dtype: int64
# sevgi ve şaşkın etiketlerinin çıkartılması
test_df = test_df[~test_df['label'].str.contains('sevgi')]
test_df = test_df[~test_df['label'].str.contains('şaşkın')]
mutlu = test_df[test_df['label'] == 'mutlu'].sample(n=250, random_state=20)
uzgun = test_df[test_df['label'] == 'üzgün'].sample(n=250, random_state=20)
korku = test_df[test_df['label'] == 'korku'].sample(n=224, random_state=20)
ofke = test_df[test_df['label'] == 'öfke'].sample(n=274, random_state=20)

new_test_df = pd.concat([mutlu, uzgun, korku, ofke])

test_df = new_test_df.sample(frac=1, random_state=20).reset_index(drop=True)
label_counts = test_df['label'].value_counts()
light_colors = sns.husl_palette(n_colors=len(label_counts))
sns.set(style="whitegrid")
plt.figure(figsize=(6, 6))
plt.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%', startangle=140, colors=light_colors)
plt.title('Test Veri Seti Etiket Dağılımı')
plt.show()

graph

Split Data

train_text = train_df['sentence']
train_label = train_df['label']

val_text = val_df['sentence']
val_label = val_df['label']

test_text = test_df['sentence']
test_label = test_df['label']

Encoding

Şimdi bu etiketleri sayısal değerlere dönüştürüyorum.

encoder = LabelEncoder() # etiketlerin sayısal değerlere dönüştürülmesi
tr_label = encoder.fit_transform(train_label)
val_label = encoder.transform(val_label)
ts_label = encoder.transform(test_label)

Text Preprocessing

Şimdi de cümleleri Tokenizer modülü ile sayısal değerlere dönüştürerek model tarafından kullanılabilir hale getiriyorum.

tokenizer = Tokenizer(num_words=10000) # metinlerin sayısal değerlere dönüştürülmesi
tokenizer.fit_on_texts(train_text)

sequences = tokenizer.texts_to_sequences(train_text)
tr_x = pad_sequences(sequences, maxlen=50) # metinlerin boyutlarının eşitlenmesi
tr_y = to_categorical(tr_label, num_classes=4) # etiketlerin kategorik hale getirilmesi

sequences = tokenizer.texts_to_sequences(val_text)
val_x = pad_sequences(sequences, maxlen=50)
val_y = to_categorical(val_label, num_classes=4)

sequences = tokenizer.texts_to_sequences(test_text)
ts_x = pad_sequences(sequences, maxlen=50)
ts_y = to_categorical(ts_label, num_classes=4)

Building Deep Learning Model

max_words = 10000
max_len = 50
embedding_dim = 32

Model Architecture

# Branch 1
inputs1 = layers.Input(shape=(max_len,))  # inputs1 için giriş katmanı tanımlanması

branch1 = layers.Embedding(max_words, embedding_dim)(inputs1) # Embedding katmanı
branch1 = layers.Conv1D(64, 3, padding='same', activation='relu')(branch1) # Conv1D katmanı (64 filtre, 3 kernel boyutu)
branch1 = layers.BatchNormalization()(branch1) # BatchNormalization katmanı. Katman çıktılarını normalize eder.
branch1 = layers.ReLU()(branch1) # ReLU katmanı
branch1 = layers.Dropout(0.5)(branch1) # Dropout katmanı. Aşırı uyum (overfitting) önlemek için
branch1 = layers.GlobalMaxPooling1D()(branch1) # GlobalMaxPooling1D katmanı (en büyük değeri alır)

# Branch 2
inputs2 = layers.Input(shape=(max_len,))  # inputs2 için giriş katmanı tanımlanması

branch2 = layers.Embedding(max_words, embedding_dim)(inputs2)
branch2 = layers.Conv1D(64, 3, padding='same', activation='relu')(branch2)
branch2 = layers.BatchNormalization()(branch2)
branch2 = layers.ReLU()(branch2)
branch2 = layers.Dropout(0.5)(branch2)
branch2 = layers.GlobalMaxPooling1D()(branch2)

concatenated = layers.Concatenate()([branch1, branch2]) # Branch1 ve Branch2'nin birleştirilmesi

#Birleştirilen katmanların dense katmanı tarafından gizli katmana bağlanması
hid_layer = layers.Dense(128, activation='relu')(concatenated) # Gizli katman
dropout = layers.Dropout(0.3)(hid_layer) # Dropout katmanı. Overfitting önlemek için
output_layer = layers.Dense(4, activation='softmax')(dropout) # Çıkış katmanı

# Define the model with separate inputs
model = Model(inputs=[inputs1, inputs2], outputs=output_layer)

Compile Model

model.compile(optimizer='adamax', loss='categorical_crossentropy', metrics=['accuracy', Precision(), Recall()])

model.summary()
Model: "functional"
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ Layer (type)        ┃ Output Shape      ┃    Param # ┃ Connected to      ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩
│ input_layer_2       │ (None, 50)        │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ input_layer_3       │ (None, 50)        │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ embedding_2         │ (None, 50, 32)    │    320,000 │ input_layer_2[0]… │
│ (Embedding)         │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ embedding_3         │ (None, 50, 32)    │    320,000 │ input_layer_3[0]… │
│ (Embedding)         │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ conv1d_2 (Conv1D)   │ (None, 50, 64)    │      6,208 │ embedding_2[0][0] │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ conv1d_3 (Conv1D)   │ (None, 50, 64)    │      6,208 │ embedding_3[0][0] │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ batch_normalizatio… │ (None, 50, 64)    │        256 │ conv1d_2[0][0]    │
│ (BatchNormalizatio… │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ batch_normalizatio… │ (None, 50, 64)    │        256 │ conv1d_3[0][0]    │
│ (BatchNormalizatio… │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ re_lu_2 (ReLU)      │ (None, 50, 64)    │          0 │ batch_normalizat… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ re_lu_3 (ReLU)      │ (None, 50, 64)    │          0 │ batch_normalizat… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_3 (Dropout) │ (None, 50, 64)    │          0 │ re_lu_2[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_4 (Dropout) │ (None, 50, 64)    │          0 │ re_lu_3[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ global_max_pooling… │ (None, 64)        │          0 │ dropout_3[0][0]   │
│ (GlobalMaxPooling1… │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ global_max_pooling… │ (None, 64)        │          0 │ dropout_4[0][0]   │
│ (GlobalMaxPooling1… │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ concatenate_1       │ (None, 128)       │          0 │ global_max_pooli… │
│ (Concatenate)       │                   │            │ global_max_pooli… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_2 (Dense)     │ (None, 128)       │     16,512 │ concatenate_1[0]… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_5 (Dropout) │ (None, 128)       │          0 │ dense_2[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_3 (Dense)     │ (None, 4)         │        516 │ dropout_5[0][0]   │
└─────────────────────┴───────────────────┴────────────┴───────────────────┘

Training The Model

batch_size = 50
epochs = 10
history = model.fit([tr_x, tr_x], tr_y, epochs=epochs, batch_size=batch_size, validation_data=([val_x, val_x], val_y))
Epoch 1/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 14s 38ms/step - accuracy: 0.2675 - loss: 1.5784 - precision_1: 0.2685 - recall_1: 0.0702 - val_accuracy: 0.2644 - val_loss: 1.3848 - val_precision_1: 0.0000e+00 - val_recall_1: 0.0000e+00
Epoch 2/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 2s 9ms/step - accuracy: 0.3341 - loss: 1.3538 - precision_1: 0.5342 - recall_1: 0.0124 - val_accuracy: 0.3556 - val_loss: 1.3767 - val_precision_1: 0.0000e+00 - val_recall_1: 0.0000e+00
Epoch 3/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 5ms/step - accuracy: 0.3941 - loss: 1.2952 - precision_1: 0.6062 - recall_1: 0.0445 - val_accuracy: 0.4590 - val_loss: 1.3262 - val_precision_1: 0.0000e+00 - val_recall_1: 0.0000e+00
Epoch 4/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 6ms/step - accuracy: 0.5009 - loss: 1.1432 - precision_1: 0.7271 - recall_1: 0.2051 - val_accuracy: 0.5370 - val_loss: 1.1861 - val_precision_1: 0.9302 - val_recall_1: 0.0811
Epoch 5/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 5ms/step - accuracy: 0.5728 - loss: 1.0054 - precision_1: 0.7464 - recall_1: 0.3528 - val_accuracy: 0.5998 - val_loss: 1.0297 - val_precision_1: 0.8799 - val_recall_1: 0.2523
Epoch 6/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 6ms/step - accuracy: 0.6539 - loss: 0.8436 - precision_1: 0.7765 - recall_1: 0.5050 - val_accuracy: 0.6353 - val_loss: 0.9254 - val_precision_1: 0.8305 - val_recall_1: 0.3972
Epoch 7/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 7ms/step - accuracy: 0.7281 - loss: 0.7166 - precision_1: 0.8066 - recall_1: 0.6189 - val_accuracy: 0.6657 - val_loss: 0.8461 - val_precision_1: 0.8419 - val_recall_1: 0.4965
Epoch 8/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 6ms/step - accuracy: 0.7787 - loss: 0.5958 - precision_1: 0.8340 - recall_1: 0.6916 - val_accuracy: 0.6991 - val_loss: 0.7823 - val_precision_1: 0.8294 - val_recall_1: 0.5714
Epoch 9/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 7ms/step - accuracy: 0.8125 - loss: 0.5114 - precision_1: 0.8518 - recall_1: 0.7635 - val_accuracy: 0.7143 - val_loss: 0.7323 - val_precision_1: 0.8171 - val_recall_1: 0.6109
Epoch 10/10
170/170 ━━━━━━━━━━━━━━━━━━━━ 1s 5ms/step - accuracy: 0.8342 - loss: 0.4520 - precision_1: 0.8707 - recall_1: 0.7920 - val_accuracy: 0.7285 - val_loss: 0.7097 - val_precision_1: 0.8307 - val_recall_1: 0.6363

Evaluation and Visullize Results

(loss, accuracy, percision, recall) = model.evaluate([tr_x, tr_x], tr_y)
print(f'Loss: {round(loss, 2)}, Accuracy: {round(accuracy, 2)}, Precision: {round(percision, 2)}, Recall: {round(recall, 2)}')
266/266 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - accuracy: 0.9416 - loss: 0.2891 - precision_1: 0.9652 - recall_1: 0.8972
Loss: 0.3, Accuracy: 0.93, Precision: 0.96, Recall: 0.89
(loss, accuracy, percision, recall) = model.evaluate([ts_x, ts_x], ts_y)
print(f'Loss: {round(loss, 2)}, Accuracy: {round(accuracy, 2)}, Precision: {round(percision, 2)}, Recall: {round(recall, 2)}')
16/32 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.6958 - loss: 0.7529 - precision_1: 0.7563 - recall_1: 0.5804 
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step - accuracy: 0.7036 - loss: 0.7366 - precision_1: 0.7747 - recall_1: 0.5994
Loss: 0.74, Accuracy: 0.7, Precision: 0.79, Recall: 0.62
history.history.keys()
dict_keys(['accuracy', 'loss', 'precision_1', 'recall_1', 'val_accuracy', 'val_loss', 'val_precision_1', 'val_recall_1'])

Visullize Results

tr_acc = history.history['accuracy']
tr_loss = history.history['loss']
val_acc = history.history['val_accuracy']
val_loss = history.history['val_loss']

index_loss = np.argmin(val_loss)
val_lowest = val_loss[index_loss]
index_acc = np.argmax(val_acc)
acc_highest = val_acc[index_acc]


Epochs = [i + 1 for i in range(len(tr_acc))]
loss_label = f'Best epoch = {str(index_loss + 1)}'
acc_label = f'Best epoch = {str(index_acc + 1)}'


plt.figure(figsize=(20, 12))
plt.style.use('fivethirtyeight')


plt.subplot(2, 2, 1)
plt.plot(Epochs, tr_loss, 'r', label='Training loss')
plt.plot(Epochs, val_loss, 'g', label='Validation loss')
plt.scatter(index_loss + 1, val_lowest, s=150, c='blue', label=loss_label)
plt.title('Training and Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)

plt.subplot(2, 2, 2)
plt.plot(Epochs, tr_acc, 'r', label='Training Accuracy')
plt.plot(Epochs, val_acc, 'g', label='Validation Accuracy')
plt.scatter(index_acc + 1, acc_highest, s=150, c='blue', label=acc_label)
plt.title('Training and Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.grid(True)


plt.suptitle('Model Training Metrics Over Epochs', fontsize=16)
plt.show()

graph

y_true=[] # gerçek etiketlerin tutulacağı liste
for i in range(len(ts_y)): # gerçek etiketlerin alınması
    x = np.argmax(ts_y[i]) 
    y_true.append(x)


preds = model.predict([ts_x, ts_x]) # tahminlerin alınması
y_pred = np.argmax(preds, axis=1) # tahminlerin en yüksek değerli indexlerinin alınması
y_true = np.argmax(ts_y, axis=1) # gerçek etiketlerin en yüksek değerli indexlerinin alınması
y_pred
32/32 ━━━━━━━━━━━━━━━━━━━━ 1s 10ms/step
array([2, 0, 3, 3, 1, 2, 0, 0, 2, 1, 2, 3, 3, 1, 3, 3, 3, 3, 2, 3, 3, 1,
       1, 3, 0, 1, 2, 1, 3, 0, 3, 0, 3, 2, 3, 1, 3, 3, 2, 0, 0, 2, 2, 3,
       0, 0, 1, 2, 3, 0, 3, 1, 1, 1, 0, 3, 1, 1, 3, 1, 3, 3, 0, 2, 1, 3,
       2, 3, 1, 0, 2, 1, 3, 2, 2, 0, 0, 2, 1, 1, 3, 0, 3, 3, 0, 1, 2, 1,
       1, 3, 1, 1, 3, 0, 3, 0, 3, 3, 2, 1, 3, 0, 2, 0, 2, 3, 2, 1, 3, 2,
       3, 2, 3, 1, 3, 2, 3, 0, 1, 1, 3, 3, 3, 0, 3, 0, 3, 2, 1, 1, 3, 2,
       2, 3, 1, 3, 3, 2, 1, 2, 1, 3, 0, 1, 2, 2, 2, 1, 0, 0, 1, 2, 1, 1,
       2, 2, 3, 0, 2, 3, 1, 3, 0, 0, 2, 3, 2, 1, 2, 2, 1, 2, 0, 3, 1, 0,
       1, 0, 3, 1, 3, 1, 3, 0, 3, 1, 1, 1, 0, 1, 2, 2, 1, 3, 3, 3, 1, 2,
       2, 1, 0, 2, 0, 1, 1, 2, 3, 3, 2, 3, 3, 0, 0, 2, 2, 3, 3, 3, 1, 3,
       1, 3, 3, 0, 0, 2, 0, 1, 2, 2, 2, 2, 0, 0, 3, 3, 2, 0, 1, 3, 1, 0,
       0, 1, 1, 3, 1, 2, 2, 2, 0, 3, 1, 0, 3, 2, 3, 3, 0, 3, 1, 2, 1, 2,
       3, 2, 1, 2, 2, 0, 1, 1, 3, 3, 3, 3, 1, 3, 0, 3, 2, 0, 3, 0, 1, 0,
       3, 3, 0, 0, 3, 2, 1, 0, 3, 3, 2, 1, 3, 3, 1, 3, 2, 1, 2, 1, 2, 3,
       3, 3, 2, 3, 3, 3, 0, 0, 3, 0, 2, 1, 2, 3, 1, 3, 0, 3, 1, 3, 1, 2,
       1, 3, 3, 0, 3, 0, 3, 1, 3, 0, 1, 1, 3, 3, 3, 3, 0, 1, 3, 2, 2, 2,
       1, 1, 2, 3, 0, 2, 2, 1, 3, 3, 3, 3, 0, 3, 0, 0, 1, 2, 3, 3, 1, 2,
       2, 0, 1, 2, 2, 2, 1, 3, 1, 1, 2, 3, 2, 0, 2, 1, 3, 0, 2, 3, 0, 3,
       0, 0, 2, 0, 3, 3, 2, 3, 2, 3, 3, 2, 1, 0, 2, 3, 1, 3, 2, 3, 1, 0,
       0, 2, 2, 0, 3, 0, 3, 3, 0, 3, 3, 2, 0, 2, 2, 1, 3, 3, 0, 1, 3, 0,
       2, 2, 2, 1, 2, 3, 1, 2, 1, 0, 3, 2, 1, 0, 3, 1, 0, 2, 3, 2, 0, 1,
       1, 2, 0, 0, 1, 1, 3, 1, 2, 0, 3, 0, 3, 3, 3, 1, 3, 1, 1, 2, 1, 3,
       0, 3, 0, 0, 2, 2, 0, 0, 3, 0, 2, 0, 2, 1, 2, 0, 1, 1, 3, 1, 3, 2,
       1, 0, 2, 1, 3, 3, 3, 1, 2, 1, 1, 3, 2, 1, 3, 1, 1, 2, 2, 3, 3, 3,
       1, 0, 2, 3, 1, 0, 3, 3, 0, 2, 3, 0, 0, 2, 3, 0, 3, 0, 2, 0, 3, 1,
...
       3, 2, 1, 2, 1, 3, 1, 1, 3, 3, 0, 3, 2, 0, 3, 3, 2, 0, 3, 2, 0, 0,
       0, 2, 0, 2, 1, 2, 3, 2, 2, 2, 3, 0, 0, 3, 3, 2, 3, 0, 1, 0, 2, 2,
       2, 3, 0, 3, 3, 2, 0, 2, 2, 2, 1, 3, 2, 2, 3, 3, 3, 2, 3, 3, 3, 1,
       2, 1, 3, 2, 0, 1, 1, 2, 2, 2, 3, 3, 3, 0, 2, 3, 3, 3, 1, 2, 2, 2,
       3, 3, 1, 2, 3, 2, 3, 3])
plt.figure(figsize=(8,6))
emotions = {0: 'öfke', 1: 'korku', 2: 'mutlu', 3:'üzgün'}
emotions = list(emotions.values())
cm = confusion_matrix(y_true, y_pred.ravel())
sns.heatmap(cm, annot=True, fmt='d', cmap='Purples', xticklabels=emotions, yticklabels=emotions)

graph

Classification Report

clr = classification_report(y_true, y_pred)
print(clr)
              precision    recall  f1-score   support

           0       0.79      0.69      0.74       224
           1       0.78      0.76      0.77       250
           2       0.72      0.64      0.67       274
           3       0.58      0.74      0.65       250

    accuracy                           0.70       998
   macro avg       0.72      0.70      0.71       998
weighted avg       0.72      0.70      0.71       998

Save Model

Eğitilmiş olan tokenizatörün ve modelin kaydedilmesi

with open('tokenizer.pkl', 'wb') as tokenizer_file: # tokenizer nesnesinin kaydedilmesi
    pickle.dump(tokenizer, tokenizer_file)

model.save('emotions_detect_model.h5')

Prediction Function

# modülleri tekrardan import etmemin sebebi, modeli tekrar eğitmeden kaydedilen modeli kullanmak için

from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import load_model
import pickle
import matplotlib.pyplot as plt
import numpy as np
def predict(text, model_path, token_path):
    
    model = load_model(model_path)
    
    
    with open(token_path, 'rb') as f:
        tokenizer = pickle.load(f)
    
    sequences = tokenizer.texts_to_sequences([text]) # Tahmin edilecek metni önceden eğitilen tokenizer ile sayısal değerlere dönüştürülmesi
    x_new = pad_sequences(sequences, maxlen=50) # Metinlerin boyutlarının eşitlenmesi
    predictions = model.predict([x_new, x_new]) # Tahmin işlemi
    
    emotions = {0: 'üzgün', 1: 'mutlu', 2: 'korku', 3:'öfke'}

    # Tahmin sonuçlarının görselleştirilmesi
    label = list(emotions.values())
    probs = list(predictions[0])
    labels = label
    plt.subplot(1, 1, 1)
    bars = plt.barh(labels, probs)
    plt.xlabel('Tahmin', fontsize=15)
    plt.ylabel('Duygular', fontsize=15)
    ax = plt.gca()
    ax.bar_label(bars, fmt = '%.2f')
    plt.show()

    return emotions[np.argmax(predictions)] # En yüksek değerli indexin alınması ve duygunun döndürülmesi

Prediction

txt = 'Projeyi bitirdiğim için kendimi harika hissediyorum'
predict(txt, 'emotions_detect_model.h5', 'tokenizer.pkl')
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 330ms/step
'mutlu'

graph