243 Commits

Autor SHA1 Mensagem Data
Vsevolod Rodionov 0b31eed0d1 Update README.md 2016-09-20 14:16:38 +03:00
Juan Cazala a5fbefea5a Replace juancazala.com with caza.la 2016-09-16 19:42:46 -03:00
Vsevolod Rodionov 3d8265d804 version bump for CDNJS - no actual changes
see https://github.com/cazala/synaptic/issues/137
2016-09-13 12:14:35 +03:00
Vsevolod Rodionov 34c93cb718 Bringing synaptic.min.js and webpack.config that is outputting 100% identical .js and .min.js files - just a dirty fix for CDNJS
that is related to https://github.com/cazala/synaptic/issues/137, we're using fn.toString() and bunch of regex-es to create a worker for now (I know, it's bad, still we already have a fix, but it is breaking some of our actually-interal, but overly-exposed APIs, so it goes to v2), and we need to either have one version minified by us or it will be minified by CDNs.
2016-09-12 01:36:48 +03:00
Juan Cazala d3e2ea8488 Merge pull request #133 from bobalazek/master
Rate error bugfix
2016-08-19 18:17:12 -03:00
Borut 4cfd5a828f Rate error bugfix 2016-08-19 22:05:07 +02:00
Juan Cazala 24807634e8 Added slack badge 2016-08-19 12:12:56 -03:00
Juan Cazala ebac6d8c33 Merge pull request #121 from Jabher/karma_tests
bringing karma for browser testing
2016-08-03 11:26:45 -03:00
Juan Cazala b0a9559beb Merge pull request #120 from filet-mign0n/testreadme
replaced gulp with mocha in test readme
2016-07-29 17:29:12 -03:00
Vsevolod Rodionov 5a6c487102 bringing karma for browser testing 2016-07-29 15:47:27 +03:00
Filet Mig0n 9a06d558aa replaced gulp with mocha 2016-07-26 16:51:31 -07:00
Juan Cazala 0a544dbc9e Replaced pre-commit with pre-push 2016-07-26 11:06:49 -03:00
Juan Cazala 3c433021e5 Bump version 2016-07-25 15:39:24 -03:00
Juan Cazala e2240eb7b3 Added prebuild script 2016-07-25 15:38:57 -03:00
Juan Cazala efb642c2a7 v1.0.8 2016-07-25 15:26:02 -03:00
Juan Cazala 697de49de0 v1.0.8 2016-07-25 15:25:11 -03:00
Juan Cazala 82d64f27a9 Added precommit 2016-07-25 15:23:23 -03:00
Juan Cazala 116df545fe Merge pull request #115 from Jabher/master
removing useless variables && declaring missed ones
2016-07-25 15:11:33 -03:00
Vsevolod Rodionov e6953b5028 changing list of supported node.js versions for Travis CI in accordance with package.json manifest ("node": ">=4") 2016-07-25 17:45:06 +03:00
Vsevolod Rodionov 47745614e3 test refactor - see comment
The first thing is that prev tests were relaying upon expectation of "it" function executed synchroniously. However, actual result was another: functions were called after everything was fired. So all assertions expectations like "this is result on 200th iteration" were whong as all of them were fired after all 1000 iterations ran.

 Another thing was default assertion library able to simple asserions. In order to simplify the debugging chai was used - it allows to write something like `assert.isAtMost(val1, val2, ...)`, and if everything fails it outputs something like "expected 0.52 to be at most 0.49", so actual BDD-style tests are used now.
2016-07-22 18:43:39 +03:00
Vsevolod Rodionov 5041da2c25 replacing assertion lib: using chai for now 2016-07-22 12:20:45 +03:00
Vsevolod Rodionov 05113ec720 dist build 2016-07-20 00:26:53 +03:00
Vsevolod Rodionov d3044fbe2a updating travis node.js envs 2016-07-19 15:56:34 +03:00
Vsevolod Rodionov f6e8d79f2a removing useless variables && declaring missed ones 2016-07-18 01:10:52 +03:00
Juan Cazala e1ff6b86df Merge pull request #114 from bobalazek/master
Fixed rate callback and tests
2016-07-17 11:44:22 -03:00
Borut c233227b10 Fixed rate callback and tests 2016-07-17 09:27:48 +02:00
Juan Cazala 8ff4f28075 Merge pull request #110 from bobalazek/master
Rate callback
2016-07-15 10:42:04 -03:00
Borut 533d77aaea Schould be able to set a callback the rate 2016-07-12 22:38:14 +02:00
Juan Cazala 29bd2ecf28 Delete index.html 2016-07-09 16:58:49 -03:00
Juan Cazala 8a7d82b25c Update README.md 2016-07-09 16:55:43 -03:00
Juan Cazala 45e4cc2ab3 Delete launch.json 2016-07-09 16:52:31 -03:00
Juan Cazala bd5062bdaa Ignore .settings 2016-07-09 16:51:56 -03:00
Juan Cazala 0345fe648d Fixed bundle path 2016-07-09 16:47:50 -03:00
Juan Cazala b820493823 Merge branch 'master' of https://github.com/cazala/synaptic 2016-07-08 19:02:18 -03:00
Juan Cazala 7ee75f9984 v1.0.6 2016-07-08 19:01:04 -03:00
Juan Cazala 25e1e151a2 Replaced gulp with webpack 2016-07-08 19:00:24 -03:00
Juan Cazala c5be6ffa3d Merge pull request #105 from yogiben/patch-1
Add instructions to accessing examples
2016-07-07 01:50:34 -03:00
Ben Jones 50d28c328f Update README.md 2016-07-07 00:12:35 +02:00
Juan Cazala 5524e29646 v1.0.5 2016-07-04 21:56:38 -03:00
Juan Cazala abdce5117a v1.0.5 2016-07-04 21:55:54 -03:00
Juan Cazala a8d237f577 Merge pull request #102 from Cristy94/master
Improve workerTrain performance
2016-07-04 21:49:12 -03:00
Cristy94 238be47c90 Remove ES6 template strings so travis build doesn't fail 2016-06-30 12:20:59 +03:00
Cristy94 4a8301d3f9 Revert accidental typo 2016-06-29 23:35:08 +03:00
Cristy94 6fc3bbf898 Improve multi-threaded training performance (#100)
I have made the changes described in #100. After this update, training 6
networks at the same time reduced the time from over 5 minutes (I
stopped it after that) to under 30 seconds, it is way, way faster. I
think I didn't include the schedule call, but everything should work
(including logging after X iterations).
2016-06-29 23:21:09 +03:00
Juan Cazala 8895db5052 Update README.md 2016-06-07 18:05:25 -03:00
Juan Cazala dab9030d19 Added CDN link 2016-05-23 10:50:37 -03:00
Juan Cazala fb0037bb0e Merge pull request #79 from vkaracic/patch-1
Update synaptic.js
2016-03-19 12:02:39 -03:00
Vedran Karačić 74cdcc35ac Update synaptic.js
Small typo :)
2016-03-19 11:56:07 +01:00
Juan Cazala 82375f977d Merge pull request #76 from cazala/development
v1.0.4
2016-03-17 10:37:39 -03:00
Juan Cazala b752e29788 v1.0.4 2016-03-17 10:33:57 -03:00
Juan Cazala ab3470dd8d Merge pull request #75 from lucasBertola/master
fix bug in timingTask
2016-03-17 10:28:10 -03:00
Bertola lucas b71201262a fix bug in timingTask 2016-03-16 21:42:12 +01:00
Juan Cazala e8ce3a998c build version 1.0.3 2016-03-02 13:28:25 -03:00
Juan Cazala afeb75eeef build dist files 2016-03-02 13:28:12 -03:00
Juan Cazala 65dbed4936 Merge pull request #64 from funerr/corss-validation
Fix options.crossValidate bug and make sin tests more lenient
2015-10-18 20:51:07 -03:00
agam360 3975fcb894 Fix options.crossValidate bug and make sin tests more lenient 2015-10-17 16:21:40 +03:00
Juan Cazala f22842a350 Merge pull request #61 from funerr/cross-validation
Cross validation
2015-10-11 16:13:57 -03:00
agam360 afa660ecde Fix crossvalidation error bug and create its unit test 2015-10-09 03:19:43 +03:00
agam360 d9ea8fac74 Fix test 2015-10-09 03:06:36 +03:00
agam360 576e8977fd Adding test 2015-10-09 02:31:09 +03:00
agam360 806387cae5 Fix syntax error and undefined options 2015-10-09 00:44:47 +03:00
agam360 c44c226151 Add cross-validation code 2015-10-09 00:43:06 +03:00
Juan Cazala a5d5045784 Update bower.json 2015-09-01 11:42:41 -03:00
Juan Cazala b2c3220c70 updated version tag 2015-09-01 11:42:24 -03:00
Juan Cazala b1a0846e87 Merge pull request #55 from SkY3r/patch-1
>=0.10 Node Compatibility
2015-08-27 14:03:18 -03:00
SkY3r bdefeb2853 >=0.10 Node Compatibility
Error by installing on new versions of the Node:

