Compare commits

...
442 Commits
Author SHA1 Message Date
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
41 changed files with 1876 additions and 408 deletions
+2 -1
View File
@@ -9,6 +9,7 @@ model_weights/
app/models/
pip-wheel-metadata/
test_tube_exp/
tests/tests_tt_dir/
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -119,4 +120,4 @@ ENV/
.mypy_cache/
# 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
+6 -4
View File
@@ -11,12 +11,14 @@
</p>
<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://travis-ci.org/williamFalcon/test-tube"><img src="https://travis-ci.org/williamFalcon/pytorch-lightning.svg?branch=master"></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>
</p>
```bash
pip install pytorch-lightning
pip install pytorch-lightning
```
## Docs
@@ -116,8 +118,8 @@ def validation_end(self, outputs):
return tqdm_dic
```
## TensorboardX
Lightning is fully integrated with tensorboardX.
## Tensorboard
Lightning is fully integrated with tensorboard.
<p align="center">
<a href="https://williamfalcon.github.io/pytorch-lightning/">
+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

@@ -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.
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:
+78 -5
View File
@@ -3,6 +3,26 @@ Lightning makes multi-gpu training and 16 bit training trivial.
*Note:*
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 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.
```python
# set these flags
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
# lightning sets these flags for you automatically
# 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
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
+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)
# 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
@@ -1 +0,0 @@
from .lightning_module_template import LightningTemplateModel
+1
View File
@@ -0,0 +1 @@
from .new_project_templates.lightning_module_template import LightningTemplateModel
@@ -28,6 +28,9 @@ class LightningTemplateModel(LightningModule):
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
self.__build_model()
@@ -78,15 +81,21 @@ class LightningTemplateModel(LightningModule):
# 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,
'tqdm_metrics': {}
'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):
@@ -104,11 +113,22 @@ class LightningTemplateModel(LightningModule):
# 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)
output = OrderedDict({
'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
def validation_end(self, outputs):
@@ -117,6 +137,10 @@ class LightningTemplateModel(LightningModule):
: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:
@@ -128,9 +152,6 @@ class LightningTemplateModel(LightningModule):
tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
return tqdm_dic
def update_tng_log_metrics(self, logs):
return logs
# ---------------------
# MODEL SAVING
# ---------------------
@@ -210,7 +231,7 @@ class LightningTemplateModel(LightningModule):
return self._test_dataloader
@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
: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)
+322 -118
View File
@@ -1,11 +1,12 @@
"""
The trainer handles all the logic for running a val loop, training loop, distributing, etc...
"""
from time import sleep
import subprocess
import traceback
import warnings
import os
import pdb
import re
import torch
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.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:
from apex import amp
APEX_AVAILABLE = True
except ModuleNotFoundError:
except ModuleNotFoundError: # pragma: no cover
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):
def __init__(self,
experiment,
checkpoint_callback, early_stop_callback,
early_stop_callback=None,
checkpoint_callback=None,
gradient_clip=0,
cluster=None,
process_position=0,
@@ -44,20 +67,58 @@ class Trainer(TrainerIO):
check_val_every_n_epoch=1,
fast_dev_run=False,
accumulate_grad_batches=1,
enable_early_stop=True, 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,
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,
log_save_interval=100, add_log_row_interval=10,
lr_scheduler_milestones=None,
distributed_backend='dp',
use_amp=False,
print_nan_grads=False,
print_weights_summary=True,
amp_level='O2',
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
self.nb_gpu_nodes = nb_gpu_nodes
self.gradient_clip = gradient_clip
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.fast_dev_run = fast_dev_run
self.on_gpu = gpus is not None and torch.cuda.is_available()
@@ -67,8 +128,12 @@ class Trainer(TrainerIO):
self.cluster = cluster
self.process_position = process_position
self.current_gpu_name = current_gpu_name
self.print_weights_summary = print_weights_summary
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.model = None
self.max_nb_epochs = max_nb_epochs
@@ -82,21 +147,68 @@ class Trainer(TrainerIO):
self.print_nan_grads = print_nan_grads
self.data_parallel_device_ids = None
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.
# if gpus = -1 then use all available devices
# otherwise, split the string using commas
if gpus is not None:
if gpus == '-1':
self.data_parallel_device_ids = list(range(0, torch.cuda.device_count()))
if type(gpus) is list:
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:
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)
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
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
self.proc_rank = 0
@@ -127,7 +239,7 @@ class Trainer(TrainerIO):
if self.use_amp:
print('using 16bit precision')
if use_amp and not APEX_AVAILABLE:
if use_amp and not APEX_AVAILABLE: # pragma: no cover
msg = '''
You set use_amp=True but do not have apex installed.
Install apex first using this guide and rerun with use_amp=True:
@@ -135,7 +247,11 @@ class Trainer(TrainerIO):
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):
"""
@@ -149,12 +265,17 @@ class Trainer(TrainerIO):
self.val_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):
f_op = getattr(self.model, f_name, None)
model = self.__get_model()
f_op = getattr(model, f_name, None)
return callable(f_op)
@property
def __tng_tqdm_dic(self):
# ForkedPdb().set_trace()
tqdm_dic = {
'tng_loss': '{0:.3f}'.format(self.avg_loss),
'v_nb': '{}'.format(self.experiment.version),
@@ -168,13 +289,15 @@ class Trainer(TrainerIO):
return tqdm_dic
@property
def tng_tqdm_dic(self):
"""
Read-only for tqdm metrics
:return:
"""
return self.__tng_tqdm_dic
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
self.nb_tng_batches = len(self.tng_dataloader)
@@ -208,9 +331,6 @@ class Trainer(TrainerIO):
:param max_batches: Scalar
:return:
"""
if self.proc_rank == 0:
print('validating...')
# enable eval mode
model.zero_grad()
model.eval()
@@ -224,7 +344,7 @@ class Trainer(TrainerIO):
# run training
for batch_i, data_batch in enumerate(dataloader):
if data_batch is None:
if data_batch is None: # pragma: no cover
continue
# stop short when on fast dev run
@@ -234,8 +354,12 @@ class Trainer(TrainerIO):
# -----------------
# RUN VALIDATION STEP
# -----------------
if self.data_parallel:
if self.use_ddp:
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:
output = model.validation_step(data_batch, batch_i)
@@ -259,7 +383,7 @@ class Trainer(TrainerIO):
return val_results
def __get_dataloaders(self, model):
def get_dataloaders(self, model):
"""
Dataloaders are provided by the model
:param model:
@@ -269,7 +393,7 @@ class Trainer(TrainerIO):
self.test_dataloader = model.test_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 = '''
when using multiple gpus and multiple nodes you must pass a DistributedSampler to DataLoader(sampler).
@@ -282,33 +406,73 @@ class Trainer(TrainerIO):
dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset)
dataloader = Dataloader(dataset, sampler=dist_sampler)
'''
raise Exception(msg)
raise MisconfigurationException(msg)
# -----------------------------
# MODEL TRAINING
# -----------------------------
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:
# CHOOSE OPTIMIZER
# filter out the weights that were done on gpu so we can load on good old cpus
self.optimizers = model.configure_optimizers()
# run through amp wrapper
if self.use_amp:
raise MisconfigurationException('amp + cpu is not supported. Please use a GPU option')
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
# filter out the weights that were done on gpu so we can load on good old cpus
self.optimizers = model.configure_optimizers()
# run through amp wrapper
if self.use_amp:
# An example
model, optimizers = amp.initialize(
model, self.optimizers, opt_level=self.amp_level,
)
self.optimizers = optimizers
model.cuda(self.data_parallel_device_ids[0])
# when using gpus, first thing we do is spawn a new process between each worker
# applies to single gpu, multi-gpu and multi-nodes
if self.on_gpu:
self.experiment = self.experiment.get_meta_copy()
mp.spawn(self.dp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
else:
self.__run_pretrain_routine(model)
# check for this bug (amp + dp + !01 doesn't work)
# https://github.com/NVIDIA/apex/issues/227
if self.use_dp and self.use_amp:
m = f'amp level {self.amp_level} with DataParallel is not supported. ' \
f'See this note from NVIDIA for more info: https://github.com/NVIDIA/apex/issues/227. ' \
f'We recommend you switch to ddp if you want to use amp'
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
:param gpu_nb:
@@ -319,75 +483,88 @@ class Trainer(TrainerIO):
# node rank using relative slurm id
# otherwise default to node rank 0
try:
node_rank = int(os.environ['SLURM_NODEID'])
except KeyError as e:
node_rank = 0
node_id = os.environ['SLURM_NODEID']
self.node_rank = int(node_id)
except Exception as e:
self.node_rank = 0
# 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()
# 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
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)
# set up server using proc 0's ip address
ip = self.__get_root_node_ip(self.proc_rank, self.nb_gpu_nodes)
dist.init_process_group("nccl", init_method=f'tcp://{ip}:12001', rank=self.proc_rank, world_size=self.world_size)
# 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
torch.cuda.set_device(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
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.
Proc 0 writes address to a file. Every other process waits until the ip is available before it starts
:param world_gpu_nb: gpu number amongst all the world gpus
:param nb_gpu_nodes:
:param ip_file_dir:
Connect all procs in the world using the env:// init
Use the first node as the root address
:param port:
:param tries:
:return:
"""
# on one node we use localhost
if nb_gpu_nodes == 1:
return '127.0.0.1'
# sets the appropriate port
try:
port = os.environ['MASTER_PORT']
except Exception as e:
port = 12910
os.environ['MASTER_PORT'] = f'{port}'
# where to store ip_table
ip_file_dir = os.path.join(self.cluster.log_path, 'ip_tables')
# figure out the root node addr
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
root_node = self.resolve_root_node_address(root_node)
os.environ['MASTER_ADDR'] = root_node
# the first gpu in the world becomes the host
# this is based on its global rank
# 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)
dist.init_process_group("nccl", rank=self.proc_rank, world_size=self.world_size)
if world_gpu_nb == 0:
# get the proc 0 IP
root_ip = subprocess.run(['hostname', '-I'], stdout=subprocess.PIPE).stdout.decode('utf-8')
root_ip = root_ip.split(' ')[0]
def resolve_root_node_address(self, root_node):
try:
if '[' in root_node:
name = root_node.split('[')[0]
number = root_node.split(',')[0]
if '-' in number:
number = number.split('-')[0]
# save the ip to the file
with open(file=ip_file, mode='w') as f:
f.write(root_ip)
number = re.sub('[^0-9]', '', number)
root_node = name + number
return root_ip
else:
# wait up to 120 seconds until proc 0 writes
# once written, read proc 0's address and use it to configure server
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
except Exception as e:
root_node = '127.0.0.2'
return root_node
def __run_pretrain_routine(self, model):
"""
@@ -396,7 +573,7 @@ class Trainer(TrainerIO):
:return:
"""
ref_model = model
if self.on_gpu:
if self.data_parallel:
ref_model = model.module
ref_model.trainer = self
@@ -405,7 +582,7 @@ class Trainer(TrainerIO):
ref_model.on_gpu = self.on_gpu
# transfer data loaders from model
self.__get_dataloaders(ref_model)
self.get_dataloaders(ref_model)
# init training constants
self.__layout_bookeeping()
@@ -417,7 +594,7 @@ class Trainer(TrainerIO):
self.lr_schedulers.append(scheduler)
# print model summary
if self.proc_rank == 0:
if self.proc_rank == 0 and self.print_weights_summary:
ref_model.summarize()
# give model convenience properties
@@ -432,7 +609,7 @@ class Trainer(TrainerIO):
self.experiment.save()
# enable cluster checkpointing
if self.cluster is not None:
if self.cluster is not None: # pragma: no cover
self.enable_auto_hpc_walltime_manager()
# ---------------------------
@@ -448,12 +625,12 @@ class Trainer(TrainerIO):
for lr_scheduler in self.lr_schedulers:
lr_scheduler.step()
model = self.model.module if self.data_parallel else self.model
model = self.__get_model()
model.current_epoch = epoch_nb
# hook
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()
self.current_epoch = epoch_nb
@@ -468,7 +645,7 @@ class Trainer(TrainerIO):
self.batch_nb = batch_nb
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
# stop when the flag is changed or we've gone past the amount requested in the batches
@@ -500,10 +677,8 @@ class Trainer(TrainerIO):
# count items in memory
# nb_params, nb_tensors = count_mem_items()
if self.data_parallel:
metrics = self.model.module.update_tng_log_metrics(self.__tng_tqdm_dic)
else:
metrics = self.model.update_tng_log_metrics(self.__tng_tqdm_dic)
model = self.__get_model()
metrics = self.__tng_tqdm_dic
# add gpu memory
if self.on_gpu:
@@ -512,11 +687,13 @@ class Trainer(TrainerIO):
# add norms
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)
metrics.update(grad_norm_dic)
if self.__is_function_implemented('on_tng_metrics'):
model.on_tng_metrics(metrics)
# log metrics
scalar_metrics = self.__metrics_to_scalars(metrics, blacklist=self.__log_vals_blacklist())
if self.proc_rank == 0:
@@ -525,7 +702,7 @@ class Trainer(TrainerIO):
# hook
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()
# end epoch early
@@ -534,13 +711,13 @@ class Trainer(TrainerIO):
# hook
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()
# 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)
met_min_epochs = epoch_nb > self.min_nb_epochs
# stop training
stop = should_stop and met_min_epochs
@@ -563,7 +740,7 @@ class Trainer(TrainerIO):
def __log_vals_blacklist(self):
"""avoid logging some vals lightning uses to maintain state"""
blacklist = {'batch_nb', 'v_nb', 'epoch', 'gpu'}
blacklist = {'batch_nb', 'v_nb', 'gpu'}
return blacklist
def __run_tng_batch(self, data_batch, batch_nb):
@@ -572,8 +749,8 @@ class Trainer(TrainerIO):
# hook
if self.__is_function_implemented('on_batch_start'):
model = self.model.module if self.data_parallel else self.model
response = model.on_batch_start(data_batch)
model_ref = self.__get_model()
response = model_ref.on_batch_start(data_batch)
if response == -1:
return -1
@@ -583,13 +760,26 @@ class Trainer(TrainerIO):
# forward pass
# 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)
elif self.use_dp:
output = self.model(data_batch, batch_nb)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
else:
output = self.model.training_step(data_batch, batch_nb)
model_specific_tqdm_metrics_dic = output['tqdm_metrics']
loss = output['loss']
try:
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)
@@ -602,11 +792,17 @@ class Trainer(TrainerIO):
else:
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:
model = self.model.module if self.data_parallel else self.model
model = self.__get_model()
for param in model.parameters():
print(param.grad.float().sum())
# avoid memory leaks
self.batch_loss_value += loss.item()
# gradient update with accumulated gradients
@@ -614,13 +810,18 @@ class Trainer(TrainerIO):
# clip gradients
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)
# update gradients across all optimizers
for optimizer in self.optimizers:
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
optimizer.zero_grad()
@@ -640,7 +841,8 @@ class Trainer(TrainerIO):
# activate batch end hook
if self.__is_function_implemented('on_batch_end'):
self.model.on_batch_end()
model = self.__get_model()
model.on_batch_end()
return 0
@@ -655,7 +857,8 @@ class Trainer(TrainerIO):
try:
# hook
if self.__is_function_implemented('on_pre_performance_check'):
self.model.on_pre_performance_check()
model = self.__get_model()
model.on_pre_performance_check()
# use full val set on end of epoch
# use a small portion otherwise
@@ -669,7 +872,8 @@ class Trainer(TrainerIO):
# hook
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)
@@ -681,6 +885,6 @@ class Trainer(TrainerIO):
self.prog_bar.set_postfix(**tqdm_metrics)
# model checkpointing
if self.proc_rank == 0:
if self.proc_rank == 0 and self.checkpoint_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.parallel import DistributedDataParallel
import itertools
from itertools import chain
import threading
import torch
@@ -8,7 +9,7 @@ from torch.cuda._utils import _get_device_index
import pdb
def _find_tensors(obj):
def _find_tensors(obj): # pragma: no cover
r"""
Recursively find all tensors contained in the specified object.
"""
@@ -21,8 +22,7 @@ def _find_tensors(obj):
return []
def get_a_var(obj):
def get_a_var(obj): # pragma: no cover
if isinstance(obj, torch.Tensor):
return obj
@@ -42,6 +42,29 @@ class LightningDataParallel(DataParallel):
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):
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):
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()
if self.device_ids:
inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids)
@@ -89,7 +112,7 @@ class LightningDistributedDataParallel(DistributedDataParallel):
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
contained in :attr:`inputs` (positional) and :attr:`kwargs_tup` (keyword)
on each of :attr:`devices`.
-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)
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):
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())
in_sizes = []
out_sizes = []
input_ = self.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_)
input_ = self.model.example_input_array
if type(input_) is tuple or type(input_) is list:
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())
if self.model.on_gpu:
input_ = input_.cuda(0)
in_sizes.append(in_size)
if self.model.trainer.use_amp:
input_ = input_.half()
if type(out) is tuple or type(out) is list:
out_size = np.asarray([x.size() for x in out])
else:
out_size = np.array(out.size())
with torch.no_grad():
out_sizes.append(out_size)
input_ = out
for i in range(1, len(mods)):
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.out_sizes = out_sizes
@@ -114,13 +123,22 @@ class ModelSummary(object):
Layer Name, Layer Type, Input Size, Output Size, Number of Parameters
'''
df = pd.DataFrame( np.zeros( (len(self.layer_names), 3) ) )
df.columns = ['Name', 'Type', 'Params']
cols = ['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['Type'] = self.layer_types
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
return
@@ -128,10 +146,13 @@ class ModelSummary(object):
self.get_layer_names()
self.get_parameter_sizes()
self.get_parameter_nums()
if self.model.example_input_array is not None:
self.get_variable_sizes()
self.make_summary()
def print_mem_stack():
def print_mem_stack(): # pragma: no cover
for obj in gc.get_objects():
try:
if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
@@ -140,7 +161,7 @@ def print_mem_stack():
pass
def count_mem_items():
def count_mem_items(): # pragma: no cover
nb_params = 0
nb_tensors = 0
for obj in gc.get_objects():
+28 -12
View File
@@ -2,7 +2,7 @@ import torch
import os
import re
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):
@@ -41,6 +41,12 @@ class ModelIO(object):
class TrainerIO(object):
def __get_model(self):
print(type(self.model))
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
# --------------------
@@ -51,14 +57,19 @@ class TrainerIO(object):
torch.save(checkpoint, filepath)
def dump_checkpoint(self):
checkpoint = {
'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
}
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 = []
for i, optimizer in enumerate(self.optimizers):
optimizer_states.append(optimizer.state_dict())
@@ -66,7 +77,7 @@ class TrainerIO(object):
checkpoint['optimizer_states'] = optimizer_states
# request what to save 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()
# merge trainer and model saving items
@@ -76,7 +87,7 @@ class TrainerIO(object):
# --------------------
# HPC IO
# --------------------
def enable_auto_hpc_walltime_manager(self):
def enable_auto_hpc_walltime_manager(self): # pragma: no cover
if self.cluster is None:
return
@@ -103,9 +114,13 @@ class TrainerIO(object):
:param checkpoint:
:return:
"""
self.checkpoint_callback.best = checkpoint['checkpoint_callback_best']
self.early_stop_callback.wait = checkpoint['early_stop_callback_wait']
self.early_stop_callback.patience = checkpoint['early_stop_callback_patience']
if self.checkpoint_callback is not None:
self.checkpoint_callback.best = checkpoint['checkpoint_callback_best']
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.current_epoch = checkpoint['epoch']
@@ -134,7 +149,8 @@ class TrainerIO(object):
filepath = '{}/hpc_ckpt_{}.ckpt'.format(folderpath, ckpt_number)
# give model a chance to do something on hpc_save
self.on_hpc_save()
model = self.__get_model()
model.on_hpc_save()
# request what to save from the model
checkpoint_dict = self.dump_checkpoint()
@@ -154,11 +170,11 @@ class TrainerIO(object):
self.restore_training_state(checkpoint)
# 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)
# call model hook
self.on_hpc_load()
model.on_hpc_load()
def max_ckpt_in_folder(self, 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
+2 -22
View File
@@ -5,11 +5,10 @@ import math
from pytorch_lightning.root_module.memory import ModelSummary
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.optimization import OptimizerConfig
from pytorch_lightning.root_module.hooks import ModelHooks
class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
class LightningModule(GradInformation, ModelIO, ModelHooks):
def __init__(self, hparams):
super(LightningModule, self).__init__()
@@ -22,6 +21,7 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
self.loaded_optimizer_states_dict = {}
self.trainer = None
self.experiment = None
self.example_input_array = None
# track if gpu was requested for checkpointing
self.on_gpu = False
@@ -71,15 +71,6 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
"""
raise NotImplementedError
def update_tng_log_metrics(self, logs):
"""
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
@@ -92,7 +83,6 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
model_summary = ModelSummary(self)
print(model_summary)
def freeze(self):
for param in self.parameters():
param.requires_grad = False
@@ -125,16 +115,6 @@ class LightningModule(GradInformation, ModelIO, OptimizerConfig, ModelHooks):
"""
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
def load_from_metrics(cls, weights_path, tags_csv, on_gpu, map_location=None):
"""
@@ -0,0 +1,280 @@
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
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__(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)
# ---------------------
# 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 = 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
@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, 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__('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
exp = Experiment(
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 @@
atomicwrites==1.2.1
attrs==18.2.0
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
coverage==4.5.3
mkdocs==1.0.4
pytest==5.0.1
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
twine==1.13.0
urllib3==1.25.3
webencodings==0.5.1
Werkzeug==0.15.4
wrapt==1.11.2
numpy==1.16.4
torch>=1.1.0
torchvision==0.3.0
+27
View File
@@ -16,6 +16,33 @@ markers =
ignore = E731,W504
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]
ignore = E731,W504,F401,F841
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/
setup(
name="pytorch-lightning",
version='0.21',
version='0.3.5',
description="The Keras for ML researchers using PyTorch",
author="William Falcon",
author_email="waf2107@columbia.edu",
@@ -19,8 +19,7 @@ setup(
install_requires=[
"torch>=1.1.0",
"tqdm",
"test-tube>=0.653",
"tensorflow>=1.14.0"
"test-tube>=0.6.7.1",
],
packages=find_packages(),
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
+142
View File
@@ -0,0 +1,142 @@
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
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 mainasdf():
save_dir = init_save_dir()
model, hparams = get_model()
# exp file to get meta
exp = get_exp(False)
exp.argparse(hparams)
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',
use_amp=True
)
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__':
import subprocess
import re
print('getting pid')
command = "lsof -i :%s | awk '{print $2}'" % 12910
pids = subprocess.check_output(command, shell=True)
pids = pids.strip()
print(len(pids))
+506
View File
@@ -0,0 +1,506 @@
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
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
import numpy as np
import warnings
import torch
import os
import shutil
SEED = 2334
torch.manual_seed(SEED)
np.random.seed(SEED)
# ------------------------------------------------------------------------
# TESTS
# ------------------------------------------------------------------------
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_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
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],
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():
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})
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__])