# -*- coding: utf-8 -*-
"""HW3

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1SG0q85xrJVcfb4uZ9qKiNluZd-gZx12i
"""

import sys
import pandas as pd
import numpy as np
import math
from math import sqrt
from numpy import genfromtxt
from numpy import savetxt
import time


class ReaderFuncs:
  filename = ''
  def __init__(self, filename):
    self.filename = filename

  def reader_data(self):
    #header = [str(i) for i in range(28*28)]
    #header.append("Target")
    dataframe = pd.read_csv(self.filename, sep=',', header=None)
    #return dataframe.drop('Target'), dataframe['Target']
    return dataframe
  
  def reader_labels(self):
    dataframe = pd.read_csv(self.filename, sep=',', header=None)
    return dataframe
  
  def reader_data_np(self):
      my_data = genfromtxt(self.filename, delimiter=',')
      return my_data

  def reader_labels_np(self):
    my_data = genfromtxt(self.filename, delimiter=',')
    return my_data

class WriterFuncs:
  filename = ''
  def __init__(self, filename):
    self.filename = filename

  def write_labels(self, answer):
    answer_int = answer.astype(int)
    dataframe = pd.DataFrame(answer_int)
    dataframe.to_csv(self.filename, sep=',', encoding='utf-8',  index=False, header=False)
  
  def write_labels_np(self, answer):
    answer_int = answer.astype(int)
    savetxt(self.filename, answer_int, delimiter=",")
    

