|
@@ -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;
|
|
|
}
|
|
}
|