0

Here is a neural network I've been working on. It takes in an array of four zeros or ones and predicts whether that pattern of zeros and ones is a backslash.

import numpy as np

class NeuralNetwork():

correct = 0
num_predictions = 10
epochs = 5000
learningRate = 0.1

def __init__(self, sizes, sizeOfEpoch):
    self.sizeOfEpoch = sizeOfEpoch 
    self.dimensions = sizes

    self.secondLayerNeurons = np.empty(sizes[1])
    self.outputNeurons = np.empty(sizes[2])

    self.firstLayerWeights = np.random.rand(sizes[1], sizes[0])
    self.secondLayerWeights = np.random.rand(sizes[2], sizes[1])
    self.firstLayerBiases = np.random.rand(sizes[1])
    self.secondLayerBiases = np.random.rand(sizes[2])

    self.firstLayerWeightsSummations = np.zeros([sizes[1], sizes[0]])
    self.secondLayerWeightsSummations = np.zeros([sizes[2], sizes[1]])
    self.firstLayerBiasesSummations = np.zeros([sizes[1]])
    self.secondLayerBiasesSummations = np.zeros([sizes[2]])

    self.hiddenLayerErrors = np.empty(sizes[1])
    self.outputLayerErrors = np.empty(sizes[2])

def sigmoid(self, x):
    return 1/(1+np.exp(-x))

def sigmoidDerivative(self, x):
    return np.multiply(x,(1-x))

def forwardProp(self, inputs):
    for i in range (self.dimensions[1]):
        self.secondLayerNeurons[i] = self.sigmoid(np.dot(self.firstLayerWeights[i], inputs)+self.firstLayerBiases[i])
    for i in range (self.dimensions[2]):
        self.outputNeurons[i] = self.sigmoid(np.dot(self.secondLayerWeights[i], self.secondLayerNeurons)+self.secondLayerBiases[i])

def backProp(self, inputs, correct_output):
    self.outputLayerErrors = np.subtract(self.outputNeurons, correct_output)
    self.hiddenLayerErrors = np.multiply(np.dot(self.secondLayerWeights.T, self.outputLayerErrors), self.sigmoidDerivative(self.secondLayerNeurons))

    for i in range (self.dimensions[2]):
        for j in range (self.dimensions[1]):
            if j==0:
                self.secondLayerBiasesSummations[i] += self.outputLayerErrors[i]
            self.secondLayerWeightsSummations[i][j] += self.outputLayerErrors[i]*self.secondLayerNeurons[j]
    for i in range (self.dimensions[1]):
        for j in range (self.dimensions[0]):
            if j==0:
                self.firstLayerBiasesSummations[i] += self.hiddenLayerErrors[i]
            self.firstLayerWeightsSummations[i][j] += self.hiddenLayerErrors[i]*inputs[j]

def train(self, trainImages, trainLabels):
    size = str(self.sizeOfEpoch)

    for m in range (self.sizeOfEpoch):
        correct_output = trainLabels[m]

        self.forwardProp(trainImages[m].flatten())
        self.backProp(trainImages[m].flatten(), correct_output)

        if self.outputNeurons > 0.90 and trainLabels[m] == 1 or self.outputNeurons < 0.1 and trainLabels[m] == 0:
            self.correct+=1
        accuracy = str(int((self.correct/(m+1))*100)) + '%'
        percent = str(int((m/self.sizeOfEpoch)*100)) + '%'
        print ("Progress: " + percent + " -- Accuracy: " + accuracy, end="\r")
    self.change()
    self.correct = 0

    print (size+'/'+size+" -- Accuracy: "+accuracy+" -- Error: "+str(np.amax(np.absolute(self.outputLayerErrors))),end="\r")

def change(self):
    self.secondLayerBiases -= self.learningRate*self.secondLayerBiasesSummations
    self.firstLayerBiases -= self.learningRate*self.firstLayerBiasesSummations
    self.secondLayerWeights -= self.learningRate*self.secondLayerWeightsSummations
    self.firstLayerWeights -= self.learningRate*self.firstLayerWeightsSummations
    self.firstLayerSummations = np.zeros([self.dimensions[1], self.dimensions[0]])
    self.secondLayerSummations = np.zeros([self.dimensions[2], self.dimensions[1]])
    self.firstLayerBiasesSummations = np.zeros(self.dimensions[1])
    self.secondLayerBiasesSummations = np.zeros(self.dimensions[2])