class FCC:
  param = {}
  hist =  {}
  update = {}
  layers_dims = []
  Num_Layers = 0
  Input_Size = 786
  Alpha0 = 0.001
  Alpha1 = 0.001 
  Decay_Rate = 0.001
  Epochs = 150
  def __init__(self, Alpha, Num_Layers, layers_dim, Input_Size=28*28, Decay_Rate=0.05, Epochs = 50):
    #self.layers_dims[0]  = Input_Size
    self.Num_Layers = Num_Layers
    self.layers_dims = layers_dim
    self.Input_Size = Input_Size
    self.Alpha0 = Alpha
    self.Alpha1 = Alpha
    self.Decay_Rate = Decay_Rate
    self.Epochs = Epochs

  def create_layer(self, layer_num):
    #Xaviers Intitialization
    init_w = np.random.randn(self.layers_dims[layer_num],self.layers_dims[layer_num-1])
    self.param["W"+str(layer_num)] = init_w/sqrt(self.layers_dims[layer_num])
    init_b = np.random.randn(self.layers_dims[layer_num],1)
    self.param["B"+str(layer_num)] = init_b/sqrt(self.layers_dims[layer_num])

  def set_initial_input(self, input):
    self.hist["OUT"+str(0)] = input

  def sigmoid_activation_func(self, z):
    act = 1.0/(1.0 + np.exp(-z))
    return act

  def single_forward_pass_sigmoid(self, inputs, layer_num):
    net = np.dot(self.param["W"+str(layer_num)], inputs) + self.param['B'+str(layer_num)]
    out = self.sigmoid_activation_func(net)
    self.hist["OUT"+str(layer_num)] = out
    self.hist["W"+str(layer_num)] = self.param["W"+str(layer_num)]
    self.hist["NET"+str(layer_num)] = net
    return out
  
  def softmax_activation_func(self, net):
    inter = np.exp(net - np.max(net))
    ans = inter / inter.sum(axis=0, keepdims=True)
    return ans
  
  def single_forward_pass_softmax(self, inputs, layer_num):
    net = np.dot(self.param["W"+str(layer_num)], inputs) + self.param['B'+str(layer_num)]
    out = self.softmax_activation_func(net)
    self.hist["OUT"+str(layer_num)] = out
    self.hist["W"+str(layer_num)] = self.param["W"+str(layer_num)]
    self.hist["NET"+str(layer_num)] = net
    return out

  def complete_forward(self, inputs):
    curr_input = inputs.T
    self.Input_Size = inputs.shape[0]
    #print("Input Size: " + str(self.Input_Size))
    self.hist["OUT0"] = curr_input
    for i in range(1, self.Num_Layers):
      curr_input = self.single_forward_pass_sigmoid(curr_input, i)
    
    final_op = self.single_forward_pass_softmax(curr_input, self.Num_Layers)
    return final_op

  def derivate_sigmoid(self, inputs):
    inter = 1. / (1. + np.exp(-inputs))
    ans  = inter * (1. - inter)
    return ans
    
  def single_backward_pass_sigmoid(self, layer_num, prev):
    curr_derivative = self.derivate_sigmoid(self.hist["NET" + str(layer_num)])
    update_derivative = prev * curr_derivative
    update_dw = (1. / float(self.Input_Size)) * (np.dot(update_derivative, self.hist["OUT"+ str(layer_num-1)].T)) #Should this be -1 or +1
    update_db = (1. / float(self.Input_Size)) * (np.sum(update_derivative, axis=1, keepdims=True))
    if int(layer_num) > 1:
      #print("Comes here")
      prev = np.dot(self.hist["W" + str(layer_num)].T, update_derivative)

    self.update["dW" + str(layer_num)] = update_dw
    self.update["dB" + str(layer_num)] = update_db

    return prev

  def single_backward_pass_softmax(self, actual, target, layer_num):
    target_inv  = target.T
    loss  = - ( target_inv - actual)
    prev = 1.
    update_derivative = prev * loss
    update_dw = (1. / float(self.Input_Size)) * (np.dot(update_derivative, self.hist["OUT"+ str(layer_num-1)].T)) #Should this be -1 or +1 
    update_db = (1. / float(self.Input_Size)) * (np.sum(update_derivative, axis=1, keepdims=True))
    prev = np.dot(self.hist["W" + str(layer_num)].T, update_derivative)

    self.update["dW" + str(layer_num)] = update_dw
    self.update["dB" + str(layer_num)] = update_db

    return prev
    
  def complete_backward(self, actual, target):
    #self.hist["A0"] = 
    prev = self.single_backward_pass_softmax(actual, target, self.Num_Layers)
    for i in range(self.Num_Layers-1, 0, -1):
      prev  = self.single_backward_pass_sigmoid(i, prev)
    return

  def upadate_weights_backprop(self):
    #print(self.param.keys())
    for inx, val in self.param.items():
      self.param[inx]  = val - self.Alpha1 * self.update['d'+str(inx)]
      
      #Debugging Step
      #print(inx)
      #print(self.param[str(inx)])
    return
  
  def new_training_sess(self):
    self.hist = {}
    self.update = {}
    return

  def decay_learning_rate(self, epoch):
    self.Alpha1 = ((1.)/(1. + self.Decay_Rate * epoch)) * self.Alpha0
    return

  def create_batches(self, inputs, targets, batchsize):
    #assert inputs.shape[0] == targets.shape[0]
    indices = np.arange(inputs.shape[0])
    np.random.shuffle(indices)
    for start_idx in range(0, inputs.shape[0], batchsize):
      end_idx = min(start_idx + batchsize, inputs.shape[0])
      extract = indices[start_idx:end_idx]
      yield inputs[extract], targets[extract]


  def training(self, inputs, target, test_inputs, test_targets):
    # Get ACTUAL from forward and pass it to backward
    # Target is passed directly to backward pass
    # Call update weights then
    np.random.seed(100)
    for layer_num in range(len(self.layers_dims)-1):
      self.create_layer(layer_num + 1)
    
    start_time  = time.time()
    for epoch in range(self.Epochs):
        print(str(epoch))
        for batch in self.create_batches(inputs, target, 16):
            self.new_training_sess()
            batch_inputs, batch_target = batch
            final_ans  = self.complete_forward(batch_inputs)
            self.complete_backward(final_ans, batch_target)
            self.upadate_weights_backprop()
            """self.new_training_sess()
          final_ans  = self.complete_forward(inputs)
          self.complete_backward(final_ans, target)
          self.upadate_weights_backprop()"""
        if epoch % 10 == 0:
            self.decay_learning_rate(epoch)
            print(self.Alpha1)
            #if epoch % 10 == 0:
        print("Time taken till now:"+str((time.time()-start_time)/60.0))
        self.find_accuracy(inputs, target)
    return 

  def find_accuracy(self, X, Y):
      A = self.complete_forward(X)
      y_hat = np.argmax(A, axis=0)
      Y = np.argmax(Y, axis=1)
      accuracy = (y_hat == Y).mean()
      print("Accuracy:" + str(accuracy*100))

  def predict(self, single_input):
    pred = self.complete_forward(single_input)
    final_inx = np.argmax(pred, axis=0)
    #final_val = np.max(Y, axis=1)
    #accuracy = (y == Y).mean()
    return final_inx

  def predict_all(self, inputs):
    predictions = []
    for single_input in inputs:
      predictions.append(self.predict(single_input))
    return predictions
  """
  def find_accuracy(self, inputs, target):
      pred = self.forward(inputs)
      final_inx = np.argmax(pred, axis=0)
      target_inx = np.argmax(targets, axis=1)
      accuracy = (final_inx == target_inx).mean()
      return final_inx
 """

