Perceptron does not learn correctly

Question:

I try to do the basic ML. So here is my class of binary classificator perceptron.

class perceptron():
    def __init__(self, x, y, threshold=0.5, learning_rate=0.1, max_epochs=10):
        self.threshold = threshold
        self.learning_rate = learning_rate
        self.x = x
        self.y = y
        self.max_epochs = max_epochs
        
    def initialize(self):
        self.weights = np.random.rand(len(self.x[0]))
                
    def train(self):
        epoch = 0
        while True:
            error_count = 0
            epoch += 1
            for (x,y) in zip(self.x, self.y):
                error_count += self.train_observation(x, y, error_count)
            print('Epoch: {0} Error count: {1}'.format(epoch, error_count))
            if error_count == 0:
                print('Training successful')
                break
            if epoch >= self.max_epochs:
                print('Reached max epochs')
                break
                
    def train_observation(self, x, y, error_count):
        result = np.dot(x, self.weights) > self.threshold
        error = y - result
        if error != 0:
            error_count += 1
            for index, value in enumerate(x):
                self.weights[index] += self.learning_rate * error * value
        return error_count
        
    def predict(self, x):
        return int(np.dot(x, self.weights) > self.threshold)

I want to classify, if a sum of list values >=0 (means 1) or not(means 0)
so I do 50 arrays len 10, each has random int value [-3, 3]:

def sum01(x):
    if sum(x) >= 0:
        return 1
    else:
        return 0
x = np.random.randint(low=-3, high=3, size=(50,10))
y = [sum01(z) for z in a]

Then I initialize and train:

p = perceptron(x, y)
p.initialize()
p.train()

Then I check and a lot of predictions are not correct, what am I doing wrong?

predics = [(p.predict(i), sumab(i)) for i in np.random.randint(low=-3, high=3, size=(10, 10))]
print(predics)
Asked By: Roman

||

Answers:

Rerunning your code with small bug fixes, I see the loss reducing to 0 and correct outputs –

p = perceptron(x, y)
p.initialize()
p.train()
Epoch: 1 Error count: 196608
Epoch: 2 Error count: 38654836736
Epoch: 3 Error count: 268437504
Epoch: 4 Error count: 0
Training successful
predics = [(p.predict(i), sum01(i)) for i in np.random.randint(low=-3, high=3, size=(10, 10))]
print(predics)
[(1, 1), (0, 0), (0, 0), (0, 0), (1, 1), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]

SOLUTION

There are a few quick changes needed in your code –

  1. While defining x and y:
x = np.random.randint(low=-3, high=3, size=(50,10))
y = [sum01(z) for z in x] #CHANGE THIS TO x INSTEAD OF a
  1. While getting predictions:
#CHANGE sumab TO sum01
predics = [(p.predict(i), sum01(i)) for i in np.random.randint(low=-3, high=3, size=(10, 10))] 

It should work then. Your complete code becomes –

class perceptron():
    def __init__(self, x, y, threshold=0.5, learning_rate=0.1, max_epochs=10):
        self.threshold = threshold
        self.learning_rate = learning_rate
        self.x = x
        self.y = y
        self.max_epochs = max_epochs
        
    def initialize(self):
        self.weights = np.random.rand(len(self.x[0]))
                
    def train(self):
        epoch = 0
        while True:
            error_count = 0
            epoch += 1
            for (x,y) in zip(self.x, self.y):
                error_count += self.train_observation(x, y, error_count)
            print('Epoch: {0} Error count: {1}'.format(epoch, error_count))
            if error_count == 0:
                print('Training successful')
                break
            if epoch >= self.max_epochs:
                print('Reached max epochs')
                break
                
    def train_observation(self, x, y, error_count):
        result = np.dot(x, self.weights) > self.threshold
        error = y - result
        if error != 0:
            error_count += 1
            for index, value in enumerate(x):
                self.weights[index] += self.learning_rate * error * value
        return error_count
        
    def predict(self, x):
        return int(np.dot(x, self.weights) > self.threshold)
    
    
def sum01(x):
    if sum(x) >= 0:
        return 1
    else:
        return 0
    
x = np.random.randint(low=-3, high=3, size=(50,10))
y = [sum01(z) for z in x]

p = perceptron(x, y)
p.initialize()
p.train()

predics = [(p.predict(i), sum01(i)) for i in np.random.randint(low=-3, high=3, size=(10, 10))]
print(predics)
Answered By: Akshay Sehgal