2
0

xor.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <time.h>
  5. typedef struct {
  6. float or_w1;
  7. float or_w2;
  8. float or_b;
  9. float nand_w1;
  10. float nand_w2;
  11. float nand_b;
  12. float and_w1;
  13. float and_w2;
  14. float and_b;
  15. } Xor;
  16. float sigmoidf(float x)
  17. {
  18. return 1.f / (1.f + expf(-x));
  19. }
  20. float forward(Xor m, float x1, float x2)
  21. {
  22. float a = sigmoidf(m.or_w1*x1 + m.or_w2*x2 + m.or_b);
  23. float b = sigmoidf(m.nand_w1*x1 + m.nand_w2*x2 + m.nand_b);
  24. return sigmoidf(a*m.and_w1 + b*m.and_w2 + m.and_b);
  25. }
  26. typedef float sample[3];
  27. sample xor_train[] = {
  28. {0, 0, 0},
  29. {1, 0, 1},
  30. {0, 1, 1},
  31. {1, 1, 0},
  32. };
  33. // NAND-gate
  34. sample or_train[] = {
  35. {0, 0, 0},
  36. {1, 0, 1},
  37. {0, 1, 1},
  38. {1, 1, 1},
  39. };
  40. sample and_train[] = {
  41. {0, 0, 0},
  42. {1, 0, 0},
  43. {0, 1, 0},
  44. {1, 1, 1},
  45. };
  46. sample nand_train[] = {
  47. {0, 0, 1},
  48. {1, 0, 1},
  49. {0, 1, 1},
  50. {1, 1, 0},
  51. };
  52. sample nor_train[] = {
  53. {0, 0, 1},
  54. {1, 0, 0},
  55. {0, 1, 0},
  56. {1, 1, 0},
  57. };
  58. sample *train = xor_train;
  59. size_t train_count = 4;
  60. float cost(Xor m)
  61. {
  62. float result = 0.0f;
  63. for (size_t i = 0; i < train_count; ++i) {
  64. float x1 = train[i][0];
  65. float x2 = train[i][1];
  66. float y = forward(m, x1, x2);
  67. float d = y - train[i][2];
  68. result += d*d;
  69. }
  70. result /= train_count;
  71. return result;
  72. }
  73. float rand_float(void)
  74. {
  75. return (float) rand()/ (float) RAND_MAX;
  76. }
  77. Xor rand_xor(void)
  78. {
  79. Xor m;
  80. m.or_w1 = rand_float();
  81. m.or_w2 = rand_float();
  82. m.or_b = rand_float();
  83. m.nand_w1 = rand_float();
  84. m.nand_w2 = rand_float();
  85. m.nand_b = rand_float();
  86. m.and_w1 = rand_float();
  87. m.and_w2 = rand_float();
  88. m.and_b = rand_float();
  89. return m;
  90. }
  91. void print_xor(Xor m)
  92. {
  93. printf("or_w1 = %f\n", m.or_w1);
  94. printf("or_w2 = %f\n", m.or_w2);
  95. printf("or_b = %f\n", m.or_b);
  96. printf("nand_w1 = %f\n", m.nand_w1);
  97. printf("nand_w2 = %f\n", m.nand_w2);
  98. printf("nand_b = %f\n", m.nand_b);
  99. printf("and_w1 = %f\n", m.and_w1);
  100. printf("and_w2 = %f\n", m.and_w2);
  101. printf("and_b = %f\n", m.and_b);
  102. }
  103. Xor learn(Xor m, Xor g, float rate)
  104. {
  105. m.or_w1 -= rate*g.or_w1;
  106. m.or_w2 -= rate*g.or_w2;
  107. m.or_b -= rate*g.or_b;
  108. m.nand_w1 -= rate*g.nand_w1;
  109. m.nand_w2 -= rate*g.nand_w2;
  110. m.nand_b -= rate*g.nand_b;
  111. m.and_w1 -= rate*g.and_w1;
  112. m.and_w2 -= rate*g.and_w2;
  113. m.and_b -= rate*g.and_b;
  114. return m;
  115. }
  116. Xor finite_diff(Xor m, float eps)
  117. {
  118. Xor g;
  119. float c = cost(m);
  120. float saved;
  121. saved = m.or_w1;
  122. m.or_w1 += eps;
  123. g.or_w1 = (cost(m) - c)/eps;
  124. m.or_w1 = saved;
  125. saved = m.or_w2;
  126. m.or_w2 += eps;
  127. g.or_w2 = (cost(m) - c)/eps;
  128. m.or_w2 = saved;
  129. saved = m.or_b;
  130. m.or_b += eps;
  131. g.or_b = (cost(m) - c)/eps;
  132. m.or_b = saved;
  133. saved = m.nand_w1;
  134. m.nand_w1 += eps;
  135. g.nand_w1 = (cost(m) - c)/eps;
  136. m.nand_w1 = saved;
  137. saved = m.nand_w2;
  138. m.nand_w2 += eps;
  139. g.nand_w2 = (cost(m) - c)/eps;
  140. m.nand_w2 = saved;
  141. saved = m.nand_b;
  142. m.nand_b += eps;
  143. g.nand_b = (cost(m) - c)/eps;
  144. m.nand_b = saved;
  145. saved = m.and_w1;
  146. m.and_w1 += eps;
  147. g.and_w1 = (cost(m) - c)/eps;
  148. m.and_w1 = saved;
  149. saved = m.and_w2;
  150. m.and_w2 += eps;
  151. g.and_w2 = (cost(m) - c)/eps;
  152. m.and_w2 = saved;
  153. saved = m.and_b;
  154. m.and_b += eps;
  155. g.and_b = (cost(m) - c)/eps;
  156. m.and_b = saved;
  157. return g;
  158. }
  159. int main(void)
  160. {
  161. srand(time(0));
  162. Xor m = rand_xor();
  163. float eps = 1e-1;
  164. float rate = 1e-1;
  165. for (size_t i = 0; i < 100*1000; ++i) {
  166. Xor g = finite_diff(m, eps);
  167. m = learn(m, g, rate);
  168. // printf("cost = %f\n", cost(m));
  169. }
  170. printf("cost = %f\n", cost(m));
  171. printf("------------------------------\n");
  172. for (size_t i = 0; i < 2; ++i) {
  173. for (size_t j = 0; j < 2; ++j) {
  174. printf("%zu ^ %zu = %f\n", i, j, forward(m, i, j));
  175. }
  176. }
  177. printf("------------------------------\n");
  178. printf("\"OR\" neuron:\n");
  179. for (size_t i = 0; i < 2; ++i) {
  180. for (size_t j = 0; j < 2; ++j) {
  181. printf("%zu | %zu = %f\n", i, j, sigmoidf(m.or_w1*i + m.or_w2*j + m.or_b));
  182. }
  183. }
  184. printf("------------------------------\n");
  185. printf("\"NAND\" neuron:\n");
  186. for (size_t i = 0; i < 2; ++i) {
  187. for (size_t j = 0; j < 2; ++j) {
  188. printf("~(%zu & %zu) = %f\n", i, j, sigmoidf(m.nand_w1*i + m.nand_w2*j + m.nand_b));
  189. }
  190. }
  191. printf("------------------------------\n");
  192. printf("\"AND\" neuron:\n");
  193. for (size_t i = 0; i < 2; ++i) {
  194. for (size_t j = 0; j < 2; ++j) {
  195. printf("%zu & %zu = %f\n", i, j, sigmoidf(m.and_w1*i + m.and_w2*j + m.and_b));
  196. }
  197. }
  198. return 0;
  199. }