├── .gitignore ├── LICENSE ├── LRmodel.py ├── README.md ├── camera_pred.py ├── conv_network.py ├── data ├── t10k-images-idx3-ubyte ├── t10k-images-idx3-ubyte.gz ├── t10k-labels-idx1-ubyte ├── t10k-labels-idx1-ubyte.gz ├── train-images-idx3-ubyte ├── train-images-idx3-ubyte.gz ├── train-labels-idx1-ubyte └── train-labels-idx1-ubyte.gz ├── digit_recognizer.py ├── input_data.py ├── sample.gif ├── softmax.png └── weights ├── LR_params.npy ├── cnn_accuracy.npy ├── cnn_model.json └── cnn_weights.h5 /.gitignore: -------------------------------------------------------------------------------- 1 | # pychache folder ignored 2 | __pycache__/* 3 | 4 | # .idea folder ignored 5 | .idea/* 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ali Akbar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LRmodel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def softmax(z): 5 | ''' 6 | :param z: 7 | :return: 8 | ''' 9 | z -= np.max(z, axis=1).reshape(-1, 1) 10 | s = (np.exp(z) / np.sum(np.exp(z), axis=1).reshape(-1, 1)) 11 | return s 12 | 13 | 14 | def initialize(X, y): 15 | ''' 16 | :param X: features 17 | :param y: labels 18 | :return: weights, base 19 | ''' 20 | weights = np.zeros((X.shape[1], y.shape[1])) 21 | base = np.zeros((1, y.shape[1])) 22 | return weights, base 23 | 24 | 25 | def propagate(weights, base, X, y): 26 | ''' 27 | :param weights: 28 | :param base: 29 | :param X: features 30 | :param y: labels 31 | :return: cost, gradient_weights, gradient_base 32 | ''' 33 | m = X.shape[0] 34 | h = softmax(np.dot(X, weights) + base) 35 | cost = (-1/m) * np.sum(y * np.log(h) + (1 - y) * np.log(1 - h)) 36 | grad_w = (1/m) * np.dot(X.T, (h - y)) 37 | grad_b = (1/m) * np.sum((h-y), axis=0) 38 | return cost, grad_w, grad_b 39 | 40 | 41 | def predict(X, weights, base): 42 | ''' 43 | :param X: features 44 | :param weights: 45 | :param base: 46 | :return: predicted labels 47 | ''' 48 | h = softmax(np.dot(X, weights) + base) 49 | return h 50 | 51 | 52 | def evaluate(X, y, weights, base): 53 | ''' 54 | :param X: features 55 | :param y: labels 56 | :param weights: 57 | :param base: 58 | :return: accuracy 59 | ''' 60 | h = softmax(np.dot(X, weights) + base) 61 | h_argmax = np.argmax(h, axis=1) 62 | y_argmax = np.argmax(y, axis=1) 63 | accuracy = sum(h_argmax == y_argmax)/(float(len(y))) 64 | return accuracy 65 | 66 | 67 | def model(train_x, train_y, test_x, test_y, iters, alpha, print_cost=True): 68 | ''' 69 | :param train_x: training features 70 | :param train_y: training labels 71 | :param test_x: test features 72 | :param test_y: test labels 73 | :param iters: no. of iterations 74 | :param alpha: learning rate 75 | :param print_cost: printing the cost 76 | :return: weights, base 77 | ''' 78 | # reshaping (28, 28) data int 784 79 | train_x = np.reshape(train_x, (-1, 784)) 80 | test_x = np.reshape(test_x, (-1, 784)) 81 | 82 | # initializing weights and bias 83 | weights, base = initialize(train_x, train_y) 84 | print("\nTraining multiclass Logistic Regression on MNIST data...") 85 | for i in range(iters): 86 | # getting the cost, weight gradient and base gradient 87 | cost, grad_w, grad_b = propagate(weights, base, train_x, train_y) 88 | weights = weights - alpha * grad_w 89 | base = base - alpha * grad_b 90 | if print_cost and i % 100 == 0: 91 | print('cost after iteration {} : {}'.format(i, cost)) 92 | print(f'Cost after iteration {i+1} : {cost}') 93 | 94 | # calculating train and test accuracy 95 | train_accuracy = evaluate(train_x, train_y, weights, base) 96 | test_accuracy = evaluate(test_x, test_y, weights, base) 97 | train_size = len(train_y) 98 | print(f'Logistic Regression Train accuracy : {train_accuracy}%') 99 | print(f'Logistic Regression Test accuracy : {test_accuracy}%') 100 | print(f'Training size : {train_size}, alpha : {alpha}, iterations : {iters}\n\n') 101 | LR_params = {'weights': weights, 'base': base, 'train_accuracy': train_accuracy, 102 | 'test_accuracy': test_accuracy, 'train_size': train_size, 'alpha': alpha, 'iters': iters} 103 | return LR_params 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Digit Classification using Logistic Regression and CNN 2 | This is a project focusing on the classification of digits from 0-9 using Logistic Regression and Convolutional Neural Network. 3 | The trained model is used to predict digits drawn on the captured frames from the webcam using object tracking. 4 | 5 | ## Getting Started 6 | 7 | ### Built with 8 | The Logistic Regression is implemented using numpy and softmax function is used for multiclass classification. 9 | The Convolutional Neural Network uses Keras API with tensorflow as backend. 10 | 11 | 12 | 13 | ### Pretrained weights 14 | Training examples = 8000, Test examples = 1000 15 | 16 | **Logistic Regression** 17 | 18 | Train accuracy = 92.1%, 19 | Test accuracy = 91.3%, 20 | learning rate = 0.1 21 | 22 | **CNN Model** 23 | 24 | Train accuracy = 98.1%, 25 | Test accuracy = 96.2%, 26 | no. of epochs = 8 27 | 28 | (Feel free to train the models on your own.) 29 | ### Prerequisites 30 | Install Conda to resolve all requirements of python related dependencies. 31 | 32 | ## Usage 33 | ### Files usage 34 | - LRmodel.py : Logistic Regression implemented using numpy 35 | - conv_network.py : CNN model implemented using Keras API 36 | - digit_recognizer.py : File to either train or load saved weights 37 | - camera_pred.py : Used to test the models using webcam 38 | 39 | ### Training the models 40 | To Train the models on your own, delete the weights folder and run digit_recognizer.py 41 | ``` 42 | python digit_recognizer.py 43 | ``` 44 | (If any of the files in weights folder is not present, the models will be trained again.) 45 | 46 | ### Testing using Camera 47 | Run camera_pred.py (Use a green colored object to draw digit inside the red box). 48 | ``` 49 | python camera_pred.py 50 | ``` 51 | 52 | 53 | Press **c** to clear the box. 54 | 55 | 56 | -------------------------------------------------------------------------------- /camera_pred.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import math 3 | import numpy as np 4 | import time 5 | from collections import deque 6 | import digit_recognizer as dr 7 | import LRmodel 8 | 9 | cap = cv2.VideoCapture(0) 10 | # collection of points to draw 11 | center_points = deque() 12 | 13 | # green colour pointer to be detected 14 | lowergreen = np.array([50, 100, 50]) 15 | uppergreen = np.array([90, 255, 255]) 16 | 17 | # the black board for the models 18 | board = np.zeros((230, 230), dtype='uint8') 19 | 20 | while(cap.isOpened()): 21 | ret, frame = cap.read() 22 | # flipping the frame 23 | frame = cv2.flip(frame, 1) 24 | # applying gaussian blur 25 | frame = cv2.GaussianBlur(frame, (5, 5), 0) 26 | # drawing the rectangle for the board 27 | cv2.rectangle(frame, (400, 50), (600, 250), (100, 100, 255), 2) 28 | roi = frame[50:250, 400:600, :] 29 | hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 30 | # detecting colours in the range 31 | roi_range = cv2.inRange(hsv_roi, lowergreen, uppergreen) 32 | # applying contours on the detected colours 33 | image, contours, hierarchy = cv2.findContours( 34 | roi_range.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 35 | # the text to be displayed on the screen 36 | predict1_text = "Logistic Regression : " 37 | predict2_text = "CNN Model : " 38 | # flags to check when drawing started and when stopped 39 | drawing_started = False 40 | drawing_stopped = False 41 | if(len(contours) > 0): 42 | drawing_started = True 43 | # getting max contours from the contours 44 | max_contours = max(contours, key=cv2.contourArea) 45 | M = cv2.moments(max_contours) 46 | # to avoid divided by zero error 47 | try: 48 | center = (int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])) 49 | except: 50 | continue 51 | # center obtained is appended to the deque 52 | center_points.appendleft(center) 53 | else: 54 | drawing_stopped = False 55 | for i in range(1, len(center_points)): 56 | if math.sqrt((center_points[i-1][0] - center_points[i][0])**2 + 57 | (center_points[i-1][1] - center_points[i][1])**2) < 50: 58 | cv2.line(roi, center_points[i-1], center_points[i], (200, 200, 200), 5, cv2.LINE_AA) 59 | cv2.line(board, (center_points[i-1][0]+15, center_points[i-1][1]+15), 60 | (center_points[i][0]+15, center_points[i][1]+15), 255, 7, cv2.LINE_AA) 61 | # the board is resized for the prediction 62 | input = cv2.resize(board, (28, 28)) 63 | # applying morphological transformation on the drawn digit 64 | if np.max(board) != 0 and drawing_started == True and drawing_stopped == True: 65 | kernel = (5, 5) 66 | input = cv2.morphologyEx(input, cv2.MORPH_OPEN, kernel) 67 | board = cv2.morphologyEx(board, cv2.MORPH_OPEN, kernel) 68 | drawing_started = False 69 | drawing_stopped = False 70 | # predicting the digit using LR and CNN 71 | if np.max(board) != 0: 72 | LR_input = input.reshape(1, 784) 73 | test_x = input.reshape((1, 28, 28, 1)) 74 | prediction1 = np.argmax(LRmodel.predict( 75 | LR_input, dr.LR_params.item().get('weights'), dr.LR_params.item().get('base'))) 76 | prediction2 = np.argmax(dr.model_conv.predict(test_x)) 77 | predict1_text += str(prediction1) 78 | predict2_text += str(prediction2) 79 | # displaying the text on the screen 80 | cv2.putText(frame, predict1_text, 81 | (5, 420), cv2.FONT_HERSHEY_DUPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) 82 | cv2.putText(frame, predict2_text, 83 | (5, 460), cv2.FONT_HERSHEY_DUPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA) 84 | cv2.imshow('input', input) 85 | cv2.imshow('frame', frame) 86 | cv2.imshow('board', board) 87 | k = cv2.waitKey(1) & 0xFF 88 | if k == ord('q'): 89 | break 90 | # clearing the board 91 | elif k == ord('c'): 92 | board.fill(0) 93 | center_points.clear() 94 | cap.release() 95 | cv2.destroyAllWindows() 96 | -------------------------------------------------------------------------------- /conv_network.py: -------------------------------------------------------------------------------- 1 | 2 | from tensorflow.python.keras.layers import Dense, Flatten, Conv2D 3 | from tensorflow.python.keras.models import Sequential 4 | from tensorflow.python import keras 5 | import numpy as np 6 | 7 | num_classes = 10 8 | img_rows, img_cols = 28, 28 9 | seed = 7 10 | np.random.seed(seed) 11 | 12 | 13 | def model(train_x, train_y, test_x, test_y, epoch): 14 | ''' 15 | 16 | :param train_x: train features 17 | :param train_y: train labels 18 | :param test_x: test features 19 | :param test_y: test labels 20 | :param epoch: no. of epochs 21 | :return: 22 | ''' 23 | conv_model = Sequential() 24 | # first layer with input shape (img_rows, img_cols, 1) and 12 filters 25 | conv_model.add(Conv2D(12, kernel_size=(3, 3), activation='relu', 26 | input_shape=(img_rows, img_cols, 1))) 27 | # second layer with 12 filters 28 | conv_model.add(Conv2D(12, kernel_size=(3, 3), activation='relu')) 29 | # third layer with 12 filers 30 | conv_model.add(Conv2D(12, kernel_size=(3, 3), activation='relu')) 31 | # flatten layer 32 | conv_model.add(Flatten()) 33 | # adding a Dense layer 34 | conv_model.add(Dense(100, activation='relu')) 35 | # adding the final Dense layer with softmax 36 | conv_model.add(Dense(num_classes, activation='softmax')) 37 | 38 | # compile the model 39 | conv_model.compile(optimizer=keras.optimizers.Adadelta(), 40 | loss='categorical_crossentropy', 41 | metrics=['accuracy']) 42 | print("\n Training the Convolution Neural Network on MNIST data\n") 43 | # fit the model 44 | conv_model.fit(train_x, train_y, batch_size=128, epochs=epoch, 45 | validation_split=0.1, verbose=2) 46 | predicted_train_y = conv_model.predict(train_x) 47 | train_accuracy = (sum(np.argmax(predicted_train_y, axis=1) 48 | == np.argmax(train_y, axis=1))/(float(len(train_y)))) 49 | print('Train accuracy : ', train_accuracy) 50 | predicted_test_y = conv_model.predict(test_x) 51 | test_accuracy = (sum(np.argmax(predicted_test_y, axis=1) 52 | == np.argmax(test_y, axis=1))/(float(len(test_y)))) 53 | print('Test accuracy : ', test_accuracy) 54 | CNN_accuracy = {'train_accuracy': train_accuracy, 55 | 'test_accuracy': test_accuracy, 'epoch': epoch} 56 | return conv_model, CNN_accuracy 57 | -------------------------------------------------------------------------------- /data/t10k-images-idx3-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/t10k-images-idx3-ubyte -------------------------------------------------------------------------------- /data/t10k-images-idx3-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/t10k-images-idx3-ubyte.gz -------------------------------------------------------------------------------- /data/t10k-labels-idx1-ubyte: -------------------------------------------------------------------------------- 1 | '                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             -------------------------------------------------------------------------------- /data/t10k-labels-idx1-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/t10k-labels-idx1-ubyte.gz -------------------------------------------------------------------------------- /data/train-images-idx3-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/train-images-idx3-ubyte -------------------------------------------------------------------------------- /data/train-images-idx3-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/train-images-idx3-ubyte.gz -------------------------------------------------------------------------------- /data/train-labels-idx1-ubyte: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/train-labels-idx1-ubyte -------------------------------------------------------------------------------- /data/train-labels-idx1-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/data/train-labels-idx1-ubyte.gz -------------------------------------------------------------------------------- /digit_recognizer.py: -------------------------------------------------------------------------------- 1 | import input_data 2 | import conv_network 3 | import LRmodel 4 | import numpy as np 5 | from tensorflow.python import keras 6 | import os 7 | 8 | num_classes = 10 9 | img_rows, img_cols = 28, 28 10 | 11 | 12 | def prep_data(data, train_size): 13 | ''' 14 | :param data: data with both features and labels 15 | :param train_size: no. of examples in training data 16 | :return: X, y 17 | ''' 18 | x = data[0] 19 | y = data[1] 20 | out_y = keras.utils.to_categorical(y, num_classes) 21 | out_x = x.reshape(train_size, img_rows, img_cols, 1) 22 | return out_x, out_y 23 | 24 | 25 | # creating weights folder if deleted 26 | if os.path.isdir('weights') == False: 27 | os.mkdir('weights') 28 | 29 | # list of filename of the weights and saved model 30 | weights_files = os.listdir('weights') 31 | weights_files = sorted(weights_files) 32 | # files that should be there to load the models 33 | correct_files = ['LR_params.npy', 'cnn_accuracy.npy', 'cnn_model.json', 'cnn_weights.h5'] 34 | 35 | if weights_files == correct_files: 36 | # loading the LR weights 37 | LR_params = np.load('weights/LR_params.npy') 38 | # loading the cnn model using json 39 | CNN_acc = np.load('weights/cnn_accuracy.npy') 40 | json_file = open('weights/cnn_model.json', 'r') 41 | model = json_file.read() 42 | json_file.close() 43 | model_conv = keras.models.model_from_json(model) 44 | # loading the cnn weights into the models 45 | model_conv.load_weights('weights/cnn_weights.h5') 46 | # printing LR saved models parameters 47 | print('Trained Logistic Regression') 48 | print("Logistic Regression Train accuracy : ", LR_params.item().get('train_accuracy')) 49 | print("Logistic Regression Test accuracy : {}%".format(LR_params.item().get('test_accuracy'))) 50 | print("Training size : {}, alpha : {}, iterations : {}\n\n".format(LR_params.item().get('train_size'), 51 | LR_params.item().get('alpha'), LR_params.item().get('iters'))) 52 | # printing CNN saved models parameters 53 | print('Trained Convolution Neural Network') 54 | print('Train accuracy : ', CNN_acc.item().get('train_accuracy')) 55 | print('Test accuracy : ', CNN_acc.item().get('test_accuracy')) 56 | print('No. of epochs used = ', CNN_acc.item().get('epoch')) 57 | else: 58 | # loading the MNIST dataset 59 | mnist = input_data.read_data_sets("data/", one_hot=False) 60 | train_size, test_size = 8000, 1000 61 | train_data = mnist.train.next_batch(train_size) 62 | test_data = mnist.test.next_batch(test_size) 63 | 64 | # preparing training and test data 65 | train_x, train_y = prep_data(train_data, train_size) 66 | test_x, test_y = prep_data(test_data, test_size) 67 | 68 | # training and testing LR model 69 | LR_params = LRmodel.model(train_x, train_y, test_x, test_y, 70 | iters=2000, alpha=0.1, print_cost=True) 71 | # training and testing CNN model 72 | model_conv, CNN_accuracy = conv_network.model(train_x, train_y, 73 | test_x, test_y, epoch=8) 74 | np.save('weights/LR_params.npy', LR_params) 75 | np.save('weights/cnn_accuracy.npy', CNN_accuracy) 76 | # converting model to json 77 | json_model = model_conv.to_json() 78 | # saving the json model 79 | with open('weights/cnn_model.json', 'w') as json_file: 80 | json_file.write(json_model) 81 | # saving weights of the cnn models 82 | model_conv.save_weights('weights/cnn_weights.h5') 83 | -------------------------------------------------------------------------------- /input_data.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | """Functions for downloading and reading MNIST data.""" 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | # pylint: disable=unused-import 22 | import gzip 23 | import os 24 | import tempfile 25 | 26 | import numpy 27 | from six.moves import urllib 28 | from six.moves import xrange # pylint: disable=redefined-builtin 29 | import tensorflow as tf 30 | from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets 31 | # pylint: enable=unused-import 32 | -------------------------------------------------------------------------------- /sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/sample.gif -------------------------------------------------------------------------------- /softmax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/softmax.png -------------------------------------------------------------------------------- /weights/LR_params.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/weights/LR_params.npy -------------------------------------------------------------------------------- /weights/cnn_accuracy.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/weights/cnn_accuracy.npy -------------------------------------------------------------------------------- /weights/cnn_model.json: -------------------------------------------------------------------------------- 1 | {"class_name": "Sequential", "config": [{"class_name": "Conv2D", "config": {"name": "conv2d_1", "trainable": true, "batch_input_shape": [null, 28, 28, 1], "dtype": "float32", "filters": 12, "kernel_size": [3, 3], "strides": [1, 1], "padding": "valid", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Conv2D", "config": {"name": "conv2d_2", "trainable": true, "dtype": "float32", "filters": 12, "kernel_size": [3, 3], "strides": [1, 1], "padding": "valid", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Conv2D", "config": {"name": "conv2d_3", "trainable": true, "dtype": "float32", "filters": 12, "kernel_size": [3, 3], "strides": [1, 1], "padding": "valid", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true, "dtype": "float32"}}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 100, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 10, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}], "keras_version": "2.1.2-tf", "backend": "tensorflow"} -------------------------------------------------------------------------------- /weights/cnn_weights.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliakbar09a/mnist_digits_classification/1af51d775ea7ac78cced8fecc27a2b333c48d5d9/weights/cnn_weights.h5 --------------------------------------------------------------------------------