├── README.md ├── main.py ├── noncnn.py ├── nponly.py ├── readdata.py ├── reportgen.py └── withcnn.py /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Memes vs Notes Classifier is a binary classifier used to identify whether a given image is a meme or notes. 5 |

6 |

It has three different options available for training the neural network:

7 |
    8 |
  1. CNN based model using TensorFlow:

    It reads the images as 256*256*3 array. It uses three Convolution layers 9 | with 16,32,64 filters and 3,3,5 kernel size respectively. All Convolution layers use ReLU activation function. 10 | Each Convolution layer if followed by max pooling layer with stride of 2 and pool size of 2,2. 11 | Then the output matrix is flattened into a 65536-D vector. 12 | This is connected to a network of fully connected layers with 500,200,80 and 2(output layer) respectively. 13 | All of the fully connected layers use ReLU except the output layer, which uses softmax. 14 | All fully connected layers also use dropout regularization. 15 | Train Set Accuracy is 98.9%, Test Set accuracy is 98.4%.

  2. 16 |
  3. Fully Connected Using TensorFlow:

    It reads the images as 64*64*3 array. 17 | It uses 1000, 400, 100, 40, 2(output layer) and uses ReLU for every layer except the output layer, which uses softmax. 18 | All fully connected layers also use dropout regularization. 19 | Train set accuracy is 93.2%, Test Set Accuracy is 95.3%.

    20 |
  4. 21 |
  5. 22 |

    Fully Connected using NumPy only:

    It reads the images as 64*64*3 array. It uses 1000, 400, 100, 40, 2(output layer) and uses ReLU for every layer except the output layer, which uses sigmoid. 23 | It uses L2 regularization. 24 | Train set accuracy is 95.8%, Test Set Accuracy is 90.6%.

    25 |
  6. 26 |