def predict(self, testImage):
    secondLayerAnsNodes = np.empty([self.dimensions[1]])
    outputAns = np.empty([self.dimensions[2]])
    for i in range (self.dimensions[1]):
        secondLayerAnsNodes[i] = self.sigmoid(np.dot(self.firstLayerWeights[i], testImage)+self.firstLayerBiases[i])
    for i in range (self.dimensions[2]):
        outputAns[i] = self.sigmoid(np.dot(self.secondLayerWeights[i], secondLayerAnsNodes)+self.secondLayerBiases[i])
    return outputAns

if name == "main": train_images = np.array([[1,0,0,1],[1,0,1,0],[0,1,0,1],[1,1,1,1],[0,0,0,0]]) train_labels = np.array([1, 0, 0, 0, 0])

neural_network = NeuralNetwork([4, 2, 1], train_images.shape[0])

for i in range (neural_network.epochs):
    print ("\nEpoch", str(i+1) + "/" + str(neural_network.epochs))
    neural_network.train(train_images, train_labels)

for i in range (neural_network.num_predictions):
    print("\n\n\nNew Situations: " + str(i+1) + "/" + str(neural_network.num_predictions))
    A = list(map(int,input("Enter the numbers : ").strip().split()))[:4] 

    try:
        result = neural_network.predict(A)
    except ValueError:
        print("\nValueError, try again")
        continue

    print("\nOutput Data:", result[0])
    if result>0.95:
        print("Result: Back Slash")
    else:
        print("Result: Not Back Slash")

This program only predicts the training examples correctly. When I give it [0,0,0,1] or [1,0,0,0] it predicts that it is a backslash. Also, I have run the classic xor problem with this exact code (just change the dimensions of the NN and also the training I/O) and it works perfectly. I have also made a logistic regression program almost identical to this one except it doesn't have a hidden layer. For the logistic regression program, all inputs are predicted correctly.

How do I fix/change this NN so that it can correctly predict inputs it hasn't seen before?

UPDATE: It works now, I just had to add a regularization term when I change the weights and biases. Before my lambda was 0.01 but it works when I tried a larger lambda.

New change code:

for i in range (self.dimensions[2]):
    for j in range (self.dimensions[1]):
        if j == 0:
            self.secondLayerBiases[i] -= self.learningRate*(self.secondLayerBiasesSummations[i]/self.sizeOfEpoch)
        self.secondLayerWeights[i][j] -= self.learningRate*(self.secondLayerWeightsSummations[i][j]/self.sizeOfEpoch+self.Lambda*self.secondLayerWeights[i][j])
for i in range (self.dimensions[1]):
    for j in range (self.dimensions[0]):
        if j == 0:
            self.firstLayerBiases[i] -= self.learningRate*(self.firstLayerBiasesSummations[i]/self.sizeOfEpoch)
        self.firstLayerWeights[i][j] -= self.learningRate*(self.firstLayerWeightsSummations[i][j]/self.sizeOfEpoch+self.Lambda*self.firstLayerWeights[i][j])
Joey
  • 1
  • Hi again. You can probably plot the decision boundaries for your model by evaluating [x, 0, 0, y] for x=y=np.linspace(0, 1, 100) in a 3D plot. This might clear up how this can happen, if not why. See: https://matplotlib.org/3.1.0/gallery/mplot3d/surface3d.html – Multihunter Aug 06 '20 at 03:59
  • @Multihunter I'm not very familiar with making graphs but could you please explain how to do this in python and why it would help? Thanks a lot! – Joey Aug 06 '20 at 04:07
  • 1
    You are probably encountering overfitting, i.e. good performance on the training data and bad performance on unseen data. – Michael M Aug 06 '20 at 06:03

0 Answers0