Last active
October 15, 2021 10:59
-
-
Save ebraminio/77108bcc297adfda1d76c9cb71b34fa0 to your computer and use it in GitHub Desktop.
Ports of originally Python code of https://www.codementor.io/mcorr/tutorials/an-introduction-to-python-machine-learning-with-perceptrons-k7pn85vfi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// `clang a.c && time ./a.out` | |
// real 0m0.071s | |
// user 0m0.067s | |
// sys 0m0.002s | |
// `clang -O3 a.c && time ./a.out` | |
// real 0m0.029s | |
// user 0m0.025s | |
// sys 0m0.001s | |
// `gcc-6 a.c && time ./a.out` | |
// real 0m0.093s | |
// user 0m0.084s | |
// sys 0m0.003s | |
// `gcc-6 -O3 a.c && time ./a.out` | |
// real 0m0.032s | |
// user 0m0.027s | |
// sys 0m0.002s | |
#include <stdio.h> | |
#include <time.h> | |
float speed = 0.01; | |
const int num_weights = 3; | |
float weights[3]; | |
float activate(float num) { | |
// turn a sum over 0 into 1, and below 0 into -1 | |
return num > 0 ? 1 : -1; | |
} | |
float feed_forward(float inputs[]) { | |
float sum = 0; | |
// multiply inputs by weights and sum them | |
for (int i = 0; i < num_weights; ++i) { | |
sum += weights[i] * inputs[i]; | |
} | |
// return the 'activated' sum | |
return activate(sum); | |
} | |
void train(float inputs[], float desired_output) { | |
float guess = feed_forward(inputs); | |
float err = desired_output - guess; | |
for (int x = 0; x < num_weights; ++x) { | |
weights[x] += err * inputs[x] * speed; | |
} | |
} | |
int g_seed; | |
// http://stackoverflow.com/a/3747462 | |
int fastrand() { | |
g_seed = (214013 * g_seed + 2531011); | |
return (g_seed >> 16) & 0x7FFF; | |
} | |
float frand() { | |
return (float)fastrand() / 32768; | |
} | |
int main() { | |
// init random generator | |
g_seed = time(0); | |
for (int x = 0; x < num_weights; ++x) { | |
weights[x] = frand() * 2 - 1; | |
} | |
for (int x = 0; x < 1000000; ++x) { | |
int x_coord = frand() * 500 - 250; | |
int y_coord = frand() * 500 - 250; | |
int line_y = .5 * x_coord + 10; // line: f(x) = 0.5x + 10 | |
float arr[3] = { x_coord, y_coord, 1 }; | |
train(arr, y_coord > line_y ? 1 : -1); | |
} | |
float arr1[3] = { -7, 9, 1 }; | |
printf("(-7, 9): %f\n", feed_forward(arr1)); | |
float arr2[3] = { 3, 1, 1 }; | |
printf("(3, 1): %f\n", feed_forward(arr2)); | |
printf("%f, %f, %f", weights[0], weights[1], weights[2]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// `time csharp perceptron.cs`: | |
// real 0m0.902s | |
// user 0m0.835s | |
// sys 0m0.044s | |
class Perceptron { | |
private double speed; | |
public double[] weights; | |
public Perceptron(double learnSpeed, int numWeights) { | |
speed = learnSpeed; | |
weights = new double[numWeights]; | |
var rand = new Random(); | |
for (var i = 0; i < numWeights; ++i) { | |
weights[i] = rand.NextDouble() * 2 - 1; | |
} | |
} | |
public double FeedForward(double[] inputs) { | |
var sum = .0; | |
// multiply inputs by weights and sum them | |
for (var x = 0; x < weights.Length; ++x) | |
sum += weights[x] * inputs[x]; | |
// return the 'activated' sum | |
return Activate(sum); | |
} | |
public double Activate(double num) { | |
return num > 0 ? 1 : -1; | |
} | |
public void Train(double[] inputs, double desiredOutput) { | |
var guess = FeedForward(inputs); | |
var error = desiredOutput - guess; | |
for (var x = 0; x < weights.Length; ++x) | |
weights[x] += error * inputs[x] * speed; | |
} | |
} | |
var p = new Perceptron(0.01, 3); | |
var rand = new Random(); | |
for (var x = 0; x < 1000000; ++x) { | |
var xCoord = rand.NextDouble() * 500 - 250; | |
var yCoord = rand.NextDouble() * 500 - 250; | |
var lineY = 0.5 * xCoord + 10; // line: f(x) = 0.5x + 10 | |
if (yCoord > lineY) { // above the line | |
p.Train(new double[] { xCoord, yCoord, 1 }, 1); | |
} else { // below the line | |
p.Train(new double[] { xCoord, yCoord, 1 }, -1); | |
} | |
} | |
Console.WriteLine("(-7, 9): " + p.FeedForward(new double[] { -7, 9, 1 })); | |
Console.WriteLine("(3, 1): " + p.FeedForward(new double[] { 3, 1, 1 })); | |
for (var i = 0; i < p.weights.Length; ++i) { | |
Console.Write(p.weights[i] + ", "); | |
} | |
Console.WriteLine(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
! by Calak, | |
! gfortran perceptron.f -Ofast -o perceptron && time ./perceptron | |
! Not the same machine as others, | |
! ./main 0.02s user 0.00s system 97% cpu 0.024 total | |
module Perceptron | |
real :: speed = 0.01, weights(3) | |
contains | |
real function activate(num) | |
real :: num | |
!turn a sum over 0 into 1, and below 0 into -1 | |
activate = merge(1., -1., num > 0) | |
end function activate | |
real function feed_forward(inputs) | |
real :: inputs(:), sum | |
!multiply inputs by weights and sum them | |
sum = dot_product(weights, inputs) | |
!return the "activated" sum | |
feed_forward = activate(sum) | |
end function feed_forward | |
subroutine train(inputs, desired_output) | |
real :: inputs(:), desired_output, guess, err | |
guess = feed_forward(inputs) | |
err = desired_output - guess | |
weights = weights + err * inputs * speed | |
end subroutine train | |
end module Perceptron | |
program main | |
use Perceptron | |
integer :: x_coord, y_coord, line_y, g_seed | |
integer*8 :: x | |
real, dimension(3) :: arr, arr1, arr2 | |
g_seed = time() | |
weights = (/ (frand() * 2 - 1, x = 1, size(weights)) /) | |
do x = 0, 1000000 | |
x_coord = frand() * 500 - 250 | |
y_coord = frand() * 500 - 250 | |
line_y = 0.5 * x_coord + 10 !line: f(x) = 0.5x + 10 | |
arr = (/ x_coord, y_coord, 1 /) | |
call train(arr, merge(1., -1., y_coord > line_y)) | |
end do | |
arr1 = (/ -7, 9, 1 /) | |
print *, "(-7, 9): ", feed_forward(arr1) | |
arr2 = (/ 3, 1, 1 /) | |
print *, "(3, 1): ", feed_forward(arr2) | |
print *, weights | |
contains | |
integer function fastrand() | |
g_seed = 214013 * g_seed + 2531011 | |
fastrand = and(rshift(g_seed, 16), z'7FFF') | |
end function fastrand | |
real function frand() | |
frand = real(fastrand()) / 32768 | |
end function frand | |
end program main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// `go build perceptron.go && time ./perceptron` | |
// real 0m0.167s | |
// user 0m0.157s | |
// sys 0m0.007s | |
import ( | |
"math/rand" | |
"fmt" | |
) | |
var ( | |
speed float32 = 0.01 | |
num_weights = 3 | |
weights [3]float32 | |
) | |
func feed_forward(inputs []float32) float32 { | |
var sum float32 | |
// multiply inputs by weights and sum them | |
for i := 0; i < num_weights; i++ { | |
sum += weights[i] * inputs[i] | |
} | |
// return the 'activated' sum | |
return activate(sum) | |
} | |
func activate(num float32) float32 { | |
// turn a sum over 0 into 1, and below 0 into -1 | |
var result float32 | |
result = -1 | |
if num > 0 { | |
result = 1 | |
} | |
return result | |
} | |
func train(inputs []float32, desired_output float32) { | |
guess := feed_forward(inputs) | |
err := desired_output - guess | |
for x := 0; x < num_weights; x++ { | |
weights[x] += err * inputs[x] * speed | |
} | |
} | |
func main() { | |
for x := 0; x < num_weights; x++ { | |
weights[x] = rand.Float32() * 2 - 1 | |
} | |
for x := 0; x < 1000000; x++ { | |
x_coord := rand.Float32() * 500 - 250 | |
y_coord := rand.Float32() * 500 - 250 | |
line_y := .5 * x_coord + 10 // line: f(x) = 0.5x + 10 | |
arr := make([]float32, 3) | |
arr[0] = x_coord | |
arr[1] = y_coord | |
arr[2] = 1 | |
var expected float32 | |
expected = -1 | |
if y_coord > line_y { | |
expected = 1 | |
} | |
train(arr, expected) | |
} | |
arr := make([]float32, 3) | |
arr[0] = -7 | |
arr[1] = 9 | |
arr[2] = 1 | |
fmt.Printf("(-7, 9): %f\n", feed_forward(arr)) | |
arr[0] = 3 | |
arr[1] = 1 | |
arr[2] = 1 | |
fmt.Printf("(3, 1): %f\n", feed_forward(arr)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// `time node perceptron.js` | |
// real 0m0.199s | |
// user 0m0.172s | |
// sys 0m0.022s | |
function perceptron(speed, numWeights) { | |
var weights = []; | |
for (var i = 0; i < numWeights; ++i) { | |
weights.push(Math.random() * 2 - 1); | |
} | |
function feedForward(inputs) { | |
var sum = 0; | |
// multiply inputs by weights and sum them | |
for (var x = 0; x < weights.length; ++x) | |
sum += weights[x] * inputs[x]; | |
// return the 'activated' sum | |
return activate(sum); | |
} | |
function activate(num) { | |
return num > 0 ? 1 : -1; | |
} | |
return { | |
feedForward, | |
activate, | |
weights, | |
train(inputs, desiredOutput) { | |
var guess = feedForward(inputs); | |
var error = desiredOutput - guess; | |
for (var x = 0; x < weights.length; ++x) | |
weights[x] += error * inputs[x] * speed; | |
} | |
} | |
} | |
function trainer() { | |
var p = perceptron(0.01, 3); | |
for (var x = 0; x < 1000000; ++x) { | |
var xCoord = Math.random() * 500 - 250; | |
var yCoord = Math.random() * 500 - 250; | |
var lineY = 0.5 * xCoord + 10; // line: f(x) = 0.5x + 10; | |
if (yCoord > lineY) { // above the line | |
p.train([xCoord, yCoord, 1], 1); | |
} else { // below the line | |
p.train([xCoord, yCoord, 1], -1); | |
} | |
} | |
return p; // return our trained perceptron | |
} | |
var p = trainer(); | |
console.log('(-7, 9): ' + p.feedForward([-7, 9, 1])); | |
console.log('(3, 1): ' + p.feedForward([3, 1, 1])); | |
console.log(p.weights); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// `time php perceptron.php` | |
// real 0m5.710s | |
// user 0m5.635s | |
// sys 0m0.038s | |
// (hhvm is faster but I don't have it on the same setup) | |
function r() { | |
return mt_rand(0, 32767) / 32767; | |
} | |
class Perceptron { | |
var $speed; | |
var $weights; | |
function __construct($learn_speed, $num_weights) { | |
$this->speed = $learn_speed; | |
$this->weights = []; | |
for ($x = 0; $x < $num_weights; ++$x) { | |
$this->weights[] = r() * 2 - 1; | |
} | |
} | |
function getWeights() { | |
return $this->weights; | |
} | |
public function feed_forward($inputs) { | |
$sum = 0; | |
# multiply inputs by weights and sum them | |
for ($i = 0; $i < count($this->weights); ++$i) { | |
$sum += $this->weights[$i] * $inputs[$i]; | |
} | |
# return the 'activated' sum | |
return $this->activate($sum); | |
} | |
function activate($num) { | |
# turn a sum over 0 into 1, and below 0 into -1 | |
if ($num > 0) | |
return 1; | |
return -1; | |
} | |
function train($inputs, $desired_output) { | |
$guess = $this->feed_forward($inputs); | |
$error = $desired_output - $guess; | |
for ($x = 0; $x < count($this->weights); ++$x) { | |
$this->weights[$x] += $error * $inputs[$x] * $this->speed; | |
} | |
} | |
} | |
$p = new Perceptron(0.01, 3); | |
for ($x = 0; $x < 1000000; ++$x) { | |
$x_coord = r() * 500 - 250; | |
$y_coord = r() * 500 - 250; | |
$line_y = .5 * $x_coord + 10; # line: f(x) = 0.5x + 10; | |
$p->train([$x_coord, $y_coord, 1], $y_coord > $line_y | |
? 1 # above the line | |
: -1); # below the line | |
} | |
echo "(-7, 9): " . $p->feed_forward([-7, 9, 1]) . "\n"; | |
echo "(3, 1): " . $p->feed_forward([3, 1, 1]) . "\n"; | |
echo var_dump($p->weights); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# `time python3 perceptron.py` | |
# real 0m6.740s | |
# user 0m6.580s | |
# sys 0m0.044s | |
# `time pypy perceptron.py` | |
# real 0m0.593s | |
# user 0m0.536s | |
# sys 0m0.049s | |
import random | |
speed = 0.01 | |
num_weights = 3 | |
weights = [] | |
def feed_forward(inputs): | |
sum = 0 | |
# multiply inputs by weights and sum them | |
for x in range(0, len(weights)): | |
sum += weights[x] * inputs[x] | |
# return the 'activated' sum | |
return activate(sum) | |
def activate(num): | |
# turn a sum over 0 into 1, and below 0 into -1 | |
if num > 0: | |
return 1 | |
return -1 | |
def train(inputs, desired_output): | |
guess = feed_forward(inputs) | |
error = desired_output - guess | |
for x in range(0, len(weights)): | |
weights[x] += error * inputs[x] * speed | |
for x in range(0, num_weights): | |
weights.append(random.random()*2-1) | |
for x in range(0, 1000000): | |
x_coord = random.random()*500-250 | |
y_coord = random.random()*500-250 | |
line_y = .5 * x_coord + 10 # line: f(x) = 0.5x + 10 | |
if y_coord > line_y: # above the line | |
train([x_coord, y_coord, 1], 1) | |
else: # below the line | |
train([x_coord, y_coord, 1], -1) | |
print("(-7, 9): " + str(feed_forward([-7,9,1]))) | |
print("(3, 1): " + str(feed_forward([3,1,1]))) | |
print(weights) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// rustc perceptron.rs -C opt-level=3 && time ./perceptron | |
// | |
// Not the same machine as others, | |
// 0.03s user 0.00s system 98% cpu 0.032 total | |
// | |
// Add | |
// [profile.dev] | |
// overflow-checks = false | |
// to cargo while development | |
use std::time::{SystemTime, UNIX_EPOCH}; | |
mod perceptron { | |
const SPEED: f32 = 0.01; | |
pub const NUM_WEIGHTS: usize = 3; | |
#[derive(Debug)] | |
pub struct Perceptron { | |
weights: [f32; NUM_WEIGHTS], | |
} | |
impl Perceptron { | |
pub fn new(mut rand: impl FnMut() -> f32) -> Perceptron { | |
let mut perceptron = Perceptron { weights: [0.0; 3] }; | |
for x in 0..NUM_WEIGHTS { | |
perceptron.weights[x] = rand(); | |
} | |
perceptron | |
} | |
fn activate(self: &Self, num: f32) -> f32 { | |
// turn a sum over 0 into 1, and below 0 into -1 | |
if num > 0.0 { | |
1.0 | |
} else { | |
-1.0 | |
} | |
} | |
pub fn feed_forward(self: &mut Self, inputs: [f32; NUM_WEIGHTS]) -> f32 { | |
let mut sum = 0.0; | |
// multiply inputs by WEIGHTS and sum them | |
for i in 0..NUM_WEIGHTS { | |
sum += self.weights[i] * inputs[i]; | |
} | |
// return the 'activated' sum | |
self.activate(sum) | |
// or just self.activate((0..NUM_WEIGHTS).map(|i| self.weights[i] * inputs[i]).sum()) | |
} | |
pub fn train(self: &mut Self, inputs: [f32; NUM_WEIGHTS], desired_output: f32) { | |
let guess = self.feed_forward(inputs); | |
let err = desired_output - guess; | |
for x in 0..NUM_WEIGHTS { | |
self.weights[x] += err * inputs[x] * SPEED; | |
} | |
} | |
} | |
} | |
mod rand { | |
pub struct Rand { | |
seed: i32, | |
} | |
impl Rand { | |
pub fn new(seed: i32) -> Rand { | |
Rand { seed } | |
} | |
// http://stackoverflow.com/a/3747462 | |
fn fastrand(self: &mut Self) -> i32 { | |
self.seed = 214013 * self.seed + 2531011; | |
(self.seed >> 16) & 0x7FFF | |
} | |
pub fn frand(self: &mut Self) -> f32 { | |
self.fastrand() as f32 / 32768.0 | |
} | |
} | |
} | |
fn main() { | |
// init random generator | |
let mut rand = rand::Rand::new( | |
SystemTime::now() | |
.duration_since(UNIX_EPOCH) | |
.unwrap() | |
.as_secs() as i32, | |
); | |
let mut perceptron = perceptron::Perceptron::new(|| rand.frand() * 2.0 - 1.0); | |
for _ in 0..1000000 { | |
let x_coord = rand.frand() * 500.0 - 250.0; | |
let y_coord = rand.frand() * 500.0 - 250.0; | |
let line_y = x_coord / 2.0 + 10.0; // line: f(x) = 0.5x + 10 | |
let arr = [x_coord, y_coord, 1.0]; | |
perceptron.train(arr, if y_coord > line_y { 1.0 } else { -1.0 }); | |
} | |
println!("(-7, 9): {}", perceptron.feed_forward([-7.0, 9.0, 1.0])); | |
println!("(3, 1): {}", perceptron.feed_forward([3.0, 1.0, 1.0])); | |
println!("{:?}", perceptron); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' by Calak | |
DECLARE FUNCTION activate# (num AS DOUBLE) | |
DECLARE FUNCTION feedForward# (inputs() AS DOUBLE) | |
DECLARE SUB train (inputs() AS DOUBLE, desiredOutput AS DOUBLE) | |
CONST speed = .01 | |
DIM numWeights AS INTEGER: numWeights = 3 | |
REDIM SHARED weights(numWeights - 1) AS DOUBLE | |
RANDOMIZE TIMER | |
DIM x AS LONG | |
FOR x = 0 TO UBOUND(weights) | |
weights(x) = RND * 2 - 1 | |
NEXT x | |
DIM xCoord AS INTEGER, yCoord AS INTEGER, lineY AS INTEGER | |
DIM arr(2) AS DOUBLE, expected AS DOUBLE | |
FOR x = 0 TO 1000000 | |
xCoord = RND * 500 - 250 | |
yCoord = RND * 500 - 250 | |
lineY = .5 * xCoord + 10 ' line: f(x) = 0.5x + 10 | |
arr(0) = xCoord: arr(1) = yCoord: arr(2) = 1 | |
IF yCoord > lineY THEN expected = 1 ELSE expected = -1 | |
CALL train(arr(), expected) | |
NEXT x | |
DIM arr1(2) AS DOUBLE, arr2(2) AS DOUBLE | |
arr1(0) = -7: arr1(1) = 9: arr1(2) = 1 | |
PRINT "(-7, 9): "; feedForward(arr1()) | |
arr2(0) = 3: arr2(1) = 1: arr2(2) = 1 | |
PRINT "(3, 1): "; feedForward(arr2()) | |
PRINT weights(0), weights(1), weights(2) | |
END | |
FUNCTION activate# (num AS DOUBLE) | |
' turn a sum over 0 into 1, and below 0 into -1 | |
IF num > 0 THEN activate = 1 ELSE activate = -1 | |
END FUNCTION | |
FUNCTION feedForward# (inputs() AS DOUBLE) | |
DIM sum AS DOUBLE, i AS INTEGER | |
' multiply inputs by weights and sum them | |
FOR i = 0 TO UBOUND(weights) | |
sum = sum + weights(i) * inputs(i) | |
NEXT i | |
' return the "activated" sum | |
feedForward = activate(sum) | |
END FUNCTION | |
SUB train (inputs() AS DOUBLE, desiredOutput AS DOUBLE) | |
DIM guess AS DOUBLE, er AS DOUBLE | |
guess = feedForward(inputs()) | |
er = desiredOutput - guess | |
DIM x AS INTEGER | |
FOR x = 0 TO UBOUND(weights) | |
weights(x) = weights(x) + er * inputs(x) * speed | |
NEXT x | |
END SUB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment