<jupyter_start><jupyter_text><jupyter_code>import urllib.request
import gzip
import numpy as np
import matplotlib
import os
from scipy.stats import truncnorm
# matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

def load_dataset():
  """
	image_size = 28 
	image_pixels = image_size * image_size
  """
  def download(filename, source = "http://yann.lecun.com/exdb/mnist/"):
    print("downloading ", filename)
    urllib.request.urlretrieve(source+filename, filename)
  
  def load_mnist_images(filename):
    if not os.path.exists(filename):
      download(filename)
    with gzip.open(filename,'rb') as f:
      data = np.frombuffer(f.read(), np.uint8, offset=16)
      data = data.reshape(-1, 1, 28, 28)        
      return data/np.float32(256)
  
  def load_mnist_labels(filename):
    if not os.path.exists(filename):
      download(filename)
    with gzip.open(filename,'rb') as f:
      data = np.frombuffer(f.read(), np.uint8, offset=8)
      # data = data.reshape(-1, 1, 28, 28)
      return data
  
  X_train = load_mnist_images('train-images-idx3-ubyte.gz')
  Y_train = load_mnist_labels('train-labels-idx1-ubyte.gz')
  X_test = load_mnist_images('t10k-images-idx3-ubyte.gz')
  Y_test = load_mnist_labels('t10k-labels-idx1-ubyte.gz')
  # plt.show(plt.imshow(X_train[1][0]))
  return X_train, Y_train, X_test, Y_test

X_train,Y_train,X_test,Y_test = load_dataset()
print("Dataset loaded.")

training = np.array(X_train)
result = training.reshape([60000, 1,1,784])
X_train = result.reshape([60000,784])

testing = np.array(X_test)
result = testing.reshape([10000,1,1,784])
X_test = result.reshape([10000,784])

Y_test = Y_test.reshape([-1,1])
Y_train = Y_train.reshape([-1,1])

X_train = np.asfarray(X_train)
Y_train = np.asfarray(Y_train)
X_test = np.asfarray(X_test)
Y_test = np.asfarray(Y_test)

no_of_different_labels = 10 
#  i.e. 0, 1, 2, 3, ..., 9

lr = np.arange(no_of_different_labels)

# transform labels into one hot representation
train_labels_one_hot = (lr==Y_train).astype(np.float)
test_labels_one_hot = (lr==Y_test).astype(np.float)


# we don't want zeroes and ones in the labels neither:
train_labels_one_hot[train_labels_one_hot==0] = 0.01
train_labels_one_hot[train_labels_one_hot==1] = 0.99
test_labels_one_hot[test_labels_one_hot==0] = 0.01
test_labels_one_hot[test_labels_one_hot==1] = 0.99

@np.vectorize
def sigmoid(x):
    return 1 / (1 + np.e ** -x)

def sigmoidPrime(x):
    return x * (1 - x)

activation_function = sigmoid

def truncated_normal(mean=0, sd=1, low=0, upp=10):
    return truncnorm((low - mean) / sd, 
                     (upp - mean) / sd, 
                     loc=mean, 
                     scale=sd)

def print_status(status):
    if status:
        return "Correct"
    return "Wrong"


class NeuralNetwork:
    
    def __init__(self, 
                 no_of_in_nodes, 
                 no_of_out_nodes, 
                 no_of_hidden_nodes,
                 learning_rate):
        self.no_of_in_nodes = no_of_in_nodes
        self.no_of_out_nodes = no_of_out_nodes
        self.no_of_hidden_nodes = no_of_hidden_nodes
        self.learning_rate = learning_rate 
        self.create_weight_matrices()
        
    def create_weight_matrices(self):
        """ 
        A method to initialize the weight 
        matrices of the neural network
        """
        rad = 1 / np.sqrt(self.no_of_in_nodes)
        X = truncated_normal(mean=0, sd=1, low=-rad, upp=rad)
        self.wih = X.rvs((self.no_of_hidden_nodes, self.no_of_in_nodes))
        rad = 1 / np.sqrt(self.no_of_hidden_nodes)
        X = truncated_normal(mean=0, sd=1, low=-rad, upp=rad)
        self.who = X.rvs((self.no_of_out_nodes, self.no_of_hidden_nodes))

        #self.wih = np.zeros([self.no_of_hidden_nodes,self.no_of_in_nodes])
        #self.who = np.zeros([self.no_of_out_nodes, self.no_of_hidden_nodes])
        
    
    def train(self, input_vector, target_vector):
        """
        input_vector and target_vector can 
        be tuple, list or ndarray
        """
        input_vector = np.array(input_vector, ndmin=2).T
        target_vector = np.array(target_vector, ndmin=2).T
        
        output_vector1 = np.dot(self.wih, input_vector)
        output_hidden = activation_function(output_vector1)
        
        output_vector2 = np.dot(self.who, output_hidden)
        output_network = activation_function(output_vector2)
        
        output_errors = target_vector - output_network
        
        # update the weights:
        tmp = output_errors * output_network * (1.0 - output_network)     
        tmp = self.learning_rate  * np.dot(tmp, output_hidden.T)
        self.who += tmp

        # calculate hidden errors:
        hidden_errors = np.dot(self.who.T, output_errors)
        # update the weights:
        tmp = hidden_errors * output_hidden * (1.0 - output_hidden)
        self.wih += self.learning_rate * np.dot(tmp, input_vector.T)
        
    def run(self, input_vector):
        # input_vector can be tuple, list or ndarray
        input_vector = np.array(input_vector, ndmin=2).T
        output_vector = np.dot(self.wih, input_vector)
        output_vector = activation_function(output_vector)
        output_vector = np.dot(self.who, output_vector)
        output_vector = activation_function(output_vector)
    
        return output_vector
            
    def evaluate(self, data, labels):
        corrects, wrongs = 0, 0
        for i in range(len(data)):
            res = self.run(data[i])
            res_max = res.argmax()
            if res_max == labels[i]:
                corrects += 1
            else:
                wrongs += 1
        return corrects, wrongs
ANN = NeuralNetwork(no_of_in_nodes = image_pixels, 
                    no_of_out_nodes = 10, 
                    no_of_hidden_nodes = 100,
                    learning_rate = 0.1)
  
# Train the neural network 

for i in range(len(X_train)):
    ANN.train(X_train[i], train_labels_one_hot[i])
print("="*70)
print("Actual_Output ", "Predicted_Output  ", "Probability              " ,"Status")
print("="*70)

for i in range(20):
    res = ANN.run(X_test[i])
    print(int(Y_test[i][0]),"                     ", np.argmax(res),"     ", np.max(res),"      ",print_status(int(Y_test[i][0]) == np.argmax(res)) )
    print("-"*70)
# corrects, wrongs = ANN.evaluate(X_train, Y_train)
# print("Accruracy train: ", corrects / ( corrects + wrongs))
corrects, wrongs = ANN.evaluate(X_test, Y_test)
print("Accruracy: ", corrects / ( corrects + wrongs))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.120079644662276, 'fraction_numerical': 0.02190228212589983, 'mean_word_length': 2.7921022067363532, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '38917', 'license': 'MIT', 'n_tokens_mistral': 2418, 'n_tokens_neox': 2295, 'n_words': 424, 'path': 'Assignment-3-NN-implementation-for-handwritten-digit-recognition.ipynb', 'repo_name': 'jatin69/mca507-neural-networks', 'size': '6529'}