def one_hot_encoder(target):
  ans = [] 
  for ele in target:
    temp = [0] * 10
    temp[int(ele[0])] = 1
    ans.append(np.array(temp))
  np_ans = np.array(ans)
  return np_ans.reshape(len(np_ans), -1)

def process_input(inputs, target):
  #inputs  = inputs.reshape((len(inputs), -1))
  #target  = target.reshape((len(inputs), -1))
  inputs = inputs / 255.0
  # ONE Hot Encoding of the iutput occurs here
  one_hot_op = np.array([])
  if len(target) > 0:
    one_hot_op = one_hot_encoder(target)
  return inputs, one_hot_op

def predict_all(mnist, inputs):
  ans = []
  mnist.predict(inputs)
  #for single_input in inputs:
    #ans.append(mnist.predict(single_input))
  return ans

def create_layers():
  layer = []
  layer.append(28*28)
  # Hidden Layers and their size come here.
  #layer.append(512)
  #layer.append(256)
  #layer.append(200)
  layer.append(128)
  layer.append(64)
  #layer.append(500)
  #layer.append(250)
  #layer.append(50)
  #layer.append(32)
  #layer.append(32)
  #layer.append(16)
  #layer.append(40)
  #layer.append(30)
  #layer.append(20)
  layer.append(10)
  return layer

#def read_files():
  #pass

def runner(train_data_input_file, train_labels_input_file, test_data_input_file, output_file):
  tdif = ReaderFuncs(train_data_input_file)
  tlif = ReaderFuncs(train_labels_input_file)

  #t_input = tdif.reader_data_np()
  #t_target = tlif.reader_labels_np()

  t_input = tdif.reader_data().values
  t_target = tlif.reader_labels().values

  t_input, t_target = process_input(t_input, t_target)
  #print(t_input.shape)
  #print(t_target.shape)

  #For Testing Purposes Remove test_dif_target in final submission
  #test_dif = ReaderFuncs(test_data_input_file)  
  #test_input = test_dif.reader_data().values

  #test_dif_target = ReaderFuncs(output_file)
  #test_target = test_dif_target.reader_labels().values
  
  #test_input = test_dif.reader_data_np()
  #test_target = test_dif_target.reader_labels_np()

  test_input = np.array([])
  test_target = np.array([])

  #test_input, test_target  = process_input(test_input, test_target)
  #print(test_input.shape)
  #print(test_target.shape)



  #All the HyperParameters come here!
  layers_dim = create_layers()
  Num_Layers = len(layers_dim) - 1
  Alpha  = 0.005

  fc = FCC(Alpha, Num_Layers, layers_dim)
  fc.training(t_input, t_target, test_input, test_target)

  test_dif = ReaderFuncs(test_data_input_file)
  test_input = test_dif.reader_data().values
  test_input, _ = process_input(test_input, [])
  answer = fc.predict(test_input)

  test_ops  = WriterFuncs(output_file)
  test_ops.write_labels(answer)
  return
