Task: Perceptron




Go: package main

import (
    "github.com/fogleman/gg"
    "math/rand"
    "time"
)

const c = 0.00001

func linear(x float64) float64 {
    return x*0.7 + 40
}

type trainer struct {
    inputs []float64
    answer int
}

func newTrainer(x, y float64, a int) *trainer {
    return &trainer{[]float64{x, y, 1}, a}
}

type perceptron struct {
    weights  []float64
    training []*trainer
}

func newPerceptron(n, w, h int) *perceptron {
    weights := make([]float64, n)
    for i := 0; i < n; i++ {
        weights[i] = rand.Float64()*2 - 1
    }

    training := make([]*trainer, 2000)
    for i := 0; i < 2000; i++ {
        x := rand.Float64() * float64(w)
        y := rand.Float64() * float64(h)
        answer := 1
        if y < linear(x) {
            answer = -1
        }
        training[i] = newTrainer(x, y, answer)
    }
    return &perceptron{weights, training}
}

func (p *perceptron) feedForward(inputs []float64) int {
    if len(inputs) != len(p.weights) {
        panic("weights and input length mismatch, program terminated")
    }
    sum := 0.0
    for i, w := range p.weights {
        sum += inputs[i] * w
    }
    if sum > 0 {
        return 1
    }
    return -1
}

func (p *perceptron) train(inputs []float64, desired int) {
    guess := p.feedForward(inputs)
    err := float64(desired - guess)
    for i := range p.weights {
        p.weights[i] += c * err * inputs[i]
    }
}

func (p *perceptron) draw(dc *gg.Context, iterations int) {
    le := len(p.training)
    for i, count := 0, 0; i < iterations; i, count = i+1, (count+1)%le {
        p.train(p.training[count].inputs, p.training[count].answer)
    }
    x := float64(dc.Width())
    y := linear(x)
    dc.SetLineWidth(2)
    dc.SetRGB255(0, 0, 0) 
    dc.DrawLine(0, linear(0), x, y)
    dc.Stroke()
    dc.SetLineWidth(1)
    for i := 0; i < le; i++ {
        guess := p.feedForward(p.training[i].inputs)
        x := p.training[i].inputs[0] - 4
        y := p.training[i].inputs[1] - 4
        if guess > 0 {
            dc.SetRGB(0, 0, 1) 
        } else {
            dc.SetRGB(1, 0, 0) 
        }
        dc.DrawCircle(x, y, 8)
        dc.Stroke()
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    w, h := 640, 360
    perc := newPerceptron(3, w, h)
    dc := gg.NewContext(w, h)
    dc.SetRGB(1, 1, 1) 
    dc.Clear()
    perc.draw(dc, 2000)
    dc.SavePNG("perceptron.png")
}




Python: import random

TRAINING_LENGTH = 2000

class Perceptron:
    
    def __init__(self,n):
        self.c = .01
        self.weights = [random.uniform(-1.0, 1.0) for _ in range(n)]

    def feed_forward(self, inputs):
        vars = []
        for i in range(len(inputs)):
            vars.append(inputs[i] * self.weights[i])
        return self.activate(sum(vars))

    def activate(self, value):
        return 1 if value > 0 else -1

    def train(self, inputs, desired):
        guess = self.feed_forward(inputs)
        error = desired - guess
        for i in range(len(inputs)):
            self.weights[i] += self.c * error * inputs[i]
        
class Trainer():
    
    def __init__(self, x, y, a):
        self.inputs = [x, y, 1]
        self.answer = a

def F(x):
    return 2 * x + 1

if __name__ == "__main__":
    ptron = Perceptron(3)
    training = []
    for i in range(TRAINING_LENGTH):
        x = random.uniform(-10,10)
        y = random.uniform(-10,10)
        answer = 1
        if y < F(x): answer = -1
        training.append(Trainer(x,y,answer))
    result = []
    for y in range(-10,10):
        temp = []
        for x in range(-10,10):
            if ptron.feed_forward([x,y,1]) == 1:
                temp.append('^')
            else:
                temp.append('.')
        result.append(temp)
    
    print('Untrained')
    for row in result:
        print(''.join(v for v in row))

    for t in training:
        ptron.train(t.inputs, t.answer)
    
    result = []
    for y in range(-10,10):
        temp = []
        for x in range(-10,10):
            if ptron.feed_forward([x,y,1]) == 1:
                temp.append('^')
            else:
                temp.append('.')
        result.append(temp)
    
    print('Trained')
    for row in result:
        print(''.join(v for v in row))