27 | 28 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import withcnn 2 | import noncnn 3 | import nponly 4 | 5 | print("Welcome to Memes vs Notes Classifier") 6 | print("Select Your Choice of Training Algorithm:") 7 | print("a. TensorFlow based using CNN") 8 | print("b. TensorFlow based using Fully Connected Layers Only") 9 | print("c. Only NumPy based using Fully Connected Layers Only") 10 | x = input("Enter Your Choice: ") 11 | 12 | if x == 'a': 13 | withcnn.main() 14 | elif x == 'b': 15 | noncnn.main() 16 | elif x == 'c': 17 | nponly.main() 18 | 19 | -------------------------------------------------------------------------------- /noncnn.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 3 | #used to suppress debug messages 4 | import tensorflow as tf 5 | import numpy as np 6 | import readdata as rd 7 | from numpy.random import seed 8 | import random as pyrand 9 | from PIL import Image 10 | seed(1) 11 | tf.random.set_seed(2) 12 | np.random.seed(3) 13 | pyrand.seed(4) 14 | alpha = 0.0018 15 | epoch = 7 16 | batchsize = 32 17 | 18 | 19 | def mymodel(): 20 | model = tf.keras.models.Sequential([ 21 | tf.keras.layers.Dense(1000, activation='relu'), 22 | tf.keras.layers.Dropout(0.35), 23 | tf.keras.layers.Dense(400, activation='relu'), 24 | tf.keras.layers.Dropout(0.35), 25 | tf.keras.layers.Dense(100, activation='relu'), 26 | tf.keras.layers.Dropout(0.35), 27 | tf.keras.layers.Dense(40, activation='relu'), 28 | tf.keras.layers.Dropout(0.35), 29 | tf.keras.layers.Dense(2, activation='softmax') 30 | ]) 31 | return model 32 | 33 | 34 | def train_model(): 35 | X_train, Y_train, X_test, Y_test = rd.readshrink() 36 | X_train = X_train.reshape((-1, 64*64*3))/255 - 0.5 37 | X_test = X_test.reshape((-1, 64*64*3))/255 - 0.5 38 | #X_train, X_test = X_train/255 - 0.5, X_test/255 - 0.5 39 | print(X_train.shape, Y_train.shape) 40 | model = mymodel() 41 | loss_fn = tf.keras.losses.CategoricalCrossentropy() 42 | model.compile(loss=loss_fn, metrics=["accuracy"], 43 | optimizer=tf.keras.optimizers.Adam(learning_rate=alpha)) 44 | model.evaluate(X_test, Y_test) 45 | model.fit(X_train, Y_train, epochs=epoch,validation_split=0.0208, 46 | batch_size=batchsize, shuffle=True) 47 | model.evaluate(X_test, Y_test) 48 | 49 | 50 | def main(): 51 | print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU'))) 52 | train_model() 53 | -------------------------------------------------------------------------------- /nponly.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import readdata # self made library 3 | import matplotlib.pyplot as plt 4 | import math 5 | from sklearn.utils import shuffle 6 | import reportgen as rg 7 | 8 | #Activation Functions 9 | def sigmoid(x): 10 | return 1 / (1 + np.exp(-x)) 11 | 12 | 13 | def relu(x): 14 | return np.maximum(x, 0) 15 | 16 | 17 | def relu_back(x): 18 | return np.where(x>0,np.ones(x.shape),np.zeros(x.shape)) 19 | 20 | 21 | def sigmoid_back(x): 22 | return np.exp(x)/((1+np.exp(x))**2) 23 | 24 | 25 | def leakyrelu(x): 26 | return np.where(x > 0, x, x * 0.01) 27 | #where function uses operation 1 for true condition, 2nd for false 28 | 29 | 30 | def leakyrelu_back(x): 31 | return np.where(x > 0, 1, 0.01) 32 | 33 | 34 | buffer = 10**-8 35 | learning_rate = 0.001 36 | epoch = 4 37 | batch_size = 32 38 | lamda = 0.25 39 | report_name = "Report No 1" # report name 40 | 41 | 42 | def initialise_parameters(network): 43 | parameters = {} # empty dictionary 44 | np.random.seed(6) 45 | for i in range(1,len(network)): # initialises weights and biases 46 | w_temp = np.random.randn(network[i-1], network[i])*np.sqrt(2/network[i-1]) 47 | #weight initialization recommended by andrew ng in course 2 48 | b_temp = np.zeros((1, network[i])) 49 | parameters["W"+str(i)] = w_temp 50 | parameters["b"+str(i)] = b_temp 51 | return parameters 52 | 53 | 54 | def forward_prop(A0, parameters): 55 | iter = len(parameters)//2 # no of weight arrays, i.e hidden layers+1 56 | A_temp = A0 57 | cache = {"A0": A0} # contains 2n+1 keys, n is no of layers 58 | for i in range(iter): 59 | Z_temp = np.dot(A_temp ,parameters["W"+str(i+1)]) + parameters["b"+str(i+1)] 60 | if i == iter - 1: # last layer uses sigmoid 61 | A_temp = sigmoid(Z_temp) 62 | else: 63 | A_temp = leakyrelu(Z_temp) 64 | cache["Z" + str(i + 1)] = Z_temp 65 | cache["A" + str(i + 1)] = A_temp 66 | return A_temp, cache 67 | 68 | 69 | def calc_cost(AL, Y_real, parameters=None): 70 | m = Y_real.shape[0] 71 | cost = (-1/m)*(np.sum(np.multiply(Y_real,np.log(AL+buffer))+np.multiply(1-Y_real,np.log(1-AL+buffer)))) 72 | #cost function, buffer added to avoid log(0) error 73 | if lamda: 74 | for i in range(len(parameters)//2): 75 | cost += (-0.5/m)*lamda*np.sum(parameters["W"+str(i+1)]**2) 76 | cost = np.squeeze(cost) 77 | return cost 78 | 79 | 80 | def backprop(AL,Y,caches, parameters): 81 | grads = {} 82 | L = len(caches)//2 83 | m = Y.shape[0] 84 | dAL = - (np.divide(Y, AL+buffer) - np.divide(1 - Y, 1 - AL + buffer)) 85 | dZ = dAL*sigmoid_back(caches["Z"+str(L)]) 86 | dW = (1 / m) * np.dot(caches["A"+str(L-1)].T, dZ) + (lamda/(2*m))*(parameters["W"+str(L)]**2) 87 | db = (1 / m) * np.sum(dZ, axis=0) 88 | dA_prev = np.dot(dZ, parameters["W" + str(L)].T) 89 | grads["dA" + str(L)] = dA_prev 90 | grads["dW" + str(L)] = dW 91 | grads["db" + str(L)] = db.reshape(1, -1) 92 | for l in reversed(range(1,L)): 93 | dZ = dA_prev * leakyrelu_back(caches["Z" + str(l)]) 94 | dW = (1 / m) * np.dot(caches["A" + str(l-1)].T, dZ) + (lamda/m)*parameters["W"+str(l)] 95 | db = (1 / m) * np.sum(dZ, axis=0) 96 | dA_prev = np.dot(dZ, parameters["W" + str(l)].T) 97 | grads["dA" + str(l)] = dA_prev 98 | grads["dW" + str(l)] = dW 99 | grads["db" + str(l)] = db.reshape(1, -1) 100 | return grads 101 | 102 | 103 | def update_parameters(parameters, grads): 104 | L = len(parameters)//2 105 | for i in range(L): 106 | parameters["W" + str(i + 1)] -= learning_rate * grads["dW" + str(i + 1)] 107 | parameters["b" + str(i + 1)] -= learning_rate * grads["db" + str(i + 1)] 108 | return #as parameters are passed by reference, no need to return 109 | 110 | 111 | def train_model(X, Y_real, parameters): 112 | Y, cache = forward_prop(X, parameters) 113 | cost = calc_cost(Y, Y_real, parameters) 114 | costs_epoch = [cost] 115 | costs_batch = [cost] 116 | accuracies = [0] 117 | X, Y_real = shuffle(X, Y_real, random_state=batch_size) 118 | X, Y_real, X_dev, Y_dev = X[:1472], Y_real[:1472], X[1472:], Y_real[1472:] 119 | for i in range(epoch): 120 | X, Y_real = shuffle(X, Y_real, random_state=epoch) 121 | for j in range(math.ceil(X.shape[0]/batch_size)): 122 | X_batch = X[j * batch_size:((j + 1) * batch_size if ((j + 1) * batch_size) < X.shape[0] else X.shape[0] - 1)] 123 | Y_batch = Y_real[j * batch_size:((j + 1) * batch_size if ((j + 1) * batch_size) < X.shape[0] else X.shape[0] - 1)] 124 | Y, cache = forward_prop(X_batch, parameters) 125 | grads = backprop(Y, Y_batch, cache, parameters) 126 | update_parameters(parameters, grads) 127 | cost = calc_cost(Y, Y_batch, parameters) 128 | costs_batch.append(cost) 129 | print("Train Cost in Epoch number ",i+1,", Batch number ",j+1," is: ",cost) 130 | Y, cache = forward_prop(X, parameters) 131 | cost = calc_cost(Y, Y_real, parameters) 132 | accuracies.append(check_accuracy(X,Y_real,parameters)) 133 | print("Train Set Accuracy after EPOCH ", i+1, " is: ", accuracies[i+1]) 134 | print("Train Set Cost after EPOCH ", i+1, " is: ", cost) 135 | Y, cache = forward_prop(X_dev, parameters) 136 | print("Dev Set Cost after EPOCH ", i+1, " is: ", 137 | calc_cost(Y,Y_dev,parameters)) 138 | print("Dev Set Accuracy after EPOCH ", i+1, " is: ", 139 | check_accuracy(X_dev,Y_dev,parameters)) 140 | costs_epoch.append(cost) 141 | return costs_epoch, costs_batch, accuracies 142 | 143 | 144 | def check_accuracy(X, Y_real, parameters): 145 | Y_ret, cache = forward_prop(X,parameters) 146 | m = Y_ret.shape[0] 147 | Y_real_max = np.squeeze(np.argmax(Y_real, axis=1)) 148 | Y_ret_max = np.squeeze(np.argmax(Y_ret, axis=1)) 149 | accuracy = 0 150 | for i in range(m): 151 | if Y_real_max[i] == Y_ret_max[i]: 152 | accuracy += 1 153 | return accuracy/m 154 | 155 | 156 | def main(): 157 | X_train, Y_train, X_test, Y_test = readdata.readshrink() 158 | X_train, X_test = X_train.reshape(X_train.shape[0],-1)/255, X_test.reshape(X_test.shape[0],-1)/255 159 | network = (X_train.shape[1], 1000, 400, 100, 40, Y_train.shape[1]) 160 | parameters = initialise_parameters(network) 161 | costs_epoch, costs_batch, accuracies = train_model(X_train,Y_train,parameters) 162 | acc_train = check_accuracy(X_train,Y_train,parameters) 163 | acc_test = check_accuracy(X_test,Y_test, parameters) 164 | print("Train+Dev set Accuracy is: ", acc_train*100, "%") 165 | print("Test set Accuracy is: ", acc_test*100, "%") 166 | notes = input("Any Special Notes to add in the report: ") 167 | rg.imagegen(report_name , costs_epoch, costs_batch, accuracies) 168 | rg.reportgen(report_name, network, epoch, 169 | learning_rate, acc_train, acc_test, costs_epoch[len(costs_epoch) - 1], 170 | batch_size, lamda, notes) 171 | # this function call generates a report(HTML page) that details things 172 | # such as network structure, number of iterations, costs, accuracy, lambda 173 | # and various graphs. 174 | return 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /readdata.py: -------------------------------------------------------------------------------- 1 | #pillow needs to be installed to read jpg images 2 | 3 | 4 | import matplotlib.image as img 5 | from sklearn.utils import shuffle 6 | import numpy as np 7 | from PIL import Image 8 | 9 | def read(): 10 | X = np.zeros((1600,256,256,3)) 11 | Y = create_Y() 12 | for x in range(800): 13 | a = img.imread(r"Stage_2\Memes\\" + str(x) + ".jpg") 14 | X[x] = a 15 | for x in range(800): 16 | a = img.imread(r"Stage_2\Notes\\" + str(x) + ".jpg") 17 | X[x+800] = a 18 | X, Y = shuffle(X,Y,random_state=0) 19 | X_train, Y_train = X[:1536], Y[:1536] 20 | X_test, Y_test = X[1536:], Y[1536:] 21 | print(X.shape) 22 | return X_train, Y_train, X_test, Y_test 23 | 24 | 25 | def readshrink(): 26 | X = np.zeros((1600, 64, 64, 3)) 27 | Y = create_Y() 28 | for x in range(800): 29 | a = Image.open(r"Stage_2\Memes\\" + str(x) + ".jpg") 30 | a = a.resize((64,64)) 31 | X[x] = a 32 | for x in range(800): 33 | a = Image.open(r"Stage_2\Notes\\" + str(x) + ".jpg") 34 | a = a.resize((64,64)) 35 | X[x+800] = a 36 | X, Y = shuffle(X,Y,random_state=17) 37 | X_train, Y_train = X[:1536], Y[:1536] 38 | X_test, Y_test = X[1536:], Y[1536:] 39 | print(X.shape) 40 | return X_train, Y_train, X_test, Y_test 41 | 42 | 43 | 44 | def create_Y(): 45 | Y = np.zeros((1600,2)) 46 | for x in range(800): 47 | Y[x,0] = 1 48 | for x in range(800,1600): 49 | Y[x,1] = 1 50 | return Y -------------------------------------------------------------------------------- /reportgen.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | import matplotlib.pyplot as plt 3 | import copy 4 | 5 | def reportgen(filename="test", network=[784,16,16,10], epochs=100, learn_rate=0.05, 6 | train_acc=1, test_acc=1, cost_f=1, batch_size=32, lamda=0, note=""): 7 | f = open(filename+".html", "w") 8 | f.writelines("\n\n" + "Report: " + str(filename) + "") 9 | f.writelines("\n\n\n") 10 | f.writelines("\n") 11 | f.writelines("