#python3 NeuralNetwork.py train_image.csv train_label.csv test_image.csv
# For Submission purposes
if __name__ == "__main__":
  # For Actual Model
  train_data_input_file = str(sys.argv[1])
  train_labels_input_file = str(sys.argv[2])
  test_data_input_file = str(sys.argv[3])
  output_file = str("test_predictions.csv")
  
  # For testing on collab
  
  """# For testing on Local
  train_data_input_file = str("train_image.csv")
  train_labels_input_file = str("train_label.csv")
  test_data_input_file = str("test_image.csv")"""

  runner(train_data_input_file, train_labels_input_file, test_data_input_file, output_file)
# -*- coding: utf-8 -*-
"""HW3

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1SG0q85xrJVcfb4uZ9qKiNluZd-gZx12i
"""

import sys
import pandas as pd
import numpy as np
import math
from math import sqrt
from numpy import genfromtxt
from numpy import savetxt
import time


class ReaderFuncs:
  filename = ''
  def __init__(self, filename):
    self.filename = filename

  def reader_data(self):
    #header = [str(i) for i in range(28*28)]
    #header.append("Target")
    dataframe = pd.read_csv(self.filename, sep=',', header=None)
    #return dataframe.drop('Target'), dataframe['Target']
    return dataframe
  
  def reader_labels(self):
    dataframe = pd.read_csv(self.filename, sep=',', header=None)
    return dataframe
  
  def reader_data_np(self):
      my_data = genfromtxt(self.filename, delimiter=',')
      return my_data

  def reader_labels_np(self):
    my_data = genfromtxt(self.filename, delimiter=',')
    return my_data

class WriterFuncs:
  filename = ''
  def __init__(self, filename):
    self.filename = filename

  def write_labels(self, answer):
    answer_int = answer.astype(int)
    dataframe = pd.DataFrame(answer_int)
    dataframe.to_csv(self.filename, sep=',', encoding='utf-8',  index=False, header=False)
  
  def write_labels_np(self, answer):
    answer_int = answer.astype(int)
    savetxt(self.filename, answer_int, delimiter=",")
    

