ffnet.js 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. export const ffnet = (function() {
  2. function dot(a, b) {
  3. let r = 0;
  4. for (let i = 0; i < a.length; i++) {
  5. r += a[i] * b[i];
  6. }
  7. return r;
  8. }
  9. function add(a, b) {
  10. return a.map((v1, i) => v1 + b[i]);
  11. }
  12. return {
  13. sigmoid: function (z) {
  14. return z.map(v => 1.0 / (1.0 + Math.exp(-v)));
  15. },
  16. relu: function (z) {
  17. return z.map(v => Math.max(v, 0));
  18. },
  19. FFNeuralNetwork: class {
  20. constructor(shapes) {
  21. function _InitRandomArray(sz) {
  22. return [...Array(sz)].map(_ => Math.random() * 2 - 1);
  23. }
  24. this._shapes = shapes;
  25. this._biases = shapes.slice(1).map(x => _InitRandomArray(x.size));
  26. this._weights = [];
  27. for (let i = 1; i < shapes.length; i++) {
  28. this._weights.push(
  29. [...Array(shapes[i].size)].map(_=>_InitRandomArray(shapes[i-1].size)));
  30. }
  31. }
  32. predict(inputs) {
  33. let X = inputs;
  34. for (let i = 0; i < this._weights.length; i++) {
  35. const layer_weights = this._weights[i];
  36. const layer_bias = this._biases[i];
  37. // z = wx + b
  38. const z = add(layer_weights.map(w => dot(X, w)), layer_bias);
  39. // a = σ(z)
  40. const a = this._shapes[i+1].activation(z);
  41. // The output from the layer becomes the input to the next.
  42. X = a;
  43. }
  44. return X;
  45. }
  46. toArray() {
  47. return [...this._biases.flat()].concat(
  48. [...this._weights.flat().flat()]);
  49. }
  50. fromArray(values) {
  51. const arr = [...values];
  52. let i = 0;
  53. for (let b of this._biases) {
  54. b.splice(0, b.length, ...arr.splice(0, b.length));
  55. }
  56. for (let w of this._weights) {
  57. for (let w1 of w) {
  58. w1.splice(0, w1.length, ...arr.splice(0, w1.length));
  59. }
  60. }
  61. }
  62. }
  63. };
  64. })();