<jupyter_start><jupyter_text>Setup<jupyter_code>from google.colab import drive
drive.mount('/content/drive')
!gdown 'https://drive.google.com/uc?id=1JffwGvZ-LAx_Cq4Bb4quyJAMsEf63vVz'
!unzip trainingandtestdata.zip<jupyter_output>Archive:  trainingandtestdata.zip
  inflating: testdata.manual.2009.06.14.csv  
  inflating: training.1600000.processed.noemoticon.csv<jupyter_text>Data Preparation<jupyter_code>import numpy as np
import math
import re
import pandas as pd
from bs4 import BeautifulSoup

import tensorflow as tf
from tensorflow.keras import layers
import tensorflow_datasets as tfds
# tensorflow_datasets contains tokenizer function
cols = ["sentiment", "id", "date", "query", "user", "text"]

train_data = pd.read_csv("training.1600000.processed.noemoticon.csv", header=None, names=cols, engine="python", encoding="latin1")
test_data = pd.read_csv("testdata.manual.2009.06.14.csv", header=None, names=cols, engine="python", encoding="latin1")

data = train_data
print(len(data))
data.head()
data.drop(["id", "date", "query", "user"], axis=1, inplace=True)
data.head()
def clean_tweet(tweet):
  tweet = BeautifulSoup(tweet, "lxml").get_text()
  tweet = re.sub(r"@[A-Za-z0-9]+", " ", tweet)
  # get rid of all mentions in the tweet
  tweet = re.sub(r"https?://[A-Za-z0-9./]+", " ", tweet)
  # get rid of all urls
  tweet = re.sub(r"[^a-zA-Z.!?']", " ", tweet)
  # to only keep letters and standard punctuation
  tweet = re.sub(r" +", " ", tweet)
  # replace multiple whitespaces by a single whitespace
  return tweet
data_clean = [clean_tweet(tweet) for tweet in data.text]
print(data_clean[0])
data_labels = data.iloc[0:, 0:1]
data_labels = np.array(data_labels)
data_labels[data_labels == 4] = 1
# data_labels[data_labels == 2] = 1
print(np.unique(data_labels))
print(len(data_labels))
print(len(data_clean))
# converting words into numbers using tensorflow tokenizer

tokenizer = tfds.features.text.SubwordTextEncoder.build_from_corpus(
    data_clean, target_vocab_size=2**16
)

data_inputs = [tokenizer.encode(sentence) for sentence in data_clean]
print(len(data_inputs[0]))
print(data_inputs[0])
# Add padding to make length of all sentences equal

MAX_LEN = max([len(sentence) for sentence in data_inputs])

# this makes all our sentences of length=MAX_LEN by adding 0s at the end
data_inputs = tf.keras.preprocessing.sequence.pad_sequences(data_inputs,
                                                            value=0,
                                                            padding="post",
                                                            maxlen=MAX_LEN)
print(len(data_inputs[0]))
print(MAX_LEN)
print(data_inputs[0])
# splitting dataset into train and test set

test_idx = np.random.randint(0, 800000, 8000)
# 8000 random negative tweets stored in test_idx right now

test_idx = np.concatenate((test_idx, test_idx+800000))
# this combines 8000 random negative tweets and 8000 random positive tweets to give us total 16000 testing tweets

test_inputs = data_inputs[test_idx]
test_labels = data_labels[test_idx]

train_inputs = np.delete(data_inputs, test_idx, axis=0)
train_labels = np.delete(data_labels, test_idx, axis=0)