class FCC:
  param = {}
  hist =  {}
  update = {}
  layers_dims = []
  Num_Layers = 0
  Input_Size = 786
  Alpha0 = 0.001
  Alpha1 = 0.001 
  Decay_Rate = 0.001
  Epochs = 150
  def __init__(self, Alpha, Num_Layers, layers_dim, Input_Size=28*28, Decay_Rate=0.05, Epochs = 50):
    #self.layers_dims[0]  = Input_Size
    self.Num_Layers = Num_Layers
    self.layers_dims = layers_dim
    self.Input_Size = Input_Size
    self.Alpha0 = Alpha
    self.Alpha1 = Alpha
    self.Decay_Rate = Decay_Rate
    self.Epochs = Epochs

  def create_layer(self, layer_num):
    #Xaviers Intitialization
    init_w = np.random.randn(self.layers_dims[layer_num],self.layers_dims[layer_num-1])
    self.param["W"+str(layer_num)] = init_w/sqrt(self.layers_dims[layer_num])
    init_b = np.random.randn(self.layers_dims[layer_num],1)
    self.param["B"+str(layer_num)] = init_b/sqrt(self.layers_dims[layer_num])

  def set_initial_input(self, input):
    self.hist["OUT"+str(0)] = input

  def sigmoid_activation_func(self, z):
    act = 1.0/(1.0 + np.exp(-z))
    return act

  def single_forward_pass_sigmoid(self, inputs, layer_num):
    net = np.dot(self.param["W"+str(layer_num)], inputs) + self.param['B'+str(layer_num)]
    out = self.sigmoid_activation_func(net)
    self.hist["OUT"+str(layer_num)] = out
    self.hist["W"+str(layer_num)] = self.param["W"+str(layer_num)]
    self.hist["NET"+str(layer_num)] = net
    return out
  
  def softmax_activation_func(self, net):
    inter = np.exp(net - np.max(net))
    ans = inter / inter.sum(axis=0, keepdims=True)
    return ans
  
  def single_forward_pass_softmax(self, inputs, layer_num):
    net = np.dot(self.param["W"+str(layer_num)], inputs) + self.param['B'+str(layer_num)]
    out = self.softmax_activation_func(net)
    self.hist["OUT"+str(layer_num)] = out
    self.hist["W"+str(layer_num)] = self.param["W"+str(layer_num)]
    self.hist["NET"+str(layer_num)] = net
    return out

  def complete_forward(self, inputs):
    curr_input = inputs.T
    self.Input_Size = inputs.shape[0]
    #print("Input Size: " + str(self.Input_Size))
    self.hist["OUT0"] = curr_input
    for i in range(1, self.Num_Layers):
      curr_input = self.single_forward_pass_sigmoid(curr_input, i)
    
    final_op = self.single_forward_pass_softmax(curr_input, self.Num_Layers)
    return final_op

  def derivate_sigmoid(self, inputs):
    inter = 1. / (1. + np.exp(-inputs))
    ans  = inter * (1. - inter)
    return ans
    
  def single_backward_pass_sigmoid(self, layer_num, prev):
    curr_derivative = self.derivate_sigmoid(self.hist["NET" + str(layer_num)])
    update_derivative = prev * curr_derivative
    update_dw = (1. / float(self.Input_Size)) * (np.dot(update_derivative, self.hist["OUT"+ str(layer_num-1)].T)) #Should this be -1 or +1
    update_db = (1. / float(self.Input_Size)) * (np.sum(update_derivative, axis=1, keepdims=True))
    if int(layer_num) > 1:
      #print("Comes here")
      prev = np.dot(self.hist["W" + str(layer_num)].T, update_derivative)

    self.update["dW" + str(layer_num)] = update_dw
    self.update["dB" + str(layer_num)] = update_db

    return prev

  def single_backward_pass_softmax(self, actual, target, layer_num):
    target_inv  = target.T
    loss  = - ( target_inv - actual)
    prev = 1.
    update_derivative = prev * loss
    update_dw = (1. / float(self.Input_Size)) * (np.dot(update_derivative, self.hist["OUT"+ str(layer_num-1)].T)) #Should this be -1 or +1 
    update_db = (1. / float(self.Input_Size)) * (np.sum(update_derivative, axis=1, keepdims=True))
    prev = np.dot(self.hist["W" + str(layer_num)].T, update_derivative)

    self.update["dW" + str(layer_num)] = update_dw
    self.update["dB" + str(layer_num)] = update_db

    return prev
    
  def complete_backward(self, actual, target):
    #self.hist["A0"] = 
    prev = self.single_backward_pass_softmax(actual, target, self.Num_Layers)
    for i in range(self.Num_Layers-1, 0, -1):
      prev  = self.single_backward_pass_sigmoid(i, prev)
    return

  def upadate_weights_backprop(self):
    #print(self.param.keys())
    for inx, val in self.param.items():
      self.param[inx]  = val - self.Alpha1 * self.update['d'+str(inx)]
      
      #Debugging Step
      #print(inx)
      #print(self.param[str(inx)])
    return
  
  def new_training_sess(self):
    self.hist = {}
    self.update = {}
    return

  def decay_learning_rate(self, epoch):
    self.Alpha1 = ((1.)/(1. + self.Decay_Rate * epoch)) * self.Alpha0
    return

  def create_batches(self, inputs, targets, batchsize):
    #assert inputs.shape[0] == targets.shape[0]
    indices = np.arange(inputs.shape[0])
    np.random.shuffle(indices)
    for start_idx in range(0, inputs.shape[0], batchsize):
      end_idx = min(start_idx + batchsize, inputs.shape[0])
      extract = indices[start_idx:end_idx]
      yield inputs[extract], targets[extract]


  def training(self, inputs, target, test_inputs, test_targets):
    # Get ACTUAL from forward and pass it to backward
    # Target is passed directly to backward pass
    # Call update weights then
    np.random.seed(100)
    for layer_num in range(len(self.layers_dims)-1):
      self.create_layer(layer_num + 1)
    
    start_time  = time.time()
    for epoch in range(self.Epochs):
        print(str(epoch))
        for batch in self.create_batches(inputs, target, 16):
            self.new_training_sess()
            batch_inputs, batch_target = batch
            final_ans  = self.complete_forward(batch_inputs)
            self.complete_backward(final_ans, batch_target)
            self.upadate_weights_backprop()
            """self.new_training_sess()
          final_ans  = self.complete_forward(inputs)
          self.complete_backward(final_ans, target)
          self.upadate_weights_backprop()"""
        if epoch % 10 == 0:
            self.decay_learning_rate(epoch)
            print(self.Alpha1)
            #if epoch % 10 == 0:
        print("Time taken till now:"+str((time.time()-start_time)/60.0))
        self.find_accuracy(inputs, target)
    return 

  def find_accuracy(self, X, Y):
      A = self.complete_forward(X)
      y_hat = np.argmax(A, axis=0)
      Y = np.argmax(Y, axis=1)
      accuracy = (y_hat == Y).mean()
      print("Accuracy:" + str(accuracy*100))

  def predict(self, single_input):
    pred = self.complete_forward(single_input)
    final_inx = np.argmax(pred, axis=0)
    #final_val = np.max(Y, axis=1)
    #accuracy = (y == Y).mean()
    return final_inx

  def predict_all(self, inputs):
    predictions = []
    for single_input in inputs:
      predictions.append(self.predict(single_input))
    return predictions
  """
  def find_accuracy(self, inputs, target):
      pred = self.forward(inputs)
      final_inx = np.argmax(pred, axis=0)
      target_inx = np.argmax(targets, axis=1)
      accuracy = (final_inx == target_inx).mean()
      return final_inx
 """

