| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <time.h>
- typedef struct {
- float or_w1;
- float or_w2;
- float or_b;
- float nand_w1;
- float nand_w2;
- float nand_b;
- float and_w1;
- float and_w2;
- float and_b;
- } Xor;
- float sigmoidf(float x)
- {
- return 1.f / (1.f + expf(-x));
- }
- float forward(Xor m, float x1, float x2)
- {
- float a = sigmoidf(m.or_w1*x1 + m.or_w2*x2 + m.or_b);
- float b = sigmoidf(m.nand_w1*x1 + m.nand_w2*x2 + m.nand_b);
- return sigmoidf(a*m.and_w1 + b*m.and_w2 + m.and_b);
- }
- typedef float sample[3];
- sample xor_train[] = {
- {0, 0, 0},
- {1, 0, 1},
- {0, 1, 1},
- {1, 1, 0},
- };
- // NAND-gate
- sample or_train[] = {
- {0, 0, 0},
- {1, 0, 1},
- {0, 1, 1},
- {1, 1, 1},
- };
- sample and_train[] = {
- {0, 0, 0},
- {1, 0, 0},
- {0, 1, 0},
- {1, 1, 1},
- };
- sample nand_train[] = {
- {0, 0, 1},
- {1, 0, 1},
- {0, 1, 1},
- {1, 1, 0},
- };
- sample nor_train[] = {
- {0, 0, 1},
- {1, 0, 0},
- {0, 1, 0},
- {1, 1, 0},
- };
- sample *train = xor_train;
- size_t train_count = 4;
- float cost(Xor m)
- {
- float result = 0.0f;
- for (size_t i = 0; i < train_count; ++i) {
- float x1 = train[i][0];
- float x2 = train[i][1];
- float y = forward(m, x1, x2);
- float d = y - train[i][2];
- result += d*d;
- }
- result /= train_count;
- return result;
- }
- float rand_float(void)
- {
- return (float) rand()/ (float) RAND_MAX;
- }
- Xor rand_xor(void)
- {
- Xor m;
- m.or_w1 = rand_float();
- m.or_w2 = rand_float();
- m.or_b = rand_float();
- m.nand_w1 = rand_float();
- m.nand_w2 = rand_float();
- m.nand_b = rand_float();
- m.and_w1 = rand_float();
- m.and_w2 = rand_float();
- m.and_b = rand_float();
- return m;
- }
- void print_xor(Xor m)
- {
- printf("or_w1 = %f\n", m.or_w1);
- printf("or_w2 = %f\n", m.or_w2);
- printf("or_b = %f\n", m.or_b);
- printf("nand_w1 = %f\n", m.nand_w1);
- printf("nand_w2 = %f\n", m.nand_w2);
- printf("nand_b = %f\n", m.nand_b);
- printf("and_w1 = %f\n", m.and_w1);
- printf("and_w2 = %f\n", m.and_w2);
- printf("and_b = %f\n", m.and_b);
- }
- Xor learn(Xor m, Xor g, float rate)
- {
- m.or_w1 -= rate*g.or_w1;
- m.or_w2 -= rate*g.or_w2;
- m.or_b -= rate*g.or_b;
- m.nand_w1 -= rate*g.nand_w1;
- m.nand_w2 -= rate*g.nand_w2;
- m.nand_b -= rate*g.nand_b;
- m.and_w1 -= rate*g.and_w1;
- m.and_w2 -= rate*g.and_w2;
- m.and_b -= rate*g.and_b;
- return m;
- }
- Xor finite_diff(Xor m, float eps)
- {
- Xor g;
- float c = cost(m);
- float saved;
- saved = m.or_w1;
- m.or_w1 += eps;
- g.or_w1 = (cost(m) - c)/eps;
- m.or_w1 = saved;
- saved = m.or_w2;
- m.or_w2 += eps;
- g.or_w2 = (cost(m) - c)/eps;
- m.or_w2 = saved;
- saved = m.or_b;
- m.or_b += eps;
- g.or_b = (cost(m) - c)/eps;
- m.or_b = saved;
- saved = m.nand_w1;
- m.nand_w1 += eps;
- g.nand_w1 = (cost(m) - c)/eps;
- m.nand_w1 = saved;
- saved = m.nand_w2;
- m.nand_w2 += eps;
- g.nand_w2 = (cost(m) - c)/eps;
- m.nand_w2 = saved;
- saved = m.nand_b;
- m.nand_b += eps;
- g.nand_b = (cost(m) - c)/eps;
- m.nand_b = saved;
- saved = m.and_w1;
- m.and_w1 += eps;
- g.and_w1 = (cost(m) - c)/eps;
- m.and_w1 = saved;
- saved = m.and_w2;
- m.and_w2 += eps;
- g.and_w2 = (cost(m) - c)/eps;
- m.and_w2 = saved;
- saved = m.and_b;
- m.and_b += eps;
- g.and_b = (cost(m) - c)/eps;
- m.and_b = saved;
- return g;
- }
- int main(void)
- {
- srand(time(0));
- Xor m = rand_xor();
- float eps = 1e-1;
- float rate = 1e-1;
- for (size_t i = 0; i < 100*1000; ++i) {
- Xor g = finite_diff(m, eps);
- m = learn(m, g, rate);
- // printf("cost = %f\n", cost(m));
- }
- printf("cost = %f\n", cost(m));
- printf("------------------------------\n");
- for (size_t i = 0; i < 2; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- printf("%zu ^ %zu = %f\n", i, j, forward(m, i, j));
- }
- }
- printf("------------------------------\n");
- printf("\"OR\" neuron:\n");
- for (size_t i = 0; i < 2; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- printf("%zu | %zu = %f\n", i, j, sigmoidf(m.or_w1*i + m.or_w2*j + m.or_b));
- }
- }
- printf("------------------------------\n");
- printf("\"NAND\" neuron:\n");
- for (size_t i = 0; i < 2; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- printf("~(%zu & %zu) = %f\n", i, j, sigmoidf(m.nand_w1*i + m.nand_w2*j + m.nand_b));
- }
- }
- printf("------------------------------\n");
- printf("\"AND\" neuron:\n");
- for (size_t i = 0; i < 2; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- printf("%zu & %zu = %f\n", i, j, sigmoidf(m.and_w1*i + m.and_w2*j + m.and_b));
- }
- }
- return 0;
- }
|