print(len(test_inputs))
print(len(test_labels))
print(len(train_inputs))
print(len(train_labels))<jupyter_output>16000
16000
1584082
1584082<jupyter_text>Model<jupyter_code>class DCNN(tf.keras.Model):
  def __init__(self,
               vocab_size,
               emb_dim=128,
               nb_filters=50,
               FFN_units=512,
               nb_classes=2,
               dropout_rate=0.1,
               training=False,
               name="dcnn"):
    super(DCNN, self).__init__(name=name)

    # embedding layer
    self.embedding = layers.Embedding(vocab_size, emb_dim)

    # this create feature maps to find similarity between 2 simultaneous words(dimension of filter map=2xemb_dim)
    # we use 1d convolutions since width of feature maps is same as width of input matrix
    self.bigram = layers.Conv1D(filters=nb_filters, kernel_size=2, padding="valid", activation="relu")
    self.pool_1 = layers.GlobalMaxPool1D()
    # this create feature maps to find similarity between 3 simultaneous words(dimension of filter map=3xemb_dim)
    self.trigram = layers.Conv1D(filters=nb_filters, kernel_size=3, padding="valid", activation="relu")
    self.pool_2 = layers.GlobalMaxPool1D()
    # this create feature maps to find similarity between 4 simultaneous words(dimension of filter map=4xemb_dim)
    self.fourgram = layers.Conv1D(filters=nb_filters, kernel_size=4, padding="valid", activation="relu")
    self.pool_3 = layers.GlobalMaxPool1D()

    # full connection layers
    self.dense_1 = layers.Dense(units=FFN_units, activation="relu")
    self.dropout = layers.Dropout(rate=dropout_rate)

    # output layer
    if nb_classes == 2:
      self.last_dense = layers.Dense(units=1, activation="sigmoid")
    else:
      self.last_dense = layers.Dense(units=nb_units, activation="softmax")

  def call(self, inputs, training):
    x = self.embedding(inputs)

    x_1 = self.bigram(x)
    x_1 = self.pool_1(x_1)
    x_2 = self.trigram(x)
    x_2 = self.pool_2(x_2)
    x_3 = self.fourgram(x)
    x_3 = self.pool_3(x_3)

    merged = tf.concat([x_1, x_2, x_3], axis=-1)
    # size = (batch_size, 3*nb_filters)
    merged = self.dense_1(merged)
    merged = self.dropout(merged, training)
    output = self.last_dense(merged)

    return output
VOCAB_SIZE = tokenizer.vocab_size
EMB_DIM = 200
NB_FILTERS = 100
FFN_UNITS = 256
NB_CLASSES = len(np.unique(data_labels))
DROPOUT_RATE = 0.2
BATCH_SIZE = 32
NB_EPOCHS = 2
dcnn = DCNN(vocab_size=VOCAB_SIZE,
            emb_dim=EMB_DIM,
            nb_filters=NB_FILTERS,
            FFN_units=FFN_UNITS,
            nb_classes=NB_CLASSES,
            dropout_rate=DROPOUT_RATE)
if NB_CLASSES == 2:
  dcnn.compile(loss="binary_crossentropy",
               optimizer="adam",
               metrics=["accuracy"])
else:
  dcnn.compile(loss="sparse_categorical_crossentropy",
               optimizer="adam",
               metrics=["sparse_categorical_accuracy"])
checkpoint_path = "drive/My Drive/models/tweets-sentiment/"

ckpt = tf.train.Checkpoint(dcnn=dcnn)

ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=2)

if ckpt_manager.latest_checkpoint:
  ckpt.restore(ckpt_manager.latest_checkpoint)
  print("Latest checkpoint restored!")
dcnn.fit(train_inputs,
         train_labels,
         batch_size=BATCH_SIZE,
         epochs=NB_EPOCHS)

ckpt_manager.save()<jupyter_output>Epoch 1/2
49503/49503 [==============================] - 6340s 128ms/step - loss: 0.3989 - accuracy: 0.8197
Epoch 2/2
 7652/49503 [===>..........................] - ETA: 1:28:58 - loss: 0.3269 - accuracy: 0.8592Buffered data was truncated after reaching the output size limit.<jupyter_text>Evaluation<jupyter_code>results = dcnn.evaluate(test_inputs, 
                        test_labels, 
                        batch_size=BATCH_SIZE)

print(results)
dcnn(np.array([tokenizer.encode('I love you')]), training=False).numpy()
dcnn(np.array([tokenizer.encode('I hate you')]), training=False).numpy()
dcnn(np.array([tokenizer.encode('I wish no one ever have to do that again')]), training=False).numpy()
dcnn(np.array([tokenizer.encode('You are so funny!')]), training=False).numpy()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12339787292064358, 'fraction_numerical': 0.032997000272702484, 'mean_word_length': 3.8608349900596424, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 15, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '661893', 'license': 'MIT', 'n_tokens_mistral': 2694, 'n_tokens_neox': 2473, 'n_words': 517, 'path': 'CustomCNN-SentimentAnalysis(NLP)/model.ipynb', 'repo_name': 'Frostday/Small-Tensorflow-Projects', 'size': '7334'}