Compare commits

...
534 Commits
Author SHA1 Message Date
William Falcon 7dd22f82c6 release v0.3.6.4 2019-07-27 13:42:41 -04:00
William Falcon a3bd66167b Update trainer.py 2019-07-27 13:41:38 -04:00
William Falcon 0ce180f6ec updated docs 2019-07-26 23:23:56 -04:00
William Falcon 8e7d3c6737 added clean slurm save load test 2019-07-26 23:16:03 -04:00
William Falcon 4cacb5a21b release v0.3.6.3 2019-07-26 23:09:49 -04:00
William Falcon 60e60fcd8b added clean slurm save load test 2019-07-26 23:09:27 -04:00
William Falcon cf898a6ecf Merge pull request #22 from williamFalcon/loading
Loading
2019-07-26 23:08:17 -04:00
William Falcon 587c195298 added clean slurm save load test 2019-07-26 23:04:41 -04:00
William Falcon 64586f271d added clean slurm save load test 2019-07-26 23:02:18 -04:00
William Falcon 53b781709e added clean slurm save load test 2019-07-26 22:57:49 -04:00
William Falcon f183ac2a1c added clean slurm save load test 2019-07-26 22:51:33 -04:00
William Falcon 61c82611eb added clean slurm save load test 2019-07-26 22:40:07 -04:00
William Falcon 3224365190 added clean slurm save load test 2019-07-26 22:39:44 -04:00
William Falcon 2a4081e537 added clean slurm save load test 2019-07-26 22:33:31 -04:00
William Falcon 8e3a0443c7 added clean slurm save load test 2019-07-26 22:33:00 -04:00
William Falcon f5a01edfb8 added clean slurm save load test 2019-07-26 22:32:34 -04:00
William Falcon f1de62671d added clean slurm save load test 2019-07-26 22:32:27 -04:00
William Falcon 57edb08bd8 added clean slurm save load test 2019-07-26 22:28:09 -04:00
William Falcon ffa7a0dbab added clean slurm save load test 2019-07-26 22:26:55 -04:00
William Falcon b5419fcd8b added clean slurm save load test 2019-07-26 22:24:01 -04:00
William Falcon c61e13f0ff fixed hpc save, load. cleaned apu 2019-07-26 22:13:41 -04:00
William Falcon a6ae97ac09 fixed hpc save, load. cleaned apu 2019-07-26 22:13:06 -04:00
William Falcon 348223a702 fixed hpc save, load. cleaned apu 2019-07-26 22:09:35 -04:00
William Falcon 64de447545 fixed hpc save, load. cleaned apu 2019-07-26 22:07:02 -04:00
William Falcon 265411572f fixed hpc save, load. cleaned apu 2019-07-26 22:04:27 -04:00
William Falcon 4148c36abd added model save load test 2019-07-26 21:55:01 -04:00
William Falcon 0ee0344820 removed old template 2019-07-26 21:39:53 -04:00
William Falcon a5a80f35ec removed old template 2019-07-26 21:39:28 -04:00
William Falcon 92a1f559b5 remove state_dict 2019-07-26 21:39:01 -04:00
William Falcon aacf1947ea auto state-dict and remove the way the model is loaded during hpc 2019-07-26 21:38:06 -04:00
William Falcon e2c7fa44b7 auto state-dict and remove the way the model is loaded during hpc 2019-07-26 21:37:06 -04:00
William Falcon ff1ed9db7e release v0.3.6.1 2019-07-26 19:11:32 -04:00
William Falcon baf2ccefea Merge pull request #21 from williamFalcon/r
R
2019-07-26 19:10:48 -04:00
William Falcon df37c8418a updated test-tube dep number 2019-07-26 18:57:18 -04:00
William Falcon d6bfb94215 added global rank var name 2019-07-26 18:52:38 -04:00
William Falcon 12f717ad4a added global rank var name 2019-07-26 18:52:02 -04:00
William Falcon 56d41eaa8c Merge pull request #20 from williamFalcon/test2
Test2
2019-07-26 12:47:13 -04:00
William Falcon 84edf35f33 added saving tests to cpu 2019-07-26 12:35:28 -04:00
William Falcon a374a7ea00 added saving tests to cpu 2019-07-26 12:33:35 -04:00
William Falcon fbc1bbd161 added saving tests to cpu 2019-07-26 12:31:26 -04:00
William Falcon 84f03a1335 added saving tests to cpu 2019-07-26 12:29:19 -04:00
William Falcon 1a835969a6 added saving tests to cpu 2019-07-26 12:14:58 -04:00
William Falcon 2ee8f157ce added checkpoint test on cpu 2019-07-26 11:51:25 -04:00
William Falcon 51a5cc36e3 added checkpoint test on cpu 2019-07-26 11:50:02 -04:00
William Falcon c4b37d1efe updated readme 2019-07-25 20:13:22 -04:00
William Falcon 0489ed1e89 updated readme 2019-07-25 19:55:22 -04:00
William Falcon 677edc46d8 removed exception crashing from val 2019-07-25 19:49:45 -04:00
William Falcon 7e52f6ea97 cleaned up some if statements 2019-07-25 17:14:33 -04:00
William Falcon 7e728d97e7 removed save model logging 2019-07-25 14:36:22 -04:00
William Falcon 08bf9e16ae updated docs 2019-07-25 12:46:11 -04:00
William Falcon 7166b1acbc updated docs 2019-07-25 12:44:48 -04:00
William Falcon d18f38c0d7 updated docs 2019-07-25 12:40:09 -04:00
William Falcon f844f110af updated docs 2019-07-25 12:37:59 -04:00
William Falcon 1cbe54f8ba updated docs 2019-07-25 12:35:28 -04:00
William Falcon 79a79fb27d updated examples 2019-07-25 12:33:53 -04:00
William Falcon b1cd5d9d31 updated examples 2019-07-25 12:30:59 -04:00
William Falcon 6bd58de40e updated examples 2019-07-25 12:30:18 -04:00
William Falcon a1dd4d3e2c release v0.3.6 2019-07-25 12:22:50 -04:00
William Falcon b914866131 updated docs 2019-07-25 12:12:45 -04:00
William Falcon e182559c83 updated docs 2019-07-25 12:11:49 -04:00
William Falcon 9b99a02061 removed hparams req 2019-07-25 12:09:09 -04:00
William Falcon 20227b1382 removed hparams req 2019-07-25 12:08:00 -04:00
William Falcon d0d5653b06 removed hparams req 2019-07-25 12:04:20 -04:00
William Falcon b0d38d532d updated docs 2019-07-25 12:01:52 -04:00
William Falcon 4562580461 updated docs 2019-07-25 11:58:06 -04:00
William Falcon d272f29c88 updated docs 2019-07-25 11:52:54 -04:00
William Falcon 600c755460 updated docs 2019-07-25 11:44:25 -04:00
William Falcon d09a9e2c96 release v0.3.51 2019-07-25 11:38:57 -04:00
William Falcon 0f79e9d74e updated docs 2019-07-25 11:35:11 -04:00
William Falcon 9fa8120805 updated docs 2019-07-25 11:30:17 -04:00
William Falcon 715bf23105 updated docs 2019-07-25 11:28:34 -04:00
William Falcon 88ac4a0849 testing multiple calles 2019-07-25 11:19:58 -04:00
William Falcon 383746b87a testing multiple calles 2019-07-25 11:19:20 -04:00
William Falcon fffc09830f switched cpu amp order 2019-07-25 11:11:14 -04:00
William Falcon aadf8e16aa switched cpu amp order 2019-07-25 11:10:21 -04:00
William Falcon 4b04dc06d4 switched cpu amp order 2019-07-25 11:08:31 -04:00
William Falcon 0e42d28415 fixed root node addr 2019-07-25 11:05:15 -04:00
William Falcon 09dba13cde updated test models with lazy decorators 2019-07-25 11:01:08 -04:00
William Falcon 42a45bb273 updated test models with lazy decorators 2019-07-25 11:00:35 -04:00
William Falcon 5604e955eb updated test models with lazy decorators 2019-07-25 10:59:10 -04:00
William Falcon 6d34224e68 updated test models with lazy decorators 2019-07-25 10:56:42 -04:00
William Falcon 24a3246bc1 updated test models with lazy decorators 2019-07-25 10:56:03 -04:00
William Falcon 39b15855ed added lazy decorator 2019-07-25 10:39:48 -04:00
William Falcon c6da6eb46c updated readme 2019-07-25 10:33:35 -04:00
William Falcon d23d25646a cleaned readme 2019-07-25 10:26:47 -04:00
William Falcon bd6521a584 cleaned readme 2019-07-25 10:25:41 -04:00
William Falcon 2ce3e3e108 cleaned readme 2019-07-25 10:25:12 -04:00
William Falcon deeb82d28f cleaned readme 2019-07-25 10:23:51 -04:00
William Falcon 74817c2fb1 cleaned readme 2019-07-25 10:11:51 -04:00
William Falcon b989358c9b added downloads badge 2019-07-25 09:55:50 -04:00
William Falcon 0d47561a31 added downloads badge 2019-07-25 09:55:30 -04:00
William Falcon b8c7baa8ac release v0.3.5 2019-07-24 22:08:02 -04:00
William Falcon caf874538c added init to test folder 2019-07-24 22:00:00 -04:00
William Falcon ff0459df60 added init to test folder 2019-07-24 21:56:38 -04:00
William Falcon 6e0b2af827 added init to test folder 2019-07-24 21:51:17 -04:00
William Falcon 204a81a10e added init to test folder 2019-07-24 21:50:27 -04:00
William Falcon 2ddf51bf3e added init to test folder 2019-07-24 21:44:46 -04:00
William Falcon a680ad1540 added init to test folder 2019-07-24 21:40:19 -04:00
William Falcon 735df77862 added init to test folder 2019-07-24 21:35:38 -04:00
William Falcon 9856520c0c added init to test folder 2019-07-24 21:32:31 -04:00
William Falcon a186cf12dc added instructions to test 2019-07-24 21:31:43 -04:00
William Falcon 104b4dc1ff removed deps 2019-07-24 21:28:34 -04:00
William Falcon 9b44ed1c3f removed deps 2019-07-24 21:22:24 -04:00
William Falcon 2ca0166a0d removed deps 2019-07-24 21:19:26 -04:00
William Falcon 9fa8293e7a Update README.md 2019-07-24 21:15:17 -04:00
William Falcon 55648311ba Update README.md 2019-07-24 21:14:43 -04:00
William Falcon 39ed4472c2 removed dep 2019-07-24 21:13:00 -04:00
William Falcon 9d6311c69b added travis 2019-07-24 21:09:36 -04:00
William Falcon 497ec95f55 added mkdocs config 2019-07-24 21:04:46 -04:00
William Falcon b75129dde4 added mkdocs config 2019-07-24 21:04:20 -04:00
William Falcon 91bc8cbc02 added mkdocs config 2019-07-24 21:03:24 -04:00
William Falcon 135b826ebb removed dep 2019-07-24 20:56:43 -04:00
William Falcon 24c07bdff3 removed dep 2019-07-24 20:56:09 -04:00
William Falcon 3ebf3bbcfd removed dep 2019-07-24 20:55:16 -04:00
William Falcon 097a9d2617 Merge pull request #18 from williamFalcon/tests
removed dep
2019-07-24 20:54:42 -04:00
William Falcon afb5d0e638 removed dep 2019-07-24 20:52:53 -04:00
William Falcon 303ab0ca9b Update README.md 2019-07-24 20:52:08 -04:00
William Falcon d118b774fb Update README.md 2019-07-24 20:48:19 -04:00
William Falcon e060c2008f Update README.md 2019-07-24 20:46:33 -04:00
William Falcon 17f2d376ed Update README.md 2019-07-24 20:45:59 -04:00
William Falcon 2d3ab895a5 Merge pull request #17 from williamFalcon/tests
added coverage badge
2019-07-24 20:41:57 -04:00
William Falcon c263badbb5 Merge pull request #16 from williamFalcon/tests
Tests
2019-07-24 20:41:12 -04:00
williamFalcon 3ccfb2a858 added coverage badge 2019-07-24 17:39:20 -07:00
William Falcon 63a4af3ba7 added testing for metrics 2019-07-24 20:33:31 -04:00
William Falcon 23e7521300 added dp reduce out test 2019-07-24 20:22:54 -04:00
William Falcon d6e7994922 added dp reduce out test 2019-07-24 20:21:57 -04:00
William Falcon 37a26741cc testing map location 2019-07-24 20:08:17 -04:00
William Falcon c72a189c54 dp doesnt support amp with any setting 2019-07-24 19:48:48 -04:00
William Falcon a4bb80b936 dp doesnt support amp with any setting 2019-07-24 19:43:38 -04:00
William Falcon 5a1b3d17d2 pt dpp some ignores 2019-07-24 19:39:18 -04:00
William Falcon 1361d37598 pt dpp some ignores 2019-07-24 19:37:04 -04:00
William Falcon 8391b744c0 pt dpp some ignores 2019-07-24 19:36:35 -04:00
William Falcon e3463c8fe3 pt dpp some ignores 2019-07-24 19:35:31 -04:00
William Falcon a8d126b2a2 pt dpp some ignores 2019-07-24 19:32:41 -04:00
William Falcon 10c3266ed4 pt dpp some ignores 2019-07-24 19:30:27 -04:00
William Falcon 6fb27c4526 pt dpp some ignores 2019-07-24 19:29:51 -04:00
William Falcon db9a8cfe78 ignoring dist parallel forward 2019-07-24 19:24:58 -04:00
William Falcon a3ad0e0ac1 ignoring dist parallel forward 2019-07-24 19:23:11 -04:00
William Falcon 4260769e14 ignoring dist parallel forward 2019-07-24 19:18:23 -04:00
William Falcon 9be15aa29f added cpu + amp error 2019-07-24 19:17:08 -04:00
William Falcon a5756d91be added cpu + amp error 2019-07-24 19:12:03 -04:00
William Falcon fcda19aa25 added cpu + amp error 2019-07-24 19:07:53 -04:00
William Falcon efbd1a1c18 added cpu 16 bit 2019-07-24 19:05:46 -04:00
William Falcon ed9d977c4a added cpu 16 bit 2019-07-24 19:05:20 -04:00
William Falcon 65ce10c255 testing -1 gpu option 2019-07-24 19:02:19 -04:00
William Falcon f58c83b399 made root note address individually testable 2019-07-24 18:57:42 -04:00
William Falcon 750fefac0c made root note address individually testable 2019-07-24 18:55:38 -04:00
William Falcon ccd4018dd9 made root note address individually testable 2019-07-24 18:53:12 -04:00
William Falcon 53a0b9f365 moved slurm flag resolution to init 2019-07-24 18:46:21 -04:00
William Falcon f4d8fe5d77 moved slurm flag resolution to init 2019-07-24 18:42:22 -04:00
William Falcon 18ce3e5a23 moved slurm flag resolution to init 2019-07-24 18:40:54 -04:00
William Falcon fb8b03b042 moved slurm flag resolution to init 2019-07-24 18:39:27 -04:00
William Falcon 982f0d4b3a running ddp tests 2019-07-24 18:33:54 -04:00
William Falcon 40b86808c8 running ddp tests 2019-07-24 18:32:48 -04:00
William Falcon 70a2e66ae9 running ddp tests 2019-07-24 18:30:47 -04:00
William Falcon abbbcac9fa running ddp tests 2019-07-24 18:30:35 -04:00
William Falcon 9d588f337f running ddp tests 2019-07-24 18:30:08 -04:00
William Falcon 3451a62650 running ddp tests 2019-07-24 18:27:40 -04:00
William Falcon 1313a7f397 fixed correct module on hpc save 2019-07-24 18:22:49 -04:00
William Falcon 6e2bf991f0 fixed correct module on hpc save 2019-07-24 18:21:22 -04:00
William Falcon a0e2b5ee54 fixed correct module on hpc save 2019-07-24 18:20:56 -04:00
William Falcon 8f0d9af168 fixed correct module on hpc save 2019-07-24 18:18:58 -04:00
William Falcon 7fa759ffed fixed correct module on hpc save 2019-07-24 18:16:31 -04:00
William Falcon 3600535bc5 fixed correct module on hpc save 2019-07-24 18:16:22 -04:00
William Falcon d7be0aae1c fixed correct module on hpc save 2019-07-24 18:16:02 -04:00
William Falcon 7217ecdb18 fixed correct module on hpc save 2019-07-24 18:12:46 -04:00
William Falcon 2e0fde7da7 fixed correct module on hpc save 2019-07-24 18:11:29 -04:00
William Falcon 10330f1991 fixed correct module on hpc save 2019-07-24 18:10:30 -04:00
William Falcon 549a158ec0 fixed correct module on hpc save 2019-07-24 18:09:04 -04:00
William Falcon a63f74281a fixed correct module on hpc save 2019-07-24 18:03:19 -04:00
William Falcon 423bc5c6c9 testing hpc save load 2019-07-24 18:01:33 -04:00
William Falcon 2408aa886d testing hpc save load 2019-07-24 18:00:15 -04:00
William Falcon 97980355e3 testing hpc save load 2019-07-24 17:58:00 -04:00
William Falcon 17f56c83b5 testing hpc save load 2019-07-24 17:57:15 -04:00
William Falcon 8191f268ec test memory printing 2019-07-24 17:56:47 -04:00
William Falcon 436e929458 test memory printing 2019-07-24 17:47:51 -04:00
William Falcon 7f420c0cc2 test memory printing 2019-07-24 17:41:08 -04:00
William Falcon ffdf11b7ed test memory printing 2019-07-24 17:35:39 -04:00
William Falcon 5ebe494212 test memory printing 2019-07-24 17:34:08 -04:00
William Falcon 66abd0d382 test memory printing 2019-07-24 17:31:56 -04:00
William Falcon 1d28b468bd remove exception line 2019-07-24 17:30:16 -04:00
William Falcon d372b21b5e ignore test module model 2019-07-24 17:28:23 -04:00
William Falcon c277ab1036 ignore tests file 2019-07-24 17:27:33 -04:00
William Falcon 56997a0622 ignore argparse from example for tests 2019-07-24 17:26:40 -04:00
William Falcon 63ce8af27c added multiple outputs to LightningTestModel 2019-07-24 17:23:19 -04:00
William Falcon 516ee9c985 added multiple outputs to LightningTestModel 2019-07-24 17:21:18 -04:00
William Falcon 0aa91c7fdc added multiple outputs to LightningTestModel 2019-07-24 17:19:31 -04:00
William Falcon 3521e87286 added multiple outputs to LightningTestModel 2019-07-24 17:18:58 -04:00
William Falcon 9101a70024 refactor tests 2019-07-24 17:12:12 -04:00
William Falcon b30fbf80d0 added test for no dist sampler 2019-07-24 17:11:25 -04:00
William Falcon d1d33e8db6 added test for no dist sampler 2019-07-24 17:10:14 -04:00
William Falcon 164751c918 added test for no dist sampler 2019-07-24 17:09:14 -04:00
William Falcon 096132b389 added test for no dist sampler 2019-07-24 17:04:12 -04:00
William Falcon 9e5dd7a7ea added test for no dist sampler 2019-07-24 17:02:39 -04:00
William Falcon 1e0bae14da added test for no dist sampler 2019-07-24 17:01:25 -04:00
William Falcon 8064a77aa7 added test for no dist sampler 2019-07-24 16:57:21 -04:00
William Falcon 5c21683566 added model for tests 2019-07-24 16:45:59 -04:00
William Falcon f69ff593b5 ignoring multi-node flag 2019-07-24 16:37:05 -04:00
William Falcon 383b4cdac7 added sample input for summary 2019-07-24 16:35:32 -04:00
William Falcon b824f184ff added sample input for summary 2019-07-24 16:31:55 -04:00
William Falcon 5f814e48c4 added sample input for summary 2019-07-24 16:30:27 -04:00
William Falcon 8db8cd2539 added sample input for summary 2019-07-24 16:28:55 -04:00
William Falcon 77a7f3e33e added sample input for summary 2019-07-24 16:27:16 -04:00
William Falcon b8cc62ee52 added sample input for summary 2019-07-24 16:24:58 -04:00
William Falcon 3a86e0fc6c added sample input for summary 2019-07-24 16:23:30 -04:00
William Falcon 7c3786aa52 added sample input for summary 2019-07-24 16:22:09 -04:00
William Falcon 83ccd21bec added sample input for summary 2019-07-24 16:20:42 -04:00
William Falcon f3b0cbf998 removed dead code in grads 2019-07-24 16:19:19 -04:00
William Falcon 97aa69c8f6 removed dead code in grads 2019-07-24 16:16:26 -04:00
William Falcon 7a868c51ae removed dead code in grads 2019-07-24 16:10:32 -04:00
William Falcon 2f4bd676e8 added coverage file 2019-07-24 16:09:24 -04:00
William Falcon ad3d00bcae added coverage file 2019-07-24 16:08:35 -04:00
William Falcon cfd2792d76 added coverage file 2019-07-24 16:04:36 -04:00
William Falcon dfccc03da8 added coverage file 2019-07-24 16:04:18 -04:00
William Falcon 843675e9a1 added coverage file 2019-07-24 16:00:48 -04:00
William Falcon eae4fa0495 added coverage file 2019-07-24 15:57:18 -04:00
William Falcon cc875cd603 added coverage file 2019-07-24 15:56:33 -04:00
William Falcon e3ed5bfbc7 added coverage file 2019-07-24 15:56:27 -04:00
William Falcon 23e0986141 removed coverage file 2019-07-24 15:54:14 -04:00
William Falcon ea7be12bb1 added coverage file 2019-07-24 15:52:59 -04:00
William Falcon 9b792bf4d4 removed dead code in model save 2019-07-24 15:48:41 -04:00
William Falcon d4d0f54a37 removed dead code in model save 2019-07-24 15:48:35 -04:00
William Falcon b7ca857434 removed dead code in model save 2019-07-24 15:44:04 -04:00
William Falcon b836e6f321 removed dead code in model save 2019-07-24 15:43:10 -04:00
William Falcon 08c76c47bd removed opt check 2019-07-24 15:38:15 -04:00
William Falcon 74d714f159 removed opt check 2019-07-24 15:33:08 -04:00
William Falcon 79c0054c38 removed forkedpdb 2019-07-24 15:28:23 -04:00
William Falcon ebc120a3c3 removed forkedpdb 2019-07-24 15:27:59 -04:00
William Falcon bc40be3490 removed old files 2019-07-24 15:23:52 -04:00
William Falcon 1f67fbdb80 removed old files 2019-07-24 15:23:38 -04:00
William Falcon 1a6ee20dff removed old files 2019-07-24 15:15:14 -04:00
William Falcon 8b6217733a added auto port find 2019-07-24 15:11:50 -04:00
William Falcon b1e16c2e7b added auto port find 2019-07-24 15:11:29 -04:00
William Falcon 9f0d963e37 added auto port find 2019-07-24 15:08:59 -04:00
William Falcon b5c67d91e5 added auto port find 2019-07-24 15:00:14 -04:00
William Falcon 90ff418017 added auto port find 2019-07-24 14:59:51 -04:00
William Falcon 98be54de80 added auto port find 2019-07-24 14:59:40 -04:00
William Falcon e3f01388df added auto port find 2019-07-24 14:57:54 -04:00
William Falcon afa25a26d9 added auto port find 2019-07-24 14:57:17 -04:00
William Falcon 46886f0c3c added auto port find 2019-07-24 14:57:09 -04:00
William Falcon 9a3f373d16 added auto port find 2019-07-24 14:56:35 -04:00
William Falcon 8651173920 added auto port find 2019-07-24 14:55:26 -04:00
William Falcon e52190e22b added auto port find 2019-07-24 14:55:00 -04:00
William Falcon 0c239da17c added auto port find 2019-07-24 14:54:20 -04:00
William Falcon d0343604b3 added auto port find 2019-07-24 14:53:08 -04:00
William Falcon 4b2096d2c6 added auto port find 2019-07-24 14:52:19 -04:00
William Falcon 01c0d9a2d4 added auto port find 2019-07-24 14:48:56 -04:00
William Falcon 34ddb0ec98 added auto port find 2019-07-24 14:45:47 -04:00
William Falcon 5439dc0844 auto port kill before starting ddp 2019-07-24 14:38:09 -04:00
William Falcon 446a44b085 auto port kill before starting ddp 2019-07-24 14:36:47 -04:00
William Falcon 8f06118154 auto port kill before starting ddp 2019-07-24 14:36:29 -04:00
William Falcon 1ae91aac32 moved port name 2019-07-24 14:30:31 -04:00
William Falcon b20a122e9c fixed amp bug 2019-07-24 14:23:52 -04:00
William Falcon 9e187574de fixed amp bug 2019-07-24 14:17:36 -04:00
William Falcon 5fe833ae01 fixed amp bug 2019-07-24 14:16:05 -04:00
William Falcon ca1835e063 fixed amp bug 2019-07-24 14:14:36 -04:00
William Falcon 4d559d9e3b fixed amp bug 2019-07-24 14:12:41 -04:00
William Falcon 1b273a32ee fixed amp bug 2019-07-24 14:11:05 -04:00
William Falcon dd4f8899c8 refactored model tests 2019-07-24 14:06:35 -04:00
William Falcon 42b86a160d refactored model tests 2019-07-24 14:04:17 -04:00
William Falcon d004fc5725 refactored model tests 2019-07-24 14:00:29 -04:00
William Falcon 6169d22813 refactored model tests 2019-07-24 13:59:51 -04:00
William Falcon c26d200c41 refactored model tests 2019-07-24 13:57:34 -04:00
William Falcon ecb68b52f8 refactored model tests 2019-07-24 13:56:49 -04:00
William Falcon ef843d5f96 refactored model tests 2019-07-24 13:56:21 -04:00
William Falcon cf7da86c7c refactored model tests 2019-07-24 13:55:20 -04:00
William Falcon 0e9e07835c refactored model tests 2019-07-24 13:53:34 -04:00
William Falcon a729cfc9cc refactored model tests 2019-07-24 13:51:54 -04:00
William Falcon 3521051877 refactored model tests 2019-07-24 13:51:12 -04:00
William Falcon 53f1f18442 refactored model tests 2019-07-24 13:50:02 -04:00
William Falcon 7d1e1eb7f9 refactored model tests 2019-07-24 13:49:28 -04:00
William Falcon 4e6c7f80e5 refactored model tests 2019-07-24 13:47:37 -04:00
William Falcon aba7006fc2 refactored model tests 2019-07-24 13:46:32 -04:00
William Falcon 3d31219c85 refactored model tests 2019-07-24 13:45:22 -04:00
William Falcon 8a43f4307e refactored model tests 2019-07-24 13:42:42 -04:00
William Falcon b90841dc3d refactored model tests 2019-07-24 13:41:28 -04:00
William Falcon 24ceafa05c refactored model tests 2019-07-24 12:14:26 -04:00
William Falcon c7ad04be57 refactored model tests 2019-07-24 12:13:28 -04:00
William Falcon e5f73304b3 refactored model tests 2019-07-24 12:04:48 -04:00
William Falcon de95179556 refactored model tests 2019-07-24 12:04:11 -04:00
William Falcon f50026c21f refactored model tests 2019-07-24 12:03:39 -04:00
William Falcon 078cad768b fixed multi-gpu tests 2019-07-24 12:00:40 -04:00
William Falcon 98f6afd99a added test for model loading and predicting 2019-07-24 11:56:25 -04:00
William Falcon 8781d8aeab added test for model loading and predicting 2019-07-24 11:56:16 -04:00
William Falcon d3651ba15c added test for model loading and predicting 2019-07-24 11:55:22 -04:00
William Falcon aa90040387 added test for model loading and predicting 2019-07-24 11:54:08 -04:00
William Falcon 85eaa28872 added test for model loading and predicting 2019-07-24 11:51:38 -04:00
William Falcon 926fa206ff added safeguards for callbacks in loading saving 2019-07-24 11:45:59 -04:00
William Falcon aac5ba00ef added safeguards for callbacks in loading saving 2019-07-24 11:42:47 -04:00
William Falcon 0705e3e858 added safeguards for callbacks in loading saving 2019-07-24 11:42:38 -04:00
William Falcon cd931c8220 added safeguards for callbacks in loading saving 2019-07-24 11:40:45 -04:00
William Falcon 245ef862f8 added safeguards for callbacks in loading saving 2019-07-24 11:38:16 -04:00
William Falcon 3fc8166f51 added safeguards for callbacks in loading saving 2019-07-24 11:35:55 -04:00
William Falcon 2e30dd94bc added safeguards for callbacks in loading saving 2019-07-24 11:35:46 -04:00
William Falcon 55a33edd0a added safeguards for callbacks in loading saving 2019-07-24 11:34:56 -04:00
William Falcon 98c112598e added safeguards for callbacks in loading saving 2019-07-24 11:31:13 -04:00
William Falcon 8a3abec83a added safeguards for callbacks in loading saving 2019-07-24 11:30:14 -04:00
William Falcon 8fd7a6001b added safeguards for callbacks in loading saving 2019-07-24 11:14:19 -04:00
William Falcon a4b8aa0a41 removed dummy d 2019-07-24 11:10:22 -04:00
William Falcon 480dcb0213 removed dummy d 2019-07-24 11:09:50 -04:00
William Falcon 5606fd86df removed dummy d 2019-07-24 11:00:36 -04:00
William Falcon 8e131f9d79 removed dummy d 2019-07-24 10:59:15 -04:00
William Falcon 88f064d276 removed dummy d 2019-07-24 10:57:46 -04:00
William Falcon eb4b3a5752 removed dummy d 2019-07-24 10:55:56 -04:00
William Falcon b684fdf502 removed dummy d 2019-07-24 10:55:17 -04:00
William Falcon e4313b0b3d removed dummy d 2019-07-24 10:52:24 -04:00
William Falcon 853232b694 removed dummy d 2019-07-24 10:51:35 -04:00
William Falcon b8cc9b2dba removed dummy d 2019-07-24 10:51:07 -04:00
William Falcon caa5cf2cee removed dummy d 2019-07-24 10:50:29 -04:00
William Falcon f41fdc1ad8 added debugging util 2019-07-24 10:47:49 -04:00
William Falcon 0009aa2bcd added debugging util 2019-07-24 10:44:35 -04:00
William Falcon 938fd58009 added debugging util 2019-07-24 10:42:57 -04:00
William Falcon 60dae4d501 added debugging util 2019-07-24 10:42:01 -04:00
William Falcon d7edaa867f added debugging util 2019-07-24 10:39:59 -04:00
William Falcon b3ed4abe0f added debugging util 2019-07-24 10:38:45 -04:00
William Falcon 5b9a59d486 added debugging util 2019-07-24 10:38:22 -04:00
William Falcon b41f49dbef added debugging util 2019-07-24 10:34:21 -04:00
William Falcon 96ca1c1b39 added debugging util 2019-07-24 10:33:03 -04:00
William Falcon 1fd6158cea added debugging util 2019-07-24 10:32:21 -04:00
William Falcon 57a99e2aa5 updated test docs 2019-07-24 10:30:41 -04:00
William Falcon 490da9f7d3 updated test docs 2019-07-24 10:28:44 -04:00
William Falcon da19e0f7bc updated test docs 2019-07-24 10:24:15 -04:00
William Falcon f478fd9425 updated test docs 2019-07-24 10:19:42 -04:00
William Falcon 73c104c80a updated test docs 2019-07-24 10:17:08 -04:00
William Falcon cfbf305c9c updated test docs 2019-07-24 10:09:47 -04:00
William Falcon db95187b6b updated reqs 2019-07-24 09:44:36 -04:00
William Falcon 6479f493ed updated reqs 2019-07-24 09:39:43 -04:00
William Falcon 1793d40b95 updated reqs 2019-07-24 09:33:41 -04:00
William Falcon a8a8ccb499 updated reqs 2019-07-24 09:32:51 -04:00
William Falcon d77914e466 updated reqs 2019-07-24 09:29:46 -04:00
William Falcon 0cf9fa1a60 updated reqs 2019-07-24 09:24:41 -04:00
William Falcon 8e9737c194 updated reqs 2019-07-24 09:23:30 -04:00
William Falcon 297174eb63 updated reqs 2019-07-24 09:18:37 -04:00
William Falcon 76aeab7c93 updated reqs 2019-07-24 09:17:10 -04:00
William Falcon 8d44ebbb38 updated reqs 2019-07-24 09:15:26 -04:00
William Falcon e5c92e75ec updated reqs 2019-07-24 09:13:02 -04:00
William Falcon c689034650 updated reqs 2019-07-24 09:12:37 -04:00
William Falcon 81cd8037db updated reqs 2019-07-24 09:06:26 -04:00
William Falcon 8bbd65c95d added test docs 2019-07-24 09:04:36 -04:00
William Falcon b776fce2e7 added test docs 2019-07-24 08:56:22 -04:00
William Falcon e62973dfd3 added min accuracy to models test 2019-07-24 08:53:59 -04:00
William Falcon 5f810275c9 added min accuracy to models test 2019-07-24 08:53:00 -04:00
William Falcon 6ad542e2b6 added gpu check for each gpu test 2019-07-24 08:44:00 -04:00
William Falcon b59866f855 added cpu, gpu tests 2019-07-24 08:31:57 -04:00
William Falcon 5875fadc67 added cpu model test 2019-07-24 07:26:18 -04:00
William Falcon 1eda58fa93 adding tests 2019-07-24 07:19:50 -04:00
William Falcon 0527a4214b release v0.3.4.1 2019-07-23 13:31:47 -04:00
William Falcon ed66d65a70 fixed dp + amp bug 2019-07-23 13:30:07 -04:00
William Falcon 37349ee099 find_unused_parameters=True 2019-07-22 07:30:23 -04:00
William Falcon 5ed5e657e1 release v0.3.4 2019-07-21 20:06:24 -04:00
William Falcon 7da133d91d fixed ddp crash 2019-07-21 20:06:03 -04:00
William Falcon 3f76152470 added on_after_backward 2019-07-21 18:23:48 -04:00
William Falcon d98b9f2f93 release v0.3.3 2019-07-21 18:16:12 -04:00
William Falcon f6416f737d added grad hook 2019-07-21 18:15:58 -04:00
William Falcon 3888825333 release v0.3.2 2019-07-21 12:21:21 -04:00
William Falcon 0479784e7b added analysis notebook 2019-07-21 12:20:01 -04:00
William Falcon 7e053fc731 added analysis notebook 2019-07-21 12:18:46 -04:00
William Falcon 7ac344e43a updated docs 2019-07-21 08:35:29 -04:00
William Falcon f6b98fe74f updated docs 2019-07-21 08:33:53 -04:00
William Falcon 25f5491ac7 updated docs 2019-07-21 08:32:17 -04:00
William Falcon df77f5042b updated docs 2019-07-21 08:30:17 -04:00
William Falcon d273271b4b updated docs 2019-07-21 08:29:12 -04:00
William Falcon babaa088d7 release v0.3.1 2019-07-21 08:20:21 -04:00
William Falcon 8217ebe029 updated auto ddp for > 1 node 2019-07-21 08:20:06 -04:00
William Falcon 9311812829 updated docs 2019-07-21 08:17:12 -04:00
William Falcon 2357815640 release v0.3 2019-07-21 08:08:21 -04:00
William Falcon ab87244884 release v0.2.6 2019-07-20 09:39:00 -04:00
William Falcon 2aa0b3be5c removed logging 2019-07-20 09:31:10 -04:00
William Falcon 0fdf290201 removed logging 2019-07-20 09:22:47 -04:00
William Falcon 1a39f703ad removed logging 2019-07-20 09:22:04 -04:00
William Falcon 955e9ea6d5 removed logging 2019-07-20 09:18:45 -04:00
William Falcon 10e031a843 removed logging 2019-07-20 09:17:20 -04:00
William Falcon 229d168c20 removed logging 2019-07-20 09:15:09 -04:00
William Falcon 468bd141f4 added slurm managed flag catch for non-slurm peeps 2019-07-20 09:08:24 -04:00
William Falcon 00678c6053 added slurm managed flag catch for non-slurm peeps 2019-07-20 08:53:36 -04:00
William Falcon bbb5001aac added slurm managed flag catch for non-slurm peeps 2019-07-20 08:53:24 -04:00
William Falcon a514674358 added slurm managed flag catch for non-slurm peeps 2019-07-20 08:38:17 -04:00
William Falcon 9757841e67 release v0.2.5.2 2019-07-18 17:59:39 -04:00
William Falcon 0ac7a8590b added slurm managed flag catch for non-slurm peeps 2019-07-18 17:59:16 -04:00
William Falcon 6e12431e6b added slurm managed flag catch for non-slurm peeps 2019-07-18 17:58:38 -04:00
William Falcon c2e2298586 release v0.2.5.1 2019-07-18 17:14:34 -04:00
William Falcon 319feb7da5 removed printing. added auto process gen if slurm tasks do not match 2019-07-18 17:13:57 -04:00
William Falcon 5195124d4e added slurm no process warning 2019-07-18 17:06:56 -04:00
William Falcon 4e67983f23 added slurm no process warning 2019-07-18 17:05:09 -04:00
William Falcon c02b6c4c88 added slurm no process warning 2019-07-18 17:03:27 -04:00
William Falcon ad44d9168b added slurm no process warning 2019-07-18 16:47:46 -04:00
William Falcon 53a1a6d462 removed print lines 2019-07-18 16:37:48 -04:00
William Falcon 59d60eaf18 testing single process ddp 2019-07-18 15:06:20 -04:00
William Falcon 112be99b19 testing single process ddp 2019-07-18 14:57:56 -04:00
William Falcon 0e67773d2e testing single process ddp 2019-07-18 14:53:01 -04:00
William Falcon 394cdeeb8b added epoch flag back 2019-07-18 13:32:36 -04:00
William Falcon d0a8292e02 release v0.2.5 2019-07-18 12:13:00 -04:00
William Falcon d7409afed9 added arg docs 2019-07-18 12:11:59 -04:00
William Falcon f01cb63234 added arg docs 2019-07-18 12:10:07 -04:00
William Falcon 8be7480f31 added arg docs 2019-07-18 12:09:25 -04:00
William Falcon 751bc7c695 added arg docs 2019-07-18 12:08:47 -04:00
William Falcon 3be26dbb95 added arg docs 2019-07-18 12:08:17 -04:00
William Falcon 2ca0864ce8 added arg docs 2019-07-18 12:07:11 -04:00
William Falcon b1041220ac added arg docs 2019-07-18 12:05:52 -04:00
William Falcon da842c0cd6 added arg docs 2019-07-18 12:04:45 -04:00
William Falcon c4971e8432 added arg docs 2019-07-18 12:04:19 -04:00
William Falcon e81dbce38c set dp as default backend 2019-07-18 11:59:14 -04:00
William Falcon 0d992689d5 set dp as default backend 2019-07-18 11:58:27 -04:00
William Falcon 4085b3fa69 set dp as default backend 2019-07-18 11:57:39 -04:00
William Falcon b684bb55c5 set dp as default backend 2019-07-18 11:56:48 -04:00
William Falcon f98f88ff08 set dp as default backend 2019-07-18 11:51:43 -04:00
William Falcon f0955df4f0 set dp as default backend 2019-07-18 11:50:23 -04:00
William Falcon 7744c7117d set dp as default backend 2019-07-18 11:49:42 -04:00
William Falcon 22f4d6e26e set dp as default backend 2019-07-18 11:49:28 -04:00
William Falcon d49a83dec0 set dp as default backend 2019-07-18 11:48:16 -04:00
William Falcon 6d1d5ef68e set dp as default backend 2019-07-18 11:45:55 -04:00
William Falcon 3a1525222d set dp as default backend 2019-07-18 11:42:47 -04:00
William Falcon f650253cae set dp as default backend 2019-07-18 11:40:10 -04:00
William Falcon c67c84b443 set dp as default backend 2019-07-18 11:40:00 -04:00
William Falcon 4db32984c6 set dp as default backend 2019-07-18 11:39:13 -04:00
William Falcon 81d39786d9 set dp as default backend 2019-07-18 11:39:06 -04:00
William Falcon 63de076765 set dp as default backend 2019-07-18 11:36:48 -04:00
William Falcon 256ca62a3c set dp as default backend 2019-07-18 11:36:31 -04:00
William Falcon 39d04eb795 set dp as default backend 2019-07-18 11:35:59 -04:00
William Falcon e02857fcce set dp as default backend 2019-07-18 11:33:51 -04:00
William Falcon c163caf8cb set dp as default backend 2019-07-18 11:31:45 -04:00
William Falcon 2096a0aa84 set dp as default backend 2019-07-18 11:29:38 -04:00
William Falcon c253f96c53 set dp as default backend 2019-07-18 11:29:21 -04:00
William Falcon 551daca047 set dp as default backend 2019-07-18 11:25:02 -04:00
William Falcon ded0abead7 set dp as default backend 2019-07-18 11:21:35 -04:00
William Falcon e86b191691 set dp as default backend 2019-07-18 11:20:11 -04:00
William Falcon 3321e8c541 set dp as default backend 2019-07-18 11:18:19 -04:00
William Falcon bc3a805202 set dp as default backend 2019-07-18 11:16:16 -04:00
William Falcon 162b9f4f27 set dp as default backend 2019-07-18 11:15:21 -04:00
William Falcon e5bc3ea5b4 added training router 2019-07-18 11:09:37 -04:00
William Falcon baa139f97a added training router 2019-07-18 11:09:00 -04:00
William Falcon 470f3e6d29 added training router 2019-07-18 11:08:48 -04:00
William Falcon c12a0b57da added dp and ddp flag 2019-07-18 11:03:16 -04:00
William Falcon e7ecfa15f8 added option and flag 2019-07-18 10:56:45 -04:00
William Falcon 9051eb0039 updated docs 2019-07-17 15:56:55 -04:00
William Falcon bb8dbfca09 release v0.2.4.1 2019-07-17 10:04:14 -04:00
William Falcon 0240c70780 updated required deps 2019-07-17 10:03:58 -04:00
William Falcon a41abad5b2 Update trainer.py 2019-07-16 17:02:21 -04:00
William Falcon a83588b14e Update trainer.py 2019-07-16 13:12:56 -04:00
William Falcon 80192752b7 Merge pull request #13 from cinjon/on_tng_metrics
add a hook for on_tng_metrics so that users get access to the grad_no…
2019-07-16 12:59:16 -04:00
Cinjon Resnick fbd3873a0f add a hook for on_tng_metrics so that users get access to the grad_norm and mem_map dicts. 2019-07-16 12:51:48 -04:00
William Falcon 28cfddbe65 accept dist sampler classes 2019-07-16 12:44:58 -04:00
William Falcon b4bdb283ce release v0.2.4 2019-07-16 10:05:14 -04:00
William Falcon 967e57f071 early stop starts counting once min epochs met 2019-07-16 10:00:03 -04:00
William Falcon d12f6b7dd8 added summary flag 2019-07-15 21:11:29 -04:00
William Falcon 182c025c88 removed validation call 2019-07-15 20:48:46 -04:00
William Falcon 58e6199ce8 removed validation call 2019-07-15 14:56:56 -04:00
William Falcon 6a33f0d483 made early stop checkpoint optional 2019-07-15 14:54:38 -04:00
William Falcon dd230a93e8 made early stop checkpoint optional 2019-07-15 14:53:37 -04:00
William Falcon 3aa9cfc18e made checkpoint callback optional 2019-07-15 13:18:56 -04:00
William Falcon e57f461323 made checkpoint callback optional 2019-07-15 13:17:38 -04:00
William Falcon ab00514ef6 fixed metrics request not forced anymore 2019-07-15 13:03:08 -04:00
William Falcon 1dd58b4687 Merge branch 'master' of https://github.com/williamFalcon/pytorch-lightning 2019-07-15 13:01:17 -04:00
William Falcon b4b8a3dfde fixed none bug 2019-07-15 13:01:08 -04:00
William Falcon d8782c7b90 Update README.md 2019-07-15 09:21:30 -04:00
William Falcon d5878e9a72 release v0.2.3 2019-07-14 18:15:15 -04:00
William Falcon ad24bef1c9 removed print statements 2019-07-14 18:12:41 -04:00
William Falcon 50246a5066 working on single gpu init speed 2019-07-14 17:33:48 -04:00
William Falcon 21914cb1c1 working on single gpu init speed 2019-07-14 17:15:20 -04:00
William Falcon 904935cf98 working on single gpu init speed 2019-07-14 17:11:52 -04:00
William Falcon 468e75c180 working on single gpu init speed 2019-07-14 17:10:13 -04:00
William Falcon 849f52b7a6 modified single gpu init 2019-07-14 17:01:18 -04:00
William Falcon e520297781 modified single gpu init 2019-07-14 16:57:15 -04:00
William Falcon cefc27112d ddp flag change 2019-07-13 22:28:08 -04:00
William Falcon 6876f60098 merge 2019-07-13 22:21:17 -04:00
William Falcon fc1653e337 Merge branch 'nccl' of https://github.com/williamFalcon/pytorch-lightning into nccl 2019-07-13 22:19:41 -04:00
William Falcon e9f5913dac enabling gpu size = 1 to run without data parallel 2019-07-13 22:16:10 -04:00
William Falcon 7da82c2560 added fallback local init 2019-07-13 22:16:10 -04:00
William Falcon a2639c6894 added fallback local init 2019-07-13 22:16:10 -04:00
William Falcon eb05fa316f added fallback local init 2019-07-13 22:16:10 -04:00
William Falcon 6d55adb0d8 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon cff0500a63 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon f3ca184fb6 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 3239c9fdf8 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 7e37f68a5b fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 960937ebe9 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon a87784b4c5 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 5812efcf24 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon e82014ec6c fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon dc87a4fc91 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 4f5eef2e78 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 6c02afefca fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 4696e12641 fixed nccl init 2019-07-13 22:16:10 -04:00
William Falcon 7c688fbf2e enabling gpu size = 1 to run without data parallel 2019-07-13 22:09:17 -04:00
William Falcon 9ccfc7bd33 added fallback local init 2019-07-13 22:03:36 -04:00
William Falcon 52a98d76d8 added fallback local init 2019-07-13 10:16:50 -04:00
William Falcon 8b0cda84e7 added fallback local init 2019-07-13 10:13:52 -04:00
William Falcon 9f41a9e8b7 fixed nccl init 2019-07-12 16:35:20 -04:00
William Falcon b7baa96186 fixed nccl init 2019-07-12 16:29:44 -04:00
William Falcon faa2d4fa8b fixed nccl init 2019-07-12 16:23:20 -04:00
William Falcon 4f5da45fae fixed nccl init 2019-07-12 16:17:50 -04:00
William Falcon 7e54ad3f7c fixed nccl init 2019-07-12 16:16:46 -04:00
William Falcon 3bf366bcd8 fixed nccl init 2019-07-12 16:08:23 -04:00
William Falcon 6219f24a03 fixed nccl init 2019-07-12 16:07:57 -04:00
William Falcon 0bd81db538 fixed nccl init 2019-07-12 16:05:46 -04:00
William Falcon c84700814d fixed nccl init 2019-07-12 16:03:17 -04:00
William Falcon c244599ae8 fixed nccl init 2019-07-12 15:59:33 -04:00
William Falcon d99b121379 fixed nccl init 2019-07-12 15:59:12 -04:00
William Falcon 91b869d043 fixed nccl init 2019-07-12 15:55:28 -04:00
William Falcon 08e1ab64b5 fixed nccl init 2019-07-12 15:53:45 -04:00
William Falcon c1b21fb1e4 Merge pull request #11 from cinjon/modulefix
trainer: module fix.
2019-07-12 15:28:48 -04:00
William Falcon 8451bb7745 fixed nccl init 2019-07-12 15:25:34 -04:00
William Falcon 1a1771cfd8 fixed nccl init 2019-07-12 15:24:42 -04:00
William Falcon 1952e9be49 fixed nccl init 2019-07-12 15:11:32 -04:00
William Falcon 19391b1df1 fixed nccl init 2019-07-12 15:04:20 -04:00
William Falcon 369174c4d3 fixed nccl init 2019-07-12 14:36:00 -04:00
William Falcon 5ba0a2ed48 fixed nccl init 2019-07-12 14:28:49 -04:00
William Falcon 88061b2284 Merge branch 'master' of https://github.com/williamFalcon/pytorch-lightning 2019-07-12 13:42:53 -04:00
William Falcon ba38037917 fixed nccl init 2019-07-12 13:39:58 -04:00
William Falcon a7bb731a1d testing env init 2019-07-12 13:19:10 -04:00
William Falcon 58531888e0 testing env init 2019-07-12 13:17:33 -04:00
William Falcon 56ac885f03 Merge pull request #12 from cinjon/commafix
root_module: fix comma splits.
2019-07-12 13:13:57 -04:00
William Falcon 5e033fd97a testing env init 2019-07-12 13:11:08 -04:00
William Falcon 5d14b97aa6 testing file init 2019-07-12 12:57:54 -04:00
William Falcon 0b0addbcbe testing file init 2019-07-12 12:56:44 -04:00
Cinjon Resnick 098d518398 trainer: module fix. 2019-07-12 12:54:35 -04:00
William Falcon ba111e681e testing file init 2019-07-12 12:41:54 -04:00
Cinjon Resnick 3de053c903 root_module: fix comma splits. 2019-07-12 12:38:39 -04:00
William Falcon ac1bd57b8b testing file init 2019-07-12 12:33:54 -04:00
William Falcon 3f0fab9160 reset master 2019-07-12 12:32:36 -04:00
William Falcon 24c13aadc0 testing file init 2019-07-12 12:06:19 -04:00
William Falcon 885bad3555 testing master_Addr flag 2019-07-12 11:55:14 -04:00
William Falcon 6dde1d7ae3 testing master_Addr flag 2019-07-12 11:43:05 -04:00
William Falcon c223960edb testing master_Addr flag 2019-07-12 11:30:57 -04:00
William Falcon 32646cf2ee release v0.2.2 2019-07-11 16:19:11 -04:00
William Falcon 415ee4903b simplify trainer output 2019-07-11 15:23:33 -04:00
William Falcon a21dc5a187 simplify trainer output 2019-07-11 15:15:22 -04:00
William Falcon 0929908229 simplify trainer output 2019-07-11 15:08:45 -04:00
William Falcon cc12a1c8fa added clarifying comments 2019-07-11 14:58:47 -04:00
William Falcon 91b3a0aac6 added clarifying comments 2019-07-11 14:57:26 -04:00
William Falcon ed35f4e076 updated amp use 2019-07-11 14:35:41 -04:00
William Falcon c4781cb415 Merge branch 'master' of https://github.com/williamFalcon/pytorch-lightning 2019-07-11 14:18:07 -04:00
William Falcon 730a06640b updated amp use 2019-07-11 14:17:43 -04:00
William Falcon 6eb25edb31 release v0.21 2019-07-09 19:56:11 -04:00
46 changed files with 2373 additions and 814 deletions
+2 -1
View File
@@ -9,6 +9,7 @@ model_weights/
app/models/ app/models/
pip-wheel-metadata/ pip-wheel-metadata/
test_tube_exp/ test_tube_exp/
tests/tests_tt_dir/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
@@ -119,4 +120,4 @@ ENV/
.mypy_cache/ .mypy_cache/
# data # data
mnist/ mnist/
+19
View File
@@ -0,0 +1,19 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation with MkDocs
mkdocs:
configuration: mkdocs.yml
# Optionally build your docs in additional formats such as PDF and ePub
formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.7
install:
- requirements: docs/doc_requirements.txt
+16
View File
@@ -0,0 +1,16 @@
language: python
python:
- "3.7"
# command to install dependencies
cache: pip
install:
- pip install -e .
- pip install -r requirements.txt
- pip install -U numpy
# keep build from timing out
dist: xenial
# command to run tests
script:
- py.test # or py.test for Python versions 3.5 and below
+98 -23
View File
@@ -9,31 +9,103 @@
<p align="center"> <p align="center">
The Keras for ML researchers using PyTorch. More control. Less boilerplate. The Keras for ML researchers using PyTorch. More control. Less boilerplate.
</p> </p>
<p align="center"> <p align="center">
<a href="https://badge.fury.io/py/pytorch-lightning"><img src="https://badge.fury.io/py/pytorch-lightning.svg" alt="PyPI version" height="18"></a> <a href="https://badge.fury.io/py/pytorch-lightning"><img src="https://badge.fury.io/py/pytorch-lightning.svg" alt="PyPI version" height="18"></a>
<!-- <a href="https://travis-ci.org/williamFalcon/test-tube"><img src="https://travis-ci.org/williamFalcon/pytorch-lightning.svg?branch=master"></a> --> <a href="https://pepy.tech/project/pytorch-lightning"><img src="https://pepy.tech/badge/pytorch-lightning" alt="PyPI version" height="18"></a>
<a href="https://github.com/williamFalcon/pytorch-lightning/tree/master/tests"><img src="https://github.com/williamFalcon/pytorch-lightning/blob/master/coverage.svg"></a>
<a href="https://travis-ci.org/williamFalcon/pytorch-lightning"><img src="https://travis-ci.org/williamFalcon/pytorch-lightning.svg?branch=master"></a>
<a href="https://williamfalcon.github.io/pytorch-lightning/"><img src="https://readthedocs.org/projects/pytorch-lightning/badge/?version=latest"></a>
<a href="https://github.com/williamFalcon/pytorch-lightning/blob/master/COPYING"><img src="https://img.shields.io/badge/License-MIT-yellow.svg"></a> <a href="https://github.com/williamFalcon/pytorch-lightning/blob/master/COPYING"><img src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
</p> </p>
```bash ```bash
pip install pytorch-lightning pip install pytorch-lightning
``` ```
## Docs ## Docs
**[View the docs here](https://williamfalcon.github.io/pytorch-lightning/)** **[View the docs here](https://williamfalcon.github.io/pytorch-lightning/)**
## What is it? ## What is it?
Keras and fast.ai are too abstract for researchers. Lightning abstracts the full training loop but gives you control in the critical points. Lightning defers training and validation loop logic to you. It guarantees correct, modern best practices for the core training logic.
## Why do I want to use lightning? ## Why do I want to use lightning?
Because you don't want to define a training loop, validation loop, gradient clipping, checkpointing, loading, When starting a new project the last thing you want to do is recode a training loop, model loading/saving, distributed training, when to validate, etc... You're likely to spend a long time ironing out all the bugs without even getting to the core of your research.
gpu training, etc... every time you start a project. Let lightning handle all of that for you! Just define your
data and what happens in the training, testing and validation loop and lightning will do the rest. With lightning, you guarantee those parts of your code work so you can focus on what the meat of the research: Data and training, validation loop logic. Don't worry about multiple gpus or speeding up your code, lightning will do that for you!
## How do I do use it?
To use lightning do 2 things: To use lightning do 2 things:
1. [Define a Trainer](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/trainer_cpu_template.py). 1. [Define a LightningModel](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/)
2. [Define a LightningModel](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/lightning_module_template.py). ```python
import pytorch_lightning as ptl
import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
class CoolModel(ptl.LightningModule):
def __init(self):
super(CoolModel, self).__init__()
# not the best model...
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x))
def my_loss(self, y_hat, y):
return F.cross_entropy(y_hat, y)
def training_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'tng_loss': self.my_loss(y_hat, y)}
def validation_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'val_loss': self.my_loss(y_hat, y)}
def validation_end(self, outputs):
avg_loss = torch.stack([x for x in outputs['val_loss']]).mean()
return avg_loss
def configure_optimizers(self):
return [torch.optim.Adam(self.parameters(), lr=0.02)]
@ptl.data_loader
def tng_dataloader(self):
return DataLoader(MNIST('path/to/save', train=True), batch_size=32)
@ptl.data_loader
def val_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
@ptl.data_loader
def test_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
```
2. Fit with a [trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
```python
from pytorch_lightning import Trainer
from test_tube import Experiment
model = CoolModel()
# fit on 32 gpus across 4 nodes
exp = Experiment(save_dir='some/dir')
trainer = Trainer(experiment=exp, nb_gpu_nodes=4, gpus=[0,1,2,3,4,5,6,7])
trainer.fit(model)
# see all experiment metrics here
# tensorboard --log_dir some/dir
```
## What does lightning control for me? ## What does lightning control for me?
Everything! Everything!
@@ -116,8 +188,8 @@ def validation_end(self, outputs):
return tqdm_dic return tqdm_dic
``` ```
## TensorboardX ## Tensorboard
Lightning is fully integrated with tensorboardX. Lightning is fully integrated with tensorboard.
<p align="center"> <p align="center">
<a href="https://williamfalcon.github.io/pytorch-lightning/"> <a href="https://williamfalcon.github.io/pytorch-lightning/">
@@ -148,7 +220,7 @@ And run tensorboard from that dir
tensorboard --logdir /some/path tensorboard --logdir /some/path
``` ```
## Lightning automatically automates all of the following ([each is also configurable](https://williamfalcon.github.io/pytorch-lightning/Trainer/)): ## Lightning automates all of the following ([each is also configurable](https://williamfalcon.github.io/pytorch-lightning/Trainer/)):
###### Checkpointing ###### Checkpointing
@@ -215,19 +287,22 @@ pip install pytorch-lightning
# clone lightning for the demo # clone lightning for the demo
git clone https://github.com/williamFalcon/pytorch-lightning.git git clone https://github.com/williamFalcon/pytorch-lightning.git
cd examples/new_project_templates/ cd pytorch_lightning/examples/new_project_templates/
# run demo (on cpu) # all of the following demos use the SAME model to show no modification needs to be made to your code
python trainer_gpu_cluster_template.py
# train on cpu
python single_cpu_template.py
# train on multiple-gpus
python single_gpu_node_template.py --gpus "0,1"
# train on 32 gpus on a cluster (run on a SLURM managed cluster)
python multi_node_cluster_template.py --nb_gpu_nodes 4 --gpus '0,1,2,3,4,5,6,7'
``` ```
Without changing the model AT ALL, you can run the model on a single gpu, over multiple gpus, or over multiple nodes. ## Bleeding edge
If you can't wait for the next release, install the most up to date code with:
```bash ```bash
# run a grid search on two gpus pip install git+https://github.com/williamFalcon/pytorch-lightning.git@master --upgrade
python fully_featured_trainer.py --gpus "0;1" ```
# run single model on multiple gpus
python fully_featured_trainer.py --gpus "0;1" --interactive
```
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<mask id="a">
<rect width="99" height="20" rx="3" fill="#fff"/>
</mask>
<g mask="url(#a)">
<path fill="#555" d="M0 0h63v20H0z"/>
<path fill="#4c1" d="M63 0h36v20H63z"/>
<path fill="url(#b)" d="M0 0h99v20H0z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
<text x="31.5" y="14">coverage</text>
<text x="80" y="15" fill="#010101" fill-opacity=".3">99%</text>
<text x="80" y="14">99%</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 901 B

+107 -70
View File
@@ -3,7 +3,7 @@
A lightning module is a strict superclass of nn.Module, it provides a standard interface for the trainer to interact with the model. A lightning module is a strict superclass of nn.Module, it provides a standard interface for the trainer to interact with the model.
The easiest thing to do is copy [this template](../../examples/new_project_templates/lightning_module_template.py) and modify accordingly. The easiest thing to do is copy [this template](../../pytorch_lightning/examples/new_project_templates/lightning_module_template.py) and modify accordingly.
Otherwise, to Define a Lightning Module, implement the following methods: Otherwise, to Define a Lightning Module, implement the following methods:
@@ -14,8 +14,6 @@ Otherwise, to Define a Lightning Module, implement the following methods:
- [validation_end](RequiredTrainerInterface.md#validation_end) - [validation_end](RequiredTrainerInterface.md#validation_end)
- [configure_optimizers](RequiredTrainerInterface.md#configure_optimizers) - [configure_optimizers](RequiredTrainerInterface.md#configure_optimizers)
- [get_save_dict](RequiredTrainerInterface.md#get_save_dict)
- [load_model_specific](RequiredTrainerInterface.md#load_model_specific)
- [tng_dataloader](RequiredTrainerInterface.md#tng_dataloader) - [tng_dataloader](RequiredTrainerInterface.md#tng_dataloader)
- [tng_dataloader](RequiredTrainerInterface.md#tng_dataloader) - [tng_dataloader](RequiredTrainerInterface.md#tng_dataloader)
@@ -23,9 +21,63 @@ Otherwise, to Define a Lightning Module, implement the following methods:
**Optional**: **Optional**:
- [on_save_checkpoint](RequiredTrainerInterface.md#on_save_checkpoint)
- [on_load_checkpoint](RequiredTrainerInterface.md#on_load_checkpoint)
- [update_tng_log_metrics](RequiredTrainerInterface.md#update_tng_log_metrics) - [update_tng_log_metrics](RequiredTrainerInterface.md#update_tng_log_metrics)
- [add_model_specific_args](RequiredTrainerInterface.md#add_model_specific_args) - [add_model_specific_args](RequiredTrainerInterface.md#add_model_specific_args)
---
**Minimal example**
```python
import pytorch_lightning as ptl
import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
class CoolModel(ptl.LightningModule):
def __init(self):
super(CoolModel, self).__init__()
# not the best model...
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x))
def my_loss(self, y_hat, y):
return F.cross_entropy(y_hat, y)
def training_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'tng_loss': self.my_loss(y_hat, y)}
def validation_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'val_loss': self.my_loss(y_hat, y)}
def validation_end(self, outputs):
avg_loss = torch.stack([x for x in outputs['val_loss']]).mean()
return avg_loss
def configure_optimizers(self):
return [torch.optim.Adam(self.parameters(), lr=0.02)]
@ptl.data_loader
def tng_dataloader(self):
return DataLoader(MNIST('path/to/save', train=True), batch_size=32)
@ptl.data_loader
def val_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
@ptl.data_loader
def test_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
```
--- ---
### training_step ### training_step
@@ -193,34 +245,35 @@ def configure_optimizers(self):
``` ```
--- ---
### get_save_dict ### on_save_checkpoint
``` {.python} ``` {.python}
def get_save_dict(self) def on_save_checkpoint(self, checkpoint)
``` ```
Called by lightning to checkpoint your model. Lightning saves current epoch, current batch nb, etc... Called by lightning to checkpoint your model. Lightning saves the training state (current epoch, global_step, etc)
All you have to return is what specifically about your lightning model you want to checkpoint. and also saves the model state_dict. If you want to save anything else, use this method to add your own
key-value pair.
##### Return ##### Return
Dictionary - No required keys. Most of the time as described in this example. Nothing
**Example** **Example**
``` {.python} ``` {.python}
def get_save_dict(self): def on_save_checkpoint(self, checkpoint):
# 99% of use cases this is all you need to return # 99% of use cases you don't need to implement this method
checkpoint = {'state_dict': self.state_dict()} checkpoint['something_cool_i_want_to_save'] = my_cool_pickable_object
return checkpoint
``` ```
--- ---
### load_model_specific ### on_load_checkpoint
``` {.python} ``` {.python}
def load_model_specific(self, checkpoint) def on_load_checkpoint(self, checkpoint)
``` ```
Called by lightning to restore your model. This is your chance to restore your model using the keys you added in get_save_dict. Called by lightning to restore your model. Lighting auto-restores global step, epoch, etc...
Lightning will automatically restore current epoch, batch nb, etc. It also restores the model state_dict.
If you saved something with **on_save_checkpoint** this is your chance to restore this.
##### Return ##### Return
Nothing Nothing
@@ -228,19 +281,19 @@ Nothing
**Example** **Example**
``` {.python} ``` {.python}
def load_model_specific(self, checkpoint): def on_load_checkpoint(self, checkpoint):
# you defined 'state_dict' in get_save_dict() # 99% of the time you don't need to implement this method
self.load_state_dict(checkpoint['state_dict']) self.something_cool_i_want_to_save = checkpoint['something_cool_i_want_to_save']
``` ```
--- ---
### tng_dataloader ### tng_dataloader
``` {.python} ``` {.python}
@property @ptl.data_loader
def tng_dataloader(self) def tng_dataloader(self)
``` ```
Called by lightning during training loop. Define it as a property. Called by lightning during training loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
##### Return ##### Return
Pytorch DataLoader Pytorch DataLoader
@@ -248,32 +301,26 @@ Pytorch DataLoader
**Example** **Example**
``` {.python} ``` {.python}
@property @ptl.data_loader
def tng_dataloader(self): def tng_dataloader(self):
if self._tng_dataloader is None: transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
try: dataset = MNIST(root='/path/to/mnist/', train=True, transform=transform, download=True)
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))]) loader = torch.utils.data.DataLoader(
dataset = MNIST(root='/path/to/mnist/', train=True, transform=transform, download=True) dataset=dataset,
loader = torch.utils.data.DataLoader( batch_size=self.hparams.batch_size,
dataset=dataset, shuffle=True
batch_size=self.hparams.batch_size, )
shuffle=True return loader
)
self._tng_dataloader = loader
except Exception as e:
raise e
return self._tng_dataloader
``` ```
--- ---
### val_dataloader ### val_dataloader
``` {.python} ``` {.python}
@property @ptl.data_loader
def tng_dataloader(self) def tng_dataloader(self)
``` ```
Called by lightning during validation loop. Define it as a property. Called by lightning during validation loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
##### Return ##### Return
Pytorch DataLoader Pytorch DataLoader
@@ -281,32 +328,27 @@ Pytorch DataLoader
**Example** **Example**
``` {.python} ``` {.python}
@property @ptl.data_loader
def val_dataloader(self): def val_dataloader(self):
if self._val_dataloader is None: transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
try: dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))]) loader = torch.utils.data.DataLoader(
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True) dataset=dataset,
loader = torch.utils.data.DataLoader( batch_size=self.hparams.batch_size,
dataset=dataset, shuffle=True
batch_size=self.hparams.batch_size, )
shuffle=True
) return loader
self._val_dataloader = loader
except Exception as e:
raise e
return self._val_dataloader
``` ```
--- ---
### test_dataloader ### test_dataloader
``` {.python} ``` {.python}
@property @ptl.data_loader
def test_dataloader(self) def test_dataloader(self)
``` ```
Called by lightning during test loop. Define it as a property. Called by lightning during test loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
##### Return ##### Return
Pytorch DataLoader Pytorch DataLoader
@@ -314,22 +356,17 @@ Pytorch DataLoader
**Example** **Example**
``` {.python} ``` {.python}
@property @ptl.data_loader
def test_dataloader(self): def test_dataloader(self):
if self._test_dataloader is None: transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
try: dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))]) loader = torch.utils.data.DataLoader(
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True) dataset=dataset,
loader = torch.utils.data.DataLoader( batch_size=self.hparams.batch_size,
dataset=dataset, shuffle=True
batch_size=self.hparams.batch_size, )
shuffle=True
) return loader
self._test_dataloader = loader
except Exception as e:
raise e
return self._test_dataloader
``` ```
--- ---
+2 -1
View File
@@ -21,7 +21,8 @@ pretrained_model = MyLightningModule.load_from_metrics(
map_location=None map_location=None
) )
# predict # predict
pretrained_model.eval()
pretrained_model.freeze() pretrained_model.freeze()
y_hat = pretrained_model(x) y_hat = pretrained_model(x)
``` ```
+78 -5
View File
@@ -3,6 +3,26 @@ Lightning makes multi-gpu training and 16 bit training trivial.
*Note:* *Note:*
None of the flags below require changing anything about your lightningModel definition. None of the flags below require changing anything about your lightningModel definition.
---
#### Choosing a backend
Lightning supports two backends. DataParallel and DistributedDataParallel. Both can be used for single-node multi-GPU training.
For multi-node training you must use DistributedDataParallel.
You can toggle between each mode by setting this flag.
``` {.python}
# DEFAULT uses DataParallel
trainer = Trainer(distributed_backend='dp')
# change to distributed data parallel
trainer = Trainer(distributed_backend='ddp')
```
If you request multiple nodes, the back-end will auto-switch to ddp.
We recommend you use DistributedDataparallel even for single-node multi-GPU training. It is MUCH faster than DP but *may*
have configuration issues depending on your cluster.
For a deeper understanding of what lightning is doing, feel free to read [this guide](https://medium.com/@_willfalcon/9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565).
--- ---
#### 16-bit mixed precision #### 16-bit mixed precision
16 bit precision can cut your memory footprint by half. If using volta architecture GPUs it can give a dramatic training speed-up as well. 16 bit precision can cut your memory footprint by half. If using volta architecture GPUs it can give a dramatic training speed-up as well.
@@ -37,16 +57,69 @@ Make sure you're on a GPU machine. You can set as many GPUs as you want.
In this setting, the model will run on all 8 GPUs at once using DataParallel under the hood. In this setting, the model will run on all 8 GPUs at once using DataParallel under the hood.
```python ```python
# set these flags # set these flags
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # lightning sets these flags for you automatically
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7" # no need to set yourself
# os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
# os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
# DEFAULT
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7]) # to use DataParallel (default)
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7], distributed_backend='dp')
# RECOMMENDED use DistributedDataParallel
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7], distributed_backend='ddp')
``` ```
--- ---
#### Multi-node #### Multi-node
COMING SOON. Multi-node training is easily done by specifying these flags.
```python
# train on 12*8 GPUs
trainer = Trainer(gpus=[0,1,2,3,4,5,6,7], nb_gpu_nodes=12)
```
In addition, make sure to set up your SLURM job correctly via the [SlurmClusterObject](https://williamfalcon.github.io/test-tube/hpc/SlurmCluster/). In particular, specify the number of tasks per node correctly.
```python
cluster = SlurmCluster(
hyperparam_optimizer=test_tube.HyperOptArgumentParser(),
log_path='/some/path/to/save',
)
# OPTIONAL FLAGS WHICH MAY BE CLUSTER DEPENDENT
# which interface your nodes use for communication
cluster.add_command('export NCCL_SOCKET_IFNAME=^docker0,lo')
# see output of the NCCL connection process
# NCCL is how the nodes talk to each other
cluster.add_command('export NCCL_DEBUG=INFO')
# setting a master port here is a good idea.
cluster.add_command(f'export MASTER_PORT={PORT}')
# good to load the latest NCCL version
cluster.load_modules(['NCCL/2.4.7-1-cuda.10.0'])
# configure cluster
cluster.per_experiment_nb_nodes = 12
cluster.per_experiment_nb_gpus = 8
cluster.add_slurm_cmd(cmd='ntasks-per-node', value=8, comment='1 task per gpu')
```
Finally, make sure to add a distributed sampler to your dataset. The distributed sampler copies a
portion of your dataset onto each GPU. (World_size = gpus_per_node * nb_nodes).
```python
# ie: this:
dataset = myDataset()
dataloader = Dataloader(dataset)
# becomes:
dataset = myDataset()
dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset)
dataloader = Dataloader(dataset, sampler=dist_sampler)
```
--- ---
#### Self-balancing architecture #### Self-balancing architecture
+1 -1
View File
@@ -19,7 +19,7 @@ Cut the learning rate by 10 at every epoch listed in this list.
trainer = Trainer(lr_scheduler_milestones=None) trainer = Trainer(lr_scheduler_milestones=None)
# cut LR by 10 at 100, 200, and 300 epochs # cut LR by 10 at 100, 200, and 300 epochs
trainer = Trainer(lr_scheduler_milestones=[100, 200, 300]) trainer = Trainer(lr_scheduler_milestones='100, 200, 300')
``` ```
--- ---
+1
View File
@@ -0,0 +1 @@
mkdocs-material==4.4.0
+5 -4
View File
@@ -1,10 +1,11 @@
###### New project Quick Start ###### New project Quick Start
To start a new project define these two files. To start a new project define these two files.
1. [Define a LightningModule](/LightningModule/RequiredTrainerInterface/#template-model-definition) 1. [Define a LightningModule](/pytorch-lightning/LightningModule/RequiredTrainerInterface/)
2. Pick a trainer 2. [Define a trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
- [Basic CPU Trainer](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/trainer_cpu_template.py) - [Basic CPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/single_cpu_template.py)
- [GPU cluster Trainer](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/trainer_gpu_cluster_template.py) - [Multi-GPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/single_gpu_node_template.py)
- [GPU cluster Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/multi_node_cluster_template.py)
###### Docs shortcuts ###### Docs shortcuts
- [LightningModule](LightningModule/RequiredTrainerInterface/) - [LightningModule](LightningModule/RequiredTrainerInterface/)
@@ -1 +0,0 @@
from .lightning_module_template import LightningTemplateModel
+2 -1
View File
@@ -1,2 +1,3 @@
from .models import Trainer from .models import Trainer
from .root_module.root_module import LightningModule from .root_module.root_module import LightningModule
from .root_module.decorators import data_loader
+1
View File
@@ -0,0 +1 @@
from .new_project_templates.lightning_module_template import LightningTemplateModel
@@ -10,6 +10,7 @@ from torch import optim
from torch.utils.data import DataLoader from torch.utils.data import DataLoader
from torch.utils.data.distributed import DistributedSampler from torch.utils.data.distributed import DistributedSampler
import pytorch_lightning as ptl
from pytorch_lightning.root_module.root_module import LightningModule from pytorch_lightning.root_module.root_module import LightningModule
@@ -24,10 +25,14 @@ class LightningTemplateModel(LightningModule):
:param hparams: :param hparams:
""" """
# init superclass # init superclass
super(LightningTemplateModel, self).__init__(hparams) super(LightningTemplateModel, self).__init__()
self.hparams = hparams
self.batch_size = hparams.batch_size self.batch_size = hparams.batch_size
# if you specify an example input, the summary will show input/output for each layer
self.example_input_array = torch.rand(5, 28 * 28)
# build model # build model
self.__build_model() self.__build_model()
@@ -78,15 +83,21 @@ class LightningTemplateModel(LightningModule):
# forward pass # forward pass
x, y = data_batch x, y = data_batch
x = x.view(x.size(0), -1) x = x.view(x.size(0), -1)
y_hat = self.forward(x) y_hat = self.forward(x)
# calculate loss # calculate loss
loss_val = self.loss(y, y_hat) loss_val = self.loss(y, y_hat)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
output = OrderedDict({ output = OrderedDict({
'loss': loss_val, 'loss': loss_val
'tqdm_metrics': {}
}) })
# can also return just a scalar instead of a dict (return loss_val)
return output return output
def validation_step(self, data_batch, batch_i): def validation_step(self, data_batch, batch_i):
@@ -104,11 +115,22 @@ class LightningTemplateModel(LightningModule):
# acc # acc
labels_hat = torch.argmax(y_hat, dim=1) labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0) val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
if self.on_gpu:
val_acc = val_acc.cuda(loss_val.device.index)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
val_acc = val_acc.unsqueeze(0)
output = OrderedDict({ output = OrderedDict({
'val_loss': loss_val, 'val_loss': loss_val,
'val_acc': torch.tensor(val_acc), 'val_acc': val_acc,
}) })
# can also return just a scalar instead of a dict (return loss_val)
return output return output
def validation_end(self, outputs): def validation_end(self, outputs):
@@ -117,6 +139,10 @@ class LightningTemplateModel(LightningModule):
:param outputs: list of individual outputs of each validation step :param outputs: list of individual outputs of each validation step
:return: :return:
""" """
# if returned a scalar from validation_step, outputs is a list of tensor scalars
# we return just the average in this case (if we want)
# return torch.stack(outputs).mean()
val_loss_mean = 0 val_loss_mean = 0
val_acc_mean = 0 val_acc_mean = 0
for output in outputs: for output in outputs:
@@ -128,20 +154,6 @@ class LightningTemplateModel(LightningModule):
tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()} tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
return tqdm_dic return tqdm_dic
def update_tng_log_metrics(self, logs):
return logs
# ---------------------
# MODEL SAVING
# ---------------------
def get_save_dict(self):
checkpoint = {'state_dict': self.state_dict()}
return checkpoint
def load_model_specific(self, checkpoint):
self.load_state_dict(checkpoint['state_dict'])
pass
# --------------------- # ---------------------
# TRAINING SETUP # TRAINING SETUP
# --------------------- # ---------------------
@@ -179,38 +191,23 @@ class LightningTemplateModel(LightningModule):
return loader return loader
@property @ptl.data_loader
def tng_dataloader(self): def tng_dataloader(self):
if self._tng_dataloader is None: print('tng data loader called')
try: return self.__dataloader(train=True)
self._tng_dataloader = self.__dataloader(train=True)
except Exception as e:
print(e)
raise e
return self._tng_dataloader
@property @ptl.data_loader
def val_dataloader(self): def val_dataloader(self):
if self._val_dataloader is None: print('val data loader called')
try: return self.__dataloader(train=False)
self._val_dataloader = self.__dataloader(train=False)
except Exception as e:
print(e)
raise e
return self._val_dataloader
@property @ptl.data_loader
def test_dataloader(self): def test_dataloader(self):
if self._test_dataloader is None: print('test data loader called')
try: return self.__dataloader(train=False)
self._test_dataloader = self.__dataloader(train=False)
except Exception as e:
print(e)
raise e
return self._test_dataloader
@staticmethod @staticmethod
def add_model_specific_args(parent_parser, root_dir): def add_model_specific_args(parent_parser, root_dir): # pragma: no cover
""" """
Parameters you define here will be available to your model through self.hparams Parameters you define here will be available to your model through self.hparams
:param parent_parser: :param parent_parser:
@@ -0,0 +1,112 @@
"""
Runs a model on a single node across N-gpus.
"""
import os
import sys
import numpy as np
from time import sleep
import torch
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
from pytorch_lightning.models.trainer import Trainer
from pytorch_lightning.utils.arg_parse import add_default_args
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
SEED = 2334
torch.manual_seed(SEED)
np.random.seed(SEED)
from lightning_module_template import LightningTemplateModel
def main(hparams):
"""
Main training routine specific for this project
:param hparams:
:return:
"""
# ------------------------
# 1 INIT LIGHTNING MODEL
# ------------------------
print('loading model...')
model = LightningTemplateModel(hparams)
print('model built')
# ------------------------
# 2 INIT TEST TUBE EXP
# ------------------------
# init experiment
exp = Experiment(
name=hyperparams.experiment_name,
save_dir=hyperparams.test_tube_save_path,
autosave=False,
description='test demo'
)
exp.argparse(hparams)
exp.save()
# ------------------------
# 3 DEFINE CALLBACKS
# ------------------------
model_save_path = '{}/{}/{}'.format(hparams.model_save_path, exp.name, exp.version)
early_stop = EarlyStopping(
monitor='val_acc',
patience=3,
verbose=True,
mode='max'
)
checkpoint = ModelCheckpoint(
filepath=model_save_path,
save_best_only=True,
verbose=True,
monitor='val_loss',
mode='min'
)
# ------------------------
# 4 INIT TRAINER
# ------------------------
trainer = Trainer(
experiment=exp,
checkpoint_callback=checkpoint,
early_stop_callback=early_stop,
gpus=hparams.gpus,
)
# ------------------------
# 5 START TRAINING
# ------------------------
trainer.fit(model)
if __name__ == '__main__':
# dirs
root_dir = os.path.dirname(os.path.realpath(__file__))
demo_log_dir = os.path.join(root_dir, 'pt_lightning_demo_logs')
checkpoint_dir = os.path.join(demo_log_dir, 'model_weights')
test_tube_dir = os.path.join(demo_log_dir, 'test_tube_data')
# although we user hyperOptParser, we are using it only as argparse right now
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
# gpu args
parent_parser.add_argument('--gpus', type=str, default='-1', help='how many gpus to use in the node. -1 uses all the gpus on the node')
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
# allow model to overwrite or extend args
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
hyperparams = parser.parse_args()
# ---------------------
# RUN TRAINING
# ---------------------
# run on HPC cluster
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
main(hyperparams)
@@ -0,0 +1,112 @@
"""
Runs a model on a single node across N-gpus.
"""
import os
import sys
import numpy as np
from time import sleep
import torch
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
from pytorch_lightning.models.trainer import Trainer
from pytorch_lightning.utils.arg_parse import add_default_args
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
SEED = 2334
torch.manual_seed(SEED)
np.random.seed(SEED)
from lightning_module_template import LightningTemplateModel
def main(hparams):
"""
Main training routine specific for this project
:param hparams:
:return:
"""
# ------------------------
# 1 INIT LIGHTNING MODEL
# ------------------------
print('loading model...')
model = LightningTemplateModel(hparams)
print('model built')
# ------------------------
# 2 INIT TEST TUBE EXP
# ------------------------
# init experiment
exp = Experiment(
name=hyperparams.experiment_name,
save_dir=hyperparams.test_tube_save_path,
autosave=False,
description='test demo'
)
exp.argparse(hparams)
exp.save()
# ------------------------
# 3 DEFINE CALLBACKS
# ------------------------
model_save_path = '{}/{}/{}'.format(hparams.model_save_path, exp.name, exp.version)
early_stop = EarlyStopping(
monitor='val_acc',
patience=3,
verbose=True,
mode='max'
)
checkpoint = ModelCheckpoint(
filepath=model_save_path,
save_best_only=True,
verbose=True,
monitor='val_loss',
mode='min'
)
# ------------------------
# 4 INIT TRAINER
# ------------------------
trainer = Trainer(
experiment=exp,
checkpoint_callback=checkpoint,
early_stop_callback=early_stop,
gpus=hparams.gpus,
)
# ------------------------
# 5 START TRAINING
# ------------------------
trainer.fit(model)
if __name__ == '__main__':
# dirs
root_dir = os.path.dirname(os.path.realpath(__file__))
demo_log_dir = os.path.join(root_dir, 'pt_lightning_demo_logs')
checkpoint_dir = os.path.join(demo_log_dir, 'model_weights')
test_tube_dir = os.path.join(demo_log_dir, 'test_tube_data')
# although we user hyperOptParser, we are using it only as argparse right now
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
# gpu args
parent_parser.add_argument('--gpus', type=str, default='0', help='how many gpus to use in the node. -1 uses all the gpus on the node')
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
# allow model to overwrite or extend args
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
hyperparams = parser.parse_args()
# ---------------------
# RUN TRAINING
# ---------------------
# run on HPC cluster
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
main(hyperparams)
@@ -1,203 +0,0 @@
import torch.nn as nn
import numpy as np
from pytorch_lightning.root_module.root_module import LightningModule
from test_tube import HyperOptArgumentParser
from torchvision.datasets import MNIST
import torchvision.transforms as transforms
import torch
import torch.nn.functional as F
class ExampleModel1(LightningModule):
"""
Sample model to show how to define a template
"""
def __init__(self, hparams):
# init superclass
super(ExampleModel1, self).__init__(hparams)
self.batch_size = hparams.batch_size
# build model
self.__build_model()
# ---------------------
# MODEL SETUP
# ---------------------
def __build_model(self):
"""
Layout model
:return:
"""
self.c_d1 = nn.Linear(in_features=self.hparams.in_features, out_features=self.hparams.hidden_dim)
self.c_d1_bn = nn.BatchNorm1d(self.hparams.hidden_dim)
self.c_d1_drop = nn.Dropout(self.hparams.drop_prob)
self.c_d2 = nn.Linear(in_features=self.hparams.hidden_dim, out_features=self.hparams.out_features)
# ---------------------
# TRAINING
# ---------------------
def forward(self, x):
x = self.c_d1(x)
x = F.tanh(x)
x = self.c_d1_bn(x)
x = self.c_d1_drop(x)
x = self.c_d2(x)
logits = F.log_softmax(x, dim=1)
return logits
def loss(self, labels, logits):
nll = F.nll_loss(logits, labels)
return nll
def training_step(self, data_batch):
"""
Called inside the training loop
:param data_batch:
:return:
"""
# forward pass
x, y = data_batch
x = x.view(x.size(0), -1)
y_hat = self.forward(x)
# calculate loss
loss_val = self.loss(y, y_hat)
tqdm_dic = {'jefe': 1}
return loss_val, tqdm_dic
def validation_step(self, data_batch):
"""
Called inside the validation loop
:param data_batch:
:return:
"""
x, y = data_batch
x = x.view(x.size(0), -1)
y_hat = self.forward(x)
loss_val = self.loss(y, y_hat)
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
output = {'y_hat': y_hat, 'val_loss': loss_val.item(), 'val_acc': val_acc}
return output
def validation_end(self, outputs):
"""
Called at the end of validation to aggregate outputs
:param outputs: list of individual outputs of each validation step
:return:
"""
val_loss_mean = 0
accs = []
for output in outputs:
val_loss_mean += output['val_loss']
accs.append(output['val_acc'])
val_loss_mean /= len(outputs)
tqdm_dic = {'val_loss': val_loss_mean, 'val_acc': np.mean(accs)}
return tqdm_dic
def update_tng_log_metrics(self, logs):
return logs
# ---------------------
# MODEL SAVING
# ---------------------
def get_save_dict(self):
checkpoint = {
'state_dict': self.state_dict(),
}
return checkpoint
def load_model_specific(self, checkpoint):
self.load_state_dict(checkpoint['state_dict'])
pass
# ---------------------
# TRAINING SETUP
# ---------------------
def configure_optimizers(self):
"""
return whatever optimizers we want here
:return: list of optimizers
"""
optimizer = self.choose_optimizer(self.hparams.optimizer_name, self.parameters(), {'lr': self.hparams.learning_rate}, 'optimizer')
self.optimizers = [optimizer]
return self.optimizers
def __dataloader(self, train):
# init data generators
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
dataset = MNIST(root=self.hparams.data_root, train=train, transform=transform, download=True)
loader = torch.utils.data.DataLoader(
dataset=dataset,
batch_size=self.hparams.batch_size,
shuffle=True
)
return loader
@property
def tng_dataloader(self):
if self._tng_dataloader is None:
try:
self._tng_dataloader = self.__dataloader(train=True)
except Exception as e:
print(e)
raise e
return self._tng_dataloader
@property
def val_dataloader(self):
if self._val_dataloader is None:
try:
self._val_dataloader = self.__dataloader(train=False)
except Exception as e:
print(e)
raise e
return self._val_dataloader
@property
def test_dataloader(self):
if self._test_dataloader is None:
try:
self._test_dataloader = self.__dataloader(train=False)
except Exception as e:
print(e)
raise e
return self._test_dataloader
@staticmethod
def add_model_specific_args(parent_parser):
parser = HyperOptArgumentParser(strategy=parent_parser.strategy, parents=[parent_parser])
# param overwrites
# parser.set_defaults(gradient_clip=5.0)
# network params
parser.opt_list('--drop_prob', default=0.2, options=[0.2, 0.5], type=float, tunable=False)
parser.add_argument('--in_features', default=28*28)
parser.add_argument('--hidden_dim', default=500)
parser.add_argument('--out_features', default=10)
# data
parser.add_argument('--data_root', default='/Users/williamfalcon/Developer/personal/research_lib/research_proj/datasets/mnist', type=str)
# training params (opt)
parser.opt_list('--learning_rate', default=0.001, type=float, options=[0.0001, 0.0005, 0.001, 0.005],
tunable=False)
parser.opt_list('--batch_size', default=256, type=int, options=[32, 64, 128, 256], tunable=False)
parser.opt_list('--optimizer_name', default='adam', type=str, options=['adam'], tunable=False)
return parser
+343 -138
View File
@@ -1,11 +1,12 @@
""" """
The trainer handles all the logic for running a val loop, training loop, distributing, etc... The trainer handles all the logic for running a val loop, training loop, distributing, etc...
""" """
from time import sleep
import subprocess import subprocess
import traceback import traceback
import warnings import warnings
import os import os
import pdb
import re
import torch import torch
from torch.utils.data.distributed import DistributedSampler from torch.utils.data.distributed import DistributedSampler
@@ -17,21 +18,43 @@ import tqdm
from pytorch_lightning.root_module.memory import get_gpu_memory_map from pytorch_lightning.root_module.memory import get_gpu_memory_map
from pytorch_lightning.root_module.model_saving import TrainerIO from pytorch_lightning.root_module.model_saving import TrainerIO
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel, LightningDataParallel
from pytorch_lightning.utils.debugging import MisconfigurationException
try: try:
from apex import amp from apex import amp
APEX_AVAILABLE = True APEX_AVAILABLE = True
except ModuleNotFoundError: except Exception:
APEX_AVAILABLE = False APEX_AVAILABLE = False
def reduce_distributed_output(output, nb_gpus):
if nb_gpus <= 1:
return output
# when using DP, we get one output per gpu
# average outputs and return
if type(output) is torch.Tensor:
return output.mean()
for k, v in output.items():
# recurse on nested dics
if isinstance(output[k], dict):
output[k] = reduce_distributed_output(output[k], nb_gpus)
# reduce only metrics that have the same nb of gpus
elif output[k].size(0) == nb_gpus:
reduced = torch.mean(output[k])
output[k] = reduced
return output
class Trainer(TrainerIO): class Trainer(TrainerIO):
def __init__(self, def __init__(self,
experiment, experiment,
checkpoint_callback, early_stop_callback, early_stop_callback=None,
checkpoint_callback=None,
gradient_clip=0, gradient_clip=0,
cluster=None, cluster=None,
process_position=0, process_position=0,
@@ -44,20 +67,58 @@ class Trainer(TrainerIO):
check_val_every_n_epoch=1, check_val_every_n_epoch=1,
fast_dev_run=False, fast_dev_run=False,
accumulate_grad_batches=1, accumulate_grad_batches=1,
enable_early_stop=True, max_nb_epochs=1000, min_nb_epochs=1, max_nb_epochs=1000, min_nb_epochs=1,
train_percent_check=1.0, val_percent_check=1.0, test_percent_check=1.0, val_check_interval=0.95, train_percent_check=1.0, val_percent_check=1.0, test_percent_check=1.0,
val_check_interval=0.95,
log_save_interval=100, add_log_row_interval=10, log_save_interval=100, add_log_row_interval=10,
lr_scheduler_milestones=None, lr_scheduler_milestones=None,
distributed_backend='dp',
use_amp=False, use_amp=False,
print_nan_grads=False, print_nan_grads=False,
print_weights_summary=True,
amp_level='O2', amp_level='O2',
nb_sanity_val_steps=5): nb_sanity_val_steps=5):
"""
:param experiment: Test-tube experiment
:param early_stop_callback: from pytorch_lightning import EarlyStopping
:param checkpoint_callback: from pytorch_lightning import Checkpoint
:param gradient_clip:
:param cluster:
:param process_position:
:param current_gpu_name:
:param nb_gpu_nodes:
:param gpus:
:param progress_bar:
:param overfit_pct:
:param track_grad_norm:
:param check_val_every_n_epoch:
:param fast_dev_run:
:param accumulate_grad_batches:
:param max_nb_epochs:
:param min_nb_epochs:
:param train_percent_check:
:param val_percent_check:
:param test_percent_check:
:param val_check_interval:
:param log_save_interval:
:param add_log_row_interval:
:param lr_scheduler_milestones:
:param distributed_backend: 'np' to use DistributedParallel, 'ddp' to use DistributedDataParallel
:param use_amp:
:param print_nan_grads:
:param print_weights_summary:
:param amp_level:
:param nb_sanity_val_steps:
"""
# Transfer params # Transfer params
self.nb_gpu_nodes = nb_gpu_nodes self.nb_gpu_nodes = nb_gpu_nodes
self.gradient_clip = gradient_clip self.gradient_clip = gradient_clip
self.check_val_every_n_epoch = check_val_every_n_epoch self.check_val_every_n_epoch = check_val_every_n_epoch
self.enable_early_stop = enable_early_stop self.enable_early_stop = early_stop_callback is not None
self.track_grad_norm = track_grad_norm self.track_grad_norm = track_grad_norm
self.fast_dev_run = fast_dev_run self.fast_dev_run = fast_dev_run
self.on_gpu = gpus is not None and torch.cuda.is_available() self.on_gpu = gpus is not None and torch.cuda.is_available()
@@ -67,8 +128,12 @@ class Trainer(TrainerIO):
self.cluster = cluster self.cluster = cluster
self.process_position = process_position self.process_position = process_position
self.current_gpu_name = current_gpu_name self.current_gpu_name = current_gpu_name
self.print_weights_summary = print_weights_summary
self.checkpoint_callback = checkpoint_callback self.checkpoint_callback = checkpoint_callback
self.checkpoint_callback.save_function = self.save_checkpoint
if self.checkpoint_callback is not None:
self.checkpoint_callback.save_function = self.save_checkpoint
self.early_stop = early_stop_callback self.early_stop = early_stop_callback
self.model = None self.model = None
self.max_nb_epochs = max_nb_epochs self.max_nb_epochs = max_nb_epochs
@@ -82,21 +147,67 @@ class Trainer(TrainerIO):
self.print_nan_grads = print_nan_grads self.print_nan_grads = print_nan_grads
self.data_parallel_device_ids = None self.data_parallel_device_ids = None
self.world_size = 1 self.world_size = 1
self.node_rank = 0
self.use_ddp = False
self.use_dp = False
# training bookeeping
self.total_batch_nb = 0
self.running_loss = []
self.avg_loss = 0
self.batch_nb = 0
self.tqdm_metrics = {}
self.nb_val_batches = None
self.nb_tng_batches = None
self.nb_test_batches = None
# gpus come in as a string. # gpus come in as a string.
# if gpus = -1 then use all available devices # if gpus = -1 then use all available devices
# otherwise, split the string using commas # otherwise, split the string using commas
if gpus is not None: if gpus is not None:
if gpus == '-1': if type(gpus) is list:
self.data_parallel_device_ids = list(range(0, torch.cuda.device_count())) self.data_parallel_device_ids = gpus
elif type(gpus) is str:
if gpus == '-1':
self.data_parallel_device_ids = list(range(0, torch.cuda.device_count()))
else:
self.data_parallel_device_ids = [int(x.strip()) for x in gpus.split(',')]
else: else:
self.data_parallel_device_ids = [int(x.strip()) for x in gpus.split(',')] raise Exception('gpus has to be a string or list of ids')
# set the correct cuda visible devices (using pci order) # set the correct cuda visible devices (using pci order)
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join([str(x) for x in self.data_parallel_device_ids]) os.environ["CUDA_VISIBLE_DEVICES"] = ','.join([str(x) for x in self.data_parallel_device_ids])
print(f'VISIBLE GPUS: {os.environ["CUDA_VISIBLE_DEVICES"]}')
self.data_parallel = self.data_parallel_device_ids is not None and len(self.data_parallel_device_ids) > 0 # make DP and DDP mutually exclusive
# single GPU will also use DP with devices=[0]
have_gpus = self.data_parallel_device_ids is not None and len(self.data_parallel_device_ids) > 0
if have_gpus:
self.use_dp = distributed_backend == 'dp'
self.use_ddp = distributed_backend == 'ddp'
# use ddp automatically if nb_gpu_nodes > 1
if nb_gpu_nodes > 1 and self.use_dp: # pragma: no cover
self.use_ddp = True
self.use_dp = False
w = 'DataParallel does not support nb_gpu_nodes > 1. ' \
'Switching to DistributedDataParallel for you. ' \
'To silence this warning set distributed_backend=ddp'
warnings.warn(w)
# extract SLURM flag vars
# whenever we have the correct number of tasks, we let slurm manage processes
# otherwise we launch the required number of processes
if self.use_ddp:
self.nb_requested_gpus = len(self.data_parallel_device_ids) * self.nb_gpu_nodes
self.nb_slurm_tasks = 0
try:
self.nb_slurm_tasks = int(os.environ['SLURM_NTASKS'])
self.is_slurm_managing_tasks = self.nb_slurm_tasks == self.nb_requested_gpus
except Exception as e:
# likely not on slurm, so set the slurm managed flag to false
self.is_slurm_managing_tasks = False
# process info # process info
self.proc_rank = 0 self.proc_rank = 0
@@ -127,7 +238,7 @@ class Trainer(TrainerIO):
if self.use_amp: if self.use_amp:
print('using 16bit precision') print('using 16bit precision')
if use_amp and not APEX_AVAILABLE: if use_amp and not APEX_AVAILABLE: # pragma: no cover
msg = ''' msg = '''
You set use_amp=True but do not have apex installed. You set use_amp=True but do not have apex installed.
Install apex first using this guide and rerun with use_amp=True: Install apex first using this guide and rerun with use_amp=True:
@@ -135,7 +246,11 @@ class Trainer(TrainerIO):
this run will NOT use 16 bit precision this run will NOT use 16 bit precision
''' '''
warnings.warn(msg) raise ModuleNotFoundError(msg)
@property
def data_parallel(self):
return self.use_dp or self.use_ddp
def __determine_data_use_amount(self, train_percent_check, val_percent_check, test_percent_check, overfit_pct): def __determine_data_use_amount(self, train_percent_check, val_percent_check, test_percent_check, overfit_pct):
""" """
@@ -149,12 +264,17 @@ class Trainer(TrainerIO):
self.val_percent_check = overfit_pct self.val_percent_check = overfit_pct
self.test_percent_check = overfit_pct self.test_percent_check = overfit_pct
def __get_model(self):
return self.model.module if self.data_parallel else self.model
def __is_function_implemented(self, f_name): def __is_function_implemented(self, f_name):
f_op = getattr(self.model, f_name, None) model = self.__get_model()
f_op = getattr(model, f_name, None)
return callable(f_op) return callable(f_op)
@property @property
def __tng_tqdm_dic(self): def __tng_tqdm_dic(self):
# ForkedPdb().set_trace()
tqdm_dic = { tqdm_dic = {
'tng_loss': '{0:.3f}'.format(self.avg_loss), 'tng_loss': '{0:.3f}'.format(self.avg_loss),
'v_nb': '{}'.format(self.experiment.version), 'v_nb': '{}'.format(self.experiment.version),
@@ -168,13 +288,15 @@ class Trainer(TrainerIO):
return tqdm_dic return tqdm_dic
@property
def tng_tqdm_dic(self):
"""
Read-only for tqdm metrics
:return:
"""
return self.__tng_tqdm_dic
def __layout_bookeeping(self): def __layout_bookeeping(self):
# training bookeeping
self.total_batch_nb = 0
self.running_loss = []
self.avg_loss = 0
self.batch_nb = 0
self.tqdm_metrics = {}
# determine number of training batches # determine number of training batches
self.nb_tng_batches = len(self.tng_dataloader) self.nb_tng_batches = len(self.tng_dataloader)
@@ -208,9 +330,6 @@ class Trainer(TrainerIO):
:param max_batches: Scalar :param max_batches: Scalar
:return: :return:
""" """
if self.proc_rank == 0:
print('validating...')
# enable eval mode # enable eval mode
model.zero_grad() model.zero_grad()
model.eval() model.eval()
@@ -224,7 +343,7 @@ class Trainer(TrainerIO):
# run training # run training
for batch_i, data_batch in enumerate(dataloader): for batch_i, data_batch in enumerate(dataloader):
if data_batch is None: if data_batch is None: # pragma: no cover
continue continue
# stop short when on fast dev run # stop short when on fast dev run
@@ -234,8 +353,12 @@ class Trainer(TrainerIO):
# ----------------- # -----------------
# RUN VALIDATION STEP # RUN VALIDATION STEP
# ----------------- # -----------------
if self.data_parallel: if self.use_ddp:
output = model(data_batch, batch_i) output = model(data_batch, batch_i)
elif self.use_dp:
output = model(data_batch, batch_i)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
else: else:
output = model.validation_step(data_batch, batch_i) output = model.validation_step(data_batch, batch_i)
@@ -259,7 +382,7 @@ class Trainer(TrainerIO):
return val_results return val_results
def __get_dataloaders(self, model): def get_dataloaders(self, model):
""" """
Dataloaders are provided by the model Dataloaders are provided by the model
:param model: :param model:
@@ -269,7 +392,7 @@ class Trainer(TrainerIO):
self.test_dataloader = model.test_dataloader self.test_dataloader = model.test_dataloader
self.val_dataloader = model.val_dataloader self.val_dataloader = model.val_dataloader
if self.on_gpu and type(self.tng_dataloader.sampler) is not DistributedSampler: if self.use_ddp and not isinstance(self.tng_dataloader.sampler, DistributedSampler):
msg = ''' msg = '''
when using multiple gpus and multiple nodes you must pass a DistributedSampler to DataLoader(sampler). when using multiple gpus and multiple nodes you must pass a DistributedSampler to DataLoader(sampler).
@@ -282,33 +405,73 @@ class Trainer(TrainerIO):
dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset) dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset)
dataloader = Dataloader(dataset, sampler=dist_sampler) dataloader = Dataloader(dataset, sampler=dist_sampler)
''' '''
raise Exception(msg) raise MisconfigurationException(msg)
# ----------------------------- # -----------------------------
# MODEL TRAINING # MODEL TRAINING
# ----------------------------- # -----------------------------
def fit(self, model): def fit(self, model):
# when using multi-node or DDP within a node start each module in a separate process
if self.use_ddp:
# must copy only the meta of the exp so it survives pickle/unpickle when going to new process
self.experiment = self.experiment.get_meta_copy()
if self.is_slurm_managing_tasks:
task = int(os.environ['SLURM_LOCALID'])
self.ddp_train(task, model)
else:
msg = f"""
You requested {self.nb_requested_gpus} GPUs but launched {self.nb_slurm_tasks} slurm tasks.
We will launch {self.nb_requested_gpus} processes for you.
We recommend you let slurm manage the processes by setting: --ntasks-per-node={self.nb_requested_gpus}
If you're not using SLURM, ignore this message!
"""
warnings.warn(msg)
mp.spawn(self.ddp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
# 1 gpu or dp option triggers training using DP module
# easier to avoid NCCL issues
elif self.use_dp:
self.__dp_train(model)
# ON CPU
else:
# run through amp wrapper
if self.use_amp:
raise MisconfigurationException('amp + cpu is not supported. Please use a GPU option')
# CHOOSE OPTIMIZER
# filter out the weights that were done on gpu so we can load on good old cpus
self.optimizers = model.configure_optimizers()
self.__run_pretrain_routine(model)
# return 1 when finished
# used for testing or when we need to know that training succeeded
return 1
def __dp_train(self, model):
# CHOOSE OPTIMIZER # CHOOSE OPTIMIZER
# filter out the weights that were done on gpu so we can load on good old cpus # filter out the weights that were done on gpu so we can load on good old cpus
self.optimizers = model.configure_optimizers() self.optimizers = model.configure_optimizers()
# run through amp wrapper model.cuda(self.data_parallel_device_ids[0])
if self.use_amp:
# An example
model, optimizers = amp.initialize(
model, self.optimizers, opt_level=self.amp_level,
)
self.optimizers = optimizers
# when using gpus, first thing we do is spawn a new process between each worker # check for this bug (amp + dp + !01 doesn't work)
# applies to single gpu, multi-gpu and multi-nodes # https://github.com/NVIDIA/apex/issues/227
if self.on_gpu: if self.use_dp and self.use_amp:
self.experiment = self.experiment.get_meta_copy() m = f'amp level {self.amp_level} with DataParallel is not supported. ' \
mp.spawn(self.dp_train, nprocs=len(self.data_parallel_device_ids), args=(model, )) f'See this note from NVIDIA for more info: https://github.com/NVIDIA/apex/issues/227. ' \
else: f'We recommend you switch to ddp if you want to use amp'
self.__run_pretrain_routine(model) raise MisconfigurationException(m)
def dp_train(self, gpu_nb, model): model = LightningDataParallel(model, device_ids=self.data_parallel_device_ids)
self.__run_pretrain_routine(model)
def ddp_train(self, gpu_nb, model):
""" """
Entry point into a DP thread Entry point into a DP thread
:param gpu_nb: :param gpu_nb:
@@ -319,75 +482,91 @@ class Trainer(TrainerIO):
# node rank using relative slurm id # node rank using relative slurm id
# otherwise default to node rank 0 # otherwise default to node rank 0
try: try:
node_rank = int(os.environ['SLURM_NODEID']) node_id = os.environ['SLURM_NODEID']
except KeyError as e: self.node_rank = int(node_id)
node_rank = 0 except Exception as e:
self.node_rank = 0
# recover original exp before went into process # recover original exp before went into process
# init in write mode only on proc 0
self.experiment.debug = self.proc_rank > 0
self.experiment = self.experiment.get_non_ddp_exp() self.experiment = self.experiment.get_non_ddp_exp()
# show progbar only on prog_rank 0 # show progbar only on prog_rank 0
self.prog_bar = self.prog_bar and node_rank == 0 and gpu_nb == 0 self.prog_bar = self.prog_bar and self.node_rank == 0 and gpu_nb == 0
# determine which process we are and world size # determine which process we are and world size
self.proc_rank = node_rank * len(self.data_parallel_device_ids) + gpu_nb self.proc_rank = self.node_rank * len(self.data_parallel_device_ids) + gpu_nb
self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids) self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids)
# set up server using proc 0's ip address # let the exp know the rank to avoid overwriting logs
ip = self.__get_root_node_ip(self.proc_rank, self.nb_gpu_nodes) self.experiment.rank = self.proc_rank
dist.init_process_group("nccl", init_method=f'tcp://{ip}:12001', rank=self.proc_rank, world_size=self.world_size)
# set up server using proc 0's ip address
# try to init for 20 times at max in case ports are taken
# where to store ip_table
self.__init_tcp_connection()
# CHOOSE OPTIMIZER
# filter out the weights that were done on gpu so we can load on good old cpus
self.optimizers = model.configure_optimizers()
# MODEL
# copy model to each gpu # copy model to each gpu
torch.cuda.set_device(gpu_nb) torch.cuda.set_device(gpu_nb)
model.cuda(gpu_nb) model.cuda(gpu_nb)
model = LightningDistributedDataParallel(model, device_ids=[gpu_nb])
# AMP
# run through amp wrapper before going to distributed DP
if self.use_amp:
# An example
model, optimizers = amp.initialize(
model, self.optimizers, opt_level=self.amp_level,
)
self.optimizers = optimizers
model = LightningDistributedDataParallel(model, device_ids=[gpu_nb], find_unused_parameters=True)
# continue training routine # continue training routine
self.__run_pretrain_routine(model) self.__run_pretrain_routine(model)
def __get_root_node_ip(self, world_gpu_nb, nb_gpu_nodes): def __init_tcp_connection(self):
""" """
Resolves the ip address of proc 0. Connect all procs in the world using the env:// init
Proc 0 writes address to a file. Every other process waits until the ip is available before it starts Use the first node as the root address
:param port:
:param world_gpu_nb: gpu number amongst all the world gpus :param tries:
:param nb_gpu_nodes:
:param ip_file_dir:
:return: :return:
""" """
# on one node we use localhost # sets the appropriate port
if nb_gpu_nodes == 1: try:
return '127.0.0.1' port = os.environ['MASTER_PORT']
except Exception as e:
port = 12910
os.environ['MASTER_PORT'] = f'{port}'
# where to store ip_table # figure out the root node addr
ip_file_dir = os.path.join(self.cluster.log_path, 'ip_tables') try:
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
except Exception as e:
root_node = '127.0.0.2'
# the first gpu in the world becomes the host root_node = self.resolve_root_node_address(root_node)
# this is based on its global rank os.environ['MASTER_ADDR'] = root_node
# it communicates its ip by saving an ip_table to the slurm cluster logging dir
# every other process waits for this ip to appear before continuing
ip_table_name = f'.ip_meta_' + os.environ['SLURM_JOB_ID']
ip_file = os.path.join(ip_file_dir, ip_table_name)
os.makedirs(ip_file_dir, exist_ok=True)
if world_gpu_nb == 0: dist.init_process_group("nccl", rank=self.proc_rank, world_size=self.world_size)
# get the proc 0 IP
root_ip = subprocess.run(['hostname', '-I'], stdout=subprocess.PIPE).stdout.decode('utf-8')
root_ip = root_ip.split(' ')[0]
# save the ip to the file def resolve_root_node_address(self, root_node):
with open(file=ip_file, mode='w') as f: if '[' in root_node:
f.write(root_ip) name = root_node.split('[')[0]
number = root_node.split(',')[0]
if '-' in number:
number = number.split('-')[0]
return root_ip number = re.sub('[^0-9]', '', number)
else: root_node = name + number
# wait up to 120 seconds until proc 0 writes
# once written, read proc 0's address and use it to configure server return root_node
for i in range(0, 120):
sleep(1.0)
if os.path.exists(ip_file):
ip = list(open(file=ip_file, mode='r'))[0]
return ip
def __run_pretrain_routine(self, model): def __run_pretrain_routine(self, model):
""" """
@@ -396,7 +575,7 @@ class Trainer(TrainerIO):
:return: :return:
""" """
ref_model = model ref_model = model
if self.on_gpu: if self.data_parallel:
ref_model = model.module ref_model = model.module
ref_model.trainer = self ref_model.trainer = self
@@ -405,7 +584,7 @@ class Trainer(TrainerIO):
ref_model.on_gpu = self.on_gpu ref_model.on_gpu = self.on_gpu
# transfer data loaders from model # transfer data loaders from model
self.__get_dataloaders(ref_model) self.get_dataloaders(ref_model)
# init training constants # init training constants
self.__layout_bookeeping() self.__layout_bookeeping()
@@ -417,7 +596,7 @@ class Trainer(TrainerIO):
self.lr_schedulers.append(scheduler) self.lr_schedulers.append(scheduler)
# print model summary # print model summary
if self.proc_rank == 0: if self.proc_rank == 0 and self.print_weights_summary:
ref_model.summarize() ref_model.summarize()
# give model convenience properties # give model convenience properties
@@ -431,14 +610,18 @@ class Trainer(TrainerIO):
if self.proc_rank == 0: if self.proc_rank == 0:
self.experiment.save() self.experiment.save()
# track model now.
# if cluster resets state, the model will update with the saved weights
self.model = model
# enable cluster checkpointing # enable cluster checkpointing
if self.cluster is not None: # also restores training state
if self.cluster is not None: # pragma: no cover
self.enable_auto_hpc_walltime_manager() self.enable_auto_hpc_walltime_manager()
# --------------------------- # ---------------------------
# CORE TRAINING LOOP # CORE TRAINING LOOP
# --------------------------- # ---------------------------
self.model = model
self.__train() self.__train()
def __train(self): def __train(self):
@@ -448,12 +631,12 @@ class Trainer(TrainerIO):
for lr_scheduler in self.lr_schedulers: for lr_scheduler in self.lr_schedulers:
lr_scheduler.step() lr_scheduler.step()
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
model.current_epoch = epoch_nb model.current_epoch = epoch_nb
# hook # hook
if self.__is_function_implemented('on_epoch_start'): if self.__is_function_implemented('on_epoch_start'):
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
model.on_epoch_start() model.on_epoch_start()
self.current_epoch = epoch_nb self.current_epoch = epoch_nb
@@ -468,7 +651,7 @@ class Trainer(TrainerIO):
self.batch_nb = batch_nb self.batch_nb = batch_nb
self.global_step += 1 self.global_step += 1
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
model.global_step = self.global_step model.global_step = self.global_step
# stop when the flag is changed or we've gone past the amount requested in the batches # stop when the flag is changed or we've gone past the amount requested in the batches
@@ -500,10 +683,8 @@ class Trainer(TrainerIO):
# count items in memory # count items in memory
# nb_params, nb_tensors = count_mem_items() # nb_params, nb_tensors = count_mem_items()
if self.data_parallel: model = self.__get_model()
metrics = self.model.module.update_tng_log_metrics(self.__tng_tqdm_dic) metrics = self.__tng_tqdm_dic
else:
metrics = self.model.update_tng_log_metrics(self.__tng_tqdm_dic)
# add gpu memory # add gpu memory
if self.on_gpu: if self.on_gpu:
@@ -512,11 +693,13 @@ class Trainer(TrainerIO):
# add norms # add norms
if self.track_grad_norm > 0: if self.track_grad_norm > 0:
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
grad_norm_dic = model.grad_norm(self.track_grad_norm) grad_norm_dic = model.grad_norm(self.track_grad_norm)
metrics.update(grad_norm_dic) metrics.update(grad_norm_dic)
if self.__is_function_implemented('on_tng_metrics'):
model.on_tng_metrics(metrics)
# log metrics # log metrics
scalar_metrics = self.__metrics_to_scalars(metrics, blacklist=self.__log_vals_blacklist()) scalar_metrics = self.__metrics_to_scalars(metrics, blacklist=self.__log_vals_blacklist())
if self.proc_rank == 0: if self.proc_rank == 0:
@@ -525,7 +708,7 @@ class Trainer(TrainerIO):
# hook # hook
if self.__is_function_implemented('on_batch_end'): if self.__is_function_implemented('on_batch_end'):
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
model.on_batch_end() model.on_batch_end()
# end epoch early # end epoch early
@@ -534,13 +717,13 @@ class Trainer(TrainerIO):
# hook # hook
if self.__is_function_implemented('on_epoch_end'): if self.__is_function_implemented('on_epoch_end'):
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
model.on_epoch_end() model.on_epoch_end()
# early stopping # early stopping
if self.enable_early_stop: met_min_epochs = epoch_nb > self.min_nb_epochs
if self.enable_early_stop and met_min_epochs:
should_stop = self.early_stop_callback.on_epoch_end(epoch=epoch_nb, logs=self.__tng_tqdm_dic) should_stop = self.early_stop_callback.on_epoch_end(epoch=epoch_nb, logs=self.__tng_tqdm_dic)
met_min_epochs = epoch_nb > self.min_nb_epochs
# stop training # stop training
stop = should_stop and met_min_epochs stop = should_stop and met_min_epochs
@@ -563,7 +746,7 @@ class Trainer(TrainerIO):
def __log_vals_blacklist(self): def __log_vals_blacklist(self):
"""avoid logging some vals lightning uses to maintain state""" """avoid logging some vals lightning uses to maintain state"""
blacklist = {'batch_nb', 'v_nb', 'epoch', 'gpu'} blacklist = {'batch_nb', 'v_nb', 'gpu'}
return blacklist return blacklist
def __run_tng_batch(self, data_batch, batch_nb): def __run_tng_batch(self, data_batch, batch_nb):
@@ -572,8 +755,8 @@ class Trainer(TrainerIO):
# hook # hook
if self.__is_function_implemented('on_batch_start'): if self.__is_function_implemented('on_batch_start'):
model = self.model.module if self.data_parallel else self.model model_ref = self.__get_model()
response = model.on_batch_start(data_batch) response = model_ref.on_batch_start(data_batch)
if response == -1: if response == -1:
return -1 return -1
@@ -583,13 +766,26 @@ class Trainer(TrainerIO):
# forward pass # forward pass
# return a scalar value and a dic with tqdm metrics # return a scalar value and a dic with tqdm metrics
if self.data_parallel: if self.use_ddp:
output = self.model(data_batch, batch_nb) output = self.model(data_batch, batch_nb)
elif self.use_dp:
output = self.model(data_batch, batch_nb)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
else: else:
output = self.model.training_step(data_batch, batch_nb) output = self.model.training_step(data_batch, batch_nb)
model_specific_tqdm_metrics_dic = output['tqdm_metrics'] try:
loss = output['loss'] model_specific_tqdm_metrics_dic = output['tqdm_metrics']
except Exception as e:
model_specific_tqdm_metrics_dic = {}
# if output dict doesn't have the keyword loss
# then assume the output=loss if scalar
try:
loss = output['loss']
except Exception as e:
if type(output) is torch.Tensor:
loss = output
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic) self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
@@ -602,11 +798,17 @@ class Trainer(TrainerIO):
else: else:
loss.backward() loss.backward()
# insert after step hook
if self.__is_function_implemented('on_after_backward'):
model_ref = self.__get_model()
response = model_ref.on_after_backward()
if self.print_nan_grads: if self.print_nan_grads:
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
for param in model.parameters(): for param in model.parameters():
print(param.grad.float().sum()) print(param.grad.float().sum())
# avoid memory leaks
self.batch_loss_value += loss.item() self.batch_loss_value += loss.item()
# gradient update with accumulated gradients # gradient update with accumulated gradients
@@ -614,13 +816,18 @@ class Trainer(TrainerIO):
# clip gradients # clip gradients
if self.gradient_clip > 0: if self.gradient_clip > 0:
model = self.model.module if self.data_parallel else self.model model = self.__get_model()
torch.nn.utils.clip_grad_norm(model.parameters(), self.gradient_clip) torch.nn.utils.clip_grad_norm(model.parameters(), self.gradient_clip)
# update gradients across all optimizers # update gradients across all optimizers
for optimizer in self.optimizers: for optimizer in self.optimizers:
optimizer.step() optimizer.step()
# insert after step hook
if self.__is_function_implemented('on_before_zero_grad'):
model_ref = self.__get_model()
response = model_ref.on_before_zero_grad(optimizer)
# clear gradients # clear gradients
optimizer.zero_grad() optimizer.zero_grad()
@@ -640,7 +847,8 @@ class Trainer(TrainerIO):
# activate batch end hook # activate batch end hook
if self.__is_function_implemented('on_batch_end'): if self.__is_function_implemented('on_batch_end'):
self.model.on_batch_end() model = self.__get_model()
model.on_batch_end()
return 0 return 0
@@ -652,28 +860,25 @@ class Trainer(TrainerIO):
elif not can_check_epoch: elif not can_check_epoch:
return return
try: # hook
# hook if self.__is_function_implemented('on_pre_performance_check'):
if self.__is_function_implemented('on_pre_performance_check'): model = self.__get_model()
self.model.on_pre_performance_check() model.on_pre_performance_check()
# use full val set on end of epoch # use full val set on end of epoch
# use a small portion otherwise # use a small portion otherwise
max_batches = None if not self.fast_dev_run else 1 max_batches = None if not self.fast_dev_run else 1
model_specific_tqdm_metrics_dic = self.validate( model_specific_tqdm_metrics_dic = self.validate(
self.model, self.model,
self.val_dataloader, self.val_dataloader,
max_batches max_batches
) )
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic) self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
# hook # hook
if self.__is_function_implemented('on_post_performance_check'): if self.__is_function_implemented('on_post_performance_check'):
self.model.on_post_performance_check() model = self.__get_model()
model.on_post_performance_check()
except Exception as e:
print(e)
print(traceback.print_exc())
if self.progress_bar: if self.progress_bar:
# add model specific metrics # add model specific metrics
@@ -681,6 +886,6 @@ class Trainer(TrainerIO):
self.prog_bar.set_postfix(**tqdm_metrics) self.prog_bar.set_postfix(**tqdm_metrics)
# model checkpointing # model checkpointing
if self.proc_rank == 0: if self.proc_rank == 0 and self.checkpoint_callback is not None:
print('save callback...') print('save callback...')
self.checkpoint_callback.on_epoch_end(epoch=self.current_epoch, logs=self.__tng_tqdm_dic) self.checkpoint_callback.on_epoch_end(epoch=self.current_epoch, logs=self.__tng_tqdm_dic)
@@ -1,6 +1,7 @@
from torch.nn import DataParallel from torch.nn import DataParallel
from torch.nn.parallel import DistributedDataParallel from torch.nn.parallel import DistributedDataParallel
import itertools import itertools
from itertools import chain
import threading import threading
import torch import torch
@@ -8,7 +9,7 @@ from torch.cuda._utils import _get_device_index
import pdb import pdb
def _find_tensors(obj): def _find_tensors(obj): # pragma: no cover
r""" r"""
Recursively find all tensors contained in the specified object. Recursively find all tensors contained in the specified object.
""" """
@@ -21,8 +22,7 @@ def _find_tensors(obj):
return [] return []
def get_a_var(obj): # pragma: no cover
def get_a_var(obj):
if isinstance(obj, torch.Tensor): if isinstance(obj, torch.Tensor):
return obj return obj
@@ -42,6 +42,29 @@ class LightningDataParallel(DataParallel):
Override the forward call in lightning so it goes to training and validation step respectively Override the forward call in lightning so it goes to training and validation step respectively
""" """
def forward(self, *inputs, **kwargs):
if not self.device_ids:
return self.module(*inputs, **kwargs)
for t in chain(self.module.parameters(), self.module.buffers()):
if t.device != self.src_device_obj:
raise RuntimeError("module must have its parameters and buffers "
"on device {} (device_ids[0]) but found one of "
"them on device: {}".format(self.src_device_obj, t.device))
inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids)
if len(self.device_ids) == 1:
# lightning
if self.module.training:
return self.module.training_step(*inputs[0], **kwargs[0])
else:
return self.module.validation_step(*inputs[0], **kwargs[0])
replicas = self.replicate(self.module, self.device_ids[:len(inputs)])
outputs = self.parallel_apply(replicas, inputs, kwargs)
return self.gather(outputs, self.output_device)
def parallel_apply(self, replicas, inputs, kwargs): def parallel_apply(self, replicas, inputs, kwargs):
return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)]) return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
@@ -54,7 +77,7 @@ class LightningDistributedDataParallel(DistributedDataParallel):
def parallel_apply(self, replicas, inputs, kwargs): def parallel_apply(self, replicas, inputs, kwargs):
return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)]) return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
def forward(self, *inputs, **kwargs): def forward(self, *inputs, **kwargs): # pragma: no cover
self._sync_params() self._sync_params()
if self.device_ids: if self.device_ids:
inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids)
@@ -89,7 +112,7 @@ class LightningDistributedDataParallel(DistributedDataParallel):
return output return output
def parallel_apply(modules, inputs, kwargs_tup=None, devices=None): def parallel_apply(modules, inputs, kwargs_tup=None, devices=None): # pragma: no cover
r"""Applies each `module` in :attr:`modules` in parallel on arguments r"""Applies each `module` in :attr:`modules` in parallel on arguments
contained in :attr:`inputs` (positional) and :attr:`kwargs_tup` (keyword) contained in :attr:`inputs` (positional) and :attr:`kwargs_tup` (keyword)
on each of :attr:`devices`. on each of :attr:`devices`.
@@ -0,0 +1,17 @@
def data_loader(fn):
"""
Decorator to make any fx with this use the lazy property
:param fn:
:return:
"""
attr_name = '_lazy_' + fn.__name__
@property
def _data_loader(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return _data_loader
-11
View File
@@ -27,14 +27,3 @@ class GradInformation(nn.Module):
results['grad_{}_norm_total'.format(norm_type)] = round(total_norm.data.cpu().numpy().flatten()[0], 3) results['grad_{}_norm_total'.format(norm_type)] = round(total_norm.data.cpu().numpy().flatten()[0], 3)
return results return results
def describe_grads(self):
for p in self.parameters():
g = p.grad.data.numpy().flatten()
print(np.max(g), np.min(g), np.mean(g))
def describe_params(self):
for p in self.parameters():
g = p.data.numpy().flatten()
print(np.max(g), np.min(g), np.mean(g))
+24
View File
@@ -19,3 +19,27 @@ class ModelHooks(torch.nn.Module):
def on_post_performance_check(self): def on_post_performance_check(self):
pass pass
def on_tng_metrics(self, metrics):
pass
def on_before_zero_grad(self, optimizer):
"""
Called after optimizer.step() and before optimizer.zero_grad()
for optimizer in optimizers:
optimizer.step()
model.on_before_zero_grad(optimizer) # < ---- called here
optimizer.zero_grad
:param optimizer:
:return:
"""
pass
def on_after_backward(self):
"""
Called after loss.backward() and before optimizers do anything
:return:
"""
pass
+48 -27
View File
@@ -33,33 +33,42 @@ class ModelSummary(object):
mods = list(self.model.modules()) mods = list(self.model.modules())
in_sizes = [] in_sizes = []
out_sizes = [] out_sizes = []
input_ = self.example_input_array input_ = self.model.example_input_array
for i in range(1, len(mods)):
m = mods[i]
if type(input_) is list or type(input_) is tuple:
out = m(*input_)
else:
out = m(input_)
if type(input_) is tuple or type(input_) is list: if self.model.on_gpu:
in_size = [] input_ = input_.cuda(0)
for x in input_:
if type(x) is list:
in_size.append(len(x))
else:
in_size.append(x.size())
else:
in_size = np.array(input_.size())
in_sizes.append(in_size) if self.model.trainer.use_amp:
input_ = input_.half()
if type(out) is tuple or type(out) is list: with torch.no_grad():
out_size = np.asarray([x.size() for x in out])
else:
out_size = np.array(out.size())
out_sizes.append(out_size) for i in range(1, len(mods)):
input_ = out m = mods[i]
if type(input_) is list or type(input_) is tuple: # pragma: no cover
out = m(*input_)
else:
out = m(input_)
if type(input_) is tuple or type(input_) is list: # pragma: no cover
in_size = []
for x in input_:
if type(x) is list:
in_size.append(len(x))
else:
in_size.append(x.size())
else:
in_size = np.array(input_.size())
in_sizes.append(in_size)
if type(out) is tuple or type(out) is list: # pragma: no cover
out_size = np.asarray([x.size() for x in out])
else:
out_size = np.array(out.size())
out_sizes.append(out_size)
input_ = out
self.in_sizes = in_sizes self.in_sizes = in_sizes
self.out_sizes = out_sizes self.out_sizes = out_sizes
@@ -114,13 +123,22 @@ class ModelSummary(object):
Layer Name, Layer Type, Input Size, Output Size, Number of Parameters Layer Name, Layer Type, Input Size, Output Size, Number of Parameters
''' '''
df = pd.DataFrame( np.zeros( (len(self.layer_names), 3) ) ) cols = ['Name', 'Type', 'Params']
df.columns = ['Name', 'Type', 'Params'] if self.model.example_input_array is not None:
cols.extend(['In_sizes', 'Out_sizes'])
df = pd.DataFrame(np.zeros( (len(self.layer_names), len(cols))))
df.columns = cols
df['Name'] = self.layer_names df['Name'] = self.layer_names
df['Type'] = self.layer_types df['Type'] = self.layer_types
df['Params'] = self.param_nums df['Params'] = self.param_nums
if self.model.example_input_array is not None:
df['In_sizes'] = self.in_sizes
df['Out_sizes'] = self.out_sizes
self.summary = df self.summary = df
return return
@@ -128,10 +146,13 @@ class ModelSummary(object):
self.get_layer_names() self.get_layer_names()
self.get_parameter_sizes() self.get_parameter_sizes()
self.get_parameter_nums() self.get_parameter_nums()
if self.model.example_input_array is not None:
self.get_variable_sizes()
self.make_summary() self.make_summary()
def print_mem_stack(): def print_mem_stack(): # pragma: no cover
for obj in gc.get_objects(): for obj in gc.get_objects():
try: try:
if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)): if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
@@ -140,7 +161,7 @@ def print_mem_stack():
pass pass
def count_mem_items(): def count_mem_items(): # pragma: no cover
nb_params = 0 nb_params = 0
nb_tensors = 0 nb_tensors = 0
for obj in gc.get_objects(): for obj in gc.get_objects():
+49 -28
View File
@@ -2,36 +2,38 @@ import torch
import os import os
import re import re
import pdb import pdb
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel, LightningDataParallel
class ModelIO(object): class ModelIO(object):
def load_model_specific(self, checkpoint): def on_load_checkpoint(self, checkpoint):
""" """
Do something with the checkpoint Do something with the checkpoint
Gives model a chance to load something before state_dict is restored
:param checkpoint: :param checkpoint:
:return: :return:
""" """
raise NotImplementedError pass
def get_save_dict(self): def on_save_checkpoint(self, checkpoint):
""" """
Return specific things for the model Give the model a chance to add something to the checkpoint.
:return: state_dict is already there
""" """
raise NotImplementedError pass
# ------------------------- # -------------------------
# OPTIONAL HOOKS # OPTIONAL HOOKS
# ------------------------- # -------------------------
def on_hpc_save(self): def on_hpc_save(self, checkpoint):
""" """
Hook to do whatever you need right before Slurm manager saves the model Hook to do whatever you need right before Slurm manager saves the model
:return: :return:
""" """
pass pass
def on_hpc_load(self): def on_hpc_load(self, checkpoint):
""" """
Hook to do whatever you need right before Slurm manager loads the model Hook to do whatever you need right before Slurm manager loads the model
:return: :return:
@@ -41,6 +43,11 @@ class ModelIO(object):
class TrainerIO(object): class TrainerIO(object):
def __get_model(self):
is_dp_module = type(self.model) is LightningDistributedDataParallel or type(self.model) is LightningDataParallel
model = self.model.module if is_dp_module else self.model
return model
# -------------------- # --------------------
# MODEL SAVE CHECKPOINT # MODEL SAVE CHECKPOINT
# -------------------- # --------------------
@@ -51,26 +58,32 @@ class TrainerIO(object):
torch.save(checkpoint, filepath) torch.save(checkpoint, filepath)
def dump_checkpoint(self): def dump_checkpoint(self):
checkpoint = { checkpoint = {
'epoch': self.current_epoch, 'epoch': self.current_epoch,
'checkpoint_callback_best': self.checkpoint_callback.best,
'early_stop_callback_wait': self.early_stop_callback.wait,
'early_stop_callback_patience': self.early_stop_callback.patience,
'global_step': self.global_step 'global_step': self.global_step
} }
if self.checkpoint_callback is not None:
checkpoint['checkpoint_callback_best'] = self.checkpoint_callback.best
if self.early_stop_callback is not None:
checkpoint['early_stop_callback_wait'] = self.early_stop_callback.wait
checkpoint['early_stop_callback_patience'] = self.early_stop_callback.patience
optimizer_states = [] optimizer_states = []
for i, optimizer in enumerate(self.optimizers): for i, optimizer in enumerate(self.optimizers):
optimizer_states.append(optimizer.state_dict()) optimizer_states.append(optimizer.state_dict())
checkpoint['optimizer_states'] = optimizer_states checkpoint['optimizer_states'] = optimizer_states
# request what to save from the model # add the state_dict from the model
model = self.model.module if type(self.model) is LightningDistributedDataParallel else self.model model = self.__get_model()
checkpoint_dict = model.get_save_dict() checkpoint['state_dict'] = model.state_dict()
# give the model a chance to add a few things
model.on_save_checkpoint(checkpoint)
# merge trainer and model saving items
checkpoint.update(checkpoint_dict)
return checkpoint return checkpoint
# -------------------- # --------------------
@@ -103,9 +116,13 @@ class TrainerIO(object):
:param checkpoint: :param checkpoint:
:return: :return:
""" """
self.checkpoint_callback.best = checkpoint['checkpoint_callback_best'] if self.checkpoint_callback is not None:
self.early_stop_callback.wait = checkpoint['early_stop_callback_wait'] self.checkpoint_callback.best = checkpoint['checkpoint_callback_best']
self.early_stop_callback.patience = checkpoint['early_stop_callback_patience']
if self.early_stop_callback is not None:
self.early_stop_callback.wait = checkpoint['early_stop_callback_wait']
self.early_stop_callback.patience = checkpoint['early_stop_callback_patience']
self.global_step = checkpoint['global_step'] self.global_step = checkpoint['global_step']
self.current_epoch = checkpoint['epoch'] self.current_epoch = checkpoint['epoch']
@@ -134,13 +151,15 @@ class TrainerIO(object):
filepath = '{}/hpc_ckpt_{}.ckpt'.format(folderpath, ckpt_number) filepath = '{}/hpc_ckpt_{}.ckpt'.format(folderpath, ckpt_number)
# give model a chance to do something on hpc_save # give model a chance to do something on hpc_save
self.on_hpc_save() model = self.__get_model()
checkpoint = self.dump_checkpoint()
# request what to save from the model model.on_hpc_save(checkpoint)
checkpoint_dict = self.dump_checkpoint()
# do the actual save # do the actual save
torch.save(checkpoint_dict, filepath) torch.save(checkpoint, filepath)
return filepath
def hpc_load(self, folderpath, on_gpu): def hpc_load(self, folderpath, on_gpu):
filepath = '{}/hpc_ckpt_{}.ckpt'.format(folderpath, self.max_ckpt_in_folder(folderpath)) filepath = '{}/hpc_ckpt_{}.ckpt'.format(folderpath, self.max_ckpt_in_folder(folderpath))
@@ -150,15 +169,17 @@ class TrainerIO(object):
else: else:
checkpoint = torch.load(filepath, map_location=lambda storage, loc: storage) checkpoint = torch.load(filepath, map_location=lambda storage, loc: storage)
# load training state # load training state (affects trainer only)
self.restore_training_state(checkpoint) self.restore_training_state(checkpoint)
# load model state # load model state
model = self.model.module if type(self.model) is LightningDataParallel else self.model model = self.__get_model()
model.load_model_specific(checkpoint)
# load the state_dict on the model automatically
model.load_state_dict(checkpoint['state_dict'])
# call model hook # call model hook
self.on_hpc_load() model.on_hpc_load(checkpoint)
def max_ckpt_in_folder(self, path): def max_ckpt_in_folder(self, path):
files = os.listdir(path) files = os.listdir(path)
@@ -1,22 +0,0 @@
from torch import nn
from torch import optim
class OptimizerConfig(nn.Module):
def choose_optimizer(self, optimizer, params, optimizer_params, opt_name_key):
if optimizer == 'adam':
optimizer = optim.Adam(params, **optimizer_params)
if optimizer == 'sparse_adam':
optimizer = optim.SparseAdam(params, **optimizer_params)
if optimizer == 'sgd':
optimizer = optim.SGD(params, **optimizer_params)
if optimizer == 'adadelta':
optimizer = optim.Adadelta(params, **optimizer_params)
# transfer opt state if loaded
if opt_name_key in self.loaded_optimizer_states_dict:
state = self.loaded_optimizer_states_dict[opt_name_key]
optimizer.load_state_dict(state)
return optimizer
+28 -59
View File
@@ -1,19 +1,15 @@
import os
import torch import torch
import math
from pytorch_lightning.root_module.memory import ModelSummary from pytorch_lightning.root_module.memory import ModelSummary
from pytorch_lightning.root_module.grads import GradInformation from pytorch_lightning.root_module.grads import GradInformation
from pytorch_lightning.root_module.model_saving import ModelIO, load_hparams_from_tags_csv from pytorch_lightning.root_module.model_saving import ModelIO, load_hparams_from_tags_csv
from pytorch_lightning.root_module.optimization import OptimizerConfig
from pytorch_lightning.root_module.hooks import ModelHooks from pytorch_lightning.root_module.hooks import ModelHooks
from pytorch_lightning.root_module.decorators import data_loader
class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks): class LightningModule(GradInformation, ModelIO, ModelHooks):
def __init__(self, hparams): def __init__(self, *args, **kwargs):
super(LightningModule, self).__init__() super(LightningModule, self).__init__(*args, **kwargs)
self.hparams = hparams
self.dtype = torch.FloatTensor self.dtype = torch.FloatTensor
self.exp_save_path = None self.exp_save_path = None
@@ -22,15 +18,11 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
self.loaded_optimizer_states_dict = {} self.loaded_optimizer_states_dict = {}
self.trainer = None self.trainer = None
self.experiment = None self.experiment = None
self.example_input_array = None
# track if gpu was requested for checkpointing # track if gpu was requested for checkpointing
self.on_gpu = False self.on_gpu = False
# computed vars for the dataloaders
self._tng_dataloader = None
self._val_dataloader = None
self._test_dataloader = None
def forward(self, *args, **kwargs): def forward(self, *args, **kwargs):
""" """
Expand model in into whatever you need. Expand model in into whatever you need.
@@ -71,37 +63,7 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
""" """
raise NotImplementedError raise NotImplementedError
def update_tng_log_metrics(self, logs): @data_loader
"""
Chance to update metrics to be logged for training step.
For example, add music, images, etc... to log
:param logs:
:return:
"""
raise NotImplementedError
def loss(self, *args, **kwargs):
"""
Expand model_out into your components
:param model_out:
:return:
"""
raise NotImplementedError
def summarize(self):
model_summary = ModelSummary(self)
print(model_summary)
def freeze(self):
for param in self.parameters():
param.requires_grad = False
def unfreeze(self):
for param in self.parameters():
param.requires_grad = True
@property
def tng_dataloader(self): def tng_dataloader(self):
""" """
Implement a function to load an h5py of this data Implement a function to load an h5py of this data
@@ -109,7 +71,7 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
""" """
raise NotImplementedError raise NotImplementedError
@property @data_loader
def test_dataloader(self): def test_dataloader(self):
""" """
Implement a function to load an h5py of this data Implement a function to load an h5py of this data
@@ -117,7 +79,7 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
""" """
raise NotImplementedError raise NotImplementedError
@property @data_loader
def val_dataloader(self): def val_dataloader(self):
""" """
Implement a function to load an h5py of this data Implement a function to load an h5py of this data
@@ -125,16 +87,6 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
""" """
raise NotImplementedError raise NotImplementedError
@staticmethod
def get_process_position(gpus):
try:
current_gpu = os.environ["CUDA_VISIBLE_DEVICES"]
gpu_ids = gpus.split(';')
process_position = gpu_ids.index(current_gpu)
return process_position, current_gpu
except Exception as e:
return 0, 0
@classmethod @classmethod
def load_from_metrics(cls, weights_path, tags_csv, on_gpu, map_location=None): def load_from_metrics(cls, weights_path, tags_csv, on_gpu, map_location=None):
""" """
@@ -156,9 +108,26 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
else: else:
checkpoint = torch.load(weights_path, map_location=lambda storage, loc: storage) checkpoint = torch.load(weights_path, map_location=lambda storage, loc: storage)
# load the state_dict on the model automatically
model = cls(hparams) model = cls(hparams)
model.load_state_dict(checkpoint['state_dict'])
# give model a chance to load something
model.on_load_checkpoint(checkpoint)
# allow model to load
model.load_model_specific(checkpoint)
model.load_state_dict(checkpoint['state_dict'], strict=False)
return model return model
def summarize(self):
model_summary = ModelSummary(self)
print(model_summary)
def freeze(self):
for param in self.parameters():
param.requires_grad = False
def unfreeze(self):
for param in self.parameters():
param.requires_grad = True
@@ -0,0 +1,253 @@
import os
from collections import OrderedDict
import torch.nn as nn
from torchvision.datasets import MNIST
import torchvision.transforms as transforms
import torch
import torch.nn.functional as F
from test_tube import HyperOptArgumentParser
from torch import optim
from torch.utils.data import DataLoader
from torch.utils.data.distributed import DistributedSampler
from pytorch_lightning.root_module.root_module import LightningModule
import pytorch_lightning as ptl
class LightningTestModel(LightningModule):
"""
Sample model to show how to define a template
"""
def __init__(self, hparams, force_remove_distributed_sampler=False):
"""
Pass in parsed HyperOptArgumentParser to the model
:param hparams:
"""
# init superclass
super(LightningTestModel, self).__init__()
self.hparams = hparams
self.batch_size = hparams.batch_size
# if you specify an example input, the summary will show input/output for each layer
self.example_input_array = torch.rand(5, 28 * 28)
# remove to test warning for dist sampler
self.force_remove_distributed_sampler = force_remove_distributed_sampler
# build model
self.__build_model()
# ---------------------
# MODEL SETUP
# ---------------------
def __build_model(self):
"""
Layout model
:return:
"""
self.c_d1 = nn.Linear(in_features=self.hparams.in_features, out_features=self.hparams.hidden_dim)
self.c_d1_bn = nn.BatchNorm1d(self.hparams.hidden_dim)
self.c_d1_drop = nn.Dropout(self.hparams.drop_prob)
self.c_d2 = nn.Linear(in_features=self.hparams.hidden_dim, out_features=self.hparams.out_features)
# ---------------------
# TRAINING
# ---------------------
def forward(self, x):
"""
No special modification required for lightning, define as you normally would
:param x:
:return:
"""
x = self.c_d1(x)
x = torch.tanh(x)
x = self.c_d1_bn(x)
x = self.c_d1_drop(x)
x = self.c_d2(x)
logits = F.log_softmax(x, dim=1)
return logits
def loss(self, labels, logits):
nll = F.nll_loss(logits, labels)
return nll
def training_step(self, data_batch, batch_i):
"""
Lightning calls this inside the training loop
:param data_batch:
:return:
"""
# forward pass
x, y = data_batch
x = x.view(x.size(0), -1)
y_hat = self.forward(x)
# calculate loss
loss_val = self.loss(y, y_hat)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
output = OrderedDict({
'loss': loss_val
})
# can also return just a scalar instead of a dict (return loss_val)
return output
def validation_step(self, data_batch, batch_i):
"""
Lightning calls this inside the validation loop
:param data_batch:
:return:
"""
x, y = data_batch
x = x.view(x.size(0), -1)
y_hat = self.forward(x)
loss_val = self.loss(y, y_hat)
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
if self.on_gpu:
val_acc = val_acc.cuda(loss_val.device.index)
# in DP mode (default) make sure if result is scalar, there's another dim in the beginning
if self.trainer.use_dp:
loss_val = loss_val.unsqueeze(0)
val_acc = val_acc.unsqueeze(0)
# alternate possible outputs to test
if self.trainer.batch_nb % 1 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
})
return output
if self.trainer.batch_nb % 2 == 0:
return val_acc
if self.trainer.batch_nb % 3 == 0:
output = OrderedDict({
'val_loss': loss_val,
'val_acc': val_acc,
'test_dic': {'val_loss_a': loss_val}
})
return output
def validation_end(self, outputs):
"""
Called at the end of validation to aggregate outputs
:param outputs: list of individual outputs of each validation step
:return:
"""
# if returned a scalar from validation_step, outputs is a list of tensor scalars
# we return just the average in this case (if we want)
# return torch.stack(outputs).mean()
val_loss_mean = 0
val_acc_mean = 0
for output in outputs:
val_loss_mean += output['val_loss']
val_acc_mean += output['val_acc']
val_loss_mean /= len(outputs)
val_acc_mean /= len(outputs)
tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
return tqdm_dic
def on_tng_metrics(self, logs):
logs['some_tensor_to_test'] = torch.rand(1)
# ---------------------
# TRAINING SETUP
# ---------------------
def configure_optimizers(self):
"""
return whatever optimizers we want here
:return: list of optimizers
"""
optimizer = optim.Adam(self.parameters(), lr=self.hparams.learning_rate)
return [optimizer]
def __dataloader(self, train):
# init data generators
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
dataset = MNIST(root=self.hparams.data_root, train=train, transform=transform, download=True)
# when using multi-node we need to add the datasampler
train_sampler = None
batch_size = self.hparams.batch_size
try:
if self.on_gpu and not self.force_remove_distributed_sampler:
train_sampler = DistributedSampler(dataset, rank=self.trainer.proc_rank)
batch_size = batch_size // self.trainer.world_size # scale batch size
except Exception as e:
pass
should_shuffle = train_sampler is None
loader = DataLoader(
dataset=dataset,
batch_size=batch_size,
shuffle=should_shuffle,
sampler=train_sampler
)
return loader
@ptl.data_loader
def tng_dataloader(self):
return self.__dataloader(train=True)
@ptl.data_loader
def val_dataloader(self):
return self.__dataloader(train=False)
@ptl.data_loader
def test_dataloader(self):
return self.__dataloader(train=False)
@staticmethod
def add_model_specific_args(parent_parser, root_dir):
"""
Parameters you define here will be available to your model through self.hparams
:param parent_parser:
:param root_dir:
:return:
"""
parser = HyperOptArgumentParser(strategy=parent_parser.strategy, parents=[parent_parser])
# param overwrites
# parser.set_defaults(gradient_clip=5.0)
# network params
parser.opt_list('--drop_prob', default=0.2, options=[0.2, 0.5], type=float, tunable=False)
parser.add_argument('--in_features', default=28*28, type=int)
parser.add_argument('--out_features', default=10, type=int)
parser.add_argument('--hidden_dim', default=50000, type=int) # use 500 for CPU, 50000 for GPU to see speed difference
# data
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
# training params (opt)
parser.opt_list('--learning_rate', default=0.001*8, type=float, options=[0.0001, 0.0005, 0.001, 0.005],
tunable=False)
parser.opt_list('--optimizer_name', default='adam', type=str, options=['adam'], tunable=False)
# if using 2 nodes with 4 gpus each the batch size here (256) will be 256 / (2*8) = 16 per gpu
parser.opt_list('--batch_size', default=256*8, type=int, options=[32, 64, 128, 256], tunable=False,
help='batch size will be divided over all the gpus being used across all nodes')
return parser
-4
View File
@@ -52,10 +52,6 @@ def main(hparams, cluster, results_dict):
hparams.__setattr__('nb_gpus', torch.cuda.device_count()) hparams.__setattr__('nb_gpus', torch.cuda.device_count())
hparams.__setattr__('inference_mode', hparams.model_load_weights_path is not None) hparams.__setattr__('inference_mode', hparams.model_load_weights_path is not None)
# delay each training start to not overwrite logs
process_position, current_gpu = TRAINING_MODEL.get_process_position(hparams.gpus)
sleep(process_position + 1)
# init experiment # init experiment
exp = Experiment( exp = Experiment(
name=hparams.tt_name, name=hparams.tt_name,
+5
View File
@@ -0,0 +1,5 @@
import pdb
import sys
class MisconfigurationException(Exception):
pass
-104
View File
@@ -1,104 +0,0 @@
import torch
import numpy as np
from copy import deepcopy
class PretrainedEmbedding(torch.nn.Embedding):
def __init__(self, embedding_path, embedding_dim, task_vocab, freeze=True, *args, **kwargs):
"""
Loads a prebuilt pytorch embedding from any embedding formated file.
Padding=0 by default.
>>> emb = PretrainedEmbedding(embedding_path='glove.840B.300d.txt',embedding_dim=300, task_vocab={'hello': 1, 'world': 2})
>>> data = torch.Tensor([[0, 1], [0, 2]]).long()
>>> embedded = emb(data)
:param embedding_path:
:param emb_dim:
:param task_vocab:
:param freeze:
:return:
"""
# count the vocab
self.vocab_size = max(task_vocab.values()) + 1
super(PretrainedEmbedding, self).__init__(self.vocab_size, embedding_dim, padding_idx=0, *args, **kwargs)
# load pretrained embeddings
new_emb = self.__load_task_specific_embeddings(deepcopy(task_vocab), embedding_path, embedding_dim, freeze)
# transfer weights
self.weight = new_emb.weight
# apply freeze
should_freeze = not freeze
self.weight.requires_grad = should_freeze
def __load_task_specific_embeddings(self, vocab_words, embedding_path, emb_dim, freeze):
"""
Iterates embedding file to only pull out task specific embeddings
:param vocab_words:
:param embedding_path:
:param emb_dim:
:param freeze:
:return:
"""
# holds final embeddings for relevant words
embeddings = np.zeros(shape=(self.vocab_size, emb_dim))
# load embedding line by line and extract relevant embeddings
with open(embedding_path, encoding='utf-8') as f:
for line in f:
tokens = line.split(' ')
word = tokens[0]
embedding = tokens[1:]
embedding[-1] = embedding[-1][:-1] # remove last new line
if word in vocab_words:
vocab_word_i = vocab_words[word]
# skip words that try to overwrite pad idx
if vocab_word_i == 0:
del vocab_words[word]
continue
emb_vals = np.asarray([float(x) for x in embedding])
embeddings[vocab_word_i] = emb_vals
# remove vocab word to early terminate
del vocab_words[word]
# early break
if len(vocab_words) == 0:
break
# add random vectors for the non-pretrained words
# these are vocab words NOT found in the pretrained embeddings
for w, i in vocab_words.items():
# skip words that try to overwrite pad idx
if i == 0:
continue
embedding = np.random.normal(size=emb_dim)
embeddings[i] = embedding
# turn into pt embedding
embeddings = torch.FloatTensor(embeddings)
embeddings = torch.nn.Embedding.from_pretrained(embeddings, freeze=freeze)
return embeddings
if __name__ == '__main__':
emb = PretrainedEmbedding(
embedding_path='/Users/waf/Developer',
embedding_dim=300,
task_vocab={'hello': 1, 'world': 2}
)
data = torch.Tensor([[0, 1], [0, 2]]).long()
embedded = emb(data)
print(embedded)
-28
View File
@@ -1,28 +0,0 @@
from matplotlib import pyplot as plt
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
def plot_confusion_matrix(cm,
save_path,
normalize=False,
title='Confusion matrix',
ylabel='y',
xlabel='x'):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print("Normalized confusion matrix")
else:
print('Confusion matrix, without normalization')
fig = plt.figure()
plt.matshow(cm)
plt.title(title)
plt.colorbar()
plt.ylabel(ylabel)
plt.xlabel(xlabel)
plt.savefig(save_path)
+6 -32
View File
@@ -1,35 +1,9 @@
coverage==4.5.3
atomicwrites==1.2.1 mkdocs==1.0.4
attrs==18.2.0 pytest==5.0.1
certifi==2018.11.29
cffi==1.11.5
imageio==2.4.1
mkl-fft==1.0.6
mkl-random==1.0.2
more-itertools==5.0.0
numpy==1.15.4
olefile==0.46
pandas==0.23.4
Pillow==5.3.0
pluggy==0.8.0
py==1.7.0
pycparser==2.19
pytest==4.0.2
python-dateutil==2.7.5
pytz==2018.7
scikit-learn==0.20.2 scikit-learn==0.20.2
scipy==1.2.0
six==1.12.0
sklearn==0.0
tensorboard==1.14.0
tensorboardX==1.7
tensorflow==1.14.0
test-tube==0.643
torch==1.0.0
torchvision==0.2.1
tqdm==4.32.1 tqdm==4.32.1
twine==1.13.0 twine==1.13.0
urllib3==1.25.3 numpy==1.16.4
webencodings==0.5.1 torch>=1.1.0
Werkzeug==0.15.4 torchvision==0.3.0
wrapt==1.11.2
+27
View File
@@ -16,6 +16,33 @@ markers =
ignore = E731,W504 ignore = E731,W504
max-line-length = 120 max-line-length = 120
[coverage:report]
exclude_lines =
pragma: no cover
def __repr__
if self.debug:
if settings.DEBUG
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:
except Exception as e
print(e)
print(traceback.print_exc())
return *
raise Exception
warnings
print
raise RuntimeError
break
pass
os.makedirs
omit =
pytorch_lightning/callbacks/pt_callbacks.py
tests/test_models.py
pytorch_lightning/testing_models/lm_test_module.py
[flake8] [flake8]
ignore = E731,W504,F401,F841 ignore = E731,W504,F401,F841
max-line-length = 120 max-line-length = 120
+2 -3
View File
@@ -7,7 +7,7 @@ from setuptools import setup, find_packages
# http://blog.ionelmc.ro/2014/05/25/python-packaging/ # http://blog.ionelmc.ro/2014/05/25/python-packaging/
setup( setup(
name="pytorch-lightning", name="pytorch-lightning",
version='0.2', version='0.3.6.4',
description="The Keras for ML researchers using PyTorch", description="The Keras for ML researchers using PyTorch",
author="William Falcon", author="William Falcon",
author_email="waf2107@columbia.edu", author_email="waf2107@columbia.edu",
@@ -19,8 +19,7 @@ setup(
install_requires=[ install_requires=[
"torch>=1.1.0", "torch>=1.1.0",
"tqdm", "tqdm",
"test-tube>=0.653", "test-tube>=0.6.7.4",
"tensorflow>=1.14.0"
], ],
packages=find_packages(), packages=find_packages(),
long_description=open("README.md", encoding="utf-8").read(), long_description=open("README.md", encoding="utf-8").read(),
+58
View File
@@ -0,0 +1,58 @@
# Pytorch-Lightning Tests
## Running tests
The automatic travis tests ONLY run CPU-based tests. Although these cover most of the use cases,
run on a 2-GPU machine to validate the full test-suite.
To run all tests do the following:
```bash
git clone https://github.com/williamFalcon/pytorch-lightning
cd pytorch-lightning
# install module locally
pip install -e .
# install dev deps
pip install -r requirements.txt
# run tests
py.test
```
To test models that require GPU make sure to run the above command on a GPU machine.
The GPU machine must have:
1. At least 2 GPUs.
2. [NVIDIA-apex](https://github.com/NVIDIA/apex#linux) installed.
### test_models.py
This file fits a tiny model on MNIST using these different set-ups.
1. CPU only.
2. Single GPU with DP.
3. Multiple (2) GPUs using DP.
3. Multiple (2) GPUs using DDP.
3. Multiple (2) GPUs using DP + apex (for 16-bit precision).
3. Multiple (2) GPUs using DDP + apex (for 16-bit precision).
For each set up it also tests:
1. model saving.
2. model loading.
3. predicting with a loaded model.
4. simulated save from HPC signal.
5. simulated load from HPC signal.
## Running Coverage
```bash
cd pytorch-lightning
# generate coverage
pip install coverage
coverage run tests/test_models.py
# print coverage stats
coverage report -m
```
View File
+180
View File
@@ -0,0 +1,180 @@
import pytest
from pytorch_lightning import Trainer
from pytorch_lightning.examples.new_project_templates.lightning_module_template import LightningTemplateModel
from argparse import Namespace
from test_tube import Experiment
from pytorch_lightning.callbacks import ModelCheckpoint
import numpy as np
import warnings
import torch
import os
import shutil
import pdb
import pytorch_lightning as ptl
import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
class CoolModel(ptl.LightningModule):
def __init(self):
super(CoolModel, self).__init__()
# not the best model...
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x))
def my_loss(self, y_hat, y):
return F.cross_entropy(y_hat, y)
def training_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'tng_loss': self.my_loss(y_hat, y)}
def validation_step(self, batch, batch_nb):
x, y = batch
y_hat = self.forward(x)
return {'val_loss': self.my_loss(y_hat, y)}
def validation_end(self, outputs):
avg_loss = torch.stack([x for x in outputs['val_loss']]).mean()
return avg_loss
def configure_optimizers(self):
return [torch.optim.Adam(self.parameters(), lr=0.02)]
@ptl.data_loader
def tng_dataloader(self):
return DataLoader(MNIST('path/to/save', train=True), batch_size=32)
@ptl.data_loader
def val_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
@ptl.data_loader
def test_dataloader(self):
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
def get_model():
# set up model with these hyperparams
root_dir = os.path.dirname(os.path.realpath(__file__))
hparams = Namespace(**{'drop_prob': 0.2,
'batch_size': 32,
'in_features': 28*28,
'learning_rate': 0.001*8,
'optimizer_name': 'adam',
'data_root': os.path.join(root_dir, 'mnist'),
'out_features': 10,
'hidden_dim': 1000})
model = LightningTemplateModel(hparams)
return model, hparams
def get_exp(debug=True):
# set up exp object without actually saving logs
root_dir = os.path.dirname(os.path.realpath(__file__))
exp = Experiment(debug=debug, save_dir=root_dir, name='tests_tt_dir')
return exp
def init_save_dir():
root_dir = os.path.dirname(os.path.realpath(__file__))
save_dir = os.path.join(root_dir, 'save_dir')
if os.path.exists(save_dir):
shutil.rmtree(save_dir)
os.makedirs(save_dir, exist_ok=True)
return save_dir
def clear_save_dir():
root_dir = os.path.dirname(os.path.realpath(__file__))
save_dir = os.path.join(root_dir, 'save_dir')
if os.path.exists(save_dir):
shutil.rmtree(save_dir)
def load_model(exp, save_dir):
# load trained model
tags_path = exp.get_data_path(exp.name, exp.version)
tags_path = os.path.join(tags_path, 'meta_tags.csv')
checkpoints = [x for x in os.listdir(save_dir) if '.ckpt' in x]
weights_dir = os.path.join(save_dir, checkpoints[0])
trained_model = LightningTemplateModel.load_from_metrics(weights_path=weights_dir, tags_csv=tags_path, on_gpu=True)
assert trained_model is not None, 'loading model failed'
return trained_model
def run_prediction(dataloader, trained_model):
# run prediction on 1 batch
for batch in dataloader:
break
x, y = batch
x = x.view(x.size(0), -1)
y_hat = trained_model(x)
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
val_acc = val_acc.item()
print(val_acc)
assert val_acc > 0.70, f'this model is expected to get > 0.7 in test set (it got {val_acc})'
def main():
save_dir = init_save_dir()
# exp file to get meta
exp = get_exp(False)
exp.save()
# exp file to get weights
checkpoint = ModelCheckpoint(save_dir)
trainer = Trainer(
experiment=exp,
checkpoint_callback=checkpoint,
progress_bar=True,
max_nb_epochs=1,
gpus=[0, 1],
distributed_backend='dp',
)
model = CoolModel()
result = trainer.fit(model)
# correct result and ok accuracy
assert result == 1, 'amp + ddp model failed to complete'
# test model loading
pretrained_model = load_model(exp, save_dir)
# test model preds
run_prediction(model.test_dataloader, pretrained_model)
clear_save_dir()
if __name__ == '__main__':
main()
+688
View File
@@ -0,0 +1,688 @@
import pytest
from pytorch_lightning import Trainer
from pytorch_lightning.examples.new_project_templates.lightning_module_template import LightningTemplateModel
from pytorch_lightning.testing_models.lm_test_module import LightningTestModel
from argparse import Namespace
from test_tube import Experiment, SlurmCluster
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping
from pytorch_lightning.utils.debugging import MisconfigurationException
from pytorch_lightning.root_module import memory
from pytorch_lightning.models.trainer import reduce_distributed_output
from pytorch_lightning.root_module import model_saving
import numpy as np
import warnings
import torch
import os
import shutil
import pdb
SEED = 2334
torch.manual_seed(SEED)
np.random.seed(SEED)
# ------------------------------------------------------------------------
# TESTS
# ------------------------------------------------------------------------
def test_cpu_slurm_save_load():
"""
Verify model save/load/checkpoint on CPU
:return:
"""
hparams = get_hparams()
model = LightningTestModel(hparams)
save_dir = init_save_dir()
# exp file to get meta
exp = get_exp(False)
exp.argparse(hparams)
exp.save()
cluster_a = SlurmCluster()
trainer_options = dict(
max_nb_epochs=1,
cluster=cluster_a,
experiment=exp,
checkpoint_callback=ModelCheckpoint(save_dir)
)
# fit model
trainer = Trainer(**trainer_options)
result = trainer.fit(model)
real_global_step = trainer.global_step
# traning complete
assert result == 1, 'amp + ddp model failed to complete'
# predict with trained model before saving
# make a prediction
for batch in model.test_dataloader:
break
x, y = batch
x = x.view(x.size(0), -1)
model.eval()
pred_before_saving = model(x)
# test registering a save function
trainer.enable_auto_hpc_walltime_manager()
# test HPC saving
# simulate snapshot on slurm
saved_filepath = trainer.hpc_save(save_dir, exp)
assert os.path.exists(saved_filepath)
# wipe-out trainer and model
# retrain with not much data... this simulates picking training back up after slurm
# we want to see if the weights come back correctly
continue_tng_hparams = get_hparams(continue_training=True, hpc_exp_number=cluster_a.hpc_exp_number)
trainer_options = dict(
max_nb_epochs=1,
cluster=SlurmCluster(continue_tng_hparams),
experiment=exp,
checkpoint_callback=ModelCheckpoint(save_dir),
)
trainer = Trainer(**trainer_options)
model = LightningTestModel(hparams)
# set the epoch start hook so we can predict before the model does the full training
def assert_pred_same():
assert trainer.global_step == real_global_step and trainer.global_step > 0
# predict with loaded model to make sure answers are the same
trainer.model.eval()
new_pred = trainer.model(x)
assert torch.all(torch.eq(pred_before_saving, new_pred)).item() == 1
model.on_epoch_start = assert_pred_same
# by calling fit again, we trigger training, loading weights from the cluster
# and our hook to predict using current model before any more weight updates
trainer.fit(model)
clear_save_dir()
def test_loading_meta_tags():
hparams = get_hparams()
save_dir = init_save_dir()
# save tags
exp = get_exp(False)
exp.tag({'some_str':'a_str', 'an_int': 1, 'a_float': 2.0})
exp.argparse(hparams)
exp.save()
# load tags
tags_path = exp.get_data_path(exp.name, exp.version) + '/meta_tags.csv'
tags = model_saving.load_hparams_from_tags_csv(tags_path)
assert tags.batch_size == 32 and tags.hidden_dim == 1000
clear_save_dir()
def test_dp_output_reduce():
# test identity when we have a single gpu
out = torch.rand(3, 1)
assert reduce_distributed_output(out, nb_gpus=1) is out
# average when we have multiples
assert reduce_distributed_output(out, nb_gpus=2) == out.mean()
# when we have a dict of vals
out = {
'a': out,
'b': {
'c': out
}
}
reduced = reduce_distributed_output(out, nb_gpus=3)
assert reduced['a'] == out['a']
assert reduced['b']['c'] == out['b']['c']
def test_model_saving_loading():
"""
Tests use case where trainer saves the model, and user loads it from tags independently
:return:
"""
hparams = get_hparams()
model = LightningTestModel(hparams)
save_dir = init_save_dir()
# exp file to get meta
exp = get_exp(False)
exp.argparse(hparams)
exp.save()
trainer_options = dict(
max_nb_epochs=1,
cluster=SlurmCluster(),
experiment=exp,
checkpoint_callback=ModelCheckpoint(save_dir)
)
# fit model
trainer = Trainer(**trainer_options)
result = trainer.fit(model)
# traning complete
assert result == 1, 'amp + ddp model failed to complete'
# make a prediction
for batch in model.test_dataloader:
break
x, y = batch
x = x.view(x.size(0), -1)
# generate preds before saving model
model.eval()
pred_before_saving = model(x)
# save model
new_weights_path = os.path.join(save_dir, 'save_test.ckpt')
trainer.save_checkpoint(new_weights_path)
# load new model
tags_path = exp.get_data_path(exp.name, exp.version)
tags_path = os.path.join(tags_path, 'meta_tags.csv')
model_2 = LightningTestModel.load_from_metrics(weights_path=new_weights_path, tags_csv=tags_path, on_gpu=False)
model_2.eval()
# make prediction
# assert that both predictions are the same
new_pred = model_2(x)
assert torch.all(torch.eq(pred_before_saving, new_pred)).item() == 1
clear_save_dir()
def test_model_freeze_unfreeze():
hparams = get_hparams()
model = LightningTestModel(hparams)
model.freeze()
model.unfreeze()
def test_amp_gpu_ddp_slurm_managed():
"""
Make sure DDP + AMP work
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
# simulate setting slurm flags
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
os.environ['SLURM_LOCALID'] = str(0)
hparams = get_hparams()
model = LightningTestModel(hparams)
trainer_options = dict(
progress_bar=True,
max_nb_epochs=1,
gpus=[0],
distributed_backend='ddp',
use_amp=True
)
save_dir = init_save_dir()
# exp file to get meta
exp = get_exp(False)
exp.argparse(hparams)
exp.save()
# exp file to get weights
checkpoint = ModelCheckpoint(save_dir)
# add these to the trainer options
trainer_options['checkpoint_callback'] = checkpoint
trainer_options['experiment'] = exp
# fit model
trainer = Trainer(**trainer_options)
trainer.is_slurm_managing_tasks = True
result = trainer.fit(model)
# correct result and ok accuracy
assert result == 1, 'amp + ddp model failed to complete'
# test root model address
assert trainer.resolve_root_node_address('abc') == 'abc'
assert trainer.resolve_root_node_address('abc[23]') == 'abc23'
assert trainer.resolve_root_node_address('abc[23-24]') == 'abc23'
assert trainer.resolve_root_node_address('abc[23-24, 45-40, 40]') == 'abc23'
# test model loading with a map_location
map_location = 'cuda:1'
pretrained_model = load_model(exp, save_dir, True, map_location)
# test model preds
run_prediction(model.test_dataloader, pretrained_model)
if trainer.use_ddp:
# on hpc this would work fine... but need to hack it for the purpose of the test
trainer.model = pretrained_model
trainer.optimizers = pretrained_model.configure_optimizers()
# test HPC loading / saving
trainer.hpc_save(save_dir, exp)
trainer.hpc_load(save_dir, on_gpu=True)
# test freeze on gpu
model.freeze()
model.unfreeze()
clear_save_dir()
def test_early_stopping_cpu_model():
"""
Test each of the trainer options
:return:
"""
stopping = EarlyStopping()
trainer_options = dict(
early_stop_callback=stopping,
gradient_clip=1.0,
overfit_pct=0.20,
track_grad_norm=2,
print_nan_grads=True,
progress_bar=False,
experiment=get_exp(),
train_percent_check=0.1,
val_percent_check=0.1
)
model, hparams = get_model()
run_gpu_model_test(trainer_options, model, hparams, on_gpu=False)
# test freeze on cpu
model.freeze()
model.unfreeze()
def test_cpu_model_with_amp():
"""
Make sure model trains on CPU
:return:
"""
trainer_options = dict(
progress_bar=False,
experiment=get_exp(),
max_nb_epochs=1,
train_percent_check=0.4,
val_percent_check=0.4,
use_amp=True
)
model, hparams = get_model()
with pytest.raises((MisconfigurationException, ModuleNotFoundError)):
run_gpu_model_test(trainer_options, model, hparams, on_gpu=False)
def test_cpu_model():
"""
Make sure model trains on CPU
:return:
"""
trainer_options = dict(
progress_bar=False,
experiment=get_exp(),
max_nb_epochs=1,
train_percent_check=0.4,
val_percent_check=0.4
)
model, hparams = get_model()
run_gpu_model_test(trainer_options, model, hparams, on_gpu=False)
def test_all_features_cpu_model():
"""
Test each of the trainer options
:return:
"""
trainer_options = dict(
gradient_clip=1.0,
overfit_pct=0.20,
track_grad_norm=2,
print_nan_grads=True,
progress_bar=False,
experiment=get_exp(),
max_nb_epochs=1,
train_percent_check=0.4,
val_percent_check=0.4
)
model, hparams = get_model()
run_gpu_model_test(trainer_options, model, hparams, on_gpu=False)
def test_single_gpu_model():
"""
Make sure single GPU works (DP mode)
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_single_gpu_model cannot run. Rerun on a GPU node to run this test')
return
model, hparams = get_model()
trainer_options = dict(
progress_bar=False,
max_nb_epochs=1,
train_percent_check=0.1,
val_percent_check=0.1,
gpus=[0]
)
run_gpu_model_test(trainer_options, model, hparams)
def test_multi_gpu_model_dp():
"""
Make sure DP works
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_multi_gpu_model_dp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_multi_gpu_model_dp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
model, hparams = get_model()
trainer_options = dict(
progress_bar=False,
max_nb_epochs=1,
train_percent_check=0.1,
val_percent_check=0.1,
gpus='-1'
)
run_gpu_model_test(trainer_options, model, hparams)
# test memory helper functions
memory.get_gpu_memory_map()
def test_amp_gpu_dp():
"""
Make sure DP + AMP work
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_amp_gpu_dp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_amp_gpu_dp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
model, hparams = get_model()
trainer_options = dict(
max_nb_epochs=1,
gpus='0, 1', # test init with gpu string
distributed_backend='dp',
use_amp=True
)
with pytest.raises(MisconfigurationException):
run_gpu_model_test(trainer_options, model, hparams)
def test_multi_gpu_model_ddp():
"""
Make sure DDP works
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_multi_gpu_model_ddp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_multi_gpu_model_ddp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
model, hparams = get_model()
trainer_options = dict(
progress_bar=False,
max_nb_epochs=1,
train_percent_check=0.4,
val_percent_check=0.2,
gpus=[0, 1],
distributed_backend='ddp'
)
run_gpu_model_test(trainer_options, model, hparams)
def test_amp_gpu_ddp():
"""
Make sure DDP + AMP work
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
hparams = get_hparams()
model = LightningTestModel(hparams)
trainer_options = dict(
progress_bar=True,
max_nb_epochs=1,
gpus=[0, 1],
distributed_backend='ddp',
use_amp=True
)
run_gpu_model_test(trainer_options, model, hparams)
def test_ddp_sampler_error():
"""
Make sure DDP + AMP work
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a node with 2+ GPUs to run this test')
return
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
hparams = get_hparams()
model = LightningTestModel(hparams, force_remove_distributed_sampler=True)
exp = get_exp(True)
exp.save()
trainer = Trainer(
experiment=exp,
progress_bar=False,
max_nb_epochs=1,
gpus=[0, 1],
distributed_backend='ddp',
use_amp=True
)
with pytest.raises(MisconfigurationException):
trainer.get_dataloaders(model)
clear_save_dir()
# ------------------------------------------------------------------------
# UTILS
# ------------------------------------------------------------------------
def run_gpu_model_test(trainer_options, model, hparams, on_gpu=True):
save_dir = init_save_dir()
# exp file to get meta
exp = get_exp(False)
exp.argparse(hparams)
exp.save()
# exp file to get weights
checkpoint = ModelCheckpoint(save_dir)
# add these to the trainer options
trainer_options['checkpoint_callback'] = checkpoint
trainer_options['experiment'] = exp
# fit model
trainer = Trainer(**trainer_options)
result = trainer.fit(model)
# correct result and ok accuracy
assert result == 1, 'amp + ddp model failed to complete'
# test model loading
pretrained_model = load_model(exp, save_dir, on_gpu)
# test model preds
run_prediction(model.test_dataloader, pretrained_model)
if trainer.use_ddp:
# on hpc this would work fine... but need to hack it for the purpose of the test
trainer.model = pretrained_model
trainer.optimizers = pretrained_model.configure_optimizers()
# test HPC loading / saving
trainer.hpc_save(save_dir, exp)
trainer.hpc_load(save_dir, on_gpu=on_gpu)
clear_save_dir()
def get_hparams(continue_training=False, hpc_exp_number=0):
root_dir = os.path.dirname(os.path.realpath(__file__))
args = {
'drop_prob': 0.2,
'batch_size': 32,
'in_features': 28*28,
'learning_rate': 0.001*8,
'optimizer_name': 'adam',
'data_root': os.path.join(root_dir, 'mnist'),
'out_features': 10,
'hidden_dim': 1000}
if continue_training:
args['test_tube_do_checkpoint_load'] = True
args['hpc_exp_number'] = hpc_exp_number
hparams = Namespace(**args)
return hparams
def get_model():
# set up model with these hyperparams
hparams = get_hparams()
model = LightningTemplateModel(hparams)
return model, hparams
def get_exp(debug=True):
# set up exp object without actually saving logs
root_dir = os.path.dirname(os.path.realpath(__file__))
exp = Experiment(debug=debug, save_dir=root_dir, name='tests_tt_dir')
return exp
def init_save_dir():
root_dir = os.path.dirname(os.path.realpath(__file__))
save_dir = os.path.join(root_dir, 'save_dir')
if os.path.exists(save_dir):
shutil.rmtree(save_dir)
os.makedirs(save_dir, exist_ok=True)
return save_dir
def clear_save_dir():
root_dir = os.path.dirname(os.path.realpath(__file__))
save_dir = os.path.join(root_dir, 'save_dir')
if os.path.exists(save_dir):
shutil.rmtree(save_dir)
def load_model(exp, save_dir, on_gpu, map_location=None):
# load trained model
tags_path = exp.get_data_path(exp.name, exp.version)
tags_path = os.path.join(tags_path, 'meta_tags.csv')
checkpoints = [x for x in os.listdir(save_dir) if '.ckpt' in x]
weights_dir = os.path.join(save_dir, checkpoints[0])
trained_model = LightningTemplateModel.load_from_metrics(weights_path=weights_dir,
tags_csv=tags_path,
on_gpu=on_gpu,
map_location=map_location)
assert trained_model is not None, 'loading model failed'
return trained_model
def run_prediction(dataloader, trained_model):
# run prediction on 1 batch
for batch in dataloader:
break
x, y = batch
x = x.view(x.size(0), -1)
y_hat = trained_model(x)
# acc
labels_hat = torch.argmax(y_hat, dim=1)
val_acc = torch.sum(y == labels_hat).item() / (len(y) * 1.0)
val_acc = torch.tensor(val_acc)
val_acc = val_acc.item()
print(val_acc)
assert val_acc > 0.50, f'this model is expected to get > 0.50 in test set (it got {val_acc})'
def assert_ok_acc(trainer):
# this model should get 0.80+ acc
acc = trainer.tng_tqdm_dic['val_acc']
assert acc > 0.50, f'model failed to get expected 0.50 validation accuracy. Got: {acc}'
if __name__ == '__main__':
pytest.main([__file__])