def one_hot_encoder(target):
  ans = [] 
  for ele in target:
    temp = [0] * 10
    temp[int(ele[0])] = 1
    ans.append(np.array(temp))
  np_ans = np.array(ans)
  return np_ans.reshape(len(np_ans), -1)

def process_input(inputs, target):
  #inputs  = inputs.reshape((len(inputs), -1))
  #target  = target.reshape((len(inputs), -1))
  inputs = inputs / 255.0
  # ONE Hot Encoding of the iutput occurs here
  one_hot_op = np.array([])
  if len(target) > 0:
    one_hot_op = one_hot_encoder(target)
  return inputs, one_hot_op

def predict_all(mnist, inputs):
  ans = []
  mnist.predict(inputs)
  #for single_input in inputs:
    #ans.append(mnist.predict(single_input))
  return ans

def create_layers():
  layer = []
  layer.append(28*28)
  # Hidden Layers and their size come here.
  #layer.append(512)
  #layer.append(256)
  #layer.append(200)
  layer.append(128)
  layer.append(64)
  #layer.append(500)
  #layer.append(250)
  #layer.append(50)
  #layer.append(32)
  #layer.append(32)
  #layer.append(16)
  #layer.append(40)
  #layer.append(30)
  #layer.append(20)
  layer.append(10)
  return layer

#def read_files():
  #pass

def runner(train_data_input_file, train_labels_input_file, test_data_input_file, output_file):
  tdif = ReaderFuncs(train_data_input_file)
  tlif = ReaderFuncs(train_labels_input_file)

  #t_input = tdif.reader_data_np()
  #t_target = tlif.reader_labels_np()

  t_input = tdif.reader_data().values
  t_target = tlif.reader_labels().values

  t_input, t_target = process_input(t_input, t_target)
  #print(t_input.shape)
  #print(t_target.shape)

  #For Testing Purposes Remove test_dif_target in final submission
  #test_dif = ReaderFuncs(test_data_input_file)  
  #test_input = test_dif.reader_data().values

  #test_dif_target = ReaderFuncs(output_file)
  #test_target = test_dif_target.reader_labels().values
  
  #test_input = test_dif.reader_data_np()
  #test_target = test_dif_target.reader_labels_np()

  test_input = np.array([])
  test_target = np.array([])

  #test_input, test_target  = process_input(test_input, test_target)
  #print(test_input.shape)
  #print(test_target.shape)



  #All the HyperParameters come here!
  layers_dim = create_layers()
  Num_Layers = len(layers_dim) - 1
  Alpha  = 0.005

  fc = FCC(Alpha, Num_Layers, layers_dim)
  fc.training(t_input, t_target, test_input, test_target)

  test_dif = ReaderFuncs(test_data_input_file)
  test_input = test_dif.reader_data().values
  test_input, _ = process_input(test_input, [])
  answer = fc.predict(test_input)

  test_ops  = WriterFuncs(output_file)
  test_ops.write_labels(answer)
  return
