├── 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 | 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%.
16 | 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 |
21 | -
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 |
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('
\n')
24 | f.writelines("Loss Function per Mini Batch Graph is:
\n")
25 | f.writelines('
\n')
26 | f.writelines(" Rate of Change of Loss Function per Mini-Batch Graph is:
\n")
27 | f.writelines('
\n')
28 | f.writelines(" Accuracy of Train set after some EPOCHS is:
\n")
29 | f.writelines('
\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 |
--------------------------------------------------------------------------------