Report Name: " + filename + "

\n") 12 | f.writelines("

Neural Network Layer Structure is: "+str(network)+"

\n") 13 | f.writelines("

Batch Size used in training is: " + str(batch_size) + "

\n") 14 | f.writelines("

Number of EPOCHS done are: " + str(epochs) + "

\n") 15 | f.writelines("

Learning Rate used is: " + str(learn_rate) + "

\n") 16 | f.writelines("

Train set accuracy is: " + str(train_acc*100) + "%

\n") 17 | f.writelines("

Test set accuracy is: " + str(test_acc*100) + "%

\n") 18 | f.writelines("

Lambda used is: " + str(lamda) + "

\n") 19 | f.writelines("

Final Cost is: " + str(cost_f) + "

\n") 20 | if note != "": 21 | f.writelines("

Special Notes: "+note+"

\n") 22 | f.writelines("

Cost Function per EPOCH Graph is:

\n") 23 | f.writelines('
Cost Function per EPOCH Graph
\n') 24 | f.writelines("

Loss Function per Mini Batch Graph is:

\n") 25 | f.writelines('
Cost Function Graph
\n') 26 | f.writelines("

Rate of Change of Loss Function per Mini-Batch Graph is:

\n") 27 | f.writelines('
Rate of change of Cost Function Graph
\n') 28 | f.writelines("