#python3 NeuralNetwork.py train_image.csv train_label.csv test_image.csv
# For Submission purposes
if __name__ == "__main__":
  # For Actual Model
  train_data_input_file = str(sys.argv[1])
  train_labels_input_file = str(sys.argv[2])
  test_data_input_file = str(sys.argv[3])
  output_file = str("test_predictions.csv")
  
  # For testing on collab
  
  """# For testing on Local
  train_data_input_file = str("train_image.csv")
  train_labels_input_file = str("train_label.csv")
  test_data_input_file = str("test_image.csv")"""

  runner(train_data_input_file, train_labels_input_file, test_data_input_file, output_file)
# -*- coding: utf-8 -*- HW3  Automatically generated by Colaboratory.  Original file is located at     https://colab.research.google.com/drive/1SG0q85xrJVcfb4uZ9qKiNluZd-gZx12i #header = [str(i) for i in range(28*28)] #header.append("Target") #return dataframe.drop('Target'), dataframe['Target'] #self.layers_dims[0]  = Input_Size #Xaviers Intitialization #print("Input Size: " + str(self.Input_Size)) #Should this be -1 or +1 #print("Comes here") #Should this be -1 or +1 #self.hist["A0"] = #print(self.param.keys()) #Debugging Step #print(inx) #print(self.param[str(inx)]) #assert inputs.shape[0] == targets.shape[0] # Get ACTUAL from forward and pass it to backward # Target is passed directly to backward pass # Call update weights then self.new_training_sess()           final_ans  = self.complete_forward(inputs)           self.complete_backward(final_ans, target)           self.upadate_weights_backprop() #if epoch % 10 == 0: #final_val = np.max(Y, axis=1) #accuracy = (y == Y).mean() def find_accuracy(self, inputs, target):       pred = self.forward(inputs)       final_inx = np.argmax(pred, axis=0)       target_inx = np.argmax(targets, axis=1)       accuracy = (final_inx == target_inx).mean()       return final_inx #inputs  = inputs.reshape((len(inputs), -1)) #target  = target.reshape((len(inputs), -1)) # ONE Hot Encoding of the iutput occurs here #for single_input in inputs: #ans.append(mnist.predict(single_input)) # Hidden Layers and their size come here. #layer.append(512) #layer.append(256) #layer.append(200) #layer.append(500) #layer.append(250) #layer.append(50) #layer.append(32) #layer.append(32) #layer.append(16) #layer.append(40) #layer.append(30) #layer.append(20) #def read_files(): #pass #t_input = tdif.reader_data_np() #t_target = tlif.reader_labels_np() #print(t_input.shape) #print(t_target.shape) #For Testing Purposes Remove test_dif_target in final submission #test_dif = ReaderFuncs(test_data_input_file) #test_input = test_dif.reader_data().values #test_dif_target = ReaderFuncs(output_file) #test_target = test_dif_target.reader_labels().values #test_input = test_dif.reader_data_np() #test_target = test_dif_target.reader_labels_np() #test_input, test_target  = process_input(test_input, test_target) #print(test_input.shape) #print(test_target.shape) #All the HyperParameters come here! #python3 NeuralNetwork.py train_image.csv train_label.csv test_image.csv # For Submission purposes # For Actual Model # For testing on collab # For testing on Local   train_data_input_file = str("train_image.csv")   train_labels_input_file = str("train_label.csv")   test_data_input_file = str("test_image.csv")