npm WARN engine synaptic@1.0.1: wanted: {"node":"^0.10.0"} (current: {"node":"0.12.7","npm":"2.13.5"})
2015-08-27 17:48:09 +02:00
Juan Cazala 7bc08646ab Merge pull request #52 from GrantMStevens/master
fixing array joinng in standalone function to prevent commas
2015-07-29 17:39:45 +02:00
Grant Stevens a4042c4364 fixing array joinng in standalone function to prevent commas 2015-07-29 11:31:17 -04:00
Juan Cazala 4d50133633 update tag: v1.0.1 2015-07-20 03:11:42 -03:00
Juan Cazala 169bea133c update tag: v1.0.1 2015-07-20 03:11:17 -03:00
Juan Cazala 6da278357f fix #51 2015-07-17 13:55:02 -03:00
Juan Cazala 26dbe8ceee added ReLU activation function 2015-07-16 10:44:04 -03:00
Juan Cazala 8e19e852a0 removed inline requires 2015-07-15 20:24:34 -03:00
Juan Cazala 06b4566eb3 fixed typo 2015-07-15 00:46:17 -03:00
Juan Cazala 96f88da732 build list files 2015-07-15 00:07:36 -03:00
Agustin Mendez a3bd74e72a Merge pull request #49 from Qard/real-errors
Don't throw strings
2015-07-14 23:43:25 -03:00
Stephen Belanger db2a42330e Don't throw strings 2015-07-14 14:25:55 -07:00
Juan Cazala e0f20561c2 updated tag 2015-07-12 23:56:45 -03:00
Juan Cazala ec8cd5f29b new release 2015-07-12 23:07:15 -03:00
Juan Cazala f4eed6a396 new release 2015-07-12 23:06:42 -03:00
Juan Cazala 70b974ddcd normalized everything to camelCase 2015-07-12 23:06:42 -03:00
Juan Cazala 892aa1b349 added new spec to the tests: timing task 2015-07-12 23:06:42 -03:00
Juan Cazala 52fe07fc95 removed browser test file 2015-07-12 23:06:42 -03:00
Juan Cazala d4aa1d23ac unified influences into main memory array for optimized nets 2015-07-12 23:06:41 -03:00
Juan Cazala ed5e287a40 fixed bug: extra eligibility traces were copied when cloning 2015-07-12 23:06:41 -03:00
Juan Cazala 8be394c4c7 ignore debug file 2015-07-12 23:06:41 -03:00
Juan Cazala 26b75f9542 removed unnecesary license prepend 2015-07-12 23:06:41 -03:00
Juan Cazala e4b1639bf4 new features: test, timingTask and scheduled tasks Trainer.cost.BINARY 2015-07-12 23:06:41 -03:00
Juan Cazala 8c4e3db35c Merge pull request #40 from coleww/patch-1
fix toJSON comment
2015-06-21 02:25:52 -03:00
Cole Willsea cbfe912e54 fixes toJSON comment 2015-06-20 21:47:11 -07:00
Juan Cazala f1c5d7c9e2 Merge pull request #39 from anubisthejackle/patch-2
Update synaptic.js
2015-06-20 15:09:36 -03:00
Travis Weston a8e7ca02df Update synaptic.js
Performance boost to noRepeat method.
2015-06-18 16:19:12 -04:00
Juan Cazala b7664e608a fixed typo in neuron.reset() 2015-05-26 14:13:07 -03:00
Juan Cazala bbf1046fdc Update README.md 2015-05-16 23:59:52 -03:00
Juan Cazala ab840c2150 Update README.md 2015-05-16 20:29:05 -03:00
Juan Cazala 798462380c fixed workerTrain
there was an undefined variable ‘abort_training’
2015-05-16 20:15:02 -03:00
Juan Cazala 473e07962a removed extra license in uncompressed build 2015-05-16 20:15:02 -03:00
Juan Cazala 10ad23e88b Update README.md 2015-05-16 20:01:51 -03:00
Juan Cazala 84f78fcd7c Update README.md 2015-05-16 19:59:28 -03:00
Juan Cazala fe91cf0b5b browserified source for the web 2015-05-16 19:54:24 -03:00
Juan Cazala 65a07d8308 improved gulp tasks 2015-05-16 19:54:04 -03:00
Juan Cazala e0a6a21977 Update README.md 2015-05-16 19:43:31 -03:00
Juan Cazala ec02e046f8 Update README.md 2015-05-16 19:41:47 -03:00
Juan Cazala fd44c0bdfe Update README.md 2015-05-14 10:41:51 -03:00
Juan Cazala d03c61455c Merge pull request #38 from cazala/dot
added image link when exporting to dot language
2015-05-13 18:03:19 -03:00
Juan Cazala a59a06d4dc added image link when exporting to dot language 2015-05-13 18:00:03 -03:00
Juan Cazala bae5eb462c Update README.md 2015-05-13 12:05:27 -03:00
Juan Cazala 2b30b70af0 Update README.md 2015-05-13 12:02:48 -03:00
Juan Cazala 43fef38be9 Update README.md 2015-05-13 12:01:49 -03:00
Juan Cazala dbe8fd1526 Merge pull request #37 from mkondel/master
fixed gulp tasks with browserify
2015-05-12 20:24:04 -03:00
max 35edc26484 mocha fix 2015-05-12 18:05:50 -04:00
max 36de19118f mocha fix 2015-05-12 18:04:58 -04:00
max ec0b9f4b6a added minified version to gulp and repo 2015-05-12 17:51:19 -04:00
max 902eb992b8 added /dist/synaptic.js with sourcemaps 2015-05-12 17:16:52 -04:00
max 1d129e50d6 updated tests 2015-05-11 22:58:07 -04:00
max a407542612 closer to the original 2015-05-11 22:26:08 -04:00
max 3a729890cb fixed gulp tasks with browserify 2015-05-11 21:37:12 -04:00
Juan Cazala d13062eed0 Merge pull request #36 from mkondel/master
Stop training with custom conditions
2015-05-11 21:05:44 -03:00
max 9724b4457f depreciated customLog in favor of custom 2015-05-11 19:28:35 -04:00
max 3f1f5b483a depreciated customLog in favor of custom 2015-05-11 19:25:35 -04:00
max ef0b488b2f return true from customLog to stop training, otherwise should be backward compatible with code that used old customLog 2015-05-10 21:15:12 -04:00
max fcde4bd112 return true/false from customLog to allow_iterations, or stop training at any point 2015-05-10 21:04:13 -04:00
max 10cf382145 return true/false from customLog to allow_iterations, or stop training at any point 2015-05-10 21:02:21 -04:00
max 321fb4ea4c return true/false from customLog to allow_iterations, or stop training at any point 2015-05-10 20:58:12 -04:00
Juan Cazala 346cf5669f Merge pull request #32 from Sleepwalking/master
add options to Architect.LSTM
2015-05-02 22:03:39 -03:00
sleepwalking b26d7e03c2 add options to Architect.LSTM 2015-05-01 11:26:15 +08:00
Juan Cazala ac4c2684b2 Merge pull request #31 from Sleepwalking/master
Parallelize neuron activation sequence in self-connected layers
2015-05-01 00:09:34 -03:00
sleepwalking 418610215e Merge https://github.com/cazala/synaptic 2015-05-01 10:49:42 +08:00
sleepwalking 281474b46e all to else connection type 2015-05-01 10:34:57 +08:00
sleepwalking c2ebf9c054 export topology to DOT language 2015-05-01 10:30:59 +08:00
Juan Cazala 00809d2fd2 Merge pull request #29 from Sleepwalking/master
Optimization for Second-order Networks
2015-04-29 10:51:50 -03:00
sleepwalking 91b8abab12 calculate & store influences in advance 2015-04-29 20:00:22 +08:00
Juan Cazala 40a1f896b4 Merge pull request #28 from JakePrasad/master
Extra commas were being added to hardcode
2015-04-23 12:19:56 -03:00
Jake Prasad a58a3aae00 Extra commas were being added to hardcode 2015-04-20 22:11:11 -07:00
Juan Cazala 6fb5a051fe added link to source for demos 2015-04-07 00:40:06 -03:00
Juan Cazala 64eac61a99 added link to source for demos 2015-04-07 00:37:27 -03:00
Juan Cazala 1e00acb166 added more tests 2015-03-31 11:30:35 -03:00
Juan Cazala 1b430ae012 Update README.md 2015-03-24 19:14:29 -03:00
Juan Cazala 69e2acabed Update README.md 2015-03-18 17:10:35 -03:00
Juan Cazala 4c14532dce Merge pull request #22 from shamoons/tests/network-layer
Tests/network layer
2015-03-17 12:16:41 -03:00
Shamoon Siddiqui 846b25ea84 Removed extraneous parallel components 2015-03-17 09:24:41 -04:00
Shamoon Siddiqui af7a44c808 Got AND Gate search to function 2015-03-14 11:21:46 -04:00
Shamoon Siddiqui 2c7de4e9fa Starting to add test for network training 2015-03-14 11:12:13 -04:00
Juan Cazala 2d4d15bff1 grouped optimized code by layers and neurons 2015-03-13 00:52:09 -03:00
Juan Cazala a6dcace957 Update README.md 2015-03-12 13:35:12 -03:00
Juan Cazala ae0e77c1e0 updated demo links 2015-03-12 00:53:58 -03:00
Juan Cazala 9535b635ef Update README.md 2015-03-12 00:50:19 -03:00
Juan Cazala 2f8c98a399 Merge pull request #19 from jzjzjzj/patch-1
Specified hidden layers in LSTM example.
2015-03-09 21:03:51 -03:00
Juan Cazala b5f4249cdb Fix #18 2015-03-09 13:30:01 -03:00
Jānis d91a445a98 Specified hidden layers in LSTM example. 2015-03-09 09:16:48 +02:00
Juan Cazala 17f049a6f7 Update README.md 2015-03-05 15:40:25 -03:00
Juan Cazala c31aa638df Update README.md 2015-03-05 15:37:57 -03:00
Juan Cazala 7373c1268f Merge pull request #17 from shamoons/master
Changing learning rate
2015-03-05 15:32:00 -03:00
Shamoon Siddiqui f1c87a7860 Getting bucket sizes to change learning rate 2015-03-05 10:54:32 -05:00
Shamoon Siddiqui c62f108ea5 Edited README to explain new rate 2015-03-05 10:44:09 -05:00
Juan Cazala 8a25ecda4d Fixed undefined references 2015-02-18 10:56:44 -03:00
Agustin Mendez (Menduz) 0e2300aa98 Fixed common js
Fixed CommonJS compatibility
2015-02-17 21:36:42 -03:00
Agustin Mendez 1470f5e3db Update synaptic.js
Updated ninja function. Now we restore the old value of global.synaptic
2015-01-06 10:48:27 -03:00
Juan Cazala a62b054c65 deleted .npmignore 2014-12-14 23:02:43 -03:00
Juan Cazala 245eaab620 updated build 2014-12-14 02:52:15 -03:00
Juan Cazala 912976791b added optional cost function documentation 2014-12-09 23:52:16 -03:00
Juan Cazala 83264fb988 updated version 2014-12-09 23:48:58 -03:00
Juan Cazala e0cd3dee9e added optional cost function documentation 2014-12-09 23:43:25 -03:00
Juan Cazala 2e8428c3a5 fixed syntax error 2014-12-09 22:46:19 -03:00
Juan Cazala 8acbda38ec added alternative cost function feature 2014-12-09 22:40:43 -03:00
Juan Cazala 92b083bc92 added cross-entropy training option 2014-12-09 22:40:32 -03:00
Juan Cazala 933aceb869 updated readme 2014-12-06 15:42:20 -03:00
Juan Cazala 8c0374782d Updated readme 2014-12-06 15:24:45 -03:00
Juan Cazala 190f9a859a built dist 2014-12-06 15:24:20 -03:00
Juan Cazala 15b4069854 Update README.md 2014-12-05 02:36:15 -03:00
Juan Cazala 8bdebef70f Update README.md 2014-12-05 02:16:33 -03:00
Juan Cazala eb46ae5535 Update README.md 2014-12-05 02:04:37 -03:00
Juan Cazala d7f268e2ce changed dependencies versions 2014-12-05 01:59:30 -03:00
Juan Cazala 0829ba97a2 changed gulp version 2014-12-05 01:57:07 -03:00
Juan Cazala 76de621d8d fixed CI test 2014-12-05 01:47:29 -03:00
Juan Cazala ee9f140c6d fixed CI test 2014-12-05 01:42:01 -03:00
Juan Cazala ccd242b8e2 updated node engine 2014-12-05 01:37:11 -03:00
Juan Cazala ea63c9f2e1 added gulp test task 2014-12-05 01:32:29 -03:00
Juan Cazala d3e1e352be added gulp test task 2014-12-05 01:30:39 -03:00
Juan Cazala 88c5867f56 added new Hopfield architecture
hop field network + fix issue #9 + separated files and added gulp task
2014-12-05 01:29:08 -03:00
Juan Cazala d8c4da5243 improved optimized networks test
improved the equivalency test between optimized and unoptimized
networks to perform 1000 iterations producing the same output for both
networks (before it was only 5 iterations)
2014-11-01 20:58:02 -03:00
Juan Cazala 2f0d447a87 updated version
0.1.3
2014-11-01 20:35:00 -03:00
Juan Cazala 3cb8a62fe9 updated .gitignore
removed debug.html
2014-11-01 20:34:26 -03:00
Juan Cazala a1a83b6f0b updated readme
bigger titles
2014-11-01 20:32:43 -03:00
Juan Cazala cb46ea001a updated version 2014-11-01 20:30:33 -03:00
Juan Cazala 2fe1d77df2 added workerTrain: train networks using WebWorkers 2014-11-01 20:26:24 -03:00
Juan Cazala d16c16fd8d added link to introduction (wiki) 2014-10-26 21:40:39 -03:00
Juan Cazala 71648fa5c7 Merge pull request #5 from bcbcb/master
Fixed spelling errors in readme
2014-10-25 01:41:56 -03:00
bcbcb e41739a92b Fixed more spelling errors 2014-10-24 21:12:14 -07:00
bcbcb ee25127159 Fixed spelling 2014-10-24 21:09:49 -07:00
Juan Cazala 48d67de2b2 Fix spelling. 2014-10-24 10:13:37 -03:00
Juan Cazala 98f41f6fbf Merge pull request #4 from germ13/patch-1
Fix spelling.
2014-10-24 10:08:52 -03:00
juan serrano 3f94d1837e Fix spelling. 2014-10-24 02:43:01 -07:00
Juan Cazala 919b1e8cf1 added new test case
added new test case: compare if optimized and unoptimized networks
output the same results when activating/propagating, for 5 consecutive
iterations.
2014-10-24 01:05:19 -03:00
Juan Cazala 0094d1219c added build status 2014-10-23 23:53:36 -03:00
Juan Cazala 5d77f4c906 updated readme 2014-10-23 23:51:09 -03:00
Juan Cazala 84732a8ccf added default connectionTypes
When connecting two layers using the .project() method, if you don’t
specify any connectionType, ALL_TO_ALL is going to be used by default,
except for self-connections, in that case ONE_TO_ONE is going to be the
default
2014-10-23 23:49:35 -03:00
Juan Cazala 2a65c2d28d added Travis CI file 2014-10-22 18:26:44 -03:00
Juan Cazala c0f2565a9f updated readme 2014-10-22 17:26:54 -03:00
Juan Cazala 95ea3fb5e5 updated read
added contribute section at the bottom
2014-10-21 23:47:39 -03:00
Juan Cazala bd47c96f4f updated version 2014-10-21 22:13:47 -03:00
Juan Cazala d8070e28a3 added defaults to XOR
added default configuration settings for the Trainer when training an
XOR
2014-10-21 21:57:36 -03:00
Juan Cazala be38adda7c Merge pull request #2 from hartca/master
quick jshint sweep: tabs to spaces; semicolons
2014-10-21 21:47:37 -03:00
Chris cf4db74983 quick jshint sweep: tabs to spaces; semicolons 2014-10-22 01:39:14 +01:00
Juan Cazala 5c14bd1247 updated lib and test
there was a bug when training the XOR in the test module, the
iterations limit was set too low and it was finishing the training
before the net converged in an optimal result
2014-10-21 21:11:51 -03:00
Juan Cazala f7f71d11d4 added demos 2014-10-21 04:17:51 -03:00
Juan Cazala 53924ae6a5 added demos 2014-10-21 04:16:49 -03:00
Juan Cazala c100f2dae5 test readme 2014-10-20 23:08:47 -03:00
Juan Cazala 3613965a98 test readme 2014-10-20 23:08:06 -03:00
Juan Cazala 6555fdfbc7 readme file
updated read file
2014-10-20 23:05:17 -03:00
Juan Cazala e3661bc6f8 readme file
committed readme file
2014-10-20 23:04:34 -03:00
Juan Cazala 141d8632cf synaptic
lib commit
2014-10-20 23:02:22 -03:00
Juan Cazala 8c7a2453a4 added images to read 2014-10-20 09:27:26 -03:00
Juan Cazala f73820a72b lib 2014-10-20 09:15:43 -03:00
Juan Cazala e939790d5e links 2014-10-20 02:08:11 -03:00
Juan Cazala fb5694e328 links 2014-10-20 02:07:04 -03:00
Juan Cazala 42a693c7da readme 2014-10-20 01:59:31 -03:00
Juan Cazala b833deb547 updated lib 2014-10-20 01:58:21 -03:00
Juan Cazala e4dc16787b readme 2014-10-20 01:57:40 -03:00
Juan Cazala b7541310b8 readme 2014-10-20 01:19:58 -03:00
Juan Cazala 1fad9095c8 readme 2014-10-20 00:45:47 -03:00
Juan Cazala 65dbc1d60c readme 2014-10-19 23:06:57 -03:00
Juan Cazala 8e305c4f51 images added to read 2014-10-18 12:22:14 -03:00
Juan Cazala 7d13fb3f7a changed htan to tanh 2014-10-18 12:15:05 -03:00
Juan Cazala 2377bb228a readme 2014-10-17 04:17:56 -03:00
Juan Cazala 3ac81149ac readme 2014-10-17 04:17:29 -03:00
Juan Cazala a50c99da8e readme 2014-10-17 04:16:43 -03:00
Juan Cazala b00c643105 readme 2014-10-17 04:16:03 -03:00
Juan Cazala 7d129876bb readme 2014-10-17 03:14:05 -03:00
Juan Cazala bb6a51dfd3 readme 2014-10-17 02:34:15 -03:00
Juan Cazala 8931e57af7 readme 2014-10-17 02:16:13 -03:00
Juan Cazala 9271828b5f readme 2014-10-17 01:45:09 -03:00
Juan Cazala 2e46c8c031 readme 2014-10-17 01:41:26 -03:00
Juan Cazala 68fd02f8b6 package.json 2014-10-17 01:21:32 -03:00
Juan Cazala 06ab9450e8 readme 2014-10-16 03:49:58 -03:00
Juan Cazala 00037d95dc readme 2014-10-13 11:30:28 -03:00
Juan Cazala 0de7d91c91 readme 2014-10-12 17:14:34 -03:00
Juan Cazala 3729f879ea readme 2014-10-12 17:03:59 -03:00
Juan Cazala f5c7b7b64b readme 2014-10-12 16:42:29 -03:00
Juan Cazala 454439b058 readme 2014-10-12 16:41:26 -03:00
Juan Cazala 47bc37f9e9 tests 2014-10-12 16:39:00 -03:00
Juan Cazala 2958d346b7 lib 2014-10-09 23:02:44 -03:00
Juan Cazala 89ad4aa326 added .gitignore 2014-10-09 22:20:34 -03:00
22 arquivos alterados com 9439 adições e 5 exclusões
+20
Ver Arquivo
@@ -0,0 +1,20 @@
# Mac.
.DS_STORE
# Node.
node_modules
# Tmp files.
*~
# Dot.
*.dot
*.png
# Demo.
demo.js
# Degub
debug.html
.settings
+9
Ver Arquivo
@@ -0,0 +1,9 @@
language: node_js
script: "npm run test:travis"
node_js:
# always latest release
- "node"
# previous releases
- "6"
- "5"
- "4"
+29 -5
Ver Arquivo
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014 Juan Cazala
Copyright (c) 2016 Juan Cazala - juancazala.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -9,14 +9,38 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE
********************************************************************************************
SYNAPTIC (v1.0.8)
********************************************************************************************
Synaptic is a javascript neural network library for node.js and the browser, its generalized
algorithm is architecture-free, so you can build and train basically any type of first order
or even second order neural network architectures.
http://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network
The library includes a few built-in architectures like multilayer perceptrons, multilayer
long-short term memory networks (LSTM) or liquid state machines, and a trainer capable of
training any given network, and includes built-in training tasks/tests like solving an XOR,
passing a Distracted Sequence Recall test or an Embeded Reber Grammar test.
The algorithm implemented by this library has been taken from Derek D. Monner's paper:
A generalized LSTM-like training algorithm for second-order recurrent neural networks
http://www.overcomplete.net/papers/nn2012.pdf
There are references to the equations in that paper commented through the source code.
Arquivo executável
+201
Ver Arquivo
@@ -0,0 +1,201 @@
Synaptic [![Build Status](https://travis-ci.org/cazala/synaptic.svg?branch=master)](https://travis-ci.org/cazala/synaptic) [![Join the chat at https://synapticjs.slack.com](https://synaptic-slack-ugiqacqvmd.now.sh/badge.svg)](https://synaptic-slack-ugiqacqvmd.now.sh/)
========
## Important: [Synaptic 2.x](https://github.com/cazala/synaptic/issues/140) is in stage of discussion now! Feel free to participate
Synaptic is a javascript neural network library for **node.js** and the **browser**, its generalized algorithm is architecture-free, so you can build and train basically any type of first order or even [second order neural network](http://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network) architectures.
This library includes a few built-in architectures like [multilayer perceptrons](http://en.wikipedia.org/wiki/Multilayer_perceptron), [multilayer long-short term memory](http://en.wikipedia.org/wiki/Long_short_term_memory) networks (LSTM), [liquid state machines](http://en.wikipedia.org/wiki/Liquid_state_machine) or [Hopfield](http://en.wikipedia.org/wiki/Hopfield_network) networks, and a trainer capable of training any given network, which includes built-in training tasks/tests like solving an XOR, completing a Distracted Sequence Recall task or an [Embedded Reber Grammar](http://www.willamette.edu/~gorr/classes/cs449/reber.html) test, so you can easily test and compare the performance of different architectures.
The algorithm implemented by this library has been taken from Derek D. Monner's paper:
[A generalized LSTM-like training algorithm for second-order recurrent neural networks](http://www.overcomplete.net/papers/nn2012.pdf)
There are references to the equations in that paper commented through the source code.
####Introduction
If you have no prior knowledge about Neural Networks, you should start by [reading this guide](https://github.com/cazala/synaptic/wiki/Neural-Networks-101).
If you want a practical example on how to feed data to a neural network, then take a look at [this article](https://github.com/cazala/synaptic/wiki/Normalization-101).
You may also want to take a look at [this article](http://blog.webkid.io/neural-networks-in-javascript/).
####Demos
- [Solve an XOR](http://caza.la/synaptic/#/xor)
- [Discrete Sequence Recall Task](http://caza.la/synaptic/#/dsr)
- [Learn Image Filters](http://caza.la/synaptic/#/image-filters)
- [Paint an Image](http://caza.la/synaptic/#/paint-an-image)
- [Self Organizing Map](http://caza.la/synaptic/#/self-organizing-map)
- [Read from Wikipedia](http://caza.la/synaptic/#/wikipedia)
The source code of these demos can be found in [this branch](https://github.com/cazala/synaptic/tree/gh-pages/scripts).
####Getting started
- [Neurons](https://github.com/cazala/synaptic/wiki/Neurons/)
- [Layers](https://github.com/cazala/synaptic/wiki/Layers/)
- [Networks](https://github.com/cazala/synaptic/wiki/Networks/)
- [Trainer](https://github.com/cazala/synaptic/wiki/Trainer/)
- [Architect](https://github.com/cazala/synaptic/wiki/Architect/)
To try out the examples, checkout the [gh-pages](https://github.com/cazala/synaptic/tree/gh-pages) branch.
`git checkout gh-pages`
##Overview
###Installation
#####In node
You can install synaptic with [npm](http://npmjs.org):
```cmd
npm install synaptic --save
```
#####In the browser
You can install synaptic with [bower](http://bower.io):
```cmd
bower install synaptic
```
Or you can simply use the CDN link, kindly provided by [CDNjs](https://cdnjs.com/)
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/synaptic/1.0.8/synaptic.js"></script>
```
###Usage
```javascript
var synaptic = require('synaptic'); // this line is not needed in the browser
var Neuron = synaptic.Neuron,
Layer = synaptic.Layer,
Network = synaptic.Network,
Trainer = synaptic.Trainer,
Architect = synaptic.Architect;
```
Now you can start to create networks, train them, or use built-in networks from the [Architect](http://github.com/cazala/synaptic#architect).
###Examples
#####Perceptron
This is how you can create a simple **perceptron**:
![perceptron](http://www.codeproject.com/KB/dotnet/predictor/network.jpg).
```javascript
function Perceptron(input, hidden, output)
{
// create the layers
var inputLayer = new Layer(input);
var hiddenLayer = new Layer(hidden);
var outputLayer = new Layer(output);
// connect the layers
inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);
// set the layers
this.set({
input: inputLayer,
hidden: [hiddenLayer],
output: outputLayer
});
}
// extend the prototype chain
Perceptron.prototype = new Network();
Perceptron.prototype.constructor = Perceptron;
```
Now you can test your new network by creating a trainer and teaching the perceptron to learn an XOR
```javascript
var myPerceptron = new Perceptron(2,3,1);
var myTrainer = new Trainer(myPerceptron);
myTrainer.XOR(); // { error: 0.004998819355993572, iterations: 21871, time: 356 }
myPerceptron.activate([0,0]); // 0.0268581547421616
myPerceptron.activate([1,0]); // 0.9829673642853368
myPerceptron.activate([0,1]); // 0.9831714267395621
myPerceptron.activate([1,1]); // 0.02128894618097928
```
#####Long Short-Term Memory
This is how you can create a simple **long short-term memory** network with input gate, forget gate, output gate, and peephole connections:
![long short-term memory](http://people.idsia.ch/~juergen/lstmcell4.jpg)
```javascript
function LSTM(input, blocks, output)
{
// create the layers
var inputLayer = new Layer(input);
var inputGate = new Layer(blocks);
var forgetGate = new Layer(blocks);
var memoryCell = new Layer(blocks);
var outputGate = new Layer(blocks);
var outputLayer = new Layer(output);
// connections from input layer
var input = inputLayer.project(memoryCell);
inputLayer.project(inputGate);
inputLayer.project(forgetGate);
inputLayer.project(outputGate);
// connections from memory cell
var output = memoryCell.project(outputLayer);
// self-connection
var self = memoryCell.project(memoryCell);
// peepholes
memoryCell.project(inputGate);
memoryCell.project(forgetGate);
memoryCell.project(outputGate);
// gates
inputGate.gate(input, Layer.gateType.INPUT);
forgetGate.gate(self, Layer.gateType.ONE_TO_ONE);
outputGate.gate(output, Layer.gateType.OUTPUT);
// input to output direct connection
inputLayer.project(outputLayer);
// set the layers of the neural network
this.set({
input: inputLayer,
hidden: [inputGate, forgetGate, memoryCell, outputGate],
output: outputLayer
});
}
// extend the prototype chain
LSTM.prototype = new Network();
LSTM.prototype.constructor = LSTM;
```
These are examples for explanatory purposes, the [Architect](https://github.com/cazala/synaptic/wiki/Architect/) already includes Multilayer Perceptrons and
Multilayer LSTM network architectures.
##Contribute
**Synaptic** is an Open Source project that started in Buenos Aires, Argentina. Anybody in the world is welcome to contribute to the development of the project.
If you want to contribute feel free to send PR's, just make sure to run **npm run test** and **npm run build** before submiting it. This way you'll run all the test specs and build the web distribution files.
<3
+33
Ver Arquivo
@@ -0,0 +1,33 @@
{
"name": "synaptic",
"version": "1.0.8",
"homepage": "https://github.com/cazala/synaptic",
"authors": [
"Juan Cazala <juancazala@gmail.com>"
],
"description": "architecture-free neural network library for node.js and the browser",
"main": "./dist/synaptic.min.js",
"moduleType": [
"amd",
"globals",
"node"
],
"keywords": [
"neural",
"network",
"deep",
"learning",
"machine",
"learning",
"lstm",
"perceptron"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}
+2848
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2848
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+25
Ver Arquivo
@@ -0,0 +1,25 @@
// Karma configuration
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['mocha'],
files: [
'dist/synaptic.js',
'test/[^_]*.js'
],
exclude: [
],
preprocessors: {
'test/*.js': ['webpack'],
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
singleRun: false,
concurrency: Infinity,
browserNoActivityTimeout: 60000,
})
}
+58
Ver Arquivo
@@ -0,0 +1,58 @@
{
"name": "synaptic",
"version": "1.0.9",
"description": "architecture-free neural network library",
"main": "./src/synaptic",
"scripts": {
"test": "npm run test:src",
"test:src": "mocha test --require src/synaptic.js ./test",
"test:dist": "npm run build && npm run test:mocha:dist && npm run test:karma:browsers",
"test:mocha:src": "mocha test --require src/synaptic.js ./test",
"test:mocha:dist": "mocha test --require dist/synaptic.js ./test",
"test:karma:browsers": "karma start --single-run --browsers Chrome,Firefox,SafariPrivate",
"test:karma:phantomjs": "karma start --single-run --browsers PhantomJS",
"test:travis": "npm run test:mocha:src && npm run build && npm run test:mocha:dist",
"build": "webpack --config webpack.config.js"
},
"prepush": [
"test",
"build"
],
"devDependencies": {
"chai": "^3.5.0",
"chai-stats": "^0.3.0",
"karma": "^1.1.2",
"karma-chrome-launcher": "^1.0.1",
"karma-firefox-launcher": "^1.0.0",
"karma-mocha": "^1.1.1",
"karma-phantomjs-launcher": "^1.0.1",
"karma-safari-launcher": "^1.0.0",
"karma-webpack": "^1.7.0",
"mocha": "^2.2.4",
"pre-push": "^0.1.1",
"webpack": "^1.13.1"
},
"repository": {
"type": "git",
"url": "https://github.com/cazala/synaptic.git"
},
"keywords": [
"neural network",
"machine learning",
"long short term memory",
"perceptron",
"architecture free"
],
"author": "Juan Cazala <juancazala@gmail.com> (http://juancazala.com/)",
"license": {
"type": "MIT",
"url": "https://github.com/cazala/synaptic/blob/master/LICENSE"
},
"bugs": {
"url": "https://github.com/cazala/synaptic/issues"
},
"homepage": "http://synaptic.juancazala.com",
"engines": {
"node": ">=4"
}
}
+21
Ver Arquivo
@@ -0,0 +1,21 @@
// update license year and version
var fs = require('fs')
module.exports = function() {
var year = (new Date).getFullYear()
var version = require('./package.json').version
// LICENSE
var license = fs.readFileSync('LICENSE', 'utf-8')
.replace(/\(c\) ([0-9]+)/, `(c) ${year}`)
.replace(/SYNAPTIC \(v(.*)\)/, `SYNAPTIC (v${version})`)
fs.writeFileSync('LICENSE', license)
// bower.json
var bower = fs.readFileSync('bower.json', 'utf-8')
.replace(/\"version\": \"(.*)\",/, `"version": "${version}",`)
fs.writeFileSync('bower.json', bower)
// README.md
var readme = fs.readFileSync('README.md', 'utf-8')
.replace(/ajax\/libs\/synaptic\/(.*)\/synaptic.js/, `ajax/libs/synaptic/${version}/synaptic.js`)
fs.writeFileSync('README.md', readme)
// return license for dist banner
return license
}
+273
Ver Arquivo
@@ -0,0 +1,273 @@
// import
var Layer = require('./layer')
, Network = require('./network')
, Trainer = require('./trainer')
/*******************************************************************************************
ARCHITECT
*******************************************************************************************/
// Collection of useful built-in architectures
var Architect = {
// Multilayer Perceptron
Perceptron: function Perceptron() {
var args = Array.prototype.slice.call(arguments); // convert arguments to Array
if (args.length < 3)
throw new Error("not enough layers (minimum 3) !!");
var inputs = args.shift(); // first argument
var outputs = args.pop(); // last argument
var layers = args; // all the arguments in the middle
var input = new Layer(inputs);
var hidden = [];
var output = new Layer(outputs);
var previous = input;
// generate hidden layers
for (var level in layers) {
var size = layers[level];
var layer = new Layer(size);
hidden.push(layer);
previous.project(layer);
previous = layer;
}
previous.project(output);
// set layers of the neural network
this.set({
input: input,
hidden: hidden,
output: output
});
// trainer for the network
this.trainer = new Trainer(this);
},
// Multilayer Long Short-Term Memory
LSTM: function LSTM() {
var args = Array.prototype.slice.call(arguments); // convert arguments to array
if (args.length < 3)
throw new Error("not enough layers (minimum 3) !!");
var last = args.pop();
var option = {
peepholes: Layer.connectionType.ALL_TO_ALL,
hiddenToHidden: false,
outputToHidden: false,
outputToGates: false,
inputToOutput: true,
};
if (typeof last != 'number') {
var outputs = args.pop();
if (last.hasOwnProperty('peepholes'))
option.peepholes = last.peepholes;
if (last.hasOwnProperty('hiddenToHidden'))
option.hiddenToHidden = last.hiddenToHidden;
if (last.hasOwnProperty('outputToHidden'))
option.outputToHidden = last.outputToHidden;
if (last.hasOwnProperty('outputToGates'))
option.outputToGates = last.outputToGates;
if (last.hasOwnProperty('inputToOutput'))
option.inputToOutput = last.inputToOutput;
} else
var outputs = last;
var inputs = args.shift();
var layers = args;
var inputLayer = new Layer(inputs);
var hiddenLayers = [];
var outputLayer = new Layer(outputs);
var previous = null;
// generate layers
for (var layer in layers) {
// generate memory blocks (memory cell and respective gates)
var size = layers[layer];
var inputGate = new Layer(size).set({
bias: 1
});
var forgetGate = new Layer(size).set({
bias: 1
});
var memoryCell = new Layer(size);
var outputGate = new Layer(size).set({
bias: 1
});
hiddenLayers.push(inputGate);
hiddenLayers.push(forgetGate);
hiddenLayers.push(memoryCell);
hiddenLayers.push(outputGate);
// connections from input layer
var input = inputLayer.project(memoryCell);
inputLayer.project(inputGate);
inputLayer.project(forgetGate);
inputLayer.project(outputGate);
// connections from previous memory-block layer to this one
if (previous != null) {
var cell = previous.project(memoryCell);
previous.project(inputGate);
previous.project(forgetGate);
previous.project(outputGate);
}
// connections from memory cell
var output = memoryCell.project(outputLayer);
// self-connection
var self = memoryCell.project(memoryCell);
// hidden to hidden recurrent connection
if (option.hiddenToHidden)
memoryCell.project(memoryCell, Layer.connectionType.ALL_TO_ELSE);
// out to hidden recurrent connection
if (option.outputToHidden)
outputLayer.project(memoryCell);
// out to gates recurrent connection
if (option.outputToGates) {
outputLayer.project(inputGate);
outputLayer.project(outputGate);
outputLayer.project(forgetGate);
}
// peepholes
memoryCell.project(inputGate, option.peepholes);
memoryCell.project(forgetGate, option.peepholes);
memoryCell.project(outputGate, option.peepholes);
// gates
inputGate.gate(input, Layer.gateType.INPUT);
forgetGate.gate(self, Layer.gateType.ONE_TO_ONE);
outputGate.gate(output, Layer.gateType.OUTPUT);
if (previous != null)
inputGate.gate(cell, Layer.gateType.INPUT);
previous = memoryCell;
}
// input to output direct connection
if (option.inputToOutput)
inputLayer.project(outputLayer);
// set the layers of the neural network
this.set({
input: inputLayer,
hidden: hiddenLayers,
output: outputLayer
});
// trainer
this.trainer = new Trainer(this);
},
// Liquid State Machine
Liquid: function Liquid(inputs, hidden, outputs, connections, gates) {
// create layers
var inputLayer = new Layer(inputs);
var hiddenLayer = new Layer(hidden);
var outputLayer = new Layer(outputs);
// make connections and gates randomly among the neurons
var neurons = hiddenLayer.neurons();
var connectionList = [];
for (var i = 0; i < connections; i++) {
// connect two random neurons
var from = Math.random() * neurons.length | 0;
var to = Math.random() * neurons.length | 0;
var connection = neurons[from].project(neurons[to]);
connectionList.push(connection);
}
for (var j = 0; j < gates; j++) {
// pick a random gater neuron
var gater = Math.random() * neurons.length | 0;
// pick a random connection to gate
var connection = Math.random() * connectionList.length | 0;
// let the gater gate the connection
neurons[gater].gate(connectionList[connection]);
}
// connect the layers
inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);
// set the layers of the network
this.set({
input: inputLayer,
hidden: [hiddenLayer],
output: outputLayer
});
// trainer
this.trainer = new Trainer(this);
},
Hopfield: function Hopfield(size) {
var inputLayer = new Layer(size);
var outputLayer = new Layer(size);
inputLayer.project(outputLayer, Layer.connectionType.ALL_TO_ALL);
this.set({
input: inputLayer,
hidden: [],
output: outputLayer
});
var trainer = new Trainer(this);
var proto = Architect.Hopfield.prototype;
proto.learn = proto.learn || function(patterns)
{
var set = [];
for (var p in patterns)
set.push({
input: patterns[p],
output: patterns[p]
});
return trainer.train(set, {
iterations: 500000,
error: .00005,
rate: 1
});
};
proto.feed = proto.feed || function(pattern)
{
var output = this.activate(pattern);
var pattern = [];
for (var i in output)
pattern[i] = output[i] > .5 ? 1 : 0;
return pattern;
}
}
}
// Extend prototype chain (so every architectures is an instance of Network)
for (var architecture in Architect) {
Architect[architecture].prototype = new Network();
Architect[architecture].prototype.constructor = Architect[architecture];
}
// export
if (module) module.exports = Architect;
+276
Ver Arquivo
@@ -0,0 +1,276 @@
// export
if (module) module.exports = Layer;
// import
var Neuron = require('./neuron')
, Network = require('./network')
/*******************************************************************************************
LAYER
*******************************************************************************************/
function Layer(size, label) {
this.size = size | 0;
this.list = [];
this.label = label || null;
this.connectedTo = [];
while (size--) {
var neuron = new Neuron();
this.list.push(neuron);
}
}
Layer.prototype = {
// activates all the neurons in the layer
activate: function(input) {
var activations = [];
if (typeof input != 'undefined') {
if (input.length != this.size)
throw new Error("INPUT size and LAYER size must be the same to activate!");
for (var id in this.list) {
var neuron = this.list[id];
var activation = neuron.activate(input[id]);
activations.push(activation);
}
} else {
for (var id in this.list) {
var neuron = this.list[id];
var activation = neuron.activate();
activations.push(activation);
}
}
return activations;
},
// propagates the error on all the neurons of the layer
propagate: function(rate, target) {
if (typeof target != 'undefined') {
if (target.length != this.size)
throw new Error("TARGET size and LAYER size must be the same to propagate!");
for (var id = this.list.length - 1; id >= 0; id--) {
var neuron = this.list[id];
neuron.propagate(rate, target[id]);
}
} else {
for (var id = this.list.length - 1; id >= 0; id--) {
var neuron = this.list[id];
neuron.propagate(rate);
}
}
},
// projects a connection from this layer to another one
project: function(layer, type, weights) {
if (layer instanceof Network)
layer = layer.layers.input;
if (layer instanceof Layer) {
if (!this.connected(layer))
return new Layer.connection(this, layer, type, weights);
} else
throw new Error("Invalid argument, you can only project connections to LAYERS and NETWORKS!");
},
// gates a connection betwenn two layers
gate: function(connection, type) {
if (type == Layer.gateType.INPUT) {
if (connection.to.size != this.size)
throw new Error("GATER layer and CONNECTION.TO layer must be the same size in order to gate!");
for (var id in connection.to.list) {
var neuron = connection.to.list[id];
var gater = this.list[id];
for (var input in neuron.connections.inputs) {
var gated = neuron.connections.inputs[input];
if (gated.ID in connection.connections)
gater.gate(gated);
}
}
} else if (type == Layer.gateType.OUTPUT) {
if (connection.from.size != this.size)
throw new Error("GATER layer and CONNECTION.FROM layer must be the same size in order to gate!");
for (var id in connection.from.list) {
var neuron = connection.from.list[id];
var gater = this.list[id];
for (var projected in neuron.connections.projected) {
var gated = neuron.connections.projected[projected];
if (gated.ID in connection.connections)
gater.gate(gated);
}
}
} else if (type == Layer.gateType.ONE_TO_ONE) {
if (connection.size != this.size)
throw new Error("The number of GATER UNITS must be the same as the number of CONNECTIONS to gate!");
for (var id in connection.list) {
var gater = this.list[id];
var gated = connection.list[id];
gater.gate(gated);
}
}
connection.gatedfrom.push({layer: this, type: type});
},
// true or false whether the whole layer is self-connected or not
selfconnected: function() {
for (var id in this.list) {
var neuron = this.list[id];
if (!neuron.selfconnected())
return false;
}
return true;
},
// true of false whether the layer is connected to another layer (parameter) or not
connected: function(layer) {
// Check if ALL to ALL connection
var connections = 0;
for (var here in this.list) {
for (var there in layer.list) {
var from = this.list[here];
var to = layer.list[there];
var connected = from.connected(to);
if (connected.type == 'projected')
connections++;
}
}
if (connections == this.size * layer.size)
return Layer.connectionType.ALL_TO_ALL;
// Check if ONE to ONE connection
connections = 0;
for (var neuron in this.list) {
var from = this.list[neuron];
var to = layer.list[neuron];
var connected = from.connected(to);
if (connected.type == 'projected')
connections++;
}
if (connections == this.size)
return Layer.connectionType.ONE_TO_ONE;
},
// clears all the neuorns in the layer
clear: function() {
for (var id in this.list) {
var neuron = this.list[id];
neuron.clear();
}
},
// resets all the neurons in the layer
reset: function() {
for (var id in this.list) {
var neuron = this.list[id];
neuron.reset();
}
},
// returns all the neurons in the layer (array)
neurons: function() {
return this.list;
},
// adds a neuron to the layer
add: function(neuron) {
this.neurons[neuron.ID] = neuron || new Neuron();
this.list.push(neuron);
this.size++;
},
set: function(options) {
options = options || {};
for (var i in this.list) {
var neuron = this.list[i];
if (options.label)
neuron.label = options.label + '_' + neuron.ID;
if (options.squash)
neuron.squash = options.squash;
if (options.bias)
neuron.bias = options.bias;
}
return this;
}
}
// represents a connection from one layer to another, and keeps track of its weight and gain
Layer.connection = function LayerConnection(fromLayer, toLayer, type, weights) {
this.ID = Layer.connection.uid();
this.from = fromLayer;
this.to = toLayer;
this.selfconnection = toLayer == fromLayer;
this.type = type;
this.connections = {};
this.list = [];
this.size = 0;
this.gatedfrom = [];
if (typeof this.type == 'undefined')
{
if (fromLayer == toLayer)
this.type = Layer.connectionType.ONE_TO_ONE;
else
this.type = Layer.connectionType.ALL_TO_ALL;
}
if (this.type == Layer.connectionType.ALL_TO_ALL ||
this.type == Layer.connectionType.ALL_TO_ELSE) {
for (var here in this.from.list) {
for (var there in this.to.list) {
var from = this.from.list[here];
var to = this.to.list[there];
if(this.type == Layer.connectionType.ALL_TO_ELSE && from == to)
continue;
var connection = from.project(to, weights);
this.connections[connection.ID] = connection;
this.size = this.list.push(connection);
}
}
} else if (this.type == Layer.connectionType.ONE_TO_ONE) {
for (var neuron in this.from.list) {
var from = this.from.list[neuron];
var to = this.to.list[neuron];
var connection = from.project(to, weights);
this.connections[connection.ID] = connection;
this.size = this.list.push(connection);
}
}
fromLayer.connectedTo.push(this);
}
// types of connections
Layer.connectionType = {};
Layer.connectionType.ALL_TO_ALL = "ALL TO ALL";
Layer.connectionType.ONE_TO_ONE = "ONE TO ONE";
Layer.connectionType.ALL_TO_ELSE = "ALL TO ELSE";
// types of gates
Layer.gateType = {};
Layer.gateType.INPUT = "INPUT";
Layer.gateType.OUTPUT = "OUTPUT";
Layer.gateType.ONE_TO_ONE = "ONE TO ONE";
(function() {
var connections = 0;
Layer.connection.uid = function() {
return connections++;
}
})();
+645
Ver Arquivo
@@ -0,0 +1,645 @@
// export
if (module) module.exports = Network;
// import
var Neuron = require('./neuron')
, Layer = require('./layer')
, Trainer = require('./trainer')
/*******************************************************************************************
NETWORK
*******************************************************************************************/
function Network(layers) {
if (typeof layers != 'undefined') {
this.layers = layers || {
input: null,
hidden: {},
output: null
};
this.optimized = null;
}
}
Network.prototype = {
// feed-forward activation of all the layers to produce an ouput
activate: function(input) {
if (this.optimized === false)
{
this.layers.input.activate(input);
for (var layer in this.layers.hidden)
this.layers.hidden[layer].activate();
return this.layers.output.activate();
}
else
{
if (this.optimized == null)
this.optimize();
return this.optimized.activate(input);
}
},
// back-propagate the error thru the network
propagate: function(rate, target) {
if (this.optimized === false)
{
this.layers.output.propagate(rate, target);
var reverse = [];
for (var layer in this.layers.hidden)
reverse.push(this.layers.hidden[layer]);
reverse.reverse();
for (var layer in reverse)
reverse[layer].propagate(rate);
}
else
{
if (this.optimized == null)
this.optimize();
this.optimized.propagate(rate, target);
}
},
// project a connection to another unit (either a network or a layer)
project: function(unit, type, weights) {
if (this.optimized)
this.optimized.reset();
if (unit instanceof Network)
return this.layers.output.project(unit.layers.input, type, weights);
if (unit instanceof Layer)
return this.layers.output.project(unit, type, weights);
throw new Error("Invalid argument, you can only project connections to LAYERS and NETWORKS!");
},
// let this network gate a connection
gate: function(connection, type) {
if (this.optimized)
this.optimized.reset();
this.layers.output.gate(connection, type);
},
// clear all elegibility traces and extended elegibility traces (the network forgets its context, but not what was trained)
clear: function() {
this.restore();
var inputLayer = this.layers.input,
outputLayer = this.layers.output;
inputLayer.clear();
for (var layer in this.layers.hidden) {
var hiddenLayer = this.layers.hidden[layer];
hiddenLayer.clear();
}
outputLayer.clear();
if (this.optimized)
this.optimized.reset();
},
// reset all weights and clear all traces (ends up like a new network)
reset: function() {
this.restore();
var inputLayer = this.layers.input,
outputLayer = this.layers.output;
inputLayer.reset();
for (var layer in this.layers.hidden) {
var hiddenLayer = this.layers.hidden[layer];
hiddenLayer.reset();
}
outputLayer.reset();
if (this.optimized)
this.optimized.reset();
},
// hardcodes the behaviour of the whole network into a single optimized function
optimize: function() {
var that = this;
var optimized = {};
var neurons = this.neurons();
for (var i in neurons) {
var neuron = neurons[i].neuron;
var layer = neurons[i].layer;
while (neuron.neuron)
neuron = neuron.neuron;
optimized = neuron.optimize(optimized, layer);
}
for (var i in optimized.propagation_sentences)
optimized.propagation_sentences[i].reverse();
optimized.propagation_sentences.reverse();
var hardcode = "";
hardcode += "var F = Float64Array ? new Float64Array(" + optimized.memory +
") : []; ";
for (var i in optimized.variables)
hardcode += "F[" + optimized.variables[i].id + "] = " + (optimized.variables[
i].value || 0) + "; ";
hardcode += "var activate = function(input){\n";
for (var i in optimized.inputs)
hardcode += "F[" + optimized.inputs[i] + "] = input[" + i + "]; ";
for (var currentLayer in optimized.activation_sentences) {
if (optimized.activation_sentences[currentLayer].length > 0) {
for (var currentNeuron in optimized.activation_sentences[currentLayer]) {
hardcode += optimized.activation_sentences[currentLayer][currentNeuron].join(" ");
hardcode += optimized.trace_sentences[currentLayer][currentNeuron].join(" ");
}
}
}
hardcode += " var output = []; "
for (var i in optimized.outputs)
hardcode += "output[" + i + "] = F[" + optimized.outputs[i] + "]; ";
hardcode += "return output; }; "
hardcode += "var propagate = function(rate, target){\n";
hardcode += "F[" + optimized.variables.rate.id + "] = rate; ";
for (var i in optimized.targets)
hardcode += "F[" + optimized.targets[i] + "] = target[" + i + "]; ";
for (var currentLayer in optimized.propagation_sentences)
for (var currentNeuron in optimized.propagation_sentences[currentLayer])
hardcode += optimized.propagation_sentences[currentLayer][currentNeuron].join(" ") + " ";
hardcode += " };\n";
hardcode +=
"var ownership = function(memoryBuffer){\nF = memoryBuffer;\nthis.memory = F;\n};\n";
hardcode +=
"return {\nmemory: F,\nactivate: activate,\npropagate: propagate,\nownership: ownership\n};";
hardcode = hardcode.split(";").join(";\n");
var constructor = new Function(hardcode);
var network = constructor();
network.data = {
variables: optimized.variables,
activate: optimized.activation_sentences,
propagate: optimized.propagation_sentences,
trace: optimized.trace_sentences,
inputs: optimized.inputs,
outputs: optimized.outputs,
check_activation: this.activate,
check_propagation: this.propagate
}
network.reset = function() {
if (that.optimized) {
that.optimized = null;
that.activate = network.data.check_activation;
that.propagate = network.data.check_propagation;
}
}
this.optimized = network;
this.activate = network.activate;
this.propagate = network.propagate;
},
// restores all the values from the optimized network the their respective objects in order to manipulate the network
restore: function() {
if (!this.optimized)
return;
var optimized = this.optimized;
var getValue = function() {
var args = Array.prototype.slice.call(arguments);
var unit = args.shift();
var prop = args.pop();
var id = prop + '_';
for (var property in args)
id += args[property] + '_';
id += unit.ID;
var memory = optimized.memory;
var variables = optimized.data.variables;
if (id in variables)
return memory[variables[id].id];
return 0;
}
var list = this.neurons();
// link id's to positions in the array
var ids = {};
for (var i in list) {
var neuron = list[i].neuron;
while (neuron.neuron)
neuron = neuron.neuron;
neuron.state = getValue(neuron, 'state');
neuron.old = getValue(neuron, 'old');
neuron.activation = getValue(neuron, 'activation');
neuron.bias = getValue(neuron, 'bias');
for (var input in neuron.trace.elegibility)
neuron.trace.elegibility[input] = getValue(neuron, 'trace',
'elegibility', input);
for (var gated in neuron.trace.extended)
for (var input in neuron.trace.extended[gated])
neuron.trace.extended[gated][input] = getValue(neuron, 'trace',
'extended', gated, input);
}
// get connections
for (var i in list) {
var neuron = list[i].neuron;
while (neuron.neuron)
neuron = neuron.neuron;
for (var j in neuron.connections.projected) {
var connection = neuron.connections.projected[j];
connection.weight = getValue(connection, 'weight');
connection.gain = getValue(connection, 'gain');
}
}
},
// returns all the neurons in the network
neurons: function() {
var neurons = [];
var inputLayer = this.layers.input.neurons(),
outputLayer = this.layers.output.neurons();
for (var neuron in inputLayer)
neurons.push({
neuron: inputLayer[neuron],
layer: 'input'
});
for (var layer in this.layers.hidden) {
var hiddenLayer = this.layers.hidden[layer].neurons();
for (var neuron in hiddenLayer)
neurons.push({
neuron: hiddenLayer[neuron],
layer: layer
});
}
for (var neuron in outputLayer)
neurons.push({
neuron: outputLayer[neuron],
layer: 'output'
});
return neurons;
},
// returns number of inputs of the network
inputs: function() {
return this.layers.input.size;
},
// returns number of outputs of hte network
outputs: function() {
return this.layers.output.size;
},
// sets the layers of the network
set: function(layers) {
this.layers = layers;
if (this.optimized)
this.optimized.reset();
},
setOptimize: function(bool){
this.restore();
if (this.optimized)
this.optimized.reset();
this.optimized = bool? null : false;
},
// returns a json that represents all the neurons and connections of the network
toJSON: function(ignoreTraces) {
this.restore();
var list = this.neurons();
var neurons = [];
var connections = [];
// link id's to positions in the array
var ids = {};
for (var i in list) {
var neuron = list[i].neuron;
while (neuron.neuron)
neuron = neuron.neuron;
ids[neuron.ID] = i;
var copy = {
trace: {
elegibility: {},
extended: {}
},
state: neuron.state,
old: neuron.old,
activation: neuron.activation,
bias: neuron.bias,
layer: list[i].layer
};
copy.squash = neuron.squash == Neuron.squash.LOGISTIC ? "LOGISTIC" :
neuron.squash == Neuron.squash.TANH ? "TANH" :
neuron.squash == Neuron.squash.IDENTITY ? "IDENTITY" :
neuron.squash == Neuron.squash.HLIM ? "HLIM" :
null;
neurons.push(copy);
}
// get connections
for (var i in list) {
var neuron = list[i].neuron;
while (neuron.neuron)
neuron = neuron.neuron;
for (var j in neuron.connections.projected) {
var connection = neuron.connections.projected[j];
connections.push({
from: ids[connection.from.ID],
to: ids[connection.to.ID],
weight: connection.weight,
gater: connection.gater ? ids[connection.gater.ID] : null,
});
}
if (neuron.selfconnected())
connections.push({
from: ids[neuron.ID],
to: ids[neuron.ID],
weight: neuron.selfconnection.weight,
gater: neuron.selfconnection.gater ? ids[neuron.selfconnection.gater.ID] : null,
});
}
return {
neurons: neurons,
connections: connections
}
},
// export the topology into dot language which can be visualized as graphs using dot
/* example: ... console.log(net.toDotLang());
$ node example.js > example.dot
$ dot example.dot -Tpng > out.png
*/
toDot: function(edgeConnection) {
if (! typeof edgeConnection)
edgeConnection = false;
var code = "digraph nn {\n rankdir = BT\n";
var layers = [this.layers.input].concat(this.layers.hidden, this.layers.output);
for (var layer in layers) {
for (var to in layers[layer].connectedTo) { // projections
var connection = layers[layer].connectedTo[to];
var layerTo = connection.to;
var size = connection.size;
var layerID = layers.indexOf(layers[layer]);
var layerToID = layers.indexOf(layerTo);
/* http://stackoverflow.com/questions/26845540/connect-edges-with-graph-dot
* DOT does not support edge-to-edge connections
* This workaround produces somewhat weird graphs ...
*/
if ( edgeConnection) {
if (connection.gatedfrom.length) {
var fakeNode = "fake" + layerID + "_" + layerToID;
code += " " + fakeNode +
" [label = \"\", shape = point, width = 0.01, height = 0.01]\n";
code += " " + layerID + " -> " + fakeNode + " [label = " + size + ", arrowhead = none]\n";
code += " " + fakeNode + " -> " + layerToID + "\n";
} else
code += " " + layerID + " -> " + layerToID + " [label = " + size + "]\n";
for (var from in connection.gatedfrom) { // gatings
var layerfrom = connection.gatedfrom[from].layer;
var layerfromID = layers.indexOf(layerfrom);
code += " " + layerfromID + " -> " + fakeNode + " [color = blue]\n";
}
} else {
code += " " + layerID + " -> " + layerToID + " [label = " + size + "]\n";
for (var from in connection.gatedfrom) { // gatings
var layerfrom = connection.gatedfrom[from].layer;
var layerfromID = layers.indexOf(layerfrom);
code += " " + layerfromID + " -> " + layerToID + " [color = blue]\n";
}
}
}
}
code += "}\n";
return {
code: code,
link: "https://chart.googleapis.com/chart?chl=" + escape(code.replace("/ /g", "+")) + "&cht=gv"
}
},
// returns a function that works as the activation of the network and can be used without depending on the library
standalone: function() {
if (!this.optimized)
this.optimize();
var data = this.optimized.data;
// build activation function
var activation = "function (input) {\n";
// build inputs
for (var i in data.inputs)
activation += "F[" + data.inputs[i] + "] = input[" + i + "];\n";
// build network activation
for (var neuron in data.activate) { // shouldn't this be layer?
for (var sentence in data.activate[neuron])
activation += data.activate[neuron][sentence].join('') + "\n";
}
// build outputs
activation += "var output = [];\n";
for (var i in data.outputs)
activation += "output[" + i + "] = F[" + data.outputs[i] + "];\n";
activation += "return output;\n}";
// reference all the positions in memory
var memory = activation.match(/F\[(\d+)\]/g);
var dimension = 0;
var ids = {};
for (var address in memory) {
var tmp = memory[address].match(/\d+/)[0];
if (!(tmp in ids)) {
ids[tmp] = dimension++;
}
}
var hardcode = "F = {\n";
for (var i in ids)
hardcode += ids[i] + ": " + this.optimized.memory[i] + ",\n";
hardcode = hardcode.substring(0, hardcode.length - 2) + "\n};\n";
hardcode = "var run = " + activation.replace(/F\[(\d+)]/g, function(
index) {
return 'F[' + ids[index.match(/\d+/)[0]] + ']'
}).replace("{\n", "{\n" + hardcode + "") + ";\n";
hardcode += "return run";
// return standalone function
return new Function(hardcode)();
},
// Return a HTML5 WebWorker specialized on training the network stored in `memory`.
// Train based on the given dataSet and options.
// The worker returns the updated `memory` when done.
worker: function(memory, set, options) {
// Copy the options and set defaults (options might be different for each worker)
var workerOptions = {};
if(options) workerOptions = options;
workerOptions.rate = options.rate || .2;
workerOptions.iterations = options.iterations || 100000;
workerOptions.error = options.error || .005;
workerOptions.cost = options.cost || null;
workerOptions.crossValidate = options.crossValidate || null;
// Cost function might be different for each worker
costFunction = "var cost = " + (options && options.cost || this.cost || Trainer.cost.MSE) + ";\n";
var workerFunction = Network.getWorkerSharedFunctions();
workerFunction = workerFunction.replace(/var cost = options && options\.cost \|\| this\.cost \|\| Trainer\.cost\.MSE;/g, costFunction);
// Set what we do when training is finished
workerFunction = workerFunction.replace('return results;',
'postMessage({action: "done", message: results, memoryBuffer: F}, [F.buffer]);');
// Replace log with postmessage
workerFunction = workerFunction.replace("console.log('iterations', iterations, 'error', error, 'rate', currentRate)",
"postMessage({action: 'log', message: {\n" +
"iterations: iterations,\n" +
"error: error,\n" +
"rate: currentRate\n" +
"}\n" +
"})");
// Replace schedule with postmessage
workerFunction = workerFunction.replace("abort = this.schedule.do({ error: error, iterations: iterations, rate: currentRate })",
"postMessage({action: 'schedule', message: {\n" +
"iterations: iterations,\n" +
"error: error,\n" +
"rate: currentRate\n" +
"}\n" +
"})");
if (!this.optimized)
this.optimize();
var hardcode = "var inputs = " + this.optimized.data.inputs.length + ";\n";
hardcode += "var outputs = " + this.optimized.data.outputs.length + ";\n";
hardcode += "var F = new Float64Array([" + this.optimized.memory.toString() + "]);\n";
hardcode += "var activate = " + this.optimized.activate.toString() + ";\n";
hardcode += "var propagate = " + this.optimized.propagate.toString() + ";\n";
hardcode +=
"onmessage = function(e) {\n" +
"if (e.data.action == 'startTraining') {\n" +
"train(" + JSON.stringify(set) + "," + JSON.stringify(workerOptions) + ");\n" +
"}\n" +
"}";
var workerSourceCode = workerFunction + '\n' + hardcode;
var blob = new Blob([workerSourceCode]);
var blobURL = window.URL.createObjectURL(blob);
return new Worker(blobURL);
},
// returns a copy of the network
clone: function() {
return Network.fromJSON(this.toJSON());
}
};
/**
* Creates a static String to store the source code of the functions
* that are identical for all the workers (train, _trainSet, test)
*
* @return {String} Source code that can train a network inside a worker.
* @static
*/
Network.getWorkerSharedFunctions = function() {
// If we already computed the source code for the shared functions
if(typeof Network._SHARED_WORKER_FUNCTIONS !== 'undefined')
return Network._SHARED_WORKER_FUNCTIONS;
// Otherwise compute and return the source code
// We compute them by simply copying the source code of the train, _trainSet and test functions
// using the .toString() method
// Load and name the train function
var train_f = Trainer.prototype.train.toString();
train_f = train_f.replace('function (set', 'function train(set') + '\n';
// Load and name the _trainSet function
var _trainSet_f = Trainer.prototype._trainSet.toString().replace(/this.network./g, '');
_trainSet_f = _trainSet_f.replace('function (set', 'function _trainSet(set') + '\n';
_trainSet_f = _trainSet_f.replace('this.crossValidate', 'crossValidate');
_trainSet_f = _trainSet_f.replace('crossValidate = true', 'crossValidate = { }');
// Load and name the test function
var test_f = Trainer.prototype.test.toString().replace(/this.network./g, '');
test_f = test_f.replace('function (set', 'function test(set') + '\n';
return Network._SHARED_WORKER_FUNCTIONS = train_f + _trainSet_f + test_f;
};
// rebuild a network that has been stored in a json using the method toJSON()
Network.fromJSON = function(json) {
var neurons = [];
var layers = {
input: new Layer(),
hidden: [],
output: new Layer()
};
for (var i in json.neurons) {
var config = json.neurons[i];
var neuron = new Neuron();
neuron.trace.elegibility = {};
neuron.trace.extended = {};
neuron.state = config.state;
neuron.old = config.old;
neuron.activation = config.activation;
neuron.bias = config.bias;
neuron.squash = config.squash in Neuron.squash ? Neuron.squash[config.squash] : Neuron.squash.LOGISTIC;
neurons.push(neuron);
if (config.layer == 'input')
layers.input.add(neuron);
else if (config.layer == 'output')
layers.output.add(neuron);
else {
if (typeof layers.hidden[config.layer] == 'undefined')
layers.hidden[config.layer] = new Layer();
layers.hidden[config.layer].add(neuron);
}
}
for (var i in json.connections) {
var config = json.connections[i];
var from = neurons[config.from];
var to = neurons[config.to];
var weight = config.weight;
var gater = neurons[config.gater];
var connection = from.project(to, weight);
if (gater)
gater.gate(connection);
}
return new Network(layers);
};
+796
Ver Arquivo
@@ -0,0 +1,796 @@
// export
if (module) module.exports = Neuron;
/******************************************************************************************
NEURON
*******************************************************************************************/
function Neuron() {
this.ID = Neuron.uid();
this.label = null;
this.connections = {
inputs: {},
projected: {},
gated: {}
};
this.error = {
responsibility: 0,
projected: 0,
gated: 0
};
this.trace = {
elegibility: {},
extended: {},
influences: {}
};
this.state = 0;
this.old = 0;
this.activation = 0;
this.selfconnection = new Neuron.connection(this, this, 0); // weight = 0 -> not connected
this.squash = Neuron.squash.LOGISTIC;
this.neighboors = {};
this.bias = Math.random() * .2 - .1;
}
Neuron.prototype = {
// activate the neuron
activate: function(input) {
// activation from enviroment (for input neurons)
if (typeof input != 'undefined') {
this.activation = input;
this.derivative = 0;
this.bias = 0;
return this.activation;
}
// old state
this.old = this.state;
// eq. 15
this.state = this.selfconnection.gain * this.selfconnection.weight *
this.state + this.bias;
for (var i in this.connections.inputs) {
var input = this.connections.inputs[i];
this.state += input.from.activation * input.weight * input.gain;
}
// eq. 16
this.activation = this.squash(this.state);
// f'(s)
this.derivative = this.squash(this.state, true);
// update traces
var influences = [];
for (var id in this.trace.extended) {
// extended elegibility trace
var neuron = this.neighboors[id];
// if gated neuron's selfconnection is gated by this unit, the influence keeps track of the neuron's old state
var influence = neuron.selfconnection.gater == this ? neuron.old : 0;
// index runs over all the incoming connections to the gated neuron that are gated by this unit
for (var incoming in this.trace.influences[neuron.ID]) { // captures the effect that has an input connection to this unit, on a neuron that is gated by this unit
influence += this.trace.influences[neuron.ID][incoming].weight *
this.trace.influences[neuron.ID][incoming].from.activation;
}
influences[neuron.ID] = influence;
}
for (var i in this.connections.inputs) {
var input = this.connections.inputs[i];
// elegibility trace - Eq. 17
this.trace.elegibility[input.ID] = this.selfconnection.gain * this.selfconnection
.weight * this.trace.elegibility[input.ID] + input.gain * input.from
.activation;
for (var id in this.trace.extended) {
// extended elegibility trace
var xtrace = this.trace.extended[id];
var neuron = this.neighboors[id];
var influence = influences[neuron.ID];
// eq. 18
xtrace[input.ID] = neuron.selfconnection.gain * neuron.selfconnection
.weight * xtrace[input.ID] + this.derivative * this.trace.elegibility[
input.ID] * influence;
}
}
// update gated connection's gains
for (var connection in this.connections.gated) {
this.connections.gated[connection].gain = this.activation;
}
return this.activation;
},
// back-propagate the error
propagate: function(rate, target) {
// error accumulator
var error = 0;
// whether or not this neuron is in the output layer
var isOutput = typeof target != 'undefined';
// output neurons get their error from the enviroment
if (isOutput)
this.error.responsibility = this.error.projected = target - this.activation; // Eq. 10
else // the rest of the neuron compute their error responsibilities by backpropagation
{
// error responsibilities from all the connections projected from this neuron
for (var id in this.connections.projected) {
var connection = this.connections.projected[id];
var neuron = connection.to;
// Eq. 21
error += neuron.error.responsibility * connection.gain * connection.weight;
}
// projected error responsibility
this.error.projected = this.derivative * error;
error = 0;
// error responsibilities from all the connections gated by this neuron
for (var id in this.trace.extended) {
var neuron = this.neighboors[id]; // gated neuron
var influence = neuron.selfconnection.gater == this ? neuron.old : 0; // if gated neuron's selfconnection is gated by this neuron
// index runs over all the connections to the gated neuron that are gated by this neuron
for (var input in this.trace.influences[id]) { // captures the effect that the input connection of this neuron have, on a neuron which its input/s is/are gated by this neuron
influence += this.trace.influences[id][input].weight * this.trace.influences[
neuron.ID][input].from.activation;
}
// eq. 22
error += neuron.error.responsibility * influence;
}
// gated error responsibility
this.error.gated = this.derivative * error;
// error responsibility - Eq. 23
this.error.responsibility = this.error.projected + this.error.gated;
}
// learning rate
rate = rate || .1;
// adjust all the neuron's incoming connections
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
// Eq. 24
var gradient = this.error.projected * this.trace.elegibility[input.ID];
for (var id in this.trace.extended) {
var neuron = this.neighboors[id];
gradient += neuron.error.responsibility * this.trace.extended[
neuron.ID][input.ID];
}
input.weight += rate * gradient; // adjust weights - aka learn
}
// adjust bias
this.bias += rate * this.error.responsibility;
},
project: function(neuron, weight) {
// self-connection
if (neuron == this) {
this.selfconnection.weight = 1;
return this.selfconnection;
}
// check if connection already exists
var connected = this.connected(neuron);
if (connected && connected.type == "projected") {
// update connection
if (typeof weight != 'undefined')
connected.connection.weight = weight;
// return existing connection
return connected.connection;
} else {
// create a new connection
var connection = new Neuron.connection(this, neuron, weight);
}
// reference all the connections and traces
this.connections.projected[connection.ID] = connection;
this.neighboors[neuron.ID] = neuron;
neuron.connections.inputs[connection.ID] = connection;
neuron.trace.elegibility[connection.ID] = 0;
for (var id in neuron.trace.extended) {
var trace = neuron.trace.extended[id];
trace[connection.ID] = 0;
}
return connection;
},
gate: function(connection) {
// add connection to gated list
this.connections.gated[connection.ID] = connection;
var neuron = connection.to;
if (!(neuron.ID in this.trace.extended)) {
// extended trace
this.neighboors[neuron.ID] = neuron;
var xtrace = this.trace.extended[neuron.ID] = {};
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
xtrace[input.ID] = 0;
}
}
// keep track
if (neuron.ID in this.trace.influences)
this.trace.influences[neuron.ID].push(connection);
else
this.trace.influences[neuron.ID] = [connection];
// set gater
connection.gater = this;
},
// returns true or false whether the neuron is self-connected or not
selfconnected: function() {
return this.selfconnection.weight !== 0;
},
// returns true or false whether the neuron is connected to another neuron (parameter)
connected: function(neuron) {
var result = {
type: null,
connection: false
};
if (this == neuron) {
if (this.selfconnected()) {
result.type = 'selfconnection';
result.connection = this.selfconnection;
return result;
} else
return false;
}
for (var type in this.connections) {
for (var connection in this.connections[type]) {
var connection = this.connections[type][connection];
if (connection.to == neuron) {
result.type = type;
result.connection = connection;
return result;
} else if (connection.from == neuron) {
result.type = type;
result.connection = connection;
return result;
}
}
}
return false;
},
// clears all the traces (the neuron forgets it's context, but the connections remain intact)
clear: function() {
for (var trace in this.trace.elegibility)
this.trace.elegibility[trace] = 0;
for (var trace in this.trace.extended)
for (var extended in this.trace.extended[trace])
this.trace.extended[trace][extended] = 0;
this.error.responsibility = this.error.projected = this.error.gated = 0;
},
// all the connections are randomized and the traces are cleared
reset: function() {
this.clear();
for (var type in this.connections)
for (var connection in this.connections[type])
this.connections[type][connection].weight = Math.random() * .2 - .1;
this.bias = Math.random() * .2 - .1;
this.old = this.state = this.activation = 0;
},
// hardcodes the behaviour of the neuron into an optimized function
optimize: function(optimized, layer) {
optimized = optimized || {};
var store_activation = [];
var store_trace = [];
var store_propagation = [];
var varID = optimized.memory || 0;
var neurons = optimized.neurons || 1;
var inputs = optimized.inputs || [];
var targets = optimized.targets || [];
var outputs = optimized.outputs || [];
var variables = optimized.variables || {};
var activation_sentences = optimized.activation_sentences || [];
var trace_sentences = optimized.trace_sentences || [];
var propagation_sentences = optimized.propagation_sentences || [];
var layers = optimized.layers || { __count: 0, __neuron: 0 };
// allocate sentences
var allocate = function(store){
var allocated = layer in layers && store[layers.__count];
if (!allocated)
{
layers.__count = store.push([]) - 1;
layers[layer] = layers.__count;
}
};
allocate(activation_sentences);
allocate(trace_sentences);
allocate(propagation_sentences);
var currentLayer = layers.__count;
// get/reserve space in memory by creating a unique ID for a variablel
var getVar = function() {
var args = Array.prototype.slice.call(arguments);
if (args.length == 1) {
if (args[0] == 'target') {
var id = 'target_' + targets.length;
targets.push(varID);
} else
var id = args[0];
if (id in variables)
return variables[id];
return variables[id] = {
value: 0,
id: varID++
};
} else {
var extended = args.length > 2;
if (extended)
var value = args.pop();
var unit = args.shift();
var prop = args.pop();
if (!extended)
var value = unit[prop];
var id = prop + '_';
for (var property in args)
id += args[property] + '_';
id += unit.ID;
if (id in variables)
return variables[id];
return variables[id] = {
value: value,
id: varID++
};
}
};
// build sentence
var buildSentence = function() {
var args = Array.prototype.slice.call(arguments);
var store = args.pop();
var sentence = "";
for (var i in args)
if (typeof args[i] == 'string')
sentence += args[i];
else
sentence += 'F[' + args[i].id + ']';
store.push(sentence + ';');
};
// helper to check if an object is empty
var isEmpty = function(obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop))
return false;
}
return true;
};
// characteristics of the neuron
var noProjections = isEmpty(this.connections.projected);
var noGates = isEmpty(this.connections.gated);
var isInput = layer == 'input' ? true : isEmpty(this.connections.inputs);
var isOutput = layer == 'output' ? true : noProjections && noGates;
// optimize neuron's behaviour
var rate = getVar('rate');
var activation = getVar(this, 'activation');
if (isInput)
inputs.push(activation.id);
else {
activation_sentences[currentLayer].push(store_activation);
trace_sentences[currentLayer].push(store_trace);
propagation_sentences[currentLayer].push(store_propagation);
var old = getVar(this, 'old');
var state = getVar(this, 'state');
var bias = getVar(this, 'bias');
if (this.selfconnection.gater)
var self_gain = getVar(this.selfconnection, 'gain');
if (this.selfconnected())
var self_weight = getVar(this.selfconnection, 'weight');
buildSentence(old, ' = ', state, store_activation);
if (this.selfconnected())
if (this.selfconnection.gater)
buildSentence(state, ' = ', self_gain, ' * ', self_weight, ' * ',
state, ' + ', bias, store_activation);
else
buildSentence(state, ' = ', self_weight, ' * ', state, ' + ',
bias, store_activation);
else
buildSentence(state, ' = ', bias, store_activation);
for (var i in this.connections.inputs) {
var input = this.connections.inputs[i];
var input_activation = getVar(input.from, 'activation');
var input_weight = getVar(input, 'weight');
if (input.gater)
var input_gain = getVar(input, 'gain');
if (this.connections.inputs[i].gater)
buildSentence(state, ' += ', input_activation, ' * ',
input_weight, ' * ', input_gain, store_activation);
else
buildSentence(state, ' += ', input_activation, ' * ',
input_weight, store_activation);
}
var derivative = getVar(this, 'derivative');
switch (this.squash) {
case Neuron.squash.LOGISTIC:
buildSentence(activation, ' = (1 / (1 + Math.exp(-', state, ')))',
store_activation);
buildSentence(derivative, ' = ', activation, ' * (1 - ',
activation, ')', store_activation);
break;
case Neuron.squash.TANH:
var eP = getVar('aux');
var eN = getVar('aux_2');
buildSentence(eP, ' = Math.exp(', state, ')', store_activation);
buildSentence(eN, ' = 1 / ', eP, store_activation);
buildSentence(activation, ' = (', eP, ' - ', eN, ') / (', eP, ' + ', eN, ')', store_activation);
buildSentence(derivative, ' = 1 - (', activation, ' * ', activation, ')', store_activation);
break;
case Neuron.squash.IDENTITY:
buildSentence(activation, ' = ', state, store_activation);
buildSentence(derivative, ' = 1', store_activation);
break;
case Neuron.squash.HLIM:
buildSentence(activation, ' = +(', state, ' > 0)', store_activation);
buildSentence(derivative, ' = 1', store_activation);
case Neuron.squash.RELU:
buildSentence(activation, ' = ', state, ' > 0 ? ', state, ' : 0', store_activation);
buildSentence(derivative, ' = ', state, ' > 0 ? 1 : 0', store_activation);
break;
}
for (var id in this.trace.extended) {
// calculate extended elegibility traces in advance
var neuron = this.neighboors[id];
var influence = getVar('influences[' + neuron.ID + ']');
var neuron_old = getVar(neuron, 'old');
var initialized = false;
if (neuron.selfconnection.gater == this)
{
buildSentence(influence, ' = ', neuron_old, store_trace);
initialized = true;
}
for (var incoming in this.trace.influences[neuron.ID]) {
var incoming_weight = getVar(this.trace.influences[neuron.ID]
[incoming], 'weight');
var incoming_activation = getVar(this.trace.influences[neuron.ID]
[incoming].from, 'activation');
if (initialized)
buildSentence(influence, ' += ', incoming_weight, ' * ', incoming_activation, store_trace);
else {
buildSentence(influence, ' = ', incoming_weight, ' * ', incoming_activation, store_trace);
initialized = true;
}
}
}
for (var i in this.connections.inputs) {
var input = this.connections.inputs[i];
if (input.gater)
var input_gain = getVar(input, 'gain');
var input_activation = getVar(input.from, 'activation');
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
.elegibility[input.ID]);
if (this.selfconnected()) {
if (this.selfconnection.gater) {
if (input.gater)
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
' * ', trace, ' + ', input_gain, ' * ', input_activation,
store_trace);
else
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
' * ', trace, ' + ', input_activation, store_trace);
} else {
if (input.gater)
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
input_gain, ' * ', input_activation, store_trace);
else
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
input_activation, store_trace);
}
} else {
if (input.gater)
buildSentence(trace, ' = ', input_gain, ' * ', input_activation,
store_trace);
else
buildSentence(trace, ' = ', input_activation, store_trace);
}
for (var id in this.trace.extended) {
// extended elegibility trace
var neuron = this.neighboors[id];
var influence = getVar('influences[' + neuron.ID + ']');
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
.elegibility[input.ID]);
var xtrace = getVar(this, 'trace', 'extended', neuron.ID, input.ID,
this.trace.extended[neuron.ID][input.ID]);
if (neuron.selfconnected())
var neuron_self_weight = getVar(neuron.selfconnection, 'weight');
if (neuron.selfconnection.gater)
var neuron_self_gain = getVar(neuron.selfconnection, 'gain');
if (neuron.selfconnected())
if (neuron.selfconnection.gater)
buildSentence(xtrace, ' = ', neuron_self_gain, ' * ',
neuron_self_weight, ' * ', xtrace, ' + ', derivative, ' * ',
trace, ' * ', influence, store_trace);
else
buildSentence(xtrace, ' = ', neuron_self_weight, ' * ',
xtrace, ' + ', derivative, ' * ', trace, ' * ',
influence, store_trace);
else
buildSentence(xtrace, ' = ', derivative, ' * ', trace, ' * ',
influence, store_trace);
}
}
for (var connection in this.connections.gated) {
var gated_gain = getVar(this.connections.gated[connection], 'gain');
buildSentence(gated_gain, ' = ', activation, store_activation);
}
}
if (!isInput) {
var responsibility = getVar(this, 'error', 'responsibility', this.error
.responsibility);
if (isOutput) {
var target = getVar('target');
buildSentence(responsibility, ' = ', target, ' - ', activation,
store_propagation);
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
.elegibility[input.ID]);
var input_weight = getVar(input, 'weight');
buildSentence(input_weight, ' += ', rate, ' * (', responsibility,
' * ', trace, ')', store_propagation);
}
outputs.push(activation.id);
} else {
if (!noProjections && !noGates) {
var error = getVar('aux');
for (var id in this.connections.projected) {
var connection = this.connections.projected[id];
var neuron = connection.to;
var connection_weight = getVar(connection, 'weight');
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
if (connection.gater) {
var connection_gain = getVar(connection, 'gain');
buildSentence(error, ' += ', neuron_responsibility, ' * ',
connection_gain, ' * ', connection_weight,
store_propagation);
} else
buildSentence(error, ' += ', neuron_responsibility, ' * ',
connection_weight, store_propagation);
}
var projected = getVar(this, 'error', 'projected', this.error.projected);
buildSentence(projected, ' = ', derivative, ' * ', error,
store_propagation);
buildSentence(error, ' = 0', store_propagation);
for (var id in this.trace.extended) {
var neuron = this.neighboors[id];
var influence = getVar('aux_2');
var neuron_old = getVar(neuron, 'old');
if (neuron.selfconnection.gater == this)
buildSentence(influence, ' = ', neuron_old, store_propagation);
else
buildSentence(influence, ' = 0', store_propagation);
for (var input in this.trace.influences[neuron.ID]) {
var connection = this.trace.influences[neuron.ID][input];
var connection_weight = getVar(connection, 'weight');
var neuron_activation = getVar(connection.from, 'activation');
buildSentence(influence, ' += ', connection_weight, ' * ',
neuron_activation, store_propagation);
}
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
buildSentence(error, ' += ', neuron_responsibility, ' * ',
influence, store_propagation);
}
var gated = getVar(this, 'error', 'gated', this.error.gated);
buildSentence(gated, ' = ', derivative, ' * ', error,
store_propagation);
buildSentence(responsibility, ' = ', projected, ' + ', gated,
store_propagation);
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
var gradient = getVar('aux');
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
.trace.elegibility[input.ID]);
buildSentence(gradient, ' = ', projected, ' * ', trace,
store_propagation);
for (var id in this.trace.extended) {
var neuron = this.neighboors[id];
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
input.ID, this.trace.extended[neuron.ID][input.ID]);
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
xtrace, store_propagation);
}
var input_weight = getVar(input, 'weight');
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
store_propagation);
}
} else if (noGates) {
buildSentence(responsibility, ' = 0', store_propagation);
for (var id in this.connections.projected) {
var connection = this.connections.projected[id];
var neuron = connection.to;
var connection_weight = getVar(connection, 'weight');
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
if (connection.gater) {
var connection_gain = getVar(connection, 'gain');
buildSentence(responsibility, ' += ', neuron_responsibility,
' * ', connection_gain, ' * ', connection_weight,
store_propagation);
} else
buildSentence(responsibility, ' += ', neuron_responsibility,
' * ', connection_weight, store_propagation);
}
buildSentence(responsibility, ' *= ', derivative,
store_propagation);
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
.trace.elegibility[input.ID]);
var input_weight = getVar(input, 'weight');
buildSentence(input_weight, ' += ', rate, ' * (',
responsibility, ' * ', trace, ')', store_propagation);
}
} else if (noProjections) {
buildSentence(responsibility, ' = 0', store_propagation);
for (var id in this.trace.extended) {
var neuron = this.neighboors[id];
var influence = getVar('aux');
var neuron_old = getVar(neuron, 'old');
if (neuron.selfconnection.gater == this)
buildSentence(influence, ' = ', neuron_old, store_propagation);
else
buildSentence(influence, ' = 0', store_propagation);
for (var input in this.trace.influences[neuron.ID]) {
var connection = this.trace.influences[neuron.ID][input];
var connection_weight = getVar(connection, 'weight');
var neuron_activation = getVar(connection.from, 'activation');
buildSentence(influence, ' += ', connection_weight, ' * ',
neuron_activation, store_propagation);
}
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
buildSentence(responsibility, ' += ', neuron_responsibility,
' * ', influence, store_propagation);
}
buildSentence(responsibility, ' *= ', derivative,
store_propagation);
for (var id in this.connections.inputs) {
var input = this.connections.inputs[id];
var gradient = getVar('aux');
buildSentence(gradient, ' = 0', store_propagation);
for (var id in this.trace.extended) {
var neuron = this.neighboors[id];
var neuron_responsibility = getVar(neuron, 'error',
'responsibility', neuron.error.responsibility);
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
input.ID, this.trace.extended[neuron.ID][input.ID]);
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
xtrace, store_propagation);
}
var input_weight = getVar(input, 'weight');
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
store_propagation);
}
}
}
buildSentence(bias, ' += ', rate, ' * ', responsibility,
store_propagation);
}
return {
memory: varID,
neurons: neurons + 1,
inputs: inputs,
outputs: outputs,
targets: targets,
variables: variables,
activation_sentences: activation_sentences,
trace_sentences: trace_sentences,
propagation_sentences: propagation_sentences,
layers: layers
}
}
}
// represents a connection between two neurons
Neuron.connection = function Connection(from, to, weight) {
if (!from || !to)
throw new Error("Connection Error: Invalid neurons");
this.ID = Neuron.connection.uid();
this.from = from;
this.to = to;
this.weight = typeof weight == 'undefined' ? Math.random() * .2 - .1 :
weight;
this.gain = 1;
this.gater = null;
}
// squashing functions
Neuron.squash = {};
// eq. 5 & 5'
Neuron.squash.LOGISTIC = function(x, derivate) {
if (!derivate)
return 1 / (1 + Math.exp(-x));
var fx = Neuron.squash.LOGISTIC(x);
return fx * (1 - fx);
};
Neuron.squash.TANH = function(x, derivate) {
if (derivate)
return 1 - Math.pow(Neuron.squash.TANH(x), 2);
var eP = Math.exp(x);
var eN = 1 / eP;
return (eP - eN) / (eP + eN);
};
Neuron.squash.IDENTITY = function(x, derivate) {
return derivate ? 1 : x;
};
Neuron.squash.HLIM = function(x, derivate) {
return derivate ? 1 : x > 0 ? 1 : 0;
};
Neuron.squash.RELU = function(x, derivate) {
if (derivate)
return x > 0 ? 1 : 0;
return x > 0 ? x : 0;
};
// unique ID's
(function() {
var neurons = 0;
var connections = 0;
Neuron.uid = function() {
return neurons++;
}
Neuron.connection.uid = function() {
return connections++;
}
Neuron.quantity = function() {
return {
neurons: neurons,
connections: connections
}
}
})();
+33
Ver Arquivo
@@ -0,0 +1,33 @@
var Synaptic = {
Neuron: require('./neuron'),
Layer: require('./layer'),
Network: require('./network'),
Trainer: require('./trainer'),
Architect: require('./architect')
};
// CommonJS & AMD
if (typeof define !== 'undefined' && define.amd)
{
define([], function(){ return Synaptic });
}
// Node.js
if (typeof module !== 'undefined' && module.exports)
{
module.exports = Synaptic;
}
// Browser
if (typeof window == 'object')
{
(function(){
var oldSynaptic = window['synaptic'];
Synaptic.ninja = function(){
window['synaptic'] = oldSynaptic;
return Synaptic;
};
})();
window['synaptic'] = Synaptic;
}
+676
Ver Arquivo
@@ -0,0 +1,676 @@
// export
if (module) module.exports = Trainer;
/*******************************************************************************************
TRAINER
*******************************************************************************************/
function Trainer(network, options) {
options = options || {};
this.network = network;
this.rate = options.rate || .2;
this.iterations = options.iterations || 100000;
this.error = options.error || .005;
this.cost = options.cost || null;
this.crossValidate = options.crossValidate || null;
}
Trainer.prototype = {
// trains any given set to a network
train: function(set, options) {
var error = 1;
var iterations = bucketSize = 0;
var abort = false;
var currentRate;
var cost = options && options.cost || this.cost || Trainer.cost.MSE;
var crossValidate = false, testSet, trainSet;
var start = Date.now();
if (options) {
if (options.shuffle) {
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/array/shuffle [v1.0]
function shuffle(o) { //v1.0
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
}
if (options.iterations)
this.iterations = options.iterations;
if (options.error)
this.error = options.error;
if (options.rate)
this.rate = options.rate;
if (options.cost)
this.cost = options.cost;
if (options.schedule)
this.schedule = options.schedule;
if (options.customLog){
// for backward compatibility with code that used customLog
console.log('Deprecated: use schedule instead of customLog')
this.schedule = options.customLog;
}
if (this.crossValidate || options.crossValidate) {
if(!this.crossValidate) this.crossValidate = {};
crossValidate = true;
if (options.crossValidate.testSize)
this.crossValidate.testSize = options.crossValidate.testSize;
if (options.crossValidate.testError)
this.crossValidate.testError = options.crossValidate.testError;
}
}
currentRate = this.rate;
if(Array.isArray(this.rate)) {
var bucketSize = Math.floor(this.iterations / this.rate.length);
}
if(crossValidate) {
var numTrain = Math.ceil((1 - this.crossValidate.testSize) * set.length);
trainSet = set.slice(0, numTrain);
testSet = set.slice(numTrain);
}
var lastError = 0;
while ((!abort && iterations < this.iterations && error > this.error)) {
if (crossValidate && error <= this.crossValidate.testError) {
break;
}
var currentSetSize = set.length;
error = 0;
iterations++;
if(bucketSize > 0) {
var currentBucket = Math.floor(iterations / bucketSize);
currentRate = this.rate[currentBucket] || currentRate;
}
if(typeof this.rate === 'function') {
currentRate = this.rate(iterations, lastError);
}
if (crossValidate) {
this._trainSet(trainSet, currentRate, cost);
error += this.test(testSet).error;
currentSetSize = 1;
} else {
error += this._trainSet(set, currentRate, cost);
currentSetSize = set.length;
}
// check error
error /= currentSetSize;
lastError = error;
if (options) {
if (this.schedule && this.schedule.every && iterations %
this.schedule.every == 0)
abort = this.schedule.do({ error: error, iterations: iterations, rate: currentRate });
else if (options.log && iterations % options.log == 0) {
console.log('iterations', iterations, 'error', error, 'rate', currentRate);
};
if (options.shuffle)
shuffle(set);
}
}
var results = {
error: error,
iterations: iterations,
time: Date.now() - start
};
return results;
},
// trains any given set to a network, using a WebWorker (only for the browser). Returns a Promise of the results.
trainAsync: function(set, options) {
var train = this.workerTrain.bind(this);
return new Promise(function(resolve, reject) {
try {
train(set, resolve, options, true)
} catch(e) {
reject(e)
}
})
},
// preforms one training epoch and returns the error (private function used in this.train)
_trainSet: function(set, currentRate, costFunction) {
var errorSum = 0;
for (var train in set) {
var input = set[train].input;
var target = set[train].output;
var output = this.network.activate(input);
this.network.propagate(currentRate, target);
errorSum += costFunction(target, output);
}
return errorSum;
},
// tests a set and returns the error and elapsed time
test: function(set, options) {
var error = 0;
var input, output, target;
var cost = options && options.cost || this.cost || Trainer.cost.MSE;
var start = Date.now();
for (var test in set) {
input = set[test].input;
target = set[test].output;
output = this.network.activate(input);
error += cost(target, output);
}
error /= set.length;
var results = {
error: error,
time: Date.now() - start
};
return results;
},
// trains any given set to a network using a WebWorker [deprecated: use trainAsync instead]
workerTrain: function(set, callback, options, suppressWarning) {
if (!suppressWarning) {
console.warn('Deprecated: do not use `workerTrain`, use `trainAsync` instead.')
}
var that = this;
if (!this.network.optimized)
this.network.optimize();
// Create a new worker
var worker = this.network.worker(this.network.optimized.memory, set, options);
// train the worker
worker.onmessage = function(e) {
switch(e.data.action) {
case 'done':
var iterations = e.data.message.iterations;
var error = e.data.message.error;
var time = e.data.message.time;
that.network.optimized.ownership(e.data.memoryBuffer);
// Done callback
callback({
error: error,
iterations: iterations,
time: time
});
// Delete the worker and all its associated memory
worker.terminate();
break;
case 'log':
console.log(e.data.message);
case 'schedule':
if (options && options.schedule && typeof options.schedule.do === 'function') {
var scheduled = options.schedule.do
scheduled(e.data.message)
}
break;
}
};
// Start the worker
worker.postMessage({action: 'startTraining'});
},
// trains an XOR to the network
XOR: function(options) {
if (this.network.inputs() != 2 || this.network.outputs() != 1)
throw new Error("Incompatible network (2 inputs, 1 output)");
var defaults = {
iterations: 100000,
log: false,
shuffle: true,
cost: Trainer.cost.MSE
};
if (options)
for (var i in options)
defaults[i] = options[i];
return this.train([{
input: [0, 0],
output: [0]
}, {
input: [1, 0],
output: [1]
}, {
input: [0, 1],
output: [1]
}, {
input: [1, 1],
output: [0]
}], defaults);
},
// trains the network to pass a Distracted Sequence Recall test
DSR: function(options) {
options = options || {};
var targets = options.targets || [2, 4, 7, 8];
var distractors = options.distractors || [3, 5, 6, 9];
var prompts = options.prompts || [0, 1];
var length = options.length || 24;
var criterion = options.success || 0.95;
var iterations = options.iterations || 100000;
var rate = options.rate || .1;
var log = options.log || 0;
var schedule = options.schedule || {};
var cost = options.cost || this.cost || Trainer.cost.CROSS_ENTROPY;
var trial, correct, i, j, success;
trial = correct = i = j = success = 0;
var error = 1,
symbols = targets.length + distractors.length + prompts.length;
var noRepeat = function(range, avoid) {
var number = Math.random() * range | 0;
var used = false;
for (var i in avoid)
if (number == avoid[i])
used = true;
return used ? noRepeat(range, avoid) : number;
};
var equal = function(prediction, output) {
for (var i in prediction)
if (Math.round(prediction[i]) != output[i])
return false;
return true;
};
var start = Date.now();
while (trial < iterations && (success < criterion || trial % 1000 != 0)) {
// generate sequence
var sequence = [],
sequenceLength = length - prompts.length;
for (i = 0; i < sequenceLength; i++) {
var any = Math.random() * distractors.length | 0;
sequence.push(distractors[any]);
}
var indexes = [],
positions = [];
for (i = 0; i < prompts.length; i++) {
indexes.push(Math.random() * targets.length | 0);
positions.push(noRepeat(sequenceLength, positions));
}
positions = positions.sort();
for (i = 0; i < prompts.length; i++) {
sequence[positions[i]] = targets[indexes[i]];
sequence.push(prompts[i]);
}
//train sequence
var distractorsCorrect;
var targetsCorrect = distractorsCorrect = 0;
error = 0;
for (i = 0; i < length; i++) {
// generate input from sequence
var input = [];
for (j = 0; j < symbols; j++)
input[j] = 0;
input[sequence[i]] = 1;
// generate target output
var output = [];
for (j = 0; j < targets.length; j++)
output[j] = 0;
if (i >= sequenceLength) {
var index = i - sequenceLength;
output[indexes[index]] = 1;
}
// check result
var prediction = this.network.activate(input);
if (equal(prediction, output))
if (i < sequenceLength)
distractorsCorrect++;
else
targetsCorrect++;
else {
this.network.propagate(rate, output);
}
error += cost(output, prediction);
if (distractorsCorrect + targetsCorrect == length)
correct++;
}
// calculate error
if (trial % 1000 == 0)
correct = 0;
trial++;
var divideError = trial % 1000;
divideError = divideError == 0 ? 1000 : divideError;
success = correct / divideError;
error /= length;
// log
if (log && trial % log == 0)
console.log("iterations:", trial, " success:", success, " correct:",
correct, " time:", Date.now() - start, " error:", error);
if (schedule.do && schedule.every && trial % schedule.every == 0)
schedule.do({
iterations: trial,
success: success,
error: error,
time: Date.now() - start,
correct: correct
});
}
return {
iterations: trial,
success: success,
error: error,
time: Date.now() - start
}
},
// train the network to learn an Embeded Reber Grammar
ERG: function(options) {
options = options || {};
var iterations = options.iterations || 150000;
var criterion = options.error || .05;
var rate = options.rate || .1;
var log = options.log || 500;
var cost = options.cost || this.cost || Trainer.cost.CROSS_ENTROPY;
// gramar node
var Node = function() {
this.paths = [];
};
Node.prototype = {
connect: function(node, value) {
this.paths.push({
node: node,
value: value
});
return this;
},
any: function() {
if (this.paths.length == 0)
return false;
var index = Math.random() * this.paths.length | 0;
return this.paths[index];
},
test: function(value) {
for (var i in this.paths)
if (this.paths[i].value == value)
return this.paths[i];
return false;
}
};
var reberGrammar = function() {
// build a reber grammar
var output = new Node();
var n1 = (new Node()).connect(output, "E");
var n2 = (new Node()).connect(n1, "S");
var n3 = (new Node()).connect(n1, "V").connect(n2, "P");
var n4 = (new Node()).connect(n2, "X");
n4.connect(n4, "S");
var n5 = (new Node()).connect(n3, "V");
n5.connect(n5, "T");
n2.connect(n5, "X");
var n6 = (new Node()).connect(n4, "T").connect(n5, "P");
var input = (new Node()).connect(n6, "B");
return {
input: input,
output: output
}
};
// build an embeded reber grammar
var embededReberGrammar = function() {
var reber1 = reberGrammar();
var reber2 = reberGrammar();
var output = new Node();
var n1 = (new Node).connect(output, "E");
reber1.output.connect(n1, "T");
reber2.output.connect(n1, "P");
var n2 = (new Node).connect(reber1.input, "P").connect(reber2.input,
"T");
var input = (new Node).connect(n2, "B");
return {
input: input,
output: output
}
};
// generate an ERG sequence
var generate = function() {
var node = embededReberGrammar().input;
var next = node.any();
var str = "";
while (next) {
str += next.value;
next = next.node.any();
}
return str;
};
// test if a string matches an embeded reber grammar
var test = function(str) {
var node = embededReberGrammar().input;
var i = 0;
var ch = str.charAt(i);
while (i < str.length) {
var next = node.test(ch);
if (!next)
return false;
node = next.node;
ch = str.charAt(++i);
}
return true;
};
// helper to check if the output and the target vectors match
var different = function(array1, array2) {
var max1 = 0;
var i1 = -1;
var max2 = 0;
var i2 = -1;
for (var i in array1) {
if (array1[i] > max1) {
max1 = array1[i];
i1 = i;
}
if (array2[i] > max2) {
max2 = array2[i];
i2 = i;
}
}
return i1 != i2;
};
var iteration = 0;
var error = 1;
var table = {
"B": 0,
"P": 1,
"T": 2,
"X": 3,
"S": 4,
"E": 5
};
var start = Date.now();
while (iteration < iterations && error > criterion) {
var i = 0;
error = 0;
// ERG sequence to learn
var sequence = generate();
// input
var read = sequence.charAt(i);
// target
var predict = sequence.charAt(i + 1);
// train
while (i < sequence.length - 1) {
var input = [];
var target = [];
for (var j = 0; j < 6; j++) {
input[j] = 0;
target[j] = 0;
}
input[table[read]] = 1;
target[table[predict]] = 1;
var output = this.network.activate(input);
if (different(output, target))
this.network.propagate(rate, target);
read = sequence.charAt(++i);
predict = sequence.charAt(i + 1);
error += cost(target, output);
}
error /= sequence.length;
iteration++;
if (iteration % log == 0) {
console.log("iterations:", iteration, " time:", Date.now() - start,
" error:", error);
}
}
return {
iterations: iteration,
error: error,
time: Date.now() - start,
test: test,
generate: generate
}
},
timingTask: function(options){
if (this.network.inputs() != 2 || this.network.outputs() != 1)
throw new Error("Invalid Network: must have 2 inputs and one output");
if (typeof options == 'undefined')
options = {};
// helper
function getSamples (trainingSize, testSize){
// sample size
var size = trainingSize + testSize;
// generate samples
var t = 0;
var set = [];
for (var i = 0; i < size; i++) {
set.push({ input: [0,0], output: [0] });
}
while(t < size - 20) {
var n = Math.round(Math.random() * 20);
set[t].input[0] = 1;
for (var j = t; j <= t + n; j++){
set[j].input[1] = n / 20;
set[j].output[0] = 0.5;
}
t += n;
n = Math.round(Math.random() * 20);
for (var k = t+1; k <= (t + n) && k < size; k++)
set[k].input[1] = set[t].input[1];
t += n;
}
// separate samples between train and test sets
var trainingSet = []; var testSet = [];
for (var l = 0; l < size; l++)
(l < trainingSize ? trainingSet : testSet).push(set[l]);
// return samples
return {
train: trainingSet,
test: testSet
}
}
var iterations = options.iterations || 200;
var error = options.error || .005;
var rate = options.rate || [.03, .02];
var log = options.log === false ? false : options.log || 10;
var cost = options.cost || this.cost || Trainer.cost.MSE;
var trainingSamples = options.trainSamples || 7000;
var testSamples = options.trainSamples || 1000;
// samples for training and testing
var samples = getSamples(trainingSamples, testSamples);
// train
var result = this.train(samples.train, {
rate: rate,
log: log,
iterations: iterations,
error: error,
cost: cost
});
return {
train: result,
test: this.test(samples.test)
}
}
};
// Built-in cost functions
Trainer.cost = {
// Eq. 9
CROSS_ENTROPY: function(target, output)
{
var crossentropy = 0;
for (var i in output)
crossentropy -= (target[i] * Math.log(output[i]+1e-15)) + ((1-target[i]) * Math.log((1+1e-15)-output[i])); // +1e-15 is a tiny push away to avoid Math.log(0)
return crossentropy;
},
MSE: function(target, output)
{
var mse = 0;
for (var i in output)
mse += Math.pow(target[i] - output[i], 2);
return mse / output.length;
},
BINARY: function(target, output){
var misses = 0;
for (var i in output)
misses += Math.round(target[i] * 2) != Math.round(output[i] * 2);
return misses;
}
}
+26
Ver Arquivo
@@ -0,0 +1,26 @@
Test using mocha, from root directory:
`mocha test`
To test the web version, start a web server at the root dir of this repo, then use your OS browser.
[Python](http://xkcd.com/353/) to the rescue! From command line run this command:
```bash
$ python -m SimpleHTTPServer 8080
#go to http://localhost:8080/test/test_browser.html
```
Or you can use node.js instead:
```bash
$ npm install -g http-server
```
Then run:
```bash
$ http-server
#go to http://localhost:8080/test/test_browser.html
```
+1
Ver Arquivo
@@ -0,0 +1 @@
global.synaptic = require('../dist/synaptic');
+1
Ver Arquivo
@@ -0,0 +1 @@
global.synaptic = require('../src/synaptic');
+1
Ver Arquivo
@@ -0,0 +1 @@
[^_]*.js
Arquivo executável
+602
Ver Arquivo
@@ -0,0 +1,602 @@
// import
var chai = require('chai');
chai.use(require('chai-stats'));
var assert = chai.assert;
var Perceptron = synaptic.Architect.Perceptron;
var LSTM = synaptic.Architect.LSTM;
var Layer = synaptic.Layer;
var Network = synaptic.Network;
var Trainer = synaptic.Trainer;
var learningRate = .5;
// utils
function noRepeat(range, avoid) {
var number = Math.random() * range | 0;
for (var i in avoid) {
if (number == avoid[i]) {
return noRepeat(range, avoid);
}
}
return number;
}
function equal(prediction, output) {
for (var i in prediction)
if (Math.round(prediction[i]) != output[i])
return false;
return true;
}
function generateRandomArray(size) {
var array = [];
for (var j = 0; j < size; j++)
array.push(Math.random() + .5 | 0);
return array;
}
function calculateMse(a, b) {
var mse = 0;
for (var k in a)
mse += Math.pow(a[k] - b[k], 2);
mse /= a.length;
return mse;
}
function equalWithError(output, expected, error) {
return Math.abs(output - expected) <= error;
}
// specs
describe('Basic Neural Network', function () {
it("trains an AND gate", function () {
var inputLayer = new Layer(2),
outputLayer = new Layer(1);
inputLayer.project(outputLayer);
var network = new Network({
input: inputLayer,
output: outputLayer
});
var trainer = new Trainer(network);
var trainingSet = [{
input: [0, 0],
output: [0]
}, {
input: [0, 1],
output: [0]
}, {
input: [1, 0],
output: [0]
}, {
input: [1, 1],
output: [1]
}];
trainer.train(trainingSet, {
iterations: 1000,
error: .001
});
var test00 = Math.round(network.activate([0, 0]));
assert.equal(test00, 0, "[0,0] did not output 0");
var test01 = Math.round(network.activate([0, 1]));
assert.equal(test01, 0, "[0,1] did not output 0");
var test10 = Math.round(network.activate([1, 0]));
assert.equal(test10, 0, "[1,0] did not output 0");
var test11 = Math.round(network.activate([1, 1]));
assert.equal(test11, 1, "[1,1] did not output 1");
});
it("trains an OR gate", function () {
var inputLayer = new Layer(2),
outputLayer = new Layer(1);
inputLayer.project(outputLayer);
var network = new Network({
input: inputLayer,
output: outputLayer
});
var trainer = new Trainer(network);
var trainingSet = [{
input: [0, 0],
output: [0]
}, {
input: [0, 1],
output: [1]
}, {
input: [1, 0],
output: [1]
}, {
input: [1, 1],
output: [1]
}];
trainer.train(trainingSet, {
iterations: 1000,
error: .001
});
var test00 = Math.round(network.activate([0, 0]));
assert.equal(test00, 0, "[0,0] did not output 0");
var test01 = Math.round(network.activate([0, 1]));
assert.equal(test01, 1, "[0,1] did not output 1");
var test10 = Math.round(network.activate([1, 0]));
assert.equal(test10, 1, "[1,0] did not output 1");
var test11 = Math.round(network.activate([1, 1]));
assert.equal(test11, 1, "[1,1] did not output 1");
});
it("trains a NOT gate", function () {
var inputLayer = new Layer(1),
outputLayer = new Layer(1);
inputLayer.project(outputLayer);
var network = new Network({
input: inputLayer,
output: outputLayer
});
var trainer = new Trainer(network);
var trainingSet = [{
input: [0],
output: [1]
}, {
input: [1],
output: [0]
}];
trainer.train(trainingSet, {
iterations: 1000,
error: .001
});
var test0 = Math.round(network.activate([0]));
assert.equal(test0, 1, "0 did not output 1");
var test1 = Math.round(network.activate([1]));
assert.equal(test1, 0, "1 did not output 0");
});
});
describe("Perceptron - XOR", function () {
var perceptron = new Perceptron(2, 3, 1);
perceptron.trainer.XOR();
it("should return near-0 value on [0,0]", function () {
assert.isAtMost(perceptron.activate([0, 0]), .49, "[0,0] did not output 0");
});
it("should return near-1 value on [0,1]", function () {
assert.isAtLeast(perceptron.activate([0, 1]), .51, "[0,1] did not output 1");
});
it("should return near-1 value on [1,0]", function () {
assert.isAtLeast(perceptron.activate([1, 0]), .51, "[1,0] did not output 1");
});
it("should return near-0 value on [1,1]", function () {
assert.isAtMost(perceptron.activate([1, 1]), .49, "[1,1] did not output 0");
});
});
describe("Perceptron - SIN", function () {
var mySin = function (x) {
return (Math.sin(x) + 1) / 2;
};
var sinNetwork = new Perceptron(1, 12, 1);
var trainingSet = [];
while (trainingSet.length < 800) {
var inputValue = Math.random() * Math.PI * 2;
trainingSet.push({
input: [inputValue],
output: [mySin(inputValue)]
});
}
var results = sinNetwork.trainer.train(trainingSet, {
iterations: 2000,
log: false,
error: 1e-6,
cost: Trainer.cost.MSE,
});
[0, .5 * Math.PI, 2]
.forEach(function (x) {
var y = mySin(x);
it("should return value around " + y + " when [" + x + "] is on input", function () {
// near scalability: abs(expected-actual) < 0.5 * 10**(-decimal)
// 0.5 * Math.pow(10, -.15) => 0.35397289219206896
assert.almostEqual(sinNetwork.activate([x])[0], y, .15);
});
});
var errorResult = results.error;
it("Sin error: " + errorResult, function () {
assert.isAtMost(errorResult, .001, "Sin error not less than or equal to desired error.");
});
});
describe("Perceptron - SIN - CrossValidate", function () {
var mySin = function (x) {
return (Math.sin(x) + 1) / 2;
};
var sinNetwork = new Perceptron(1, 12, 1);
var trainingSet = Array.apply(null, Array(800)).map(function () {
var inputValue = Math.random() * Math.PI * 2;
return {
input: [inputValue],
output: [mySin(inputValue)]
};
});
var results = sinNetwork.trainer.train(trainingSet, {
iterations: 2000,
log: false,
error: 1e-6,
cost: Trainer.cost.MSE,
crossValidate: {
testSize: .3,
testError: 1e-6
}
});
var test0 = sinNetwork.activate([0])[0];
var expected0 = mySin(0);
it("input: [0] output: " + test0 + ", expected: " + expected0, function () {
assert.isAtMost(Math.abs(test0 - expected0), .035, "[0] did not output " + expected0);
});
var test05PI = sinNetwork.activate([.5 * Math.PI])[0];
var expected05PI = mySin(.5 * Math.PI);
it("input: [0.5*Math.PI] output: " + test05PI + ", expected: " + expected05PI, function () {
assert.isAtMost(Math.abs(test05PI - expected05PI), .035, "[0.5*Math.PI] did not output " + expected05PI);
});
var test2 = sinNetwork.activate([2])[0];
var expected2 = mySin(2);
it("input: [2] output: " + test2 + ", expected: " + expected2, function () {
var eq = equalWithError(test2, expected2, .035);
assert.equal(eq, true, "[2] did not output " + expected2);
});
var errorResult = results.error;
it("CrossValidation error: " + errorResult, function () {
var lessThanOrEqualError = errorResult <= .001;
assert.equal(lessThanOrEqualError, true, "CrossValidation error not less than or equal to desired error.");
});
});
describe("LSTM - Discrete Sequence Recall", function () {
var targets = [2, 4];
var distractors = [3, 5];
var prompts = [0, 1];
var length = 9;
var lstm = new LSTM(5, 3, 2);
lstm.trainer.DSR({
targets: targets,
distractors: distractors,
prompts: prompts,
length: length,
rate: .17,
iterations: 250000
});
var symbols = targets.length + distractors.length + prompts.length;
var sequence = [],
indexes = [],
positions = [];
var sequenceLength = length - prompts.length;
for (i = 0; i < sequenceLength; i++) {
var any = Math.random() * distractors.length | 0;
sequence.push(distractors[any]);
}
indexes = [], positions = [];
for (i = 0; i < prompts.length; i++) {
indexes.push(Math.random() * targets.length | 0);
positions.push(noRepeat(sequenceLength, positions));
}
positions = positions.sort();
for (i = 0; i < prompts.length; i++) {
sequence[positions[i]] = targets[indexes[i]];
sequence.push(prompts[i]);
}
var check = function (which) {
// generate input from sequence
var input = [];
for (j = 0; j < symbols; j++)
input[j] = 0;
input[sequence[which]] = 1;
// generate target output
var output = [];
for (j = 0; j < targets.length; j++)
output[j] = 0;
if (which >= sequenceLength) {
var index = which - sequenceLength;
output[indexes[index]] = 1;
}
// check result
var prediction = lstm.activate(input);
return {
prediction: prediction,
output: output
};
};
var value = function (array) {
var max = .5;
var res = -1;
for (var i in array)
if (array[i] > max) {
max = array[i];
res = i;
}
return res == -1 ? '-' : targets[res];
};
it("targets: " + targets, function () {
assert(true);
});
it("distractors: " + distractors, function () {
assert(true);
});
it("prompts: " + prompts, function () {
assert(true);
});
it("length: " + length + "\n", function () {
assert(true);
});
for (var i = 0; i < length; i++) {
var test = check(i);
it((i + 1) + ") input: " + sequence[i] + " output: " + value(test.prediction),
function () {
var ok = equal(test.prediction, test.output);
assert(ok);
});
}
});
describe("LSTM - Timing Task", function () {
var network = new LSTM(2, 7, 1);
var result = network.trainer.timingTask({
log: false,
trainSamples: 4000,
testSamples: 500
});
it("should complete the training in less than 200 iterations", function () {
assert(result.train.iterations <= 200);
});
it("should pass the test with an error smaller than 0.05", function () {
assert(result.test.error < .05);
});
});
describe("Optimized and Unoptimized Networks Equivalency", function () {
var optimized;
var unoptimized;
beforeEach(function () {
optimized = new LSTM(2, 1, 1);
unoptimized = optimized.clone();
unoptimized.setOptimize(false);
});
it('should produce the same output for both networks', function () {
this.timeout(30000);
for (var i = 0; i < 1000; i++) {
var input = generateRandomArray(2);
var target = generateRandomArray(1);
optimized.activate(input);
unoptimized.activate(input);
optimized.propagate(learningRate, target);
unoptimized.propagate(learningRate, target);
}
var mse = calculateMse(optimized.activate(input), unoptimized.activate(input));
assert.isAtMost(mse, 1e-9, 'output should be same for both networks after ' + i + ' iterations');
});
});
describe("toJSON/fromJSON Networks Equivalency", function () {
var original;
var imported;
beforeEach(function () {
original = new LSTM(10, 5, 5);
imported = Network.fromJSON(original.toJSON());
});
it('should produce the same output for both networks', function () {
this.timeout(30000);
for (var i = 0; i < 1000; i++) {
var input = generateRandomArray(10);
var output1 = original.activate(input);
var output2 = imported.activate(input);
var target = generateRandomArray(5);
// propagate networks
original.propagate(learningRate, target);
imported.propagate(learningRate, target);
assert.isAtMost(calculateMse(output1, output2), 1e-10,
'output should be same for both networks after ' + i + ' iterations');
}
});
});
describe("Cloned Networks Equivalency", function () {
var original;
var cloned;
beforeEach(function () {
original = new LSTM(10, 5, 5);
cloned = Network.fromJSON(original.toJSON());
});
it('should produce the same output for both networks', function () {
this.timeout(30000);
for (var i = 0; i < 1000; i++) {
var input = generateRandomArray(10);
var output1 = original.activate(input);
var output2 = cloned.activate(input);
var target = generateRandomArray(5);
// propagate networks
original.propagate(learningRate, target);
cloned.propagate(learningRate, target);
assert.isAtMost(calculateMse(output1, output2), 1e-10,
'output should be same for both networks after ' + i + ' iterations');
}
});
});
describe("Scheduled Tasks", function () {
var perceptron = new Perceptron(2, 3, 1);
it('should stop training at 3000 iterations', function () {
var final_stats = perceptron.trainer.XOR({
iterations: 3000,
rate: 0.000001,
error: 0.000001,
schedule: {
every: 1000,
do: function (data) {
return data.iterations == 20000;
}
}
});
assert.equal(final_stats.iterations, 3000)
});
it('should abort the training at 2000 iterations', function () {
var final_stats = perceptron.trainer.XOR({
iterations: 3000,
rate: 0.000001,
error: 0.000001,
schedule: {
every: 1000,
do: function (data) {
return data.iterations == 2000;
}
}
});
assert.equal(final_stats.iterations, 2000)
});
it('should work even if schedule.do() returns no value', function () {
var final_stats = perceptron.trainer.XOR({
iterations: 3000,
rate: 0.000001,
error: 0.000001,
schedule: {
every: 1000,
do: function (data) {}
}
});
assert.equal(final_stats.iterations, 3000)
});
});
describe("Rate Callback Check", function () {
var perceptron = new Perceptron(2, 3, 1);
it('should switch rate from 0.01 to 0.005 after 1000 iterations', function () {
var final_stats = perceptron.trainer.XOR({
iterations: 2000,
rate: function (iterations, error) {
return iterations < 1000 ? 0.01 : 0.005
},
error: 0.000001,
schedule: {
every: 1,
do: function (data) {
switch (data.iterations) {
case 1:
case 500:
case 999:
assert.equal(data.rate, 0.01);
break;
case 1000:
case 1500:
case 2000:
assert.equal(data.rate, 0.005);
break;
}
}
}
});
});
});
describe("Rate Array Check", function () {
var perceptron = new Perceptron(2, 3, 1);
it('should switch rate from 0.01 to 0.005 after 1000 iterations', function () {
var final_stats = perceptron.trainer.XOR({
iterations: 2000,
rate: [0.01, 0.005],
error: 0.000001,
schedule: {
every: 1,
do: function (data) {
switch (data.iterations) {
case 1:
case 500:
case 999:
assert.equal(data.rate, 0.01);
break;
case 1000:
case 1500:
case 2000:
assert.equal(data.rate, 0.005);
break;
}
}
}
});
});
});
+17
Ver Arquivo
@@ -0,0 +1,17 @@
var webpack = require('webpack')
var license = require('./prebuild.js')
module.exports = {
context: __dirname,
entry: {
synaptic: './src/synaptic.js',
'synaptic.min': './src/synaptic.js'
},
output: {
path: 'dist',
filename: '[name].js',
},
plugins: [
new webpack.NoErrorsPlugin(),
new webpack.BannerPlugin(license())
]
}