Selaa lähdekoodia

Implement a simple training of the perceptron

rexim 3 vuotta sitten
vanhempi
sitoutus
b0a5a280fa
1 muutettua tiedostoa jossa 86 lisäystä ja 14 poistoa
  1. 86 14
      main.c

+ 86 - 14
main.c

@@ -1,15 +1,19 @@
 #include <assert.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <string.h>
 #include <errno.h>
 #include <errno.h>
 #include <math.h>
 #include <math.h>
 #include <limits.h>
 #include <limits.h>
+#include <float.h>
 
 
 #define WIDTH 50
 #define WIDTH 50
 #define HEIGHT 50
 #define HEIGHT 50
 #define PPM_SCALER 25
 #define PPM_SCALER 25
-#define SAMPLE_SIZE 10
+#define BIAS 10.0
+#define SAMPLE_SIZE 2000
+#define TRAIN_PASSES 2000
 
 
 typedef float Layer[HEIGHT][WIDTH];
 typedef float Layer[HEIGHT][WIDTH];
 
 
@@ -55,6 +59,15 @@ void layer_fill_circle(Layer layer, int cx, int cy, int r, float value)
 
 
 void layer_save_as_ppm(Layer layer, const char *file_path)
 void layer_save_as_ppm(Layer layer, const char *file_path)
 {
 {
+    float min = FLT_MAX;
+    float max = FLT_MIN;
+    for (int y = 0; y < HEIGHT-1; ++y) {
+        for (int x = 0; x < WIDTH-1; ++x) {
+            if (layer[y][x] < min) min = layer[y][x];
+            if (layer[y][x] > max) max = layer[y][x];
+        }
+    }
+
     FILE *f = fopen(file_path, "wb");
     FILE *f = fopen(file_path, "wb");
     if (f == NULL) {
     if (f == NULL) {
         fprintf(stderr, "ERROR: could not open file %s: %m\n",
         fprintf(stderr, "ERROR: could not open file %s: %m\n",
@@ -66,10 +79,10 @@ void layer_save_as_ppm(Layer layer, const char *file_path)
 
 
     for (int y = 0; y < HEIGHT * PPM_SCALER; ++y) {
     for (int y = 0; y < HEIGHT * PPM_SCALER; ++y) {
         for (int x = 0; x < WIDTH * PPM_SCALER; ++x) {
         for (int x = 0; x < WIDTH * PPM_SCALER; ++x) {
-            float s = layer[y / PPM_SCALER][x / PPM_SCALER];
+            float s = (layer[y / PPM_SCALER][x / PPM_SCALER] - min) / (max - min);
             char pixel[3] = {
             char pixel[3] = {
+                (char) floorf(255 * (1.0f - s)),
                 (char) floorf(255 * s),
                 (char) floorf(255 * s),
-                0,
                 0
                 0
             };
             };
 
 
@@ -109,6 +122,24 @@ float feed_forward(Layer inputs, Layer weights)
     return output;
     return output;
 }
 }
 
 
+void add_inputs_from_weights(Layer inputs, Layer weights)
+{
+    for (int y = 0; y < HEIGHT; ++y) {
+        for (int x = 0; x < WIDTH; ++x) {
+            weights[y][x] += inputs[y][x];
+        }
+    }
+}
+
+void sub_inputs_from_weights(Layer inputs, Layer weights)
+{
+    for (int y = 0; y < HEIGHT; ++y) {
+        for (int x = 0; x < WIDTH; ++x) {
+            weights[y][x] -= inputs[y][x];
+        }
+    }
+}
+
 int rand_range(int low, int high)
 int rand_range(int low, int high)
 {
 {
     assert(low < high);
     assert(low < high);
@@ -147,24 +178,65 @@ void layer_random_circle(Layer layer)
     layer_fill_circle(layer, cx, cy, r, 1.0f);
     layer_fill_circle(layer, cx, cy, r, 1.0f);
 }
 }
 
 
-static Layer inputs;
-static Layer weights;
-
-int main(void)
+int train_pass(Layer inputs, Layer weights)
 {
 {
-    char file_path[256];
+    int adjusted = 0;
 
 
-#define PREFIX "rect"
     for (int i = 0; i < SAMPLE_SIZE; ++i) {
     for (int i = 0; i < SAMPLE_SIZE; ++i) {
-        printf("[INFO] generating "PREFIX" %d\n", i);
+        layer_random_rect(inputs);
+        if (feed_forward(inputs, weights) > BIAS) {
+            sub_inputs_from_weights(inputs, weights);
+            adjusted += 1;
+        }
+
+        layer_random_circle(inputs);
+        if (feed_forward(inputs, weights) < BIAS) {
+            add_inputs_from_weights(inputs, weights);
+            adjusted += 1;
+        }
+    }
+
+    return adjusted;
+}
 
 
+int check_pass(Layer inputs, Layer weights)
+{
+    int adjusted = 0;
+
+    for (int i = 0; i < SAMPLE_SIZE; ++i) {
         layer_random_rect(inputs);
         layer_random_rect(inputs);
+        if (feed_forward(inputs, weights) > BIAS) {
+            adjusted += 1;
+        }
 
 
-        snprintf(file_path, sizeof(file_path), PREFIX"-%02d.bin", i);
-        layer_save_as_bin(inputs, file_path);
-        snprintf(file_path, sizeof(file_path), PREFIX"-%02d.ppm", i);
-        layer_save_as_ppm(inputs, file_path);
+        layer_random_circle(inputs);
+        if (feed_forward(inputs, weights) < BIAS) {
+            adjusted += 1;
+        }
     }
     }
 
 
+    return adjusted;
+}
+
+static Layer inputs;
+static Layer weights;
+
+int main(void)
+{
+    srand(420);
+    int adj = check_pass(inputs, weights);
+    printf("The fail rate of untrained model is %f\n", adj / (SAMPLE_SIZE * 2.0));
+
+    for (int i = 0; i < TRAIN_PASSES; ++i) {
+        srand(69);
+        int adj = train_pass(inputs, weights);
+        printf("adjusted %d times\n", adj);
+        if (adj <= 0) break;
+    }
+
+    srand(420);
+    adj = check_pass(inputs, weights);
+    printf("The fail rate of trained model is %f\n", adj / (SAMPLE_SIZE * 2.0));
+
     return 0;
     return 0;
 }
 }