# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3 (ipykernel)
#     language: python
#     name: python3
# ---

# + [markdown] id="sp7D0ktn5eiG"
# ## Tweet Emotion Recognition: Natural Language Processing with TensorFlow
#
# ---
#
# Dataset: [Tweet Emotion Dataset](https://github.com/dair-ai/emotion_dataset)
#
# This is a starter notebook for the guided project [Tweet Emotion Recognition with TensorFlow](https://www.coursera.org/projects/tweet-emotion-tensorflow)
#
# A complete version of this notebook is available in the course resources
#
# ---
#
# ## Task 1: Introduction

# + [markdown] id="cprXxkrMxIgT"
# ## Task 2: Setup and Imports
#
# 1. Installing Hugging Face's nlp package
# 2. Importing libraries

# + id="5agZRy-45i0g"
# !pip install nlp

# + id="yKFjWz6e5eiH"
# %matplotlib inline

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import nlp
import random


def show_history(h):
    epochs_trained = len(h.history['loss'])
    plt.figure(figsize=(16, 6))

    plt.subplot(1, 2, 1)
    plt.plot(range(0, epochs_trained), h.history.get('accuracy'), label='Training')
    plt.plot(range(0, epochs_trained), h.history.get('val_accuracy'), label='Validation')
    plt.ylim([0., 1.])
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()

    plt.subplot(1, 2, 2)
    plt.plot(range(0, epochs_trained), h.history.get('loss'), label='Training')
    plt.plot(range(0, epochs_trained), h.history.get('val_loss'), label='Validation')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.show()

    
def show_confusion_matrix(y_true, y_pred, classes):
    from sklearn.metrics import confusion_matrix
    
    cm = confusion_matrix(y_true, y_pred, normalize='true')

    plt.figure(figsize=(8, 8))
    sp = plt.subplot(1, 1, 1)
    ctx = sp.matshow(cm)
    plt.xticks(list(range(0, 6)), labels=classes)
    plt.yticks(list(range(0, 6)), labels=classes)
    plt.colorbar(ctx)
    plt.show()

    
print('Using TensorFlow version', tf.__version__)

# + [markdown] id="7JsBpezExIga"
# ## Task 3: Importing Data
#
# 1. Importing the Tweet Emotion dataset
# 2. Creating train, validation and test sets
# 3. Extracting tweets and labels from the examples

# + id="0YHOvjAu5eiL"
dataset = nlp.load_dataset('emotion')

# + id="2s0h541FxIgc"
dataset

# + id="z7eCnxU25eiN"
train = dataset['train']
val = dataset['validation']
test = dataset['test']


# + id="oDYXMfZy5eiP"
def get_tweet(data):
    tweets = [x['text'] for x in data]
    labels = [x['label'] for x in data] 
    return tweets,labels


# + id="jeq3-vSB5eiR"
tweets,labels = get_tweet(train)

# + id="bHD3Tk0J5eiU"
tweets[0], labels[0]

# + [markdown] id="gcAflLv6xIgp"
# ## Task 4: Tokenizer
#
# 1. Tokenizing the tweets

# + id="qfX5-ResxIgq"
from tensorflow.keras.preprocessing.text import Tokenizer

# + id="cckUvwBo5eif"
tokenizer = Tokenizer(num_words=10000, oov_token='<UNK>')
tokenizer.fit_on_texts(tweets)
# -

tokenizer.texts_to_sequences([tweets[0]])

tweets[0]

# + [markdown] id="i3Bqm7b2xIgu"
# ## Task 5: Padding and Truncating Sequences
#
# 1. Checking length of the tweets
# 2. Creating padded sequences

# + id="mLvf_WFZxIgu"
lengths = [len(t.split(' ')) for t in tweets]
plt.hist(lengths,bins=len(set(lengths)))
plt.show()

# + id="EOi5lIE3xIgx"
maxlen = 50

from tensorflow.keras.preprocessing.sequence import pad_sequences


# + id="Q9J_Iemf5eiq"
def get_sequences(tokenizer,tweets):
    sequences = tokenizer.texts_to_sequences(tweets)
    padded = pad_sequences(sequences, truncating='post', padding = 'post',maxlen=maxlen)
    return padded


# + id="eglH77ky5ei0"
padded_train_seq = get_sequences(tokenizer,tweets)

# + id="iGR473HA5ei7"
padded_train_seq[0]

# + [markdown] id="BURhOX_KxIg8"
# ## Task 6: Preparing the Labels
#
# 1. Creating classes to index and index to classes dictionaries
# 2. Converting text labels to numeric labels

# + id="SufT2bpD5ejE"
classes = set(labels)
print(classes)

# + id="rpwzL88I7YSm"
plt.hist(labels,bins=11)

# + id="dNLF6rXL5ejN"
class_to_index = dict((c, i ) for i,c in enumerate(classes))
index_to_class = dict((v,k) for k,v in class_to_index.items())
# -

class_to_index

# + id="_08InVyM5ejc"
index_to_class

# + id="gpeDoA6gxIhE"
names_to_ids = lambda labels: np.array([class_to_index.get(x) for x in labels])

# + id="Jq0WJYsP5ejR"
train_labels = names_to_ids(labels)
print(labels[0])
print(train_labels[0])

# + id="v15KnrNC5ejW"


# + [markdown] id="c-v0Mnh8xIhP"
# ## Task 7: Creating the Model
#
# 1. Creating the model
# 2. Compiling the model

# + id="OpewXxPQ5eji"
model = tf.keras.models.Sequential([
    tf.keras.layers.Embedding(10000,16,input_length = maxlen),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32,return_sequences=True)),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
    tf.keras.layers.Dense(6,activation='softmax')
])

model.compile(
    loss= 'sparse_categorical_crossentropy',
    optimizer = 'adam',
    metrics = ['accuracy']

)
# -

model.summary()

# + [markdown] id="1HST_CHjxIhR"
# ## Task 8: Training the Model
#
# 1. Preparing a validation set
# 2. Training the model

# + id="Ff7F3hCK5ejm"
val_tweets,val_labels = get_tweet(val)
val_seq = get_sequences(tokenizer,val_tweets)
val_labels = names_to_ids(val_labels)


# + id="hlMKaZ3H5ejr"
val_tweets[0],val_labels[0]

# + id="bzBqnWQ-5ejw"
h = model.fit(
    padded_train_seq, train_labels,
    validation_data = (val_seq, val_labels),
    epochs=20,
    callbacks=[
        tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',patience=2)
    ]
)

# + [markdown] id="EdsJyMTLxIhX"
# ## Task 9: Evaluating the Model
#
# 1. Visualizing training history
# 2. Prepraring a test set
# 3. A look at individual predictions on the test set
# 4. A look at all predictions on the test set

# + id="ENCfvXeLxIhX"
show_history(h)

# + id="kWuzoz8uxIha"
test_tweets, test_labels = get_tweet(test)
test_seq = get_sequences(tokenizer,test_tweets)
test_labels = names_to_ids(test_labels)

# + id="7vRVJ_2SxIhc"
_ = model.evaluate(test_seq,test_labels)

# + id="rh638vHG5ej6"
i = random.randint(0,len(test_labels)-1)
print('Sentence: ',test_tweets[i])
print('Emotion: ', index_to_class[test_labels[i]])

p=model.predict(np.expand_dims(test_seq[i],axis=0))[0]

pred_class = index_to_class[np.argmax(p).astype('uint8')]
print('Predicted: ',pred_class)

# + id="hHl5SVCFxIhh"
preds = model.predict(test_seq)
preds = np.array([np.argmax(i) for i in preds])

# + id="NC8YQ0OexIhj"
show_confusion_matrix(test_labels,preds,list(classes))

StarcoderdataJupyterScriptsDedupFiltered