Accuracy of Train set after some EPOCHS is:

\n") 29 | f.writelines('
Accuracy Graph
\n') 30 | f.writelines("\n\n\n") 31 | f.close() 32 | webbrowser.open(filename+".html") 33 | return 34 | 35 | 36 | def imagegen(imgname, costs_epoch, costs_batch, accuracies): 37 | plt.plot(costs_epoch) 38 | plt.ylabel("Cost") 39 | plt.xlabel("No of EPOCHS") 40 | plt.savefig(imgname + ".png") # saves image 41 | plt.clf() 42 | plt.plot(costs_batch) 43 | plt.ylabel("Loss") 44 | plt.xlabel("No of Mini-Batches") 45 | plt.savefig(imgname + "b" + ".png") 46 | plt.clf() 47 | plt.plot(derivative(costs_batch)) 48 | plt.ylabel("Rate of Change of Loss") 49 | plt.xlabel("No of Mini-Batches") 50 | plt.savefig(imgname + "d" + ".png") 51 | plt.clf() 52 | axes = plt.gca() 53 | axes.set_ylim([0.5,1]) 54 | plt.plot(accuracies) 55 | plt.ylabel("Accuracy on Train set") 56 | plt.xlabel("No of EPOCHS") 57 | plt.savefig(imgname + "a" + ".png") 58 | return 59 | 60 | def derivative(x): 61 | y = copy.deepcopy(x) 62 | a = [] 63 | for z in range(1,len(y)): 64 | a.append(y[z] - y[z-1]) 65 | #print(a) 66 | return a -------------------------------------------------------------------------------- /withcnn.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 3 | #used to suppress debug messages 4 | import tensorflow as tf 5 | import numpy as np 6 | import readdata as rd 7 | from numpy.random import seed 8 | import random as pyrand 9 | seed(1) 10 | tf.random.set_seed(0) 11 | np.random.seed(1) 12 | pyrand.seed(7) 13 | alpha = 0.001 14 | epoch = 4 15 | batchsize = 64 16 | 17 | 18 | def mymodel(): 19 | model = tf.keras.models.Sequential([ 20 | tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'), 21 | tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=2), 22 | tf.keras.layers.Conv2D(32, 3, padding='same',activation='relu'), 23 | tf.keras.layers.MaxPool2D(pool_size=(2, 2),strides=2), 24 | tf.keras.layers.Conv2D(64, 5, padding='same',activation='relu'), 25 | tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=2), 26 | tf.keras.layers.Flatten(input_shape=(32,32,64)), 27 | tf.keras.layers.Dense(500, activation='relu'), 28 | tf.keras.layers.Dropout(0.12), 29 | tf.keras.layers.Dense(200, activation='relu'), 30 | tf.keras.layers.Dropout(0.12), 31 | tf.keras.layers.Dense(80, activation='relu'), 32 | tf.keras.layers.Dropout(0.12), 33 | tf.keras.layers.Dense(2, activation='softmax') 34 | ]) 35 | return model 36 | 37 | 38 | def train_model(): 39 | X_train, Y_train, X_test, Y_test = rd.read() 40 | X_train, X_test = X_train/255 - 0.5, X_test/255 - 0.5 41 | print(X_train.shape, Y_train.shape) 42 | model = mymodel() 43 | loss_fn = tf.keras.losses.CategoricalCrossentropy() 44 | model.compile(loss=loss_fn, metrics=["accuracy"], 45 | optimizer=tf.keras.optimizers.Adam(learning_rate=alpha)) 46 | model.evaluate(X_test, Y_test) 47 | model.fit(X_train, Y_train, epochs=epoch,validation_split=0.0208, 48 | batch_size=batchsize, shuffle=True) 49 | model.evaluate(X_test, Y_test) 50 | 51 | 52 | def main(): 53 | print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU'))) 54 | train_model() 55 | --------------------------------------------------------------------------------