mirror of
https://github.com/wassname/pytorch-lightning.git
synced 2026-09-12 12:40:20 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3d061a559 | ||
|
|
fec1f9fcd2 | ||
|
|
3d2b9fd234 | ||
|
|
4a2dca331e | ||
|
|
8cd764a151 | ||
|
|
fcea3971a8 | ||
|
|
3d23a56ed2 | ||
|
|
aa7245d9db | ||
|
|
a8abeaf50e | ||
|
|
d0ccbb8e1c | ||
|
|
514cab131e | ||
|
|
b820f2e95d | ||
|
|
2425ef003f | ||
|
|
5c6cdc0f27 | ||
|
|
13df930f9a | ||
|
|
6a1128410f | ||
|
|
b198435d0e | ||
|
|
cca6d2c65d | ||
|
|
f3dea818f2 | ||
|
|
ab499573a1 | ||
|
|
56f16694c4 | ||
|
|
2f7a9ad40d | ||
|
|
9ecb1f2aee | ||
|
|
e30514922b | ||
|
|
c7e8436083 | ||
|
|
afa4548b12 | ||
|
|
73b50abb57 | ||
|
|
1514810c3a | ||
|
|
08a6a250c7 | ||
|
|
48bc3465e9 | ||
|
|
0895a41fb9 | ||
|
|
8c41bfe267 | ||
|
|
5785e5965d | ||
|
|
0985a1875c | ||
|
|
c043862a55 | ||
|
|
1d1c89f495 | ||
|
|
edcb5e97df | ||
|
|
075653e6dd | ||
|
|
cb0ab9d212 | ||
|
|
d5e609398c | ||
|
|
16e5093805 | ||
|
|
7812a1339a | ||
|
|
52bdd8ee02 | ||
|
|
d56a8f9992 | ||
|
|
1cd7ee42bd | ||
|
|
d3f9d39673 | ||
|
|
1d27ebe6ad | ||
|
|
a203918a1e | ||
|
|
8a58c6f8f0 | ||
|
|
f32b9064ac | ||
|
|
9a93d00ae6 | ||
|
|
6b99a4bf15 | ||
|
|
0cd6b56061 | ||
|
|
daaf9c69ee | ||
|
|
c12d1eef32 | ||
|
|
a2d6d514d5 | ||
|
|
10e4b18452 | ||
|
|
549d0f66df | ||
|
|
b4c14a4b77 | ||
|
|
35f23bbc82 | ||
|
|
2f1df17371 | ||
|
|
04de151860 | ||
|
|
883af6e9f3 | ||
|
|
86a90bfefd | ||
|
|
d539e49085 | ||
|
|
df5e10d0aa | ||
|
|
0b92fe6cea | ||
|
|
0527a1dad1 | ||
|
|
2018380598 | ||
|
|
1e17bf76aa | ||
|
|
27e88fde31 | ||
|
|
b8ce4adfa8 | ||
|
|
cdbcbad352 | ||
|
|
8e4fe2002b | ||
|
|
b0fae55571 | ||
|
|
5c398d7a4e | ||
|
|
d5fd16a478 | ||
|
|
a931ded310 | ||
|
|
9713c41bf4 | ||
|
|
2575b157a4 | ||
|
|
95ec072d1e | ||
|
|
82d63a9677 | ||
|
|
a895bf1b71 | ||
|
|
47a691f158 | ||
|
|
d3f19c8321 | ||
|
|
a25429b05c | ||
|
|
421c4fab7d | ||
|
|
b75ee7fd8d | ||
|
|
97a9a0f6c1 | ||
|
|
8b9f021ee6 | ||
|
|
b2d1a24999 | ||
|
|
a1bb6237a6 | ||
|
|
715be66590 | ||
|
|
f8a79b3082 | ||
|
|
d9bfe964f9 | ||
|
|
4e0b9c50e7 | ||
|
|
632d07b490 | ||
|
|
a8f07adfe9 | ||
|
|
778149735c | ||
|
|
c44966a8bf | ||
|
|
eacd93e2f0 | ||
|
|
50cca25d6f | ||
|
|
0bfc99ad7a | ||
|
|
79f0856bc8 | ||
|
|
34f0044bc5 | ||
|
|
7bf7af5b43 | ||
|
|
b4a1786924 | ||
|
|
627ac0be32 | ||
|
|
5d307e0838 | ||
|
|
e9c078f799 | ||
|
|
c207593d6e | ||
|
|
904b5af93e | ||
|
|
a79de1ec8e | ||
|
|
18dbbf031b | ||
|
|
4cfcec0616 | ||
|
|
e84ead98c9 | ||
|
|
35c4ddf032 | ||
|
|
b6a83a80ca | ||
|
|
d1f8e8550e | ||
|
|
37cd0bdf97 | ||
|
|
d1e57ada67 | ||
|
|
5f4e5c0015 | ||
|
|
25a58b8540 | ||
|
|
f915e3657f | ||
|
|
c6a2544f9c | ||
|
|
01caefb4e6 | ||
|
|
2b31ced060 | ||
|
|
483d591c74 | ||
|
|
9af4267056 | ||
|
|
dc41769f02 | ||
|
|
e0a09f0fc4 | ||
|
|
3277940d14 | ||
|
|
469941a528 | ||
|
|
92f8c57ff5 | ||
|
|
5fd0bf8535 | ||
|
|
2598a91fbb | ||
|
|
1fc26af954 | ||
|
|
620ac206cf | ||
|
|
ffe0cd5965 | ||
|
|
019b4d16d0 | ||
|
|
f2ef367f7d | ||
|
|
40e5f1b4c8 | ||
|
|
181d69a727 | ||
|
|
69c9b0f692 | ||
|
|
5c1f1d9ee5 | ||
|
|
6073bf4554 | ||
|
|
f36655afc4 | ||
|
|
991f57766d | ||
|
|
4442ce7e1b | ||
|
|
fb09d408fd | ||
|
|
ffa0aec992 | ||
|
|
36bf232e4d | ||
|
|
bfa46a279a | ||
|
|
d08ca6a394 | ||
|
|
02ad828f13 | ||
|
|
432384b5a0 | ||
|
|
5ccfb860e9 | ||
|
|
12397950dd | ||
|
|
cd9ee022d9 | ||
|
|
748d1e9b66 | ||
|
|
87efc1fa4f | ||
|
|
25b5add512 | ||
|
|
143844239f | ||
|
|
715cf461b1 | ||
|
|
ea7c8e55d7 | ||
|
|
fe05f62984 | ||
|
|
085195e09b | ||
|
|
10bec87014 | ||
|
|
6bccc38294 | ||
|
|
2076b03a60 | ||
|
|
f6799a0da0 | ||
|
|
1d78b40a00 | ||
|
|
c8eb06da2b | ||
|
|
ee1029ed5e | ||
|
|
d8e801594b | ||
|
|
ef6d5a412c | ||
|
|
b58ca39621 | ||
|
|
3ef6e6a572 |
@@ -0,0 +1,44 @@
|
|||||||
|
#see https://github.com/codecov/support/wiki/Codecov-Yaml
|
||||||
|
codecov:
|
||||||
|
notify:
|
||||||
|
require_ci_to_pass: yes
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
precision: 0 # 2 = xx.xx%, 0 = xx%
|
||||||
|
round: nearest # how coverage is rounded: down/up/nearest
|
||||||
|
range: 40...100 # custom range of coverage colors from red -> yellow -> green
|
||||||
|
status:
|
||||||
|
# https://codecov.readme.io/v1.0/docs/commit-status
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
against: auto
|
||||||
|
target: 99% # specify the target coverage for each commit status
|
||||||
|
threshold: 20% # allow this little decrease on project
|
||||||
|
# https://github.com/codecov/support/wiki/Filtering-Branches
|
||||||
|
# branches: master
|
||||||
|
if_ci_failed: error
|
||||||
|
# https://github.com/codecov/support/wiki/Patch-Status
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
against: auto
|
||||||
|
target: 40% # specify the target "X%" coverage to hit
|
||||||
|
# threshold: 50% # allow this much decrease on patch
|
||||||
|
changes: false
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: true
|
||||||
|
loop: true
|
||||||
|
macro: false
|
||||||
|
method: false
|
||||||
|
javascript:
|
||||||
|
enable_partials: false
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: header, diff
|
||||||
|
require_changes: false
|
||||||
|
behavior: default # update if exists else create new
|
||||||
|
# branches: *
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: enhancement, help wanted
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Typos and doc fixes
|
||||||
|
about: Typos and doc fixes
|
||||||
|
title: ''
|
||||||
|
labels: typo
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For typos and doc fixes, please go ahead and:
|
||||||
|
|
||||||
|
1. Create an issue.
|
||||||
|
2. Fix the typo.
|
||||||
|
3. Submit a PR.
|
||||||
|
|
||||||
|
|
||||||
|
Thanks!
|
||||||
@@ -10,6 +10,7 @@ app/models/
|
|||||||
pip-wheel-metadata/
|
pip-wheel-metadata/
|
||||||
test_tube_exp/
|
test_tube_exp/
|
||||||
tests/tests_tt_dir/
|
tests/tests_tt_dir/
|
||||||
|
tests/save_dir
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|||||||
+1
-1
@@ -16,4 +16,4 @@ formats: all
|
|||||||
python:
|
python:
|
||||||
version: 3.7
|
version: 3.7
|
||||||
install:
|
install:
|
||||||
- requirements: docs/doc_requirements.txt
|
- requirements: docs/requirements.txt
|
||||||
+40
-10
@@ -1,16 +1,46 @@
|
|||||||
|
# vim ft=yaml
|
||||||
|
|
||||||
|
# After changing this file, check it on:
|
||||||
|
# http://yaml-online-parser.appspot.com/
|
||||||
|
|
||||||
|
# See doc/travis_notes.txt for some guidelines
|
||||||
|
|
||||||
|
# this file is *not* meant to cover or endorse the use of travis, but rather to
|
||||||
|
# help confirm pull requests to this project.
|
||||||
|
|
||||||
|
dist: xenial # Ubuntu 16.04
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- DISPLAY=""
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
python:
|
|
||||||
- "3.7"
|
matrix:
|
||||||
# command to install dependencies
|
include:
|
||||||
|
- python: 3.6
|
||||||
|
env: TOXENV=py36
|
||||||
|
- python: 3.7
|
||||||
|
env: TOXENV=py37
|
||||||
|
|
||||||
|
# See http://docs.travis-ci.com/user/caching/#pip-cache
|
||||||
cache: pip
|
cache: pip
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install -e .
|
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
- pip install -U numpy
|
- pip install -r ./tests/requirements.txt
|
||||||
|
- pip --version ; pip list
|
||||||
|
|
||||||
# keep build from timing out
|
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
# command to run tests
|
|
||||||
script:
|
script:
|
||||||
- py.test # or py.test for Python versions 3.5 and below
|
# integration
|
||||||
|
- tox --sitepackages
|
||||||
|
- python setup.py install --dry-run
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- coverage report
|
||||||
|
# disable auto coverage bc it isn't accurate since it misses gpu code.
|
||||||
|
# to get coverage, run local and push results
|
||||||
|
# - codecov
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Contributing
|
||||||
|
Welcome to the PyTorch Lightning community! We're building the most advanced research platform on the planet to implement the latest, best practices that the amazing PyTorch team rolls out!
|
||||||
|
|
||||||
|
## Lightning Design Principles
|
||||||
|
We encourage all sorts of contributions you're interested in adding! When coding for lightning, please follow these principles.
|
||||||
|
|
||||||
|
#### No PyTorch interference
|
||||||
|
We don't want to add any abstractions on top of pure PyTorch. This gives researchers all the control they need without having to learn yet another framework.
|
||||||
|
|
||||||
|
#### Simple Internal Code
|
||||||
|
It's useful for users to look at the code and understand very quickly what's happening. Many users won't be engineers. Thus we need to value clear, simple code over condensed ninja moves. While that's super cool, this isn't the project for that :)
|
||||||
|
|
||||||
|
#### Force User Decisions To Best Practices
|
||||||
|
There are 1,000 ways to do something. However, something eventually becomes standard practice that everyone does. Thus we pick one way of doing it and force everyone to do it this way. A good example is accumulated gradients. There are many ways to implement, we just pick one and force users to use that one. A bad forced decision would be to make users use a specific library to do something.
|
||||||
|
|
||||||
|
When something becomes a best practice, we add it to the framework. This likely looks like code in utils or in the model file that everyone keeps adding over and over again across projects. When this happens, bring that code inside the trainer and add a flag for it.
|
||||||
|
|
||||||
|
#### Simple External API
|
||||||
|
What makes sense to you may not make sense to others. Create an issue with an API change suggestion and validate that it makes sense for others. Treat code changes how you treat a startup: validate that it's a needed feature, then add if it makes sense for many people.
|
||||||
|
|
||||||
|
#### Gain User Trust
|
||||||
|
As a researcher you can't have any part of your code going wrong. So, make thorough tests that ensure an implementation of a new trick or subbtle change is correct.
|
||||||
|
|
||||||
|
## Contribution types
|
||||||
|
Currently looking for help implementing new features or adding bug fixes.
|
||||||
|
|
||||||
|
A lot of good work has already been done in project mechanics (requirements.txt, setup.py, pep8, badges, ci, etc...) we're in a good state there thanks to all the early contributors (even pre-beta release)!
|
||||||
|
|
||||||
|
## Bug fixes:
|
||||||
|
1. Submit a github issue.
|
||||||
|
2. Fix it.
|
||||||
|
3. Submit a PR!
|
||||||
|
|
||||||
|
## New Features:
|
||||||
|
1. Submit a github issue.
|
||||||
|
2. We'll agree on the feature scope.
|
||||||
|
3. Submit a PR! (with updated docs and tests 🙃).
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 William Falcon
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
+34
-6
@@ -1,9 +1,37 @@
|
|||||||
graft docs
|
# Manifest syntax https://docs.python.org/2/distutils/sourcedist.html
|
||||||
|
graft wheelhouse
|
||||||
|
|
||||||
include COPYING
|
recursive-include birl *.py
|
||||||
include AUTHORS
|
recursive-exclude __pycache__ *.py[cod] *.orig
|
||||||
|
|
||||||
recursive-include src/einsteinpy/tests *.py *.html
|
# Include the README
|
||||||
|
include *.md
|
||||||
|
|
||||||
prune docs/source/examples/.ipynb_checkpoints
|
# Include the license file
|
||||||
global-exclude *.py[cod] __pycache__ *.so *.dylib
|
include LICENSE
|
||||||
|
|
||||||
|
exclude *.sh
|
||||||
|
exclude *.toml
|
||||||
|
exclude *.svg
|
||||||
|
recursive-include examples *.py
|
||||||
|
recursive-include pytorch_lightning *.py
|
||||||
|
|
||||||
|
# exclude tests from package
|
||||||
|
recursive-exclude tests *
|
||||||
|
exclude tests
|
||||||
|
|
||||||
|
# Exclude the documentation files
|
||||||
|
recursive-exclude docs *
|
||||||
|
exclude docs
|
||||||
|
|
||||||
|
# Include the Requirements
|
||||||
|
include requirements.txt
|
||||||
|
|
||||||
|
# Exclude build configs
|
||||||
|
exclude *.yml
|
||||||
|
|
||||||
|
prune .git
|
||||||
|
prune .github
|
||||||
|
prune notebook*
|
||||||
|
prune temp*
|
||||||
|
prune test*
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
<p align="center">
|
<div align="center">
|
||||||
<a href="https://williamfalcon.github.io/pytorch-lightning/">
|
|
||||||
<img alt="" src="https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/_static/lightning_logo.png" width="50">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<h3 align="center">
|
|
||||||
PyTorch Lightning
|
|
||||||
</h3>
|
|
||||||
<p align="center">
|
|
||||||
The PyTorch Keras for ML researchers. More control. Less boilerplate.
|
|
||||||
</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://pepy.tech/project/pytorch-lightning"><img src="https://pepy.tech/badge/pytorch-lightning" alt="PyPI version" height="18"></a>
|
|
||||||
<a href="https://github.com/williamFalcon/pytorch-lightning/tree/master/tests"><img src="https://github.com/williamFalcon/pytorch-lightning/blob/master/coverage.svg"></a>
|
|
||||||
<a href="https://travis-ci.org/williamFalcon/pytorch-lightning"><img src="https://travis-ci.org/williamFalcon/pytorch-lightning.svg?branch=master"></a>
|
|
||||||
<a href="https://williamfalcon.github.io/pytorch-lightning/"><img src="https://readthedocs.org/projects/pytorch-lightning/badge/?version=latest"></a>
|
|
||||||
<a href="https://github.com/williamFalcon/pytorch-lightning/blob/master/COPYING"><img src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
# PyTorch Lightning
|
||||||
|
|
||||||
|
**The PyTorch Keras for ML researchers. More control. Less boilerplate.**
|
||||||
|
|
||||||
|
|
||||||
|
[](https://badge.fury.io/py/pytorch-lightning)
|
||||||
|
[](https://pepy.tech/project/pytorch-lightning)
|
||||||
|
[](https://travis-ci.org/williamFalcon/pytorch-lightning)
|
||||||
|
<!--
|
||||||
|
removed until windows install issues resolved.
|
||||||
|
[](https://ci.appveyor.com/project/Borda/pytorch-lightning) -->
|
||||||
|
<!--
|
||||||
|
removed until codecov badge isn't empy. likely a config error showing nothing on master.
|
||||||
|
[](https://codecov.io/gh/Borda/pytorch-lightning)
|
||||||
|
-->
|
||||||
|
[](https://github.com/williamFalcon/pytorch-lightning/tree/master/tests#running-coverage)
|
||||||
|
[](https://www.codefactor.io/repository/github/borda/pytorch-lightning)
|
||||||
|
[](https://pytorch-lightning.readthedocs.io/en/latest)
|
||||||
|
[](https://github.com/williamFalcon/pytorch-lightning/blob/master/LICENSE)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Simple installation from PyPI
|
||||||
```bash
|
```bash
|
||||||
pip install pytorch-lightning
|
pip install pytorch-lightning
|
||||||
```
|
```
|
||||||
@@ -27,14 +33,30 @@ pip install pytorch-lightning
|
|||||||
**[View the docs here](https://williamfalcon.github.io/pytorch-lightning/)**
|
**[View the docs here](https://williamfalcon.github.io/pytorch-lightning/)**
|
||||||
|
|
||||||
## What is it?
|
## What is it?
|
||||||
Lightning defers training and validation loop logic to you. It guarantees correct, modern best practices for the core training logic.
|
Lightning is a very lightweight wrapper on PyTorch. This means you don't have to learn a new library. It defers core training and validation logic to you and automates the rest. It guarantees tested, correct, modern best practices for the automated parts.
|
||||||
|
|
||||||
|
|
||||||
## Why do I want to use lightning?
|
## Why do I want to use lightning?
|
||||||
When starting a new project the last thing you want to do is recode a training loop, model loading/saving, distributed training, when to validate, etc... You're likely to spend a long time ironing out all the bugs without even getting to the core of your research.
|
When starting a new project the last thing you want to do is recode a training loop, multi-cluster training, 16-bit precision, early-stopping, model loading/saving, when to validate, etc... You're likely to spend a long time ironing out all the bugs without even getting to the core of your research.
|
||||||
|
|
||||||
With lightning, you guarantee those parts of your code work so you can focus on what the meat of the research: Data and training, validation loop logic. Don't worry about multiple gpus or speeding up your code, lightning will do that for you!
|
With lightning, you guarantee those parts of your code work so you can focus on what the meat of the research: The data and the training/validation loop logic.
|
||||||
|
|
||||||
|
Don't worry about training on multiple gpus or speeding up your code, lightning will do that for you!
|
||||||
|
|
||||||
|
---
|
||||||
|
## README Table of Contents
|
||||||
|
- [How do I use it](https://github.com/williamFalcon/pytorch-lightning#how-do-i-do-use-it)
|
||||||
|
- [What lightning automates](https://github.com/williamFalcon/pytorch-lightning#what-does-lightning-control-for-me)
|
||||||
|
- [Tensorboard integration](https://github.com/williamFalcon/pytorch-lightning#tensorboard)
|
||||||
|
- [Lightning features](https://github.com/williamFalcon/pytorch-lightning#lightning-automates-all-of-the-following-each-is-also-configurable)
|
||||||
|
- [Demos](https://github.com/williamFalcon/pytorch-lightning#demo)
|
||||||
|
- [Tutorials](https://github.com/williamFalcon/pytorch-lightning#tutorials)
|
||||||
|
- [Contributing](https://github.com/williamFalcon/pytorch-lightning/blob/master/CONTRIBUTING.md)
|
||||||
|
- [Bleeding edge install](https://github.com/williamFalcon/pytorch-lightning#bleeding-edge)
|
||||||
|
- [Lightning Design Principles](https://github.com/williamFalcon/pytorch-lightning#lightning-design-principles)
|
||||||
|
- [FAQ](https://github.com/williamFalcon/pytorch-lightning#faq)
|
||||||
|
|
||||||
|
---
|
||||||
## How do I do use it?
|
## How do I do use it?
|
||||||
|
|
||||||
To use lightning do 2 things:
|
To use lightning do 2 things:
|
||||||
@@ -47,9 +69,9 @@ from torch.utils.data import DataLoader
|
|||||||
from torchvision.datasets import MNIST
|
from torchvision.datasets import MNIST
|
||||||
import torchvision.transforms as transforms
|
import torchvision.transforms as transforms
|
||||||
|
|
||||||
import pytorch_lightning as ptl
|
import pytorch_lightning as pl
|
||||||
|
|
||||||
class CoolModel(ptl.LightningModule):
|
class CoolModel(pl.LightningModule):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CoolModel, self).__init__()
|
super(CoolModel, self).__init__()
|
||||||
@@ -79,15 +101,15 @@ class CoolModel(ptl.LightningModule):
|
|||||||
def configure_optimizers(self):
|
def configure_optimizers(self):
|
||||||
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
```
|
```
|
||||||
@@ -95,12 +117,23 @@ class CoolModel(ptl.LightningModule):
|
|||||||
2. Fit with a [trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
|
2. Fit with a [trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
|
||||||
```python
|
```python
|
||||||
from pytorch_lightning import Trainer
|
from pytorch_lightning import Trainer
|
||||||
from test_tube import Experiment
|
|
||||||
|
|
||||||
model = CoolModel()
|
model = CoolModel()
|
||||||
|
|
||||||
|
# most basic trainer, uses good defaults
|
||||||
|
trainer = Trainer()
|
||||||
|
trainer.fit(model)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with tensorboard logger and some options turned on such as multi-gpu, etc...
|
||||||
|
```python
|
||||||
|
from test_tube import Experiment
|
||||||
|
|
||||||
|
# PyTorch summarywriter with a few bells and whistles
|
||||||
exp = Experiment(save_dir=os.getcwd())
|
exp = Experiment(save_dir=os.getcwd())
|
||||||
|
|
||||||
# train on cpu using only 10% of the data (for demo purposes)
|
# train on cpu using only 10% of the data (for demo purposes)
|
||||||
|
# pass in experi
|
||||||
trainer = Trainer(experiment=exp, max_nb_epochs=1, train_percent_check=0.1)
|
trainer = Trainer(experiment=exp, max_nb_epochs=1, train_percent_check=0.1)
|
||||||
|
|
||||||
# train on 4 gpus
|
# train on 4 gpus
|
||||||
@@ -113,14 +146,16 @@ trainer = Trainer(experiment=exp, max_nb_epochs=1, train_percent_check=0.1)
|
|||||||
trainer.fit(model)
|
trainer.fit(model)
|
||||||
|
|
||||||
# view tensorflow logs
|
# view tensorflow logs
|
||||||
print(f'View tensorboard logs by running\ntensorboard --logdir {os.getcwd()}')
|
print('View tensorboard logs by running\ntensorboard --logdir %s' % os.getcwd())
|
||||||
print('and going to http://localhost:6006 on your browser')
|
print('and going to http://localhost:6006 on your browser')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## What does lightning control for me?
|
||||||
|
|
||||||
## What does lightning control for me?
|
Everything in gray!
|
||||||
Everything!
|
You define the blue parts using the LightningModule interface:
|
||||||
Except for these 6 core functions which you define:
|
|
||||||
|

|
||||||
|
|
||||||
```{.python}
|
```{.python}
|
||||||
# what to do in the training loop
|
# what to do in the training loop
|
||||||
@@ -148,7 +183,7 @@ def training_step(self, data_batch, batch_nb):
|
|||||||
# define your own forward and loss calculation
|
# define your own forward and loss calculation
|
||||||
hidden_states = self.encoder(x)
|
hidden_states = self.encoder(x)
|
||||||
|
|
||||||
# even as complex as a seq-2seq + attn model
|
# even as complex as a seq-2-seq + attn model
|
||||||
# (this is just a toy, non-working example to illustrate)
|
# (this is just a toy, non-working example to illustrate)
|
||||||
start_token = '<SOS>'
|
start_token = '<SOS>'
|
||||||
last_hidden = torch.zeros(...)
|
last_hidden = torch.zeros(...)
|
||||||
@@ -202,19 +237,11 @@ def validation_end(self, outputs):
|
|||||||
## Tensorboard
|
## Tensorboard
|
||||||
Lightning is fully integrated with tensorboard.
|
Lightning is fully integrated with tensorboard.
|
||||||
|
|
||||||
<p align="center">
|

|
||||||
<a href="https://williamfalcon.github.io/pytorch-lightning/">
|
|
||||||
<img alt="" src="https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/_static/tf_loss.png" width="900px">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
Lightning also adds a text column with all the hyperparameters for this experiment.
|
Lightning also adds a text column with all the hyperparameters for this experiment.
|
||||||
|
|
||||||
<p align="center">
|

|
||||||
<a href="https://williamfalcon.github.io/pytorch-lightning/">
|
|
||||||
<img alt="" src="https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/_static/tf_tags.png" width="900px">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
Simply note the path you set for the Experiment
|
Simply note the path you set for the Experiment
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@@ -238,6 +265,7 @@ tensorboard --logdir /some/path
|
|||||||
|
|
||||||
- [Model saving](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#model-saving)
|
- [Model saving](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#model-saving)
|
||||||
- [Model loading](https://williamfalcon.github.io/pytorch-lightning/LightningModule/methods/#load-from-metrics)
|
- [Model loading](https://williamfalcon.github.io/pytorch-lightning/LightningModule/methods/#load-from-metrics)
|
||||||
|
- [Restoring training session](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#restoring-training-session)
|
||||||
|
|
||||||
###### Computing cluster (SLURM)
|
###### Computing cluster (SLURM)
|
||||||
|
|
||||||
@@ -251,7 +279,8 @@ tensorboard --logdir /some/path
|
|||||||
- [Log GPU usage](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#Log-gpu-usage)
|
- [Log GPU usage](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#Log-gpu-usage)
|
||||||
- [Make model overfit on subset of data](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#make-model-overfit-on-subset-of-data)
|
- [Make model overfit on subset of data](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#make-model-overfit-on-subset-of-data)
|
||||||
- [Print the parameter count by layer](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-the-parameter-count-by-layer)
|
- [Print the parameter count by layer](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-the-parameter-count-by-layer)
|
||||||
- [Pring which gradients are nan](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-which-gradients-are-nan)
|
- [Print which gradients are nan](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-which-gradients-are-nan)
|
||||||
|
- [Print input and output size of every module in system](https://williamfalcon.github.io/pytorch-lightning/LightningModule/properties/#example_input_array)
|
||||||
|
|
||||||
|
|
||||||
###### Distributed training
|
###### Distributed training
|
||||||
@@ -294,7 +323,6 @@ tensorboard --logdir /some/path
|
|||||||
- [Set the number of validation sanity steps](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-the-number-of-validation-sanity-steps)
|
- [Set the number of validation sanity steps](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-the-number-of-validation-sanity-steps)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
```bash
|
```bash
|
||||||
# install lightning
|
# install lightning
|
||||||
@@ -302,7 +330,8 @@ pip install pytorch-lightning
|
|||||||
|
|
||||||
# clone lightning for the demo
|
# clone lightning for the demo
|
||||||
git clone https://github.com/williamFalcon/pytorch-lightning.git
|
git clone https://github.com/williamFalcon/pytorch-lightning.git
|
||||||
cd pytorch_lightning/examples/new_project_templates/
|
cd pytorch-lightning
|
||||||
|
cd examples/new_project_templates/
|
||||||
|
|
||||||
# all of the following demos use the SAME model to show no modification needs to be made to your code
|
# all of the following demos use the SAME model to show no modification needs to be made to your code
|
||||||
|
|
||||||
@@ -316,6 +345,31 @@ python single_gpu_node_template.py --gpus "0,1"
|
|||||||
python multi_node_cluster_template.py --nb_gpu_nodes 4 --gpus '0,1,2,3,4,5,6,7'
|
python multi_node_cluster_template.py --nb_gpu_nodes 4 --gpus '0,1,2,3,4,5,6,7'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
- [Basic Lightning use](https://towardsdatascience.com/supercharge-your-ai-research-with-pytorch-lightning-337948a99eec)
|
||||||
|
- [9 key speed features in Pytorch-Lightning](https://towardsdatascience.com/9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565)
|
||||||
|
- [SLURM, multi-node training with Lightning](https://towardsdatascience.com/trivial-multi-node-training-with-pytorch-lightning-ff75dfb809bd)
|
||||||
|
|
||||||
|
---
|
||||||
|
## FAQ
|
||||||
|
**Why was Lightning created?**
|
||||||
|
Lightning has 3 goals in mind:
|
||||||
|
1. Maximal flexibility while abstracting out the common boilerplate across research projects.
|
||||||
|
2. Reproducibility. If all projects use the LightningModule template, it will be much much easier to understand what's going on and where to look! It will also mean every implementation follows a standard format.
|
||||||
|
3. Democratizing PyTorch power user features. Distributed training? 16-bit? know you need them but don't want to take the time to implement? All good... these come built into Lightning.
|
||||||
|
|
||||||
|
**How does Lightning compare with Ignite and fast.ai?**
|
||||||
|
[Here's a thorough comparison](https://medium.com/@_willfalcon/pytorch-lightning-vs-pytorch-ignite-vs-fast-ai-61dc7480ad8a).
|
||||||
|
|
||||||
|
**Is this another library I have to learn?**
|
||||||
|
Nope! We use pure Pytorch everywhere and don't add unecessary abstractions!
|
||||||
|
|
||||||
|
**Are there plans to support Python 2?**
|
||||||
|
Nope.
|
||||||
|
|
||||||
|
**Are there plans to support virtualenv?**
|
||||||
|
Nope. Please use anaconda or miniconda.
|
||||||
|
|
||||||
## Bleeding edge
|
## Bleeding edge
|
||||||
If you can't wait for the next release, install the most up to date code with:
|
If you can't wait for the next release, install the most up to date code with:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# https://www.appveyor.com/docs/appveyor-yml/
|
||||||
|
environment:
|
||||||
|
|
||||||
|
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
|
||||||
|
# /E:ON and /V:ON options are not enabled in the batch script interpreter
|
||||||
|
# See: http://stackoverflow.com/a/13751649/163740
|
||||||
|
CMD_IN_ENV: "cmd /E:ON /V:ON /C obvci_appveyor_python_build_env.cmd"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
# Pre-installed Python versions, which Appveyor may upgrade to
|
||||||
|
# a later point release.
|
||||||
|
# See: http://www.appveyor.com/docs/installed-software#python
|
||||||
|
|
||||||
|
|
||||||
|
# - PYTHON: "C:\\Python35-x64"
|
||||||
|
# PYTHON_VERSION: "3.5.x"
|
||||||
|
# PYTHON_ARCH: "64"
|
||||||
|
# TOXENV: "py35"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python36-x64"
|
||||||
|
PYTHON_VERSION: "3.6.x"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
TOXENV: "py36"
|
||||||
|
PIP_PYVER: "36"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python37-x64"
|
||||||
|
PYTHON_VERSION: "3.7.x"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
TOXENV: "py37"
|
||||||
|
PIP_PYVER: "37"
|
||||||
|
|
||||||
|
build: off
|
||||||
|
|
||||||
|
# https://www.appveyor.com/docs/build-cache/
|
||||||
|
cache:
|
||||||
|
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||||
|
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||||
|
- '%LOCALAPPDATA%\pip\Cache -> appveyor.yml'
|
||||||
|
|
||||||
|
# scripts that run after cloning repository
|
||||||
|
install:
|
||||||
|
# If there is a newer build queued for the same PR, cancel this one.
|
||||||
|
# The AppVeyor 'rollout builds' option is supposed to serve the same
|
||||||
|
# purpose but it is problematic because it tends to cancel builds pushed
|
||||||
|
# directly to master instead of just PR builds (or the converse).
|
||||||
|
- SET PATH=%PYTHON%;%PYTHON%\\Scripts;%path%
|
||||||
|
- pip install -U --user pip
|
||||||
|
- pip install "https://download.pytorch.org/whl/cu90/torch-1.1.0-cp%PIP_PYVER%-cp%PIP_PYVER%m-win_amd%PYTHON_ARCH%.whl"
|
||||||
|
pip install "https://download.pytorch.org/whl/cu90/torchvision-0.3.0-cp%PIP_PYVER%-cp%PIP_PYVER%m-win_amd%PYTHON_ARCH%.whl"
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
- pip install -r ./tests/requirements.txt
|
||||||
|
|
||||||
|
# scripts to run before tests (working directory and environment changes are persisted from the previous steps such as "before_build")
|
||||||
|
before_test:
|
||||||
|
- python --version
|
||||||
|
- pip --version
|
||||||
|
- pip list
|
||||||
|
- dir
|
||||||
|
|
||||||
|
# to run your custom scripts instead of automatic tests
|
||||||
|
test_script:
|
||||||
|
- tox --sitepackages --parallel auto
|
||||||
|
|
||||||
|
on_success:
|
||||||
|
- coverage report
|
||||||
|
# - codecov
|
||||||
@@ -36,9 +36,9 @@ from torch.utils.data import DataLoader
|
|||||||
from torchvision.datasets import MNIST
|
from torchvision.datasets import MNIST
|
||||||
import torchvision.transforms as transforms
|
import torchvision.transforms as transforms
|
||||||
|
|
||||||
import pytorch_lightning as ptl
|
import pytorch_lightning as pl
|
||||||
|
|
||||||
class CoolModel(ptl.LightningModule):
|
class CoolModel(pl.LightningModule):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CoolModel, self).__init__()
|
super(CoolModel, self).__init__()
|
||||||
@@ -68,18 +68,27 @@ class CoolModel(ptl.LightningModule):
|
|||||||
def configure_optimizers(self):
|
def configure_optimizers(self):
|
||||||
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=32)
|
||||||
```
|
```
|
||||||
|
---
|
||||||
|
### How do these methods fit into the broader training?
|
||||||
|
The LightningModule interface is on the right. Each method corresponds to a part of a research project. Lightning automates everything not in blue.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/_static/overview_flat.jpg">
|
||||||
|
<img alt="" src="https://github.com/williamFalcon/pytorch-lightning/blob/master/docs/source/_static/overview_flat.jpg" height="900px">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -294,10 +303,10 @@ def on_load_checkpoint(self, checkpoint):
|
|||||||
### tng_dataloader
|
### tng_dataloader
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self)
|
def tng_dataloader(self)
|
||||||
```
|
```
|
||||||
Called by lightning during training loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
|
Called by lightning during training loop. Make sure to use the @pl.data_loader decorator, this ensures not calling this function until the data are needed.
|
||||||
|
|
||||||
##### Return
|
##### Return
|
||||||
PyTorch DataLoader
|
PyTorch DataLoader
|
||||||
@@ -305,7 +314,7 @@ PyTorch DataLoader
|
|||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
||||||
dataset = MNIST(root='/path/to/mnist/', train=True, transform=transform, download=True)
|
dataset = MNIST(root='/path/to/mnist/', train=True, transform=transform, download=True)
|
||||||
@@ -321,10 +330,10 @@ def tng_dataloader(self):
|
|||||||
### val_dataloader
|
### val_dataloader
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self)
|
def tng_dataloader(self)
|
||||||
```
|
```
|
||||||
Called by lightning during validation loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
|
Called by lightning during validation loop. Make sure to use the @pl.data_loader decorator, this ensures not calling this function until the data are needed.
|
||||||
|
|
||||||
##### Return
|
##### Return
|
||||||
PyTorch DataLoader
|
PyTorch DataLoader
|
||||||
@@ -332,7 +341,7 @@ PyTorch DataLoader
|
|||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
||||||
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
|
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
|
||||||
@@ -349,10 +358,10 @@ def val_dataloader(self):
|
|||||||
### test_dataloader
|
### test_dataloader
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self)
|
def test_dataloader(self)
|
||||||
```
|
```
|
||||||
Called by lightning during test loop. Make sure to use the @ptl.data_loader decorator, this ensures not calling this function until the data are needed.
|
Called by lightning during test loop. Make sure to use the @pl.data_loader decorator, this ensures not calling this function until the data are needed.
|
||||||
|
|
||||||
##### Return
|
##### Return
|
||||||
PyTorch DataLoader
|
PyTorch DataLoader
|
||||||
@@ -360,7 +369,7 @@ PyTorch DataLoader
|
|||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
``` {.python}
|
``` {.python}
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
||||||
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
|
dataset = MNIST(root='/path/to/mnist/', train=False, transform=transform, download=True)
|
||||||
|
|||||||
@@ -38,3 +38,17 @@ self.trainer.current_epoch
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
The LightningModule also offers these tricks to help debug.
|
||||||
|
|
||||||
|
---
|
||||||
|
#### example_input_array
|
||||||
|
In the LightningModule init, you can set a dummy tensor for this property
|
||||||
|
to get a print out of sizes coming into and out of every layer.
|
||||||
|
```python
|
||||||
|
def __init__(self):
|
||||||
|
# put the dimensions of the first input to your system
|
||||||
|
self.example_input_array = torch.rand(5, 28 * 28)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,51 @@ checkpoint_callback = ModelCheckpoint(
|
|||||||
trainer = Trainer(checkpoint_callback=checkpoint_callback)
|
trainer = Trainer(checkpoint_callback=checkpoint_callback)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
### Restoring training session
|
||||||
|
You might want to not only load a model but also continue training it. Use this method to
|
||||||
|
restore the trainer state as well. This will continue from the epoch and global step you last left off.
|
||||||
|
However, the dataloaders will start from the first batch again (if you shuffled it shouldn't matter).
|
||||||
|
|
||||||
|
Lightning will restore the session if you pass an experiment with the same version and there's a saved checkpoint.
|
||||||
|
``` {.python}
|
||||||
|
from test_tube import Experiment
|
||||||
|
|
||||||
|
exp = Experiment(version=a_previous_version_with_a_saved_checkpoint)
|
||||||
|
trainer = Trainer(experiment=exp)
|
||||||
|
|
||||||
|
# this fit call loads model weights and trainer state
|
||||||
|
# the trainer continues seamlessly from where you left off
|
||||||
|
# without having to do anything else.
|
||||||
|
trainer.fit(model)
|
||||||
|
```
|
||||||
|
|
||||||
|
The trainer restores:
|
||||||
|
- global_step
|
||||||
|
- current_epoch
|
||||||
|
- All optimizers
|
||||||
|
- All lr_schedulers
|
||||||
|
- Model weights
|
||||||
|
|
||||||
|
You can even change the logic of your model as long as the weights and "architecture" of
|
||||||
|
the system isn't different. If you add a layer, for instance, it might not work.
|
||||||
|
|
||||||
|
At a rough level, here's [what happens inside Trainer](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/root_module/model_saving.py#L63):
|
||||||
|
```python
|
||||||
|
|
||||||
|
self.global_step = checkpoint['global_step']
|
||||||
|
self.current_epoch = checkpoint['epoch']
|
||||||
|
|
||||||
|
# restore the optimizers
|
||||||
|
optimizer_states = checkpoint['optimizer_states']
|
||||||
|
for optimizer, opt_state in zip(self.optimizers, optimizer_states):
|
||||||
|
optimizer.load_state_dict(opt_state)
|
||||||
|
|
||||||
|
# restore the lr schedulers
|
||||||
|
lr_schedulers = checkpoint['lr_schedulers']
|
||||||
|
for scheduler, lrs_state in zip(self.lr_schedulers, lr_schedulers):
|
||||||
|
scheduler.load_state_dict(lrs_state)
|
||||||
|
|
||||||
|
# uses the model you passed into trainer
|
||||||
|
model.load_state_dict(checkpoint['state_dict'])
|
||||||
|
```
|
||||||
@@ -23,6 +23,22 @@ 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).
|
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).
|
||||||
|
|
||||||
|
---
|
||||||
|
#### Distributed and 16-bit precision.
|
||||||
|
Due to an issue with apex and DistributedDataParallel (PyTorch and NVIDIA issue), Lightning does
|
||||||
|
not allow 16-bit and DP training. We tried to get this to work, but it's an issue on their end.
|
||||||
|
|
||||||
|
Below are the possible configurations we support.
|
||||||
|
|
||||||
|
| 1 GPU | 1+ GPUs | DP | DDP | 16-bit | command |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Y | | | | | ```Trainer(gpus=[0])``` |
|
||||||
|
| Y | | | | Y | ```Trainer(gpus=[0], use_amp=True)``` |
|
||||||
|
| | Y | Y | | | ```Trainer(gpus=[0, ...])``` |
|
||||||
|
| | Y | | Y | | ```Trainer(gpus=[0, ...], distributed_backend='ddp')``` |
|
||||||
|
| | Y | | Y | Y | ```Trainer(gpus=[0, ...], distributed_backend='ddp', use_amp=True)``` |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
#### CUDA flags
|
#### CUDA flags
|
||||||
CUDA flags make certain GPUs visible to your script.
|
CUDA flags make certain GPUs visible to your script.
|
||||||
@@ -94,7 +110,7 @@ cluster.add_command('export NCCL_SOCKET_IFNAME=^docker0,lo')
|
|||||||
cluster.add_command('export NCCL_DEBUG=INFO')
|
cluster.add_command('export NCCL_DEBUG=INFO')
|
||||||
|
|
||||||
# setting a master port here is a good idea.
|
# setting a master port here is a good idea.
|
||||||
cluster.add_command(f'export MASTER_PORT={PORT}')
|
cluster.add_command('export MASTER_PORT=%r' % PORT)
|
||||||
|
|
||||||
# good to load the latest NCCL version
|
# good to load the latest NCCL version
|
||||||
cluster.load_modules(['NCCL/2.4.7-1-cuda.10.0'])
|
cluster.load_modules(['NCCL/2.4.7-1-cuda.10.0'])
|
||||||
|
|||||||
+11
-2
@@ -33,7 +33,7 @@ trainer = Trainer(process_position=1)
|
|||||||
Whenever you call .save() on the test-tube experiment it logs all the hyperparameters in current use.
|
Whenever you call .save() on the test-tube experiment it logs all the hyperparameters in current use.
|
||||||
Give lightning a test-tube Experiment object to automate this for you.
|
Give lightning a test-tube Experiment object to automate this for you.
|
||||||
``` {.python}
|
``` {.python}
|
||||||
from test-tube import Experiment
|
from test_tube import Experiment
|
||||||
|
|
||||||
exp = Experiment(...)
|
exp = Experiment(...)
|
||||||
Trainer(experiment=exp)
|
Trainer(experiment=exp)
|
||||||
@@ -44,7 +44,7 @@ Trainer(experiment=exp)
|
|||||||
Whenever you call .save() on the test-tube experiment it snapshows all code and pushes to a git tag.
|
Whenever you call .save() on the test-tube experiment it snapshows all code and pushes to a git tag.
|
||||||
Give lightning a test-tube Experiment object to automate this for you.
|
Give lightning a test-tube Experiment object to automate this for you.
|
||||||
``` {.python}
|
``` {.python}
|
||||||
from test-tube import Experiment
|
from test_tube import Experiment
|
||||||
|
|
||||||
exp = Experiment(create_git_tag=True)
|
exp = Experiment(create_git_tag=True)
|
||||||
Trainer(experiment=exp)
|
Trainer(experiment=exp)
|
||||||
@@ -52,6 +52,15 @@ Trainer(experiment=exp)
|
|||||||
|
|
||||||
---
|
---
|
||||||
### Tensorboard support
|
### Tensorboard support
|
||||||
|
In the LightningModule you can access the experiment logger by doing:
|
||||||
|
```python
|
||||||
|
self.experiment
|
||||||
|
|
||||||
|
# add image
|
||||||
|
# Look at PyTorch SummaryWriter docs for what you can do.
|
||||||
|
self.experiment.add_image(...)
|
||||||
|
```
|
||||||
|
|
||||||
The experiment object is a strict subclass of PyTorch SummaryWriter. However, this class
|
The experiment object is a strict subclass of PyTorch SummaryWriter. However, this class
|
||||||
also snapshots every detail about the experiment (data folder paths, code, hyperparams),
|
also snapshots every detail about the experiment (data folder paths, code, hyperparams),
|
||||||
and allows you to visualize it using tensorboard.
|
and allows you to visualize it using tensorboard.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ def on_epoch_start(self):
|
|||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
#### on_batch_end
|
#### on_epoch_end
|
||||||
Called in the training loop at the very end of the epoch.
|
Called in the training loop at the very end of the epoch.
|
||||||
```python
|
```python
|
||||||
def on_epoch_end(self):
|
def on_epoch_end(self):
|
||||||
@@ -33,6 +33,14 @@ def on_batch_start(self):
|
|||||||
# do something when the batch starts
|
# do something when the batch starts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
#### on_batch_end
|
||||||
|
Called in the training loop after the batch.
|
||||||
|
```python
|
||||||
|
def on_batch_end(self):
|
||||||
|
# do something when the batch ends
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
#### on_pre_performance_check
|
#### on_pre_performance_check
|
||||||
Called at the very beginning of the validation loop.
|
Called at the very beginning of the validation loop.
|
||||||
|
|||||||
+30
-28
@@ -19,42 +19,44 @@ But of course the fun is in all the advanced things it can do:
|
|||||||
|
|
||||||
**Checkpointing**
|
**Checkpointing**
|
||||||
|
|
||||||
- Model saving
|
- [Model saving](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#model-saving)
|
||||||
- Model loading
|
- [Model loading](https://williamfalcon.github.io/pytorch-lightning/LightningModule/methods/#load-from-metrics)
|
||||||
|
- [Restoring training session](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#restoring-training-session)
|
||||||
|
|
||||||
**Computing cluster (SLURM)**
|
**Computing cluster (SLURM)**
|
||||||
|
|
||||||
- [Running grid search on a cluster](SLURM%20Managed%20Cluster/#running-grid-search-on-a-cluster)
|
- [Running grid search on a cluster](https://williamfalcon.github.io/pytorch-lightning/Trainer/SLURM%20Managed%20Cluster#running-grid-search-on-a-cluster)
|
||||||
- [Walltime auto-resubmit](SLURM%20Managed%20Cluster/#walltime-auto-resubmit)
|
- [Walltime auto-resubmit](https://williamfalcon.github.io/pytorch-lightning/Trainer/SLURM%20Managed%20Cluster#walltime-auto-resubmit)
|
||||||
|
|
||||||
**Debugging**
|
**Debugging**
|
||||||
|
|
||||||
- [Fast dev run](Debugging/#fast-dev-run)
|
- [Fast dev run](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#fast-dev-run)
|
||||||
- [Inspect gradient norms](Debugging/#inspect-gradient-norms)
|
- [Inspect gradient norms](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#inspect-gradient-norms)
|
||||||
- [Log GPU usage](Debugging/#Log-gpu-usage)
|
- [Log GPU usage](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#Log-gpu-usage)
|
||||||
- [Make model overfit on subset of data](Debugging/#make-model-overfit-on-subset-of-data)
|
- [Make model overfit on subset of data](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#make-model-overfit-on-subset-of-data)
|
||||||
- [Print the parameter count by layer](Debugging/#print-the-parameter-count-by-layer)
|
- [Print the parameter count by layer](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-the-parameter-count-by-layer)
|
||||||
- [Pring which gradients are nan](Debugging/#print-which-gradients-are-nan)
|
- [Pring which gradients are nan](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-which-gradients-are-nan)
|
||||||
|
- [Print input and output size of every module in system](https://williamfalcon.github.io/pytorch-lightning/LightningModule/properties/#example_input_array)
|
||||||
|
|
||||||
|
|
||||||
**Distributed training**
|
**Distributed training**
|
||||||
|
|
||||||
- [16-bit mixed precision](Distributed%20training/#16-bit-mixed-precision)
|
- [16-bit mixed precision](https://williamfalcon.github.io/pytorch-lightning/Trainer/Distributed%20training/#16-bit-mixed-precision)
|
||||||
- [Multi-GPU](Distributed%20training/#Multi-GPU)
|
- [Multi-GPU](https://williamfalcon.github.io/pytorch-lightning/Trainer/Distributed%20training/#Multi-GPU)
|
||||||
- [Multi-node](Distributed%20training/#Multi-node)
|
- [Multi-node](https://williamfalcon.github.io/pytorch-lightning/Trainer/Distributed%20training/#Multi-node)
|
||||||
- [Single GPU](Distributed%20training/#single-gpu)
|
- [Single GPU](https://williamfalcon.github.io/pytorch-lightning/Trainer/Distributed%20training/#single-gpu)
|
||||||
- [Self-balancing architecture](Distributed%20training/#self-balancing-architecture)
|
- [Self-balancing architecture](https://williamfalcon.github.io/pytorch-lightning/Trainer/Distributed%20training/#self-balancing-architecture)
|
||||||
|
|
||||||
|
|
||||||
**Experiment Logging**
|
**Experiment Logging**
|
||||||
|
|
||||||
- [Display metrics in progress bar](Logging/#display-metrics-in-progress-bar)
|
- [Display metrics in progress bar](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#display-metrics-in-progress-bar)
|
||||||
- [Log metric row every k batches](Logging/#log-metric-row-every-k-batches)
|
- [Log metric row every k batches](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#log-metric-row-every-k-batches)
|
||||||
- [Process position](Logging/#process-position)
|
- [Process position](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#process-position)
|
||||||
- [Tensorboard support](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#tensorboard-support)
|
- [Tensorboard support](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#tensorboard-support)
|
||||||
- [Save a snapshot of all hyperparameters](Logging/#save-a-snapshot-of-all-hyperparameters)
|
- [Save a snapshot of all hyperparameters](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#save-a-snapshot-of-all-hyperparameters)
|
||||||
- [Snapshot code for a training run](Logging/#snapshot-code-for-a-training-run)
|
- [Snapshot code for a training run](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#snapshot-code-for-a-training-run)
|
||||||
- [Write logs file to csv every k batches](Logging/#write-logs-file-to-csv-every-k-batches)
|
- [Write logs file to csv every k batches](https://williamfalcon.github.io/pytorch-lightning/Trainer/Logging/#write-logs-file-to-csv-every-k-batches)
|
||||||
|
|
||||||
**Training loop**
|
**Training loop**
|
||||||
|
|
||||||
@@ -62,16 +64,16 @@ But of course the fun is in all the advanced things it can do:
|
|||||||
- [Force training for min or max epochs](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#force-training-for-min-or-max-epochs)
|
- [Force training for min or max epochs](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#force-training-for-min-or-max-epochs)
|
||||||
- [Force disable early stop](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#force-disable-early-stop)
|
- [Force disable early stop](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#force-disable-early-stop)
|
||||||
- [Gradient Clipping](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#gradient-clipping)
|
- [Gradient Clipping](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#gradient-clipping)
|
||||||
- [Hooks](hooks)
|
- [Hooks](https://williamfalcon.github.io/pytorch-lightning/Trainer/hooks/)
|
||||||
- [Learning rate scheduling](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#configure_optimizers)
|
- [Learning rate scheduling](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#configure_optimizers)
|
||||||
- [Use multiple optimizers (like GANs)](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#configure_optimizers)
|
- [Use multiple optimizers (like GANs)](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#configure_optimizers)
|
||||||
- [Set how much of the training set to check (1-100%)](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#set-how-much-of-the-training-set-to-check)
|
- [Set how much of the training set to check (1-100%)](https://williamfalcon.github.io/pytorch-lightning/Trainer/Training%20Loop/#set-how-much-of-the-training-set-to-check)
|
||||||
|
|
||||||
**Validation loop**
|
**Validation loop**
|
||||||
|
|
||||||
- [Check validation every n epochs](Validation%20Loop/#check-validation-every-n-epochs)
|
- [Check validation every n epochs](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#check-validation-every-n-epochs)
|
||||||
- [Hooks](hooks)
|
- [Hooks](https://williamfalcon.github.io/pytorch-lightning/Trainer/hooks/)
|
||||||
- [Set how much of the validation set to check](Validation%20Loop/#set-how-much-of-the-validation-set-to-check)
|
- [Set how much of the validation set to check](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-how-much-of-the-validation-set-to-check)
|
||||||
- [Set how much of the test set to check](Validation%20Loop/#set-how-much-of-the-test-set-to-check)
|
- [Set how much of the test set to check](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-how-much-of-the-test-set-to-check)
|
||||||
- [Set validation check frequency within 1 training epoch](Validation%20Loop/#set-validation-check-frequency-within-1-training-epoch)
|
- [Set validation check frequency within 1 training epoch](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-validation-check-frequency-within-1-training-epoch)
|
||||||
- [Set the number of validation sanity steps](Validation%20Loop/#set-the-number-of-validation-sanity-steps)
|
- [Set the number of validation sanity steps](https://williamfalcon.github.io/pytorch-lightning/Trainer/Validation%20loop/#set-the-number-of-validation-sanity-steps)
|
||||||
|
|||||||
+5
-3
@@ -9,9 +9,9 @@ one could be a seq-2-seq model, both (optionally) ran by the same trainer file.
|
|||||||
|
|
||||||
1. [MNIST LightningModule](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#minimal-example)
|
1. [MNIST LightningModule](https://williamfalcon.github.io/pytorch-lightning/LightningModule/RequiredTrainerInterface/#minimal-example)
|
||||||
2. [Trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
|
2. [Trainer](https://williamfalcon.github.io/pytorch-lightning/Trainer/)
|
||||||
- [Basic CPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/single_cpu_template.py)
|
- [Basic CPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/single_cpu_template.py)
|
||||||
- [Multi-GPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/single_gpu_node_template.py)
|
- [Multi-GPU Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/single_gpu_node_template.py)
|
||||||
- [GPU cluster Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/pytorch_lightning/examples/new_project_templates/multi_node_cluster_template.py)
|
- [GPU cluster Trainer Template](https://github.com/williamFalcon/pytorch-lightning/blob/master/examples/new_project_templates/multi_node_cluster_template.py)
|
||||||
|
|
||||||
###### Docs shortcuts
|
###### Docs shortcuts
|
||||||
- [LightningModule](LightningModule/RequiredTrainerInterface/)
|
- [LightningModule](LightningModule/RequiredTrainerInterface/)
|
||||||
@@ -28,6 +28,7 @@ one could be a seq-2-seq model, both (optionally) ran by the same trainer file.
|
|||||||
|
|
||||||
- [Model saving](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#model-saving)
|
- [Model saving](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#model-saving)
|
||||||
- [Model loading](https://williamfalcon.github.io/pytorch-lightning/LightningModule/methods/#load-from-metrics)
|
- [Model loading](https://williamfalcon.github.io/pytorch-lightning/LightningModule/methods/#load-from-metrics)
|
||||||
|
- [Restoring training session](https://williamfalcon.github.io/pytorch-lightning/Trainer/Checkpointing/#restoring-training-session)
|
||||||
|
|
||||||
###### Computing cluster (SLURM)
|
###### Computing cluster (SLURM)
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ one could be a seq-2-seq model, both (optionally) ran by the same trainer file.
|
|||||||
- [Make model overfit on subset of data](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#make-model-overfit-on-subset-of-data)
|
- [Make model overfit on subset of data](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#make-model-overfit-on-subset-of-data)
|
||||||
- [Print the parameter count by layer](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-the-parameter-count-by-layer)
|
- [Print the parameter count by layer](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-the-parameter-count-by-layer)
|
||||||
- [Pring which gradients are nan](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-which-gradients-are-nan)
|
- [Pring which gradients are nan](https://williamfalcon.github.io/pytorch-lightning/Trainer/debugging/#print-which-gradients-are-nan)
|
||||||
|
- [Print input and output size of every module in system](https://williamfalcon.github.io/pytorch-lightning/LightningModule/properties/#example_input_array)
|
||||||
|
|
||||||
|
|
||||||
###### Distributed training
|
###### Distributed training
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
mkdocs-material==4.4.0
|
mkdocs-material==4.4.0
|
||||||
|
mkdocs==1.0.4
|
||||||
|
Before Width: | Height: | Size: 901 B After Width: | Height: | Size: 901 B |
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 410 KiB |
@@ -1 +1,5 @@
|
|||||||
from .new_project_templates.lightning_module_template import LightningTemplateModel
|
from .new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'LightningTemplateModel'
|
||||||
|
]
|
||||||
+44
-20
@@ -1,3 +1,6 @@
|
|||||||
|
"""
|
||||||
|
Example template for defining a system
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
@@ -10,7 +13,7 @@ from torch import optim
|
|||||||
from torch.utils.data import DataLoader
|
from torch.utils.data import DataLoader
|
||||||
from torch.utils.data.distributed import DistributedSampler
|
from torch.utils.data.distributed import DistributedSampler
|
||||||
|
|
||||||
import pytorch_lightning as ptl
|
import pytorch_lightning as pl
|
||||||
from pytorch_lightning.root_module.root_module import LightningModule
|
from pytorch_lightning.root_module.root_module import LightningModule
|
||||||
|
|
||||||
|
|
||||||
@@ -44,11 +47,13 @@ class LightningTemplateModel(LightningModule):
|
|||||||
Layout model
|
Layout model
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.c_d1 = nn.Linear(in_features=self.hparams.in_features, out_features=self.hparams.hidden_dim)
|
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_bn = nn.BatchNorm1d(self.hparams.hidden_dim)
|
||||||
self.c_d1_drop = nn.Dropout(self.hparams.drop_prob)
|
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)
|
self.c_d2 = nn.Linear(in_features=self.hparams.hidden_dim,
|
||||||
|
out_features=self.hparams.out_features)
|
||||||
|
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# TRAINING
|
# TRAINING
|
||||||
@@ -146,12 +151,23 @@ class LightningTemplateModel(LightningModule):
|
|||||||
val_loss_mean = 0
|
val_loss_mean = 0
|
||||||
val_acc_mean = 0
|
val_acc_mean = 0
|
||||||
for output in outputs:
|
for output in outputs:
|
||||||
val_loss_mean += output['val_loss']
|
val_loss = output['val_loss']
|
||||||
val_acc_mean += output['val_acc']
|
|
||||||
|
# reduce manually when using dp
|
||||||
|
if self.trainer.use_dp:
|
||||||
|
val_loss = torch.mean(val_loss)
|
||||||
|
val_loss_mean += val_loss
|
||||||
|
|
||||||
|
# reduce manually when using dp
|
||||||
|
val_acc = output['val_acc']
|
||||||
|
if self.trainer.use_dp:
|
||||||
|
val_acc_mean = torch.mean(val_acc)
|
||||||
|
|
||||||
|
val_acc_mean += val_acc_mean
|
||||||
|
|
||||||
val_loss_mean /= len(outputs)
|
val_loss_mean /= len(outputs)
|
||||||
val_acc_mean /= len(outputs)
|
val_acc_mean /= len(outputs)
|
||||||
tqdm_dic = {'val_loss': val_loss_mean.item(), 'val_acc': val_acc_mean.item()}
|
tqdm_dic = {'val_loss': val_loss_mean, 'val_acc': val_acc_mean}
|
||||||
return tqdm_dic
|
return tqdm_dic
|
||||||
|
|
||||||
# ---------------------
|
# ---------------------
|
||||||
@@ -168,8 +184,10 @@ class LightningTemplateModel(LightningModule):
|
|||||||
|
|
||||||
def __dataloader(self, train):
|
def __dataloader(self, train):
|
||||||
# init data generators
|
# init data generators
|
||||||
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
transform = transforms.Compose([transforms.ToTensor(),
|
||||||
dataset = MNIST(root=self.hparams.data_root, train=train, transform=transform, download=True)
|
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
|
# when using multi-node we need to add the datasampler
|
||||||
train_sampler = None
|
train_sampler = None
|
||||||
@@ -179,7 +197,7 @@ class LightningTemplateModel(LightningModule):
|
|||||||
if self.on_gpu:
|
if self.on_gpu:
|
||||||
train_sampler = DistributedSampler(dataset, rank=self.trainer.proc_rank)
|
train_sampler = DistributedSampler(dataset, rank=self.trainer.proc_rank)
|
||||||
batch_size = batch_size // self.trainer.world_size # scale batch size
|
batch_size = batch_size // self.trainer.world_size # scale batch size
|
||||||
except Exception as e:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
should_shuffle = train_sampler is None
|
should_shuffle = train_sampler is None
|
||||||
@@ -192,23 +210,23 @@ class LightningTemplateModel(LightningModule):
|
|||||||
|
|
||||||
return loader
|
return loader
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
print('tng data loader called')
|
print('tng data loader called')
|
||||||
return self.__dataloader(train=True)
|
return self.__dataloader(train=True)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
print('val data loader called')
|
print('val data loader called')
|
||||||
return self.__dataloader(train=False)
|
return self.__dataloader(train=False)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
print('test data loader called')
|
print('test data loader called')
|
||||||
return self.__dataloader(train=False)
|
return self.__dataloader(train=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_model_specific_args(parent_parser, root_dir): # pragma: no cover
|
def add_model_specific_args(parent_parser, root_dir): # pragma: no cover
|
||||||
"""
|
"""
|
||||||
Parameters you define here will be available to your model through self.hparams
|
Parameters you define here will be available to your model through self.hparams
|
||||||
:param parent_parser:
|
:param parent_parser:
|
||||||
@@ -221,19 +239,25 @@ class LightningTemplateModel(LightningModule):
|
|||||||
# parser.set_defaults(gradient_clip=5.0)
|
# parser.set_defaults(gradient_clip=5.0)
|
||||||
|
|
||||||
# network params
|
# network params
|
||||||
parser.add_argument('--in_features', default=28*28, type=int)
|
parser.add_argument('--in_features', default=28 * 28, type=int)
|
||||||
parser.add_argument('--out_features', default=10, 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
|
# use 500 for CPU, 50000 for GPU to see speed difference
|
||||||
|
parser.add_argument('--hidden_dim', default=50000, type=int)
|
||||||
|
parser.opt_list('--drop_prob', default=0.2, options=[0.2, 0.5], type=float, tunable=False)
|
||||||
|
|
||||||
# data
|
# data
|
||||||
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
|
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
|
||||||
|
|
||||||
# training params (opt)
|
# training params (opt)
|
||||||
parser.opt_list('--learning_rate', default=0.001*8, type=float, options=[0.0001, 0.0005, 0.001, 0.005],
|
parser.opt_list('--learning_rate', default=0.001 * 8, type=float,
|
||||||
|
options=[0.0001, 0.0005, 0.001, 0.005],
|
||||||
tunable=False)
|
tunable=False)
|
||||||
parser.opt_list('--optimizer_name', default='adam', type=str, options=['adam'], 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
|
# if using 2 nodes with 4 gpus each the batch size here
|
||||||
parser.opt_list('--batch_size', default=256*8, type=int, options=[32, 64, 128, 256], tunable=False,
|
# (256) will be 256 / (2*8) = 16 per gpu
|
||||||
help='batch size will be divided over all the gpus being used across all nodes')
|
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 gpus being used across all nodes')
|
||||||
return parser
|
return parser
|
||||||
+25
-25
@@ -1,31 +1,21 @@
|
|||||||
|
"""
|
||||||
|
Multi-node example (GPU)
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
np.random.seed(SEED)
|
np.random.seed(SEED)
|
||||||
|
|
||||||
# ---------------------
|
|
||||||
# DEFINE MODEL HERE
|
|
||||||
# ---------------------
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
# ---------------------
|
|
||||||
|
|
||||||
"""
|
|
||||||
Allows training by using command line arguments
|
|
||||||
Run by:
|
|
||||||
# TYPE YOUR RUN COMMAND HERE
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def main_local(hparams):
|
def main_local(hparams):
|
||||||
main(hparams, None, None)
|
main(hparams, None, None)
|
||||||
@@ -122,8 +112,10 @@ def optimize_on_cluster(hyperparams):
|
|||||||
cluster.add_command('source activate lightning')
|
cluster.add_command('source activate lightning')
|
||||||
|
|
||||||
# run only on 32GB voltas
|
# run only on 32GB voltas
|
||||||
cluster.add_slurm_cmd(cmd='constraint', value='volta32gb', comment='use 32gb gpus')
|
cluster.add_slurm_cmd(cmd='constraint', value='volta32gb',
|
||||||
cluster.add_slurm_cmd(cmd='partition', value=hyperparams.gpu_partition, comment='use 32gb gpus')
|
comment='use 32gb gpus')
|
||||||
|
cluster.add_slurm_cmd(cmd='partition', value=hyperparams.gpu_partition,
|
||||||
|
comment='use 32gb gpus')
|
||||||
|
|
||||||
# run hopt
|
# run hopt
|
||||||
# creates and submits jobs to slurm
|
# creates and submits jobs to slurm
|
||||||
@@ -150,15 +142,23 @@ if __name__ == '__main__':
|
|||||||
parent_parser.add_argument('--gpu_partition', type=str, help='consult your cluster manual')
|
parent_parser.add_argument('--gpu_partition', type=str, help='consult your cluster manual')
|
||||||
|
|
||||||
# TODO: make 1 param
|
# TODO: make 1 param
|
||||||
parent_parser.add_argument('--per_experiment_nb_gpus', type=int, help='how many gpus to use in a node')
|
parent_parser.add_argument('--per_experiment_nb_gpus', type=int,
|
||||||
parent_parser.add_argument('--gpus', type=str, default='-1', help='how many gpus to use in the node')
|
help='how many gpus to use in a node')
|
||||||
|
parent_parser.add_argument('--gpus', type=str, default='-1',
|
||||||
|
help='how many gpus to use in the node')
|
||||||
|
|
||||||
parent_parser.add_argument('--nb_gpu_nodes', type=int, default=1, help='how many nodes to use in a cluster')
|
parent_parser.add_argument('--nb_gpu_nodes', type=int, default=1,
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
help='how many nodes to use in a cluster')
|
||||||
parent_parser.add_argument('--slurm_log_path', type=str, default=slurm_out_dir, help='where to save slurm meta')
|
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir,
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
help='where to save logs')
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
parent_parser.add_argument('--slurm_log_path', type=str, default=slurm_out_dir,
|
||||||
parent_parser.add_argument('--nb_hopt_trials', type=int, default=1, help='how many grid search trials to run')
|
help='where to save slurm meta')
|
||||||
|
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')
|
||||||
|
parent_parser.add_argument('--nb_hopt_trials', type=int, default=1,
|
||||||
|
help='how many grid search trials to run')
|
||||||
|
|
||||||
# allow model to overwrite or extend args
|
# allow model to overwrite or extend args
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
||||||
+11
-12
@@ -1,24 +1,20 @@
|
|||||||
"""
|
"""
|
||||||
Runs a model on a single node across N-gpus.
|
Runs a model on a single node on CPU only..
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from time import sleep
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
from test_tube import HyperOptArgumentParser, Experiment
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
np.random.seed(SEED)
|
np.random.seed(SEED)
|
||||||
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
def main(hparams):
|
||||||
"""
|
"""
|
||||||
@@ -94,9 +90,12 @@ if __name__ == '__main__':
|
|||||||
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
||||||
|
|
||||||
# gpu args
|
# gpu args
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
parent_parser.add_argument('--test_tube_save_path', type=str,
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
default=test_tube_dir, help='where to save logs')
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
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
|
# allow model to overwrite or extend args
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
||||||
@@ -106,5 +105,5 @@ if __name__ == '__main__':
|
|||||||
# RUN TRAINING
|
# RUN TRAINING
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# run on HPC cluster
|
# run on HPC cluster
|
||||||
print(f'RUNNING ON CPU')
|
print('RUNNING ON CPU')
|
||||||
main(hyperparams)
|
main(hyperparams)
|
||||||
+14
-13
@@ -1,24 +1,20 @@
|
|||||||
"""
|
"""
|
||||||
Runs a model on a single node across N-gpus.
|
16-bit single node, CPU example
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from time import sleep
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
from test_tube import HyperOptArgumentParser, Experiment
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
np.random.seed(SEED)
|
np.random.seed(SEED)
|
||||||
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
def main(hparams):
|
||||||
"""
|
"""
|
||||||
@@ -96,10 +92,15 @@ if __name__ == '__main__':
|
|||||||
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
||||||
|
|
||||||
# gpu args
|
# 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('--gpus', type=str, default='-1',
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
help='how many gpus to use in the node.'
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
'value -1 uses all the gpus on the node')
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
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
|
# allow model to overwrite or extend args
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
||||||
@@ -109,5 +110,5 @@ if __name__ == '__main__':
|
|||||||
# RUN TRAINING
|
# RUN TRAINING
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# run on HPC cluster
|
# run on HPC cluster
|
||||||
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
|
print('RUNNING INTERACTIVE MODE ON GPUS. gpu ids: %i' % hyperparams.gpus)
|
||||||
main(hyperparams)
|
main(hyperparams)
|
||||||
+14
-12
@@ -2,23 +2,19 @@
|
|||||||
Runs a model on a single node across N-gpus.
|
Runs a model on a single node across N-gpus.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from time import sleep
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
from test_tube import HyperOptArgumentParser, Experiment
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
np.random.seed(SEED)
|
np.random.seed(SEED)
|
||||||
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
def main(hparams):
|
||||||
"""
|
"""
|
||||||
@@ -75,6 +71,7 @@ def main(hparams):
|
|||||||
checkpoint_callback=checkpoint,
|
checkpoint_callback=checkpoint,
|
||||||
early_stop_callback=early_stop,
|
early_stop_callback=early_stop,
|
||||||
gpus=hparams.gpus,
|
gpus=hparams.gpus,
|
||||||
|
distributed_backend='ddp'
|
||||||
)
|
)
|
||||||
|
|
||||||
# ------------------------
|
# ------------------------
|
||||||
@@ -95,10 +92,15 @@ if __name__ == '__main__':
|
|||||||
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
||||||
|
|
||||||
# gpu args
|
# 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('--gpus', type=str, default='-1',
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
help='how many gpus to use in the node.'
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
' value -1 uses all the gpus on the node')
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
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
|
# allow model to overwrite or extend args
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
||||||
@@ -108,5 +110,5 @@ if __name__ == '__main__':
|
|||||||
# RUN TRAINING
|
# RUN TRAINING
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# run on HPC cluster
|
# run on HPC cluster
|
||||||
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
|
print('RUNNING INTERACTIVE MODE ON GPUS. gpu ids: %i' % hyperparams.gpus)
|
||||||
main(hyperparams)
|
main(hyperparams)
|
||||||
+14
-13
@@ -1,24 +1,20 @@
|
|||||||
"""
|
"""
|
||||||
Runs a model on a single node across N-gpus.
|
Runs a model on a single node across N-gpus using dataParallel
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from time import sleep
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
from test_tube import HyperOptArgumentParser, Experiment
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
np.random.seed(SEED)
|
np.random.seed(SEED)
|
||||||
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
def main(hparams):
|
||||||
"""
|
"""
|
||||||
@@ -95,10 +91,15 @@ if __name__ == '__main__':
|
|||||||
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
||||||
|
|
||||||
# gpu args
|
# 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('--gpus', type=str, default='-1',
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
help='how many gpus to use in the node.'
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
' value -1 uses all the gpus on the node')
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
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
|
# allow model to overwrite or extend args
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
||||||
@@ -108,5 +109,5 @@ if __name__ == '__main__':
|
|||||||
# RUN TRAINING
|
# RUN TRAINING
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# run on HPC cluster
|
# run on HPC cluster
|
||||||
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
|
print('RUNNING INTERACTIVE MODE ON GPUS. gpu ids: %i' % hyperparams.gpus)
|
||||||
main(hyperparams)
|
main(hyperparams)
|
||||||
+5
-4
@@ -3,9 +3,10 @@ import sys
|
|||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment
|
from test_tube import HyperOptArgumentParser, Experiment
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
from pytorch_lightning.models.trainer import Trainer
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
from pytorch_lightning.utilities.arg_parse import add_default_args
|
||||||
from pytorch_lightning.callbacks.pt_callbacks import EarlyStopping, ModelCheckpoint
|
from pytorch_lightning.callbacks.pt_callbacks import EarlyStopping, ModelCheckpoint
|
||||||
from docs.source.examples.example_model import ExampleModel
|
|
||||||
|
from examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
def main(hparams):
|
||||||
@@ -28,7 +29,7 @@ def main(hparams):
|
|||||||
exp.save()
|
exp.save()
|
||||||
|
|
||||||
# build model
|
# build model
|
||||||
model = ExampleModel(hparams)
|
model = LightningTemplateModel(hparams)
|
||||||
|
|
||||||
# callbacks
|
# callbacks
|
||||||
early_stop = EarlyStopping(
|
early_stop = EarlyStopping(
|
||||||
@@ -66,7 +67,7 @@ if __name__ == '__main__':
|
|||||||
add_default_args(parent_parser, root_dir)
|
add_default_args(parent_parser, root_dir)
|
||||||
|
|
||||||
# allow model to overwrite or extend args
|
# allow model to overwrite or extend args
|
||||||
parser = ExampleModel.add_model_specific_args(parent_parser)
|
parser = LightningTemplateModel.add_model_specific_args(parent_parser)
|
||||||
hyperparams = parser.parse_args()
|
hyperparams = parser.parse_args()
|
||||||
|
|
||||||
# train model
|
# train model
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
from .models import Trainer
|
from .models.trainer import Trainer
|
||||||
from .root_module.root_module import LightningModule
|
from .root_module.root_module import LightningModule
|
||||||
from .root_module.decorators import data_loader
|
from .root_module.decorators import data_loader
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'Trainer',
|
||||||
|
'LightningModule',
|
||||||
|
'data_loader',
|
||||||
|
]
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
from .pt_callbacks import EarlyStopping, ModelCheckpoint
|
from .pt_callbacks import EarlyStopping, ModelCheckpoint
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'EarlyStopping',
|
||||||
|
'ModelCheckpoint',
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import os, shutil
|
|
||||||
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel
|
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel
|
||||||
|
|
||||||
|
|
||||||
@@ -119,9 +122,9 @@ class EarlyStopping(Callback):
|
|||||||
current = logs.get(self.monitor)
|
current = logs.get(self.monitor)
|
||||||
stop_training = False
|
stop_training = False
|
||||||
if current is None:
|
if current is None:
|
||||||
print('Early stopping conditioned on metric `%s` ''which is not available. Available metrics are: %s' %
|
print('Early stopping conditioned on metric `%s` '
|
||||||
(self.monitor, ','.join(list(logs.keys()))), RuntimeWarning
|
'which is not available. Available metrics are: %s' %
|
||||||
)
|
(self.monitor, ','.join(list(logs.keys()))), RuntimeWarning)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
if self.monitor_op(current - self.min_delta, self.best):
|
if self.monitor_op(current - self.min_delta, self.best):
|
||||||
@@ -185,8 +188,7 @@ class ModelCheckpoint(Callback):
|
|||||||
|
|
||||||
if mode not in ['auto', 'min', 'max']:
|
if mode not in ['auto', 'min', 'max']:
|
||||||
print('ModelCheckpoint mode %s is unknown, '
|
print('ModelCheckpoint mode %s is unknown, '
|
||||||
'fallback to auto mode.' % (mode),
|
'fallback to auto mode.' % (mode), RuntimeWarning)
|
||||||
RuntimeWarning)
|
|
||||||
mode = 'auto'
|
mode = 'auto'
|
||||||
|
|
||||||
if mode == 'min':
|
if mode == 'min':
|
||||||
@@ -230,8 +232,8 @@ class ModelCheckpoint(Callback):
|
|||||||
if self.save_best_only:
|
if self.save_best_only:
|
||||||
current = logs.get(self.monitor)
|
current = logs.get(self.monitor)
|
||||||
if current is None:
|
if current is None:
|
||||||
print('Can save best model only with %s available, '
|
print('Can save best model only with %s available,'
|
||||||
'skipping.' % (self.monitor), RuntimeWarning)
|
' skipping.' % (self.monitor), RuntimeWarning)
|
||||||
else:
|
else:
|
||||||
if self.monitor_op(current, self.best):
|
if self.monitor_op(current, self.best):
|
||||||
if self.verbose > 0:
|
if self.verbose > 0:
|
||||||
@@ -260,4 +262,3 @@ if __name__ == '__main__':
|
|||||||
print(loss)
|
print(loss)
|
||||||
if should_stop:
|
if should_stop:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
"""
|
|
||||||
Runs a model on a single node across N-gpus.
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import numpy as np
|
|
||||||
from time import sleep
|
|
||||||
import torch
|
|
||||||
|
|
||||||
from test_tube import HyperOptArgumentParser, Experiment, SlurmCluster
|
|
||||||
from pytorch_lightning.models.trainer import Trainer
|
|
||||||
from pytorch_lightning.utils.arg_parse import add_default_args
|
|
||||||
|
|
||||||
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
|
|
||||||
|
|
||||||
SEED = 2334
|
|
||||||
torch.manual_seed(SEED)
|
|
||||||
np.random.seed(SEED)
|
|
||||||
|
|
||||||
from lightning_module_template import LightningTemplateModel
|
|
||||||
|
|
||||||
|
|
||||||
def main(hparams):
|
|
||||||
"""
|
|
||||||
Main training routine specific for this project
|
|
||||||
:param hparams:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# ------------------------
|
|
||||||
# 1 INIT LIGHTNING MODEL
|
|
||||||
# ------------------------
|
|
||||||
print('loading model...')
|
|
||||||
model = LightningTemplateModel(hparams)
|
|
||||||
print('model built')
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# 2 INIT TEST TUBE EXP
|
|
||||||
# ------------------------
|
|
||||||
|
|
||||||
# init experiment
|
|
||||||
exp = Experiment(
|
|
||||||
name=hyperparams.experiment_name,
|
|
||||||
save_dir=hyperparams.test_tube_save_path,
|
|
||||||
autosave=False,
|
|
||||||
description='test demo'
|
|
||||||
)
|
|
||||||
|
|
||||||
exp.argparse(hparams)
|
|
||||||
exp.save()
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# 3 DEFINE CALLBACKS
|
|
||||||
# ------------------------
|
|
||||||
model_save_path = '{}/{}/{}'.format(hparams.model_save_path, exp.name, exp.version)
|
|
||||||
early_stop = EarlyStopping(
|
|
||||||
monitor='val_acc',
|
|
||||||
patience=3,
|
|
||||||
verbose=True,
|
|
||||||
mode='max'
|
|
||||||
)
|
|
||||||
|
|
||||||
checkpoint = ModelCheckpoint(
|
|
||||||
filepath=model_save_path,
|
|
||||||
save_best_only=True,
|
|
||||||
verbose=True,
|
|
||||||
monitor='val_loss',
|
|
||||||
mode='min'
|
|
||||||
)
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# 4 INIT TRAINER
|
|
||||||
# ------------------------
|
|
||||||
trainer = Trainer(
|
|
||||||
experiment=exp,
|
|
||||||
checkpoint_callback=checkpoint,
|
|
||||||
early_stop_callback=early_stop,
|
|
||||||
gpus=hparams.gpus,
|
|
||||||
)
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# 5 START TRAINING
|
|
||||||
# ------------------------
|
|
||||||
trainer.fit(model)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
# dirs
|
|
||||||
root_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
demo_log_dir = os.path.join(root_dir, 'pt_lightning_demo_logs')
|
|
||||||
checkpoint_dir = os.path.join(demo_log_dir, 'model_weights')
|
|
||||||
test_tube_dir = os.path.join(demo_log_dir, 'test_tube_data')
|
|
||||||
|
|
||||||
# although we user hyperOptParser, we are using it only as argparse right now
|
|
||||||
parent_parser = HyperOptArgumentParser(strategy='grid_search', add_help=False)
|
|
||||||
|
|
||||||
# gpu args
|
|
||||||
parent_parser.add_argument('--gpus', type=str, default='0', help='how many gpus to use in the node. -1 uses all the gpus on the node')
|
|
||||||
parent_parser.add_argument('--test_tube_save_path', type=str, default=test_tube_dir, help='where to save logs')
|
|
||||||
parent_parser.add_argument('--model_save_path', type=str, default=checkpoint_dir, help='where to save model')
|
|
||||||
parent_parser.add_argument('--experiment_name', type=str, default='pt_lightning_exp_a', help='test tube exp name')
|
|
||||||
|
|
||||||
# allow model to overwrite or extend args
|
|
||||||
parser = LightningTemplateModel.add_model_specific_args(parent_parser, root_dir)
|
|
||||||
hyperparams = parser.parse_args()
|
|
||||||
|
|
||||||
# ---------------------
|
|
||||||
# RUN TRAINING
|
|
||||||
# ---------------------
|
|
||||||
# run on HPC cluster
|
|
||||||
print(f'RUNNING INTERACTIVE MODE ON GPUS. gpu ids: {hyperparams.gpus}')
|
|
||||||
main(hyperparams)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from .trainer import Trainer
|
|
||||||
@@ -1,29 +1,28 @@
|
|||||||
"""
|
"""
|
||||||
The trainer handles all the logic for running a val loop, training loop, distributing, etc...
|
The trainer handles all the logic for running a val loop, training loop, distributing, etc.. .
|
||||||
"""
|
"""
|
||||||
import subprocess
|
|
||||||
import traceback
|
|
||||||
import warnings
|
|
||||||
import os
|
|
||||||
import pdb
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import tqdm
|
||||||
import torch
|
import torch
|
||||||
from torch.utils.data.distributed import DistributedSampler
|
from torch.utils.data.distributed import DistributedSampler
|
||||||
import torch.multiprocessing as mp
|
import torch.multiprocessing as mp
|
||||||
import torch.distributed as dist
|
import torch.distributed as dist
|
||||||
import numpy as np
|
|
||||||
import tqdm
|
|
||||||
|
|
||||||
from pytorch_lightning.root_module.memory import get_gpu_memory_map
|
from pytorch_lightning.root_module.memory import get_gpu_memory_map
|
||||||
from pytorch_lightning.root_module.model_saving import TrainerIO
|
from pytorch_lightning.root_module.model_saving import TrainerIO
|
||||||
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel, LightningDataParallel
|
from pytorch_lightning.pt_overrides.override_data_parallel import (
|
||||||
from pytorch_lightning.utils.debugging import MisconfigurationException
|
LightningDistributedDataParallel, LightningDataParallel)
|
||||||
|
from pytorch_lightning.utilities.debugging import MisconfigurationException
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from apex import amp
|
from apex import amp
|
||||||
APEX_AVAILABLE = True
|
APEX_AVAILABLE = True
|
||||||
except Exception:
|
except ImportError:
|
||||||
APEX_AVAILABLE = False
|
APEX_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ def reduce_distributed_output(output, nb_gpus):
|
|||||||
class Trainer(TrainerIO):
|
class Trainer(TrainerIO):
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
experiment,
|
experiment=None,
|
||||||
early_stop_callback=None,
|
early_stop_callback=None,
|
||||||
checkpoint_callback=None,
|
checkpoint_callback=None,
|
||||||
gradient_clip=0,
|
gradient_clip=0,
|
||||||
@@ -66,17 +65,20 @@ class Trainer(TrainerIO):
|
|||||||
check_val_every_n_epoch=1,
|
check_val_every_n_epoch=1,
|
||||||
fast_dev_run=False,
|
fast_dev_run=False,
|
||||||
accumulate_grad_batches=1,
|
accumulate_grad_batches=1,
|
||||||
max_nb_epochs=1000, min_nb_epochs=1,
|
max_nb_epochs=1000,
|
||||||
train_percent_check=1.0, val_percent_check=1.0, test_percent_check=1.0,
|
min_nb_epochs=1,
|
||||||
|
train_percent_check=1.0,
|
||||||
|
val_percent_check=1.0,
|
||||||
|
test_percent_check=1.0,
|
||||||
val_check_interval=0.95,
|
val_check_interval=0.95,
|
||||||
log_save_interval=100, add_log_row_interval=10,
|
log_save_interval=100,
|
||||||
|
add_log_row_interval=10,
|
||||||
distributed_backend='dp',
|
distributed_backend='dp',
|
||||||
use_amp=False,
|
use_amp=False,
|
||||||
print_nan_grads=False,
|
print_nan_grads=False,
|
||||||
print_weights_summary=True,
|
print_weights_summary=True,
|
||||||
amp_level='O2',
|
amp_level='O2',
|
||||||
nb_sanity_val_steps=5):
|
nb_sanity_val_steps=5):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param experiment: Test-tube experiment
|
:param experiment: Test-tube experiment
|
||||||
@@ -102,16 +104,15 @@ class Trainer(TrainerIO):
|
|||||||
:param val_check_interval:
|
:param val_check_interval:
|
||||||
:param log_save_interval:
|
:param log_save_interval:
|
||||||
:param add_log_row_interval:
|
:param add_log_row_interval:
|
||||||
:param distributed_backend: 'np' to use DistributedParallel, 'ddp' to use DistributedDataParallel
|
:param distributed_backend:
|
||||||
|
'do' to use DistributedParallel, 'dp' to use DistributedDataParallel, 'n' to use none
|
||||||
:param use_amp:
|
:param use_amp:
|
||||||
:param print_nan_grads:
|
:param print_nan_grads:
|
||||||
:param print_weights_summary:
|
:param print_weights_summary:
|
||||||
:param amp_level:
|
:param amp_level:
|
||||||
:param nb_sanity_val_steps:
|
:param nb_sanity_val_steps:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Transfer params
|
# Transfer params
|
||||||
|
|
||||||
self.nb_gpu_nodes = nb_gpu_nodes
|
self.nb_gpu_nodes = nb_gpu_nodes
|
||||||
self.gradient_clip = gradient_clip
|
self.gradient_clip = gradient_clip
|
||||||
self.check_val_every_n_epoch = check_val_every_n_epoch
|
self.check_val_every_n_epoch = check_val_every_n_epoch
|
||||||
@@ -121,7 +122,9 @@ class Trainer(TrainerIO):
|
|||||||
self.on_gpu = gpus is not None and torch.cuda.is_available()
|
self.on_gpu = gpus is not None and torch.cuda.is_available()
|
||||||
self.progress_bar = progress_bar
|
self.progress_bar = progress_bar
|
||||||
self.experiment = experiment
|
self.experiment = experiment
|
||||||
self.exp_save_path = experiment.get_data_path(experiment.name, experiment.version)
|
self.exp_save_path = None
|
||||||
|
if self.experiment is not None:
|
||||||
|
self.exp_save_path = experiment.get_data_path(experiment.name, experiment.version)
|
||||||
self.cluster = cluster
|
self.cluster = cluster
|
||||||
self.process_position = process_position
|
self.process_position = process_position
|
||||||
self.current_gpu_name = current_gpu_name
|
self.current_gpu_name = current_gpu_name
|
||||||
@@ -146,6 +149,7 @@ class Trainer(TrainerIO):
|
|||||||
self.node_rank = 0
|
self.node_rank = 0
|
||||||
self.use_ddp = False
|
self.use_ddp = False
|
||||||
self.use_dp = False
|
self.use_dp = False
|
||||||
|
self.single_gpu = False
|
||||||
|
|
||||||
# training bookeeping
|
# training bookeeping
|
||||||
self.total_batch_nb = 0
|
self.total_batch_nb = 0
|
||||||
@@ -173,13 +177,14 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# set the correct cuda visible devices (using pci order)
|
# set the correct cuda visible devices (using pci order)
|
||||||
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
|
||||||
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join([str(x) for x in self.data_parallel_device_ids])
|
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join([str(x) for x in
|
||||||
print(f'VISIBLE GPUS: {os.environ["CUDA_VISIBLE_DEVICES"]}')
|
self.data_parallel_device_ids])
|
||||||
|
print('VISIBLE GPUS: %r' % os.environ["CUDA_VISIBLE_DEVICES"])
|
||||||
|
|
||||||
# make DP and DDP mutually exclusive
|
# make DP and DDP mutually exclusive
|
||||||
# single GPU will also use DP with devices=[0]
|
# 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
|
requested_gpus = self.data_parallel_device_ids is not None
|
||||||
if have_gpus:
|
if requested_gpus and len(self.data_parallel_device_ids) > 0:
|
||||||
self.use_dp = distributed_backend == 'dp'
|
self.use_dp = distributed_backend == 'dp'
|
||||||
self.use_ddp = distributed_backend == 'ddp'
|
self.use_ddp = distributed_backend == 'ddp'
|
||||||
|
|
||||||
@@ -192,6 +197,12 @@ class Trainer(TrainerIO):
|
|||||||
'To silence this warning set distributed_backend=ddp'
|
'To silence this warning set distributed_backend=ddp'
|
||||||
warnings.warn(w)
|
warnings.warn(w)
|
||||||
|
|
||||||
|
# remove dp and ddp when requesting single gpu
|
||||||
|
if self.data_parallel_device_ids is not None and len(self.data_parallel_device_ids) == 1:
|
||||||
|
self.use_ddp = False
|
||||||
|
self.use_dp = False
|
||||||
|
self.single_gpu = True
|
||||||
|
|
||||||
# extract SLURM flag vars
|
# extract SLURM flag vars
|
||||||
# whenever we have the correct number of tasks, we let slurm manage processes
|
# whenever we have the correct number of tasks, we let slurm manage processes
|
||||||
# otherwise we launch the required number of processes
|
# otherwise we launch the required number of processes
|
||||||
@@ -201,7 +212,7 @@ class Trainer(TrainerIO):
|
|||||||
try:
|
try:
|
||||||
self.nb_slurm_tasks = int(os.environ['SLURM_NTASKS'])
|
self.nb_slurm_tasks = int(os.environ['SLURM_NTASKS'])
|
||||||
self.is_slurm_managing_tasks = self.nb_slurm_tasks == self.nb_requested_gpus
|
self.is_slurm_managing_tasks = self.nb_slurm_tasks == self.nb_requested_gpus
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# likely not on slurm, so set the slurm managed flag to false
|
# likely not on slurm, so set the slurm managed flag to false
|
||||||
self.is_slurm_managing_tasks = False
|
self.is_slurm_managing_tasks = False
|
||||||
|
|
||||||
@@ -226,7 +237,8 @@ class Trainer(TrainerIO):
|
|||||||
self.val_dataloader = None
|
self.val_dataloader = None
|
||||||
|
|
||||||
# how much of the data to use
|
# how much of the data to use
|
||||||
self.__determine_data_use_amount(train_percent_check, val_percent_check, test_percent_check, overfit_pct)
|
self.__determine_data_use_amount(train_percent_check, val_percent_check,
|
||||||
|
test_percent_check, overfit_pct)
|
||||||
print('gpu available: {}, used: {}'.format(torch.cuda.is_available(), self.on_gpu))
|
print('gpu available: {}, used: {}'.format(torch.cuda.is_available(), self.on_gpu))
|
||||||
|
|
||||||
# 16 bit mixed precision training using apex
|
# 16 bit mixed precision training using apex
|
||||||
@@ -235,20 +247,52 @@ class Trainer(TrainerIO):
|
|||||||
print('using 16bit precision')
|
print('using 16bit precision')
|
||||||
|
|
||||||
if use_amp and not APEX_AVAILABLE: # pragma: no cover
|
if use_amp and not APEX_AVAILABLE: # pragma: no cover
|
||||||
msg = '''
|
msg = """
|
||||||
You set use_amp=True but do not have apex installed.
|
You set use_amp=True but do not have apex installed.
|
||||||
Install apex first using this guide and rerun with use_amp=True:
|
Install apex first using this guide and rerun with use_amp=True:
|
||||||
https://github.com/NVIDIA/apex#linux
|
https://github.com/NVIDIA/apex#linux
|
||||||
|
|
||||||
this run will NOT use 16 bit precision
|
this run will NOT use 16 bit precision
|
||||||
'''
|
"""
|
||||||
raise ModuleNotFoundError(msg)
|
raise ModuleNotFoundError(msg)
|
||||||
|
|
||||||
|
def restore_state_if_existing_checkpoint(self):
|
||||||
|
# restore trainer state and model if there is a weight for this experiment
|
||||||
|
last_epoch = -1
|
||||||
|
last_ckpt_name = None
|
||||||
|
|
||||||
|
# do nothing if there's not dir or callback
|
||||||
|
no_ckpt_callback = self.checkpoint_callback is None
|
||||||
|
if no_ckpt_callback or not os.path.exists(self.checkpoint_callback.filepath):
|
||||||
|
return
|
||||||
|
|
||||||
|
# find last epoch
|
||||||
|
checkpoints = os.listdir(self.checkpoint_callback.filepath)
|
||||||
|
for name in checkpoints:
|
||||||
|
# ignore hpc ckpts
|
||||||
|
if 'hpc_' in name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '.ckpt' in name:
|
||||||
|
epoch = name.split('epoch_')[1]
|
||||||
|
epoch = int(re.sub('[^0-9]', '', epoch))
|
||||||
|
|
||||||
|
if epoch > last_epoch:
|
||||||
|
last_epoch = epoch
|
||||||
|
last_ckpt_name = name
|
||||||
|
|
||||||
|
# restore last checkpoint
|
||||||
|
if last_ckpt_name is not None:
|
||||||
|
last_ckpt_path = os.path.join(self.checkpoint_callback.filepath, last_ckpt_name)
|
||||||
|
self.restore(last_ckpt_path, self.on_gpu)
|
||||||
|
print(f'model and trainer restored from checkpoint: {last_ckpt_path}')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data_parallel(self):
|
def data_parallel(self):
|
||||||
return self.use_dp or self.use_ddp
|
return self.use_dp or self.use_ddp
|
||||||
|
|
||||||
def __determine_data_use_amount(self, train_percent_check, val_percent_check, test_percent_check, overfit_pct):
|
def __determine_data_use_amount(self, train_percent_check, val_percent_check,
|
||||||
|
test_percent_check, overfit_pct):
|
||||||
"""
|
"""
|
||||||
Use less data for debugging purposes
|
Use less data for debugging purposes
|
||||||
"""
|
"""
|
||||||
@@ -270,13 +314,15 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def __tng_tqdm_dic(self):
|
def __tng_tqdm_dic(self):
|
||||||
# ForkedPdb().set_trace()
|
|
||||||
tqdm_dic = {
|
tqdm_dic = {
|
||||||
'tng_loss': '{0:.3f}'.format(self.avg_loss),
|
'tng_loss': '{0:.3f}'.format(self.avg_loss),
|
||||||
'v_nb': '{}'.format(self.experiment.version),
|
|
||||||
'epoch': '{}'.format(self.current_epoch),
|
'epoch': '{}'.format(self.current_epoch),
|
||||||
'batch_nb':'{}'.format(self.batch_nb),
|
'batch_nb': '{}'.format(self.batch_nb),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.experiment is not None:
|
||||||
|
tqdm_dic['v_nb'] = self.experiment.version
|
||||||
|
|
||||||
tqdm_dic.update(self.tqdm_metrics)
|
tqdm_dic.update(self.tqdm_metrics)
|
||||||
|
|
||||||
if self.on_gpu:
|
if self.on_gpu:
|
||||||
@@ -353,7 +399,15 @@ class Trainer(TrainerIO):
|
|||||||
output = model(data_batch, batch_i)
|
output = model(data_batch, batch_i)
|
||||||
elif self.use_dp:
|
elif self.use_dp:
|
||||||
output = model(data_batch, batch_i)
|
output = model(data_batch, batch_i)
|
||||||
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
|
elif self.single_gpu:
|
||||||
|
# put inputs on gpu manually
|
||||||
|
gpu_id = self.data_parallel_device_ids[0]
|
||||||
|
for i, x in enumerate(data_batch):
|
||||||
|
if isinstance(x, torch.Tensor):
|
||||||
|
data_batch[i] = x.cuda(gpu_id)
|
||||||
|
|
||||||
|
# do non dp, ddp step
|
||||||
|
output = model.validation_step(data_batch, batch_i)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
output = model.validation_step(data_batch, batch_i)
|
output = model.validation_step(data_batch, batch_i)
|
||||||
@@ -389,18 +443,19 @@ class Trainer(TrainerIO):
|
|||||||
self.val_dataloader = model.val_dataloader
|
self.val_dataloader = model.val_dataloader
|
||||||
|
|
||||||
if self.use_ddp and not isinstance(self.tng_dataloader.sampler, DistributedSampler):
|
if self.use_ddp and not isinstance(self.tng_dataloader.sampler, DistributedSampler):
|
||||||
msg = '''
|
msg = """
|
||||||
when using multiple gpus and multiple nodes you must pass a DistributedSampler to DataLoader(sampler).
|
when using multiple gpus and multiple nodes you must pass
|
||||||
|
a DistributedSampler to DataLoader(sampler).
|
||||||
ie: this:
|
|
||||||
dataset = myDataset()
|
ie: this:
|
||||||
dataloader = Dataloader(dataset)
|
dataset = myDataset()
|
||||||
|
dataloader = Dataloader(dataset)
|
||||||
becomes:
|
|
||||||
dataset = myDataset()
|
becomes:
|
||||||
dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset)
|
dataset = myDataset()
|
||||||
dataloader = Dataloader(dataset, sampler=dist_sampler)
|
dist_sampler = torch.utils.data.distributed.DistributedSampler(dataset)
|
||||||
'''
|
dataloader = Dataloader(dataset, sampler=dist_sampler)
|
||||||
|
"""
|
||||||
raise MisconfigurationException(msg)
|
raise MisconfigurationException(msg)
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
@@ -410,19 +465,21 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# when using multi-node or DDP within a node start each module in a separate process
|
# when using multi-node or DDP within a node start each module in a separate process
|
||||||
if self.use_ddp:
|
if self.use_ddp:
|
||||||
# must copy only the meta of the exp so it survives pickle/unpickle when going to new process
|
# must copy only the meta of the exp so it survives pickle/unpickle
|
||||||
self.experiment = self.experiment.get_meta_copy()
|
# when going to new process
|
||||||
|
if self.experiment is not None:
|
||||||
|
self.experiment = self.experiment.get_meta_copy()
|
||||||
|
|
||||||
if self.is_slurm_managing_tasks:
|
if self.is_slurm_managing_tasks:
|
||||||
task = int(os.environ['SLURM_LOCALID'])
|
task = int(os.environ['SLURM_LOCALID'])
|
||||||
self.ddp_train(task, model)
|
self.ddp_train(task, model)
|
||||||
else:
|
else:
|
||||||
msg = f"""
|
msg = """
|
||||||
You requested {self.nb_requested_gpus} GPUs but launched {self.nb_slurm_tasks} slurm tasks.
|
You requested %(nb_gpus)s GPUs but launched %(nb_tasks)s slurm tasks.
|
||||||
We will launch {self.nb_requested_gpus} processes for you.
|
We will launch %(nb_gpus)s processes for you.
|
||||||
We recommend you let slurm manage the processes by setting: --ntasks-per-node={self.nb_requested_gpus}
|
We recommend you let slurm manage the processes by setting: --ntasks-per-node=%(nb_gpus)s
|
||||||
If you're not using SLURM, ignore this message!
|
If you're not using SLURM, ignore this message!
|
||||||
"""
|
""" % {'nb_gpus': self.nb_requested_gpus, 'nb_tasks': self.nb_slurm_tasks}
|
||||||
warnings.warn(msg)
|
warnings.warn(msg)
|
||||||
mp.spawn(self.ddp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
|
mp.spawn(self.ddp_train, nprocs=len(self.data_parallel_device_ids), args=(model, ))
|
||||||
|
|
||||||
@@ -431,11 +488,15 @@ class Trainer(TrainerIO):
|
|||||||
elif self.use_dp:
|
elif self.use_dp:
|
||||||
self.__dp_train(model)
|
self.__dp_train(model)
|
||||||
|
|
||||||
|
elif self.single_gpu:
|
||||||
|
self.__single_gpu_train(model)
|
||||||
|
|
||||||
# ON CPU
|
# ON CPU
|
||||||
else:
|
else:
|
||||||
# run through amp wrapper
|
# run through amp wrapper
|
||||||
if self.use_amp:
|
if self.use_amp:
|
||||||
raise MisconfigurationException('amp + cpu is not supported. Please use a GPU option')
|
raise MisconfigurationException('amp + cpu is not supported.'
|
||||||
|
' Please use a GPU option')
|
||||||
|
|
||||||
# CHOOSE OPTIMIZER
|
# CHOOSE OPTIMIZER
|
||||||
# allow for lr schedulers as well
|
# allow for lr schedulers as well
|
||||||
@@ -449,6 +510,24 @@ class Trainer(TrainerIO):
|
|||||||
# used for testing or when we need to know that training succeeded
|
# used for testing or when we need to know that training succeeded
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def __single_gpu_train(self, model):
|
||||||
|
# CHOOSE OPTIMIZER
|
||||||
|
# allow for lr schedulers as well
|
||||||
|
self.optimizers = model.configure_optimizers()
|
||||||
|
if len(self.optimizers) == 2:
|
||||||
|
self.optimizers, self.lr_schedulers = self.optimizers
|
||||||
|
|
||||||
|
model.cuda(self.data_parallel_device_ids[0])
|
||||||
|
|
||||||
|
if self.use_amp:
|
||||||
|
# An example
|
||||||
|
model, optimizers = amp.initialize(
|
||||||
|
model, self.optimizers, opt_level=self.amp_level,
|
||||||
|
)
|
||||||
|
self.optimizers = optimizers
|
||||||
|
|
||||||
|
self.__run_pretrain_routine(model)
|
||||||
|
|
||||||
def __dp_train(self, model):
|
def __dp_train(self, model):
|
||||||
|
|
||||||
# CHOOSE OPTIMIZER
|
# CHOOSE OPTIMIZER
|
||||||
@@ -462,9 +541,11 @@ class Trainer(TrainerIO):
|
|||||||
# check for this bug (amp + dp + !01 doesn't work)
|
# check for this bug (amp + dp + !01 doesn't work)
|
||||||
# https://github.com/NVIDIA/apex/issues/227
|
# https://github.com/NVIDIA/apex/issues/227
|
||||||
if self.use_dp and self.use_amp:
|
if self.use_dp and self.use_amp:
|
||||||
m = f'amp level {self.amp_level} with DataParallel is not supported. ' \
|
m = """
|
||||||
f'See this note from NVIDIA for more info: https://github.com/NVIDIA/apex/issues/227. ' \
|
Amp level %r with DataParallel is not supported.
|
||||||
f'We recommend you switch to ddp if you want to use amp'
|
See this note from NVIDIA for more info: https://github.com/NVIDIA/apex/issues/227.
|
||||||
|
We recommend you switch to ddp if you want to use amp
|
||||||
|
""" % self.amp_level
|
||||||
raise MisconfigurationException(m)
|
raise MisconfigurationException(m)
|
||||||
|
|
||||||
model = LightningDataParallel(model, device_ids=self.data_parallel_device_ids)
|
model = LightningDataParallel(model, device_ids=self.data_parallel_device_ids)
|
||||||
@@ -484,13 +565,14 @@ class Trainer(TrainerIO):
|
|||||||
try:
|
try:
|
||||||
node_id = os.environ['SLURM_NODEID']
|
node_id = os.environ['SLURM_NODEID']
|
||||||
self.node_rank = int(node_id)
|
self.node_rank = int(node_id)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.node_rank = 0
|
self.node_rank = 0
|
||||||
|
|
||||||
# recover original exp before went into process
|
# recover original exp before went into process
|
||||||
# init in write mode only on proc 0
|
# init in write mode only on proc 0
|
||||||
self.experiment.debug = self.proc_rank > 0
|
if self.experiment is not None:
|
||||||
self.experiment = self.experiment.get_non_ddp_exp()
|
self.experiment.debug = self.proc_rank > 0
|
||||||
|
self.experiment = self.experiment.get_non_ddp_exp()
|
||||||
|
|
||||||
# show progbar only on prog_rank 0
|
# show progbar only on prog_rank 0
|
||||||
self.prog_bar = self.prog_bar and self.node_rank == 0 and gpu_nb == 0
|
self.prog_bar = self.prog_bar and self.node_rank == 0 and gpu_nb == 0
|
||||||
@@ -500,7 +582,8 @@ class Trainer(TrainerIO):
|
|||||||
self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids)
|
self.world_size = self.nb_gpu_nodes * len(self.data_parallel_device_ids)
|
||||||
|
|
||||||
# let the exp know the rank to avoid overwriting logs
|
# let the exp know the rank to avoid overwriting logs
|
||||||
self.experiment.rank = self.proc_rank
|
if self.experiment is not None:
|
||||||
|
self.experiment.rank = self.proc_rank
|
||||||
|
|
||||||
# set up server using proc 0's ip address
|
# set up server using proc 0's ip address
|
||||||
# try to init for 20 times at max in case ports are taken
|
# try to init for 20 times at max in case ports are taken
|
||||||
@@ -527,7 +610,8 @@ class Trainer(TrainerIO):
|
|||||||
)
|
)
|
||||||
self.optimizers = optimizers
|
self.optimizers = optimizers
|
||||||
|
|
||||||
model = LightningDistributedDataParallel(model, device_ids=[gpu_nb], find_unused_parameters=True)
|
model = LightningDistributedDataParallel(model, device_ids=[gpu_nb],
|
||||||
|
find_unused_parameters=True)
|
||||||
|
|
||||||
# continue training routine
|
# continue training routine
|
||||||
self.__run_pretrain_routine(model)
|
self.__run_pretrain_routine(model)
|
||||||
@@ -543,14 +627,14 @@ class Trainer(TrainerIO):
|
|||||||
# sets the appropriate port
|
# sets the appropriate port
|
||||||
try:
|
try:
|
||||||
port = os.environ['MASTER_PORT']
|
port = os.environ['MASTER_PORT']
|
||||||
except Exception as e:
|
except Exception:
|
||||||
port = 12910
|
port = 12910
|
||||||
os.environ['MASTER_PORT'] = f'{port}'
|
os.environ['MASTER_PORT'] = str(port)
|
||||||
|
|
||||||
# figure out the root node addr
|
# figure out the root node addr
|
||||||
try:
|
try:
|
||||||
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
|
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
|
||||||
except Exception as e:
|
except Exception:
|
||||||
root_node = '127.0.0.2'
|
root_node = '127.0.0.2'
|
||||||
|
|
||||||
root_node = self.resolve_root_node_address(root_node)
|
root_node = self.resolve_root_node_address(root_node)
|
||||||
@@ -597,27 +681,35 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# give model convenience properties
|
# give model convenience properties
|
||||||
ref_model.trainer = self
|
ref_model.trainer = self
|
||||||
ref_model.experiment = self.experiment
|
|
||||||
|
|
||||||
# run tiny validation to make sure program won't crash during val
|
if self.experiment is not None:
|
||||||
_ = self.validate(model, self.val_dataloader, max_batches=self.nb_sanity_val_steps)
|
ref_model.experiment = self.experiment
|
||||||
|
|
||||||
# save exp to get started
|
# save exp to get started
|
||||||
if self.proc_rank == 0:
|
if self.proc_rank == 0 and self.experiment is not None:
|
||||||
self.experiment.save()
|
self.experiment.save()
|
||||||
|
|
||||||
# track model now.
|
# track model now.
|
||||||
# if cluster resets state, the model will update with the saved weights
|
# if cluster resets state, the model will update with the saved weights
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
|
# restore training and model before hpc call
|
||||||
|
self.restore_state_if_existing_checkpoint()
|
||||||
|
|
||||||
# enable cluster checkpointing
|
# enable cluster checkpointing
|
||||||
# also restores training state
|
# also restores training state
|
||||||
if self.cluster is not None and self.proc_rank == 0: # pragma: no cover
|
# hpc checkpoint overrides any other checkpoints loaded before
|
||||||
|
if self.cluster is not None: # pragma: no cover
|
||||||
self.enable_auto_hpc_walltime_manager()
|
self.enable_auto_hpc_walltime_manager()
|
||||||
|
|
||||||
|
# run tiny validation to make sure program won't crash during val
|
||||||
|
ref_model.on_sanity_check_start()
|
||||||
|
_ = self.validate(model, self.val_dataloader, max_batches=self.nb_sanity_val_steps)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# CORE TRAINING LOOP
|
# CORE TRAINING LOOP
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
|
||||||
self.__train()
|
self.__train()
|
||||||
|
|
||||||
def __train(self):
|
def __train(self):
|
||||||
@@ -642,7 +734,8 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# init progbar when requested
|
# init progbar when requested
|
||||||
if self.progress_bar:
|
if self.progress_bar:
|
||||||
self.prog_bar = tqdm.tqdm(range(self.total_batches), position=self.process_position)
|
self.prog_bar = tqdm.tqdm(range(self.total_batches),
|
||||||
|
position=self.process_position)
|
||||||
|
|
||||||
for batch_nb, data_batch in enumerate(self.tng_dataloader):
|
for batch_nb, data_batch in enumerate(self.tng_dataloader):
|
||||||
self.batch_nb = batch_nb
|
self.batch_nb = batch_nb
|
||||||
@@ -651,7 +744,8 @@ class Trainer(TrainerIO):
|
|||||||
model = self.__get_model()
|
model = self.__get_model()
|
||||||
model.global_step = self.global_step
|
model.global_step = self.global_step
|
||||||
|
|
||||||
# stop when the flag is changed or we've gone past the amount requested in the batches
|
# stop when the flag is changed or we've gone past the amount
|
||||||
|
# requested in the batches
|
||||||
self.total_batch_nb += 1
|
self.total_batch_nb += 1
|
||||||
met_batch_limit = batch_nb > self.nb_tng_batches
|
met_batch_limit = batch_nb > self.nb_tng_batches
|
||||||
if met_batch_limit:
|
if met_batch_limit:
|
||||||
@@ -672,7 +766,7 @@ class Trainer(TrainerIO):
|
|||||||
|
|
||||||
# when batch should be saved
|
# when batch should be saved
|
||||||
if (batch_nb + 1) % self.log_save_interval == 0 or early_stop_epoch:
|
if (batch_nb + 1) % self.log_save_interval == 0 or early_stop_epoch:
|
||||||
if self.proc_rank == 0:
|
if self.proc_rank == 0 and self.experiment is not None:
|
||||||
self.experiment.save()
|
self.experiment.save()
|
||||||
|
|
||||||
# when metrics should be logged
|
# when metrics should be logged
|
||||||
@@ -698,8 +792,9 @@ class Trainer(TrainerIO):
|
|||||||
model.on_tng_metrics(metrics)
|
model.on_tng_metrics(metrics)
|
||||||
|
|
||||||
# log metrics
|
# log metrics
|
||||||
scalar_metrics = self.__metrics_to_scalars(metrics, blacklist=self.__log_vals_blacklist())
|
scalar_metrics = self.__metrics_to_scalars(
|
||||||
if self.proc_rank == 0:
|
metrics, blacklist=self.__log_vals_blacklist())
|
||||||
|
if self.proc_rank == 0 and self.experiment is not None:
|
||||||
self.experiment.log(scalar_metrics, global_step=self.global_step)
|
self.experiment.log(scalar_metrics, global_step=self.global_step)
|
||||||
self.experiment.save()
|
self.experiment.save()
|
||||||
|
|
||||||
@@ -720,14 +815,15 @@ class Trainer(TrainerIO):
|
|||||||
# early stopping
|
# early stopping
|
||||||
met_min_epochs = epoch_nb > self.min_nb_epochs
|
met_min_epochs = epoch_nb > self.min_nb_epochs
|
||||||
if self.enable_early_stop and met_min_epochs:
|
if self.enable_early_stop and met_min_epochs:
|
||||||
should_stop = self.early_stop_callback.on_epoch_end(epoch=epoch_nb, logs=self.__tng_tqdm_dic)
|
should_stop = self.early_stop_callback.on_epoch_end(epoch=epoch_nb,
|
||||||
|
logs=self.__tng_tqdm_dic)
|
||||||
|
|
||||||
# stop training
|
# stop training
|
||||||
stop = should_stop and met_min_epochs
|
stop = should_stop and met_min_epochs
|
||||||
if stop:
|
if stop:
|
||||||
return
|
return
|
||||||
|
|
||||||
def __metrics_to_scalars(self, metrics, blacklist=[]):
|
def __metrics_to_scalars(self, metrics, blacklist=set()):
|
||||||
new_metrics = {}
|
new_metrics = {}
|
||||||
for k, v in metrics.items():
|
for k, v in metrics.items():
|
||||||
if type(v) is torch.Tensor:
|
if type(v) is torch.Tensor:
|
||||||
@@ -767,23 +863,40 @@ class Trainer(TrainerIO):
|
|||||||
output = self.model(data_batch, batch_nb)
|
output = self.model(data_batch, batch_nb)
|
||||||
elif self.use_dp:
|
elif self.use_dp:
|
||||||
output = self.model(data_batch, batch_nb)
|
output = self.model(data_batch, batch_nb)
|
||||||
output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
|
elif self.single_gpu:
|
||||||
|
gpu_id = self.data_parallel_device_ids[0]
|
||||||
|
for i, x in enumerate(data_batch):
|
||||||
|
if isinstance(x, torch.Tensor):
|
||||||
|
data_batch[i] = x.cuda(gpu_id)
|
||||||
|
output = self.model.training_step(data_batch, batch_nb)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
output = self.model.training_step(data_batch, batch_nb)
|
output = self.model.training_step(data_batch, batch_nb)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model_specific_tqdm_metrics_dic = output['prog']
|
prog_output = output['prog']
|
||||||
except Exception as e:
|
|
||||||
|
# reduce prog metrics for tqdm when using dp
|
||||||
|
if self.use_dp:
|
||||||
|
nb_gpus = len(self.data_parallel_device_ids)
|
||||||
|
prog_output = reduce_distributed_output(prog_output, nb_gpus)
|
||||||
|
|
||||||
|
model_specific_tqdm_metrics_dic = prog_output
|
||||||
|
except Exception:
|
||||||
model_specific_tqdm_metrics_dic = {}
|
model_specific_tqdm_metrics_dic = {}
|
||||||
|
|
||||||
# if output dict doesn't have the keyword loss
|
# if output dict doesn't have the keyword loss
|
||||||
# then assume the output=loss if scalar
|
# then assume the output=loss if scalar
|
||||||
try:
|
try:
|
||||||
loss = output['loss']
|
loss = output['loss']
|
||||||
except Exception as e:
|
except Exception:
|
||||||
if type(output) is torch.Tensor:
|
if type(output) is torch.Tensor:
|
||||||
loss = output
|
loss = output
|
||||||
|
|
||||||
|
# when using dp need to reduce the loss
|
||||||
|
if self.use_dp:
|
||||||
|
loss = reduce_distributed_output(loss, len(self.data_parallel_device_ids))
|
||||||
|
|
||||||
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
|
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
|
||||||
|
|
||||||
# backward pass
|
# backward pass
|
||||||
@@ -814,7 +927,7 @@ class Trainer(TrainerIO):
|
|||||||
# clip gradients
|
# clip gradients
|
||||||
if self.gradient_clip > 0:
|
if self.gradient_clip > 0:
|
||||||
model = self.__get_model()
|
model = self.__get_model()
|
||||||
torch.nn.utils.clip_grad_norm(model.parameters(), self.gradient_clip)
|
torch.nn.utils.clip_grad_norm_(model.parameters(), self.gradient_clip)
|
||||||
|
|
||||||
# update gradients across all optimizers
|
# update gradients across all optimizers
|
||||||
for optimizer in self.optimizers:
|
for optimizer in self.optimizers:
|
||||||
@@ -828,7 +941,8 @@ class Trainer(TrainerIO):
|
|||||||
# clear gradients
|
# clear gradients
|
||||||
optimizer.zero_grad()
|
optimizer.zero_grad()
|
||||||
|
|
||||||
# queuing loss across batches blows it up proportionally... divide out the number accumulated
|
# queuing loss across batches blows it up proportionally...
|
||||||
|
# divide out the number accumulated
|
||||||
self.batch_loss_value = self.batch_loss_value / self.accumulate_grad_batches
|
self.batch_loss_value = self.batch_loss_value / self.accumulate_grad_batches
|
||||||
|
|
||||||
# track loss
|
# track loss
|
||||||
@@ -865,12 +979,12 @@ class Trainer(TrainerIO):
|
|||||||
# use full val set on end of epoch
|
# use full val set on end of epoch
|
||||||
# use a small portion otherwise
|
# use a small portion otherwise
|
||||||
max_batches = None if not self.fast_dev_run else 1
|
max_batches = None if not self.fast_dev_run else 1
|
||||||
model_specific_tqdm_metrics_dic = self.validate(
|
validation_results = self.validate(
|
||||||
self.model,
|
self.model,
|
||||||
self.val_dataloader,
|
self.val_dataloader,
|
||||||
max_batches
|
max_batches
|
||||||
)
|
)
|
||||||
self.__add_tqdm_metrics(model_specific_tqdm_metrics_dic)
|
self.__add_tqdm_metrics(validation_results)
|
||||||
|
|
||||||
# hook
|
# hook
|
||||||
if self.__is_function_implemented('on_post_performance_check'):
|
if self.__is_function_implemented('on_post_performance_check'):
|
||||||
@@ -885,4 +999,5 @@ class Trainer(TrainerIO):
|
|||||||
# model checkpointing
|
# model checkpointing
|
||||||
if self.proc_rank == 0 and self.checkpoint_callback is not None:
|
if self.proc_rank == 0 and self.checkpoint_callback is not None:
|
||||||
print('save callback...')
|
print('save callback...')
|
||||||
self.checkpoint_callback.on_epoch_end(epoch=self.current_epoch, logs=self.__tng_tqdm_dic)
|
self.checkpoint_callback.on_epoch_end(epoch=self.current_epoch,
|
||||||
|
logs=self.__tng_tqdm_dic)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from itertools import chain
|
|||||||
import threading
|
import threading
|
||||||
import torch
|
import torch
|
||||||
from torch.cuda._utils import _get_device_index
|
from torch.cuda._utils import _get_device_index
|
||||||
import pdb
|
|
||||||
|
|
||||||
|
|
||||||
def _find_tensors(obj): # pragma: no cover
|
def _find_tensors(obj): # pragma: no cover
|
||||||
@@ -64,7 +63,6 @@ class LightningDataParallel(DataParallel):
|
|||||||
outputs = self.parallel_apply(replicas, inputs, kwargs)
|
outputs = self.parallel_apply(replicas, inputs, kwargs)
|
||||||
return self.gather(outputs, self.output_device)
|
return self.gather(outputs, self.output_device)
|
||||||
|
|
||||||
|
|
||||||
def parallel_apply(self, replicas, inputs, kwargs):
|
def parallel_apply(self, replicas, inputs, kwargs):
|
||||||
return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
|
return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import numpy as np
|
|
||||||
from torch import nn
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Module to describe gradients
|
Module to describe gradients
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from torch import nn
|
||||||
|
|
||||||
|
|
||||||
class GradInformation(nn.Module):
|
class GradInformation(nn.Module):
|
||||||
|
|
||||||
@@ -18,12 +17,13 @@ class GradInformation(nn.Module):
|
|||||||
total_norm += param_norm ** norm_type
|
total_norm += param_norm ** norm_type
|
||||||
norm = param_norm ** (1 / norm_type)
|
norm = param_norm ** (1 / norm_type)
|
||||||
|
|
||||||
results['grad_{}_norm_{}'.format(norm_type, i)] = round(norm.data.cpu().numpy().flatten()[0], 3)
|
grad = round(norm.data.cpu().numpy().flatten()[0], 3)
|
||||||
except Exception as e:
|
results['grad_{}_norm_{}'.format(norm_type, i)] = grad
|
||||||
|
except Exception:
|
||||||
# this param had no grad
|
# this param had no grad
|
||||||
pass
|
pass
|
||||||
|
|
||||||
total_norm = total_norm ** (1. / norm_type)
|
total_norm = total_norm ** (1. / norm_type)
|
||||||
results['grad_{}_norm_total'.format(norm_type)] = round(total_norm.data.cpu().numpy().flatten()[0], 3)
|
grad = round(total_norm.data.cpu().numpy().flatten()[0], 3)
|
||||||
|
results['grad_{}_norm_total'.format(norm_type)] = grad
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
|
|
||||||
class ModelHooks(torch.nn.Module):
|
class ModelHooks(torch.nn.Module):
|
||||||
|
|
||||||
|
def on_sanity_check_start(self):
|
||||||
|
"""
|
||||||
|
Called before starting validate
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def on_batch_start(self, data_batch):
|
def on_batch_start(self, data_batch):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -42,4 +51,3 @@ class ModelHooks(torch.nn.Module):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import torch
|
|
||||||
import gc
|
|
||||||
import subprocess
|
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Generates a summary of a model's layers and dimensionality
|
Generates a summary of a model's layers and dimensionality
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import gc
|
||||||
|
|
||||||
|
import torch
|
||||||
|
import subprocess
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
class ModelSummary(object):
|
class ModelSummary(object):
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class ModelSummary(object):
|
|||||||
mods = list(self.model.modules())
|
mods = list(self.model.modules())
|
||||||
sizes = []
|
sizes = []
|
||||||
|
|
||||||
for i in range(1,len(mods)):
|
for i in range(1, len(mods)):
|
||||||
m = mods[i]
|
m = mods[i]
|
||||||
p = list(m.parameters())
|
p = list(m.parameters())
|
||||||
modsz = []
|
modsz = []
|
||||||
@@ -127,7 +127,7 @@ class ModelSummary(object):
|
|||||||
if self.model.example_input_array is not None:
|
if self.model.example_input_array is not None:
|
||||||
cols.extend(['In_sizes', 'Out_sizes'])
|
cols.extend(['In_sizes', 'Out_sizes'])
|
||||||
|
|
||||||
df = pd.DataFrame(np.zeros( (len(self.layer_names), len(cols))))
|
df = pd.DataFrame(np.zeros((len(self.layer_names), len(cols))))
|
||||||
df.columns = cols
|
df.columns = cols
|
||||||
|
|
||||||
df['Name'] = self.layer_names
|
df['Name'] = self.layer_names
|
||||||
@@ -152,16 +152,16 @@ class ModelSummary(object):
|
|||||||
self.make_summary()
|
self.make_summary()
|
||||||
|
|
||||||
|
|
||||||
def print_mem_stack(): # pragma: no cover
|
def print_mem_stack(): # pragma: no cover
|
||||||
for obj in gc.get_objects():
|
for obj in gc.get_objects():
|
||||||
try:
|
try:
|
||||||
if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
|
if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
|
||||||
print(type(obj), obj.size())
|
print(type(obj), obj.size())
|
||||||
except Exception as e:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def count_mem_items(): # pragma: no cover
|
def count_mem_items(): # pragma: no cover
|
||||||
nb_params = 0
|
nb_params = 0
|
||||||
nb_tensors = 0
|
nb_tensors = 0
|
||||||
for obj in gc.get_objects():
|
for obj in gc.get_objects():
|
||||||
@@ -172,7 +172,7 @@ def count_mem_items(): # pragma: no cover
|
|||||||
nb_params += 1
|
nb_params += 1
|
||||||
else:
|
else:
|
||||||
nb_tensors += 1
|
nb_tensors += 1
|
||||||
except Exception as e:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return nb_params, nb_tensors
|
return nb_params, nb_tensors
|
||||||
@@ -196,6 +196,6 @@ def get_gpu_memory_map():
|
|||||||
gpu_memory = [int(x) for x in result.strip().split('\n')]
|
gpu_memory = [int(x) for x in result.strip().split('\n')]
|
||||||
gpu_memory_map = {}
|
gpu_memory_map = {}
|
||||||
for k, v in zip(range(len(gpu_memory)), gpu_memory):
|
for k, v in zip(range(len(gpu_memory)), gpu_memory):
|
||||||
k = f'gpu_{k}'
|
k = 'gpu_%i' % k
|
||||||
gpu_memory_map[k] = v
|
gpu_memory_map[k] = v
|
||||||
return gpu_memory_map
|
return gpu_memory_map
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import torch
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import pdb
|
|
||||||
from pytorch_lightning.pt_overrides.override_data_parallel import LightningDistributedDataParallel, LightningDataParallel
|
import torch
|
||||||
|
|
||||||
|
from pytorch_lightning.pt_overrides.override_data_parallel import (
|
||||||
|
LightningDistributedDataParallel, LightningDataParallel)
|
||||||
|
|
||||||
|
|
||||||
class ModelIO(object):
|
class ModelIO(object):
|
||||||
@@ -44,7 +46,8 @@ class ModelIO(object):
|
|||||||
class TrainerIO(object):
|
class TrainerIO(object):
|
||||||
|
|
||||||
def __get_model(self):
|
def __get_model(self):
|
||||||
is_dp_module = type(self.model) is LightningDistributedDataParallel or type(self.model) is LightningDataParallel
|
is_dp_module = isinstance(self.model, (LightningDistributedDataParallel,
|
||||||
|
LightningDataParallel))
|
||||||
model = self.model.module if is_dp_module else self.model
|
model = self.model.module if is_dp_module else self.model
|
||||||
return model
|
return model
|
||||||
|
|
||||||
@@ -57,6 +60,22 @@ class TrainerIO(object):
|
|||||||
# do the actual save
|
# do the actual save
|
||||||
torch.save(checkpoint, filepath)
|
torch.save(checkpoint, filepath)
|
||||||
|
|
||||||
|
def restore(self, checkpoint_path, on_gpu):
|
||||||
|
|
||||||
|
if on_gpu:
|
||||||
|
checkpoint = torch.load(checkpoint_path)
|
||||||
|
else:
|
||||||
|
checkpoint = torch.load(checkpoint_path, map_location=lambda storage, loc: storage)
|
||||||
|
|
||||||
|
# load training state (affects trainer only)
|
||||||
|
self.restore_training_state(checkpoint)
|
||||||
|
|
||||||
|
# load model state
|
||||||
|
model = self.__get_model()
|
||||||
|
|
||||||
|
# load the state_dict on the model automatically
|
||||||
|
model.load_state_dict(checkpoint['state_dict'])
|
||||||
|
|
||||||
def dump_checkpoint(self):
|
def dump_checkpoint(self):
|
||||||
|
|
||||||
checkpoint = {
|
checkpoint = {
|
||||||
@@ -77,7 +96,7 @@ class TrainerIO(object):
|
|||||||
optimizer_states.append(optimizer.state_dict())
|
optimizer_states.append(optimizer.state_dict())
|
||||||
|
|
||||||
checkpoint['optimizer_states'] = optimizer_states
|
checkpoint['optimizer_states'] = optimizer_states
|
||||||
|
|
||||||
# save lr schedulers
|
# save lr schedulers
|
||||||
lr_schedulers = []
|
lr_schedulers = []
|
||||||
for i, scheduler in enumerate(self.lr_schedulers):
|
for i, scheduler in enumerate(self.lr_schedulers):
|
||||||
@@ -102,13 +121,16 @@ class TrainerIO(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# allow test tube to handle model check pointing automatically
|
# allow test tube to handle model check pointing automatically
|
||||||
self.cluster.set_checkpoint_save_function(
|
# only if proc 0 so we don't trigger world_size resubmits
|
||||||
self.hpc_save,
|
if self.proc_rank == 0:
|
||||||
kwargs={
|
self.cluster.set_checkpoint_save_function(
|
||||||
'folderpath': self.checkpoint_callback.filepath,
|
self.hpc_save,
|
||||||
'experiment': self.experiment
|
kwargs={
|
||||||
}
|
'folderpath': self.checkpoint_callback.filepath,
|
||||||
)
|
'experiment': self.experiment
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
self.cluster.set_checkpoint_load_function(
|
self.cluster.set_checkpoint_load_function(
|
||||||
self.hpc_load,
|
self.hpc_load,
|
||||||
kwargs={
|
kwargs={
|
||||||
@@ -138,7 +160,7 @@ class TrainerIO(object):
|
|||||||
optimizer_states = checkpoint['optimizer_states']
|
optimizer_states = checkpoint['optimizer_states']
|
||||||
for optimizer, opt_state in zip(self.optimizers, optimizer_states):
|
for optimizer, opt_state in zip(self.optimizers, optimizer_states):
|
||||||
optimizer.load_state_dict(opt_state)
|
optimizer.load_state_dict(opt_state)
|
||||||
|
|
||||||
# restore the lr schedulers
|
# restore the lr schedulers
|
||||||
lr_schedulers = checkpoint['lr_schedulers']
|
lr_schedulers = checkpoint['lr_schedulers']
|
||||||
for scheduler, lrs_state in zip(self.lr_schedulers, lr_schedulers):
|
for scheduler, lrs_state in zip(self.lr_schedulers, lr_schedulers):
|
||||||
@@ -194,15 +216,15 @@ class TrainerIO(object):
|
|||||||
# call model hook
|
# call model hook
|
||||||
model.on_hpc_load(checkpoint)
|
model.on_hpc_load(checkpoint)
|
||||||
|
|
||||||
def max_ckpt_in_folder(self, path):
|
def max_ckpt_in_folder(self, path, name_key='ckpt_'):
|
||||||
files = os.listdir(path)
|
files = os.listdir(path)
|
||||||
files = [x for x in files if 'ckpt_' in x]
|
files = [x for x in files if name_key in x]
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
ckpt_vs = []
|
ckpt_vs = []
|
||||||
for name in files:
|
for name in files:
|
||||||
name = name.split('ckpt_')[-1]
|
name = name.split(name_key)[-1]
|
||||||
name = re.sub('[^0-9]', '', name)
|
name = re.sub('[^0-9]', '', name)
|
||||||
ckpt_vs.append(int(name))
|
ckpt_vs.append(int(name))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
from pytorch_lightning.root_module.memory import ModelSummary
|
from pytorch_lightning.root_module.memory import ModelSummary
|
||||||
from pytorch_lightning.root_module.grads import GradInformation
|
from pytorch_lightning.root_module.grads import GradInformation
|
||||||
from pytorch_lightning.root_module.model_saving import ModelIO, load_hparams_from_tags_csv
|
from pytorch_lightning.root_module.model_saving import ModelIO, load_hparams_from_tags_csv
|
||||||
@@ -128,6 +129,3 @@ class LightningModule(GradInformation, ModelIO, ModelHooks):
|
|||||||
def unfreeze(self):
|
def unfreeze(self):
|
||||||
for param in self.parameters():
|
for param in self.parameters():
|
||||||
param.requires_grad = True
|
param.requires_grad = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+34
-24
@@ -1,17 +1,18 @@
|
|||||||
import os
|
import os
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import torch.nn as nn
|
|
||||||
from torchvision.datasets import MNIST
|
|
||||||
import torchvision.transforms as transforms
|
|
||||||
import torch
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
from test_tube import HyperOptArgumentParser
|
|
||||||
from torch import optim
|
from torch import optim
|
||||||
from torch.utils.data import DataLoader
|
from torch.utils.data import DataLoader
|
||||||
from torch.utils.data.distributed import DistributedSampler
|
from torch.utils.data.distributed import DistributedSampler
|
||||||
|
from torchvision.datasets import MNIST
|
||||||
|
from torchvision import transforms
|
||||||
|
from test_tube import HyperOptArgumentParser
|
||||||
|
|
||||||
from pytorch_lightning.root_module.root_module import LightningModule
|
from pytorch_lightning.root_module.root_module import LightningModule
|
||||||
import pytorch_lightning as ptl
|
from pytorch_lightning import data_loader
|
||||||
|
|
||||||
|
|
||||||
class LightningTestModel(LightningModule):
|
class LightningTestModel(LightningModule):
|
||||||
@@ -47,11 +48,13 @@ class LightningTestModel(LightningModule):
|
|||||||
Layout model
|
Layout model
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.c_d1 = nn.Linear(in_features=self.hparams.in_features, out_features=self.hparams.hidden_dim)
|
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_bn = nn.BatchNorm1d(self.hparams.hidden_dim)
|
||||||
self.c_d1_drop = nn.Dropout(self.hparams.drop_prob)
|
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)
|
self.c_d2 = nn.Linear(in_features=self.hparams.hidden_dim,
|
||||||
|
out_features=self.hparams.out_features)
|
||||||
|
|
||||||
# ---------------------
|
# ---------------------
|
||||||
# TRAINING
|
# TRAINING
|
||||||
@@ -132,16 +135,16 @@ class LightningTestModel(LightningModule):
|
|||||||
val_acc = val_acc.unsqueeze(0)
|
val_acc = val_acc.unsqueeze(0)
|
||||||
|
|
||||||
# alternate possible outputs to test
|
# alternate possible outputs to test
|
||||||
if self.trainer.batch_nb % 1 == 0:
|
if batch_i % 1 == 0:
|
||||||
output = OrderedDict({
|
output = OrderedDict({
|
||||||
'val_loss': loss_val,
|
'val_loss': loss_val,
|
||||||
'val_acc': val_acc,
|
'val_acc': val_acc,
|
||||||
})
|
})
|
||||||
return output
|
return output
|
||||||
if self.trainer.batch_nb % 2 == 0:
|
if batch_i % 2 == 0:
|
||||||
return val_acc
|
return val_acc
|
||||||
|
|
||||||
if self.trainer.batch_nb % 3 == 0:
|
if batch_i % 3 == 0:
|
||||||
output = OrderedDict({
|
output = OrderedDict({
|
||||||
'val_loss': loss_val,
|
'val_loss': loss_val,
|
||||||
'val_acc': val_acc,
|
'val_acc': val_acc,
|
||||||
@@ -190,8 +193,10 @@ class LightningTestModel(LightningModule):
|
|||||||
|
|
||||||
def __dataloader(self, train):
|
def __dataloader(self, train):
|
||||||
# init data generators
|
# init data generators
|
||||||
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])
|
transform = transforms.Compose([transforms.ToTensor(),
|
||||||
dataset = MNIST(root=self.hparams.data_root, train=train, transform=transform, download=True)
|
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
|
# when using multi-node we need to add the datasampler
|
||||||
train_sampler = None
|
train_sampler = None
|
||||||
@@ -201,7 +206,7 @@ class LightningTestModel(LightningModule):
|
|||||||
if self.on_gpu and not self.force_remove_distributed_sampler:
|
if self.on_gpu and not self.force_remove_distributed_sampler:
|
||||||
train_sampler = DistributedSampler(dataset, rank=self.trainer.proc_rank)
|
train_sampler = DistributedSampler(dataset, rank=self.trainer.proc_rank)
|
||||||
batch_size = batch_size // self.trainer.world_size # scale batch size
|
batch_size = batch_size // self.trainer.world_size # scale batch size
|
||||||
except Exception as e:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
should_shuffle = train_sampler is None
|
should_shuffle = train_sampler is None
|
||||||
@@ -214,20 +219,20 @@ class LightningTestModel(LightningModule):
|
|||||||
|
|
||||||
return loader
|
return loader
|
||||||
|
|
||||||
@ptl.data_loader
|
@data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
return self.__dataloader(train=True)
|
return self.__dataloader(train=True)
|
||||||
|
|
||||||
@ptl.data_loader
|
@data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
return self.__dataloader(train=False)
|
return self.__dataloader(train=False)
|
||||||
|
|
||||||
@ptl.data_loader
|
@data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
return self.__dataloader(train=False)
|
return self.__dataloader(train=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_model_specific_args(parent_parser, root_dir):
|
def add_model_specific_args(parent_parser, root_dir): # pragma: no cover
|
||||||
"""
|
"""
|
||||||
Parameters you define here will be available to your model through self.hparams
|
Parameters you define here will be available to your model through self.hparams
|
||||||
:param parent_parser:
|
:param parent_parser:
|
||||||
@@ -241,19 +246,24 @@ class LightningTestModel(LightningModule):
|
|||||||
|
|
||||||
# network params
|
# network params
|
||||||
parser.opt_list('--drop_prob', default=0.2, options=[0.2, 0.5], type=float, tunable=False)
|
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('--in_features', default=28 * 28, type=int)
|
||||||
parser.add_argument('--out_features', default=10, 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
|
# use 500 for CPU, 50000 for GPU to see speed difference
|
||||||
|
parser.add_argument('--hidden_dim', default=50000, type=int)
|
||||||
|
|
||||||
# data
|
# data
|
||||||
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
|
parser.add_argument('--data_root', default=os.path.join(root_dir, 'mnist'), type=str)
|
||||||
|
|
||||||
# training params (opt)
|
# training params (opt)
|
||||||
parser.opt_list('--learning_rate', default=0.001*8, type=float, options=[0.0001, 0.0005, 0.001, 0.005],
|
parser.opt_list('--learning_rate', default=0.001 * 8, type=float,
|
||||||
|
options=[0.0001, 0.0005, 0.001, 0.005],
|
||||||
tunable=False)
|
tunable=False)
|
||||||
parser.opt_list('--optimizer_name', default='adam', type=str, options=['adam'], 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
|
# if using 2 nodes with 4 gpus each the batch size here
|
||||||
parser.opt_list('--batch_size', default=256*8, type=int, options=[32, 64, 128, 256], tunable=False,
|
# (256) will be 256 / (2*8) = 16 per gpu
|
||||||
help='batch size will be divided over all the gpus being used across all nodes')
|
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 gpus being used across all nodes')
|
||||||
return parser
|
return parser
|
||||||
@@ -1,31 +1,48 @@
|
|||||||
import pdb
|
"""
|
||||||
|
List of default args which mught be useful for all the available flags
|
||||||
|
Might need to update with the new flags
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None):
|
def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None):
|
||||||
|
|
||||||
# tng, test, val check intervals
|
# tng, test, val check intervals
|
||||||
parser.add_argument('--eval_test_set', dest='eval_test_set', action='store_true', help='true = run test set also')
|
parser.add_argument('--eval_test_set', dest='eval_test_set', action='store_true',
|
||||||
parser.add_argument('--check_val_every_n_epoch', default=1, type=int, help='check val every n epochs')
|
help='true = run test set also')
|
||||||
|
parser.add_argument('--check_val_every_n_epoch', default=1, type=int,
|
||||||
|
help='check val every n epochs')
|
||||||
parser.opt_list('--accumulate_grad_batches', default=1, type=int, tunable=False,
|
parser.opt_list('--accumulate_grad_batches', default=1, type=int, tunable=False,
|
||||||
help='accumulates gradients k times before applying update. Simulates huge batch size')
|
help='accumulates gradients k times before applying update.'
|
||||||
|
' Simulates huge batch size')
|
||||||
parser.add_argument('--max_nb_epochs', default=200, type=int, help='cap epochs')
|
parser.add_argument('--max_nb_epochs', default=200, type=int, help='cap epochs')
|
||||||
parser.add_argument('--min_nb_epochs', default=2, type=int, help='min epochs')
|
parser.add_argument('--min_nb_epochs', default=2, type=int, help='min epochs')
|
||||||
parser.add_argument('--train_percent_check', default=1.0, type=float, help='how much of tng set to check')
|
parser.add_argument('--train_percent_check', default=1.0, type=float,
|
||||||
parser.add_argument('--val_percent_check', default=1.0, type=float, help='how much of val set to check')
|
help='how much of tng set to check')
|
||||||
parser.add_argument('--test_percent_check', default=1.0, type=float, help='how much of test set to check')
|
parser.add_argument('--val_percent_check', default=1.0, type=float,
|
||||||
|
help='how much of val set to check')
|
||||||
|
parser.add_argument('--test_percent_check', default=1.0, type=float,
|
||||||
|
help='how much of test set to check')
|
||||||
|
|
||||||
parser.add_argument('--val_check_interval', default=0.95, type=float, help='how much within 1 epoch to check val')
|
parser.add_argument('--val_check_interval', default=0.95, type=float,
|
||||||
parser.add_argument('--log_save_interval', default=100, type=int, help='how many batches between log saves')
|
help='how much within 1 epoch to check val')
|
||||||
parser.add_argument('--add_log_row_interval', default=100, type=int, help='add log every k batches')
|
parser.add_argument('--log_save_interval', default=100, type=int,
|
||||||
|
help='how many batches between log saves')
|
||||||
|
parser.add_argument('--add_log_row_interval', default=100, type=int,
|
||||||
|
help='add log every k batches')
|
||||||
|
|
||||||
# early stopping
|
# early stopping
|
||||||
parser.add_argument('--disable_early_stop', dest='enable_early_stop', action='store_false')
|
parser.add_argument('--disable_early_stop', dest='enable_early_stop', action='store_false')
|
||||||
parser.add_argument('--early_stop_metric', default='val_acc', type=str)
|
parser.add_argument('--early_stop_metric', default='val_acc', type=str)
|
||||||
parser.add_argument('--early_stop_mode', default='min', type=str)
|
parser.add_argument('--early_stop_mode', default='min', type=str)
|
||||||
parser.add_argument('--early_stop_patience', default=3, type=int, help='number of epochs until stop')
|
parser.add_argument('--early_stop_patience', default=3, type=int,
|
||||||
|
help='number of epochs until stop')
|
||||||
|
|
||||||
# gradient handling
|
# gradient handling
|
||||||
parser.add_argument('--gradient_clip', default=-1, type=int)
|
parser.add_argument('--gradient_clip', default=-1, type=int)
|
||||||
parser.add_argument('--track_grad_norm', default=-1, type=int, help='if > 0, will track this grad norm')
|
parser.add_argument('--track_grad_norm', default=-1, type=int,
|
||||||
|
help='if > 0, will track this grad norm')
|
||||||
|
|
||||||
# model saving
|
# model saving
|
||||||
parser.add_argument('--model_save_path', default=root_dir + '/model_weights')
|
parser.add_argument('--model_save_path', default=root_dir + '/model_weights')
|
||||||
@@ -41,7 +58,8 @@ def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None
|
|||||||
# test_tube settings
|
# test_tube settings
|
||||||
parser.add_argument('-en', '--tt_name', default='pt_test')
|
parser.add_argument('-en', '--tt_name', default='pt_test')
|
||||||
parser.add_argument('-td', '--tt_description', default='pytorch lightning test')
|
parser.add_argument('-td', '--tt_description', default='pytorch lightning test')
|
||||||
parser.add_argument('--tt_save_path', default=root_dir + '/test_tube_logs', help='logging dir')
|
parser.add_argument('--tt_save_path', default=os.path.join(root_dir, 'test_tube_logs'),
|
||||||
|
help='logging dir')
|
||||||
parser.add_argument('--enable_single_run', dest='single_run', action='store_true')
|
parser.add_argument('--enable_single_run', dest='single_run', action='store_true')
|
||||||
parser.add_argument('--nb_hopt_trials', default=1, type=int)
|
parser.add_argument('--nb_hopt_trials', default=1, type=int)
|
||||||
parser.add_argument('--log_stdout', dest='log_stdout', action='store_true')
|
parser.add_argument('--log_stdout', dest='log_stdout', action='store_true')
|
||||||
@@ -52,25 +70,30 @@ def add_default_args(parser, root_dir, rand_seed=None, possible_model_names=None
|
|||||||
parser.add_argument('--default_tensor_type', default='torch.cuda.FloatTensor', type=str)
|
parser.add_argument('--default_tensor_type', default='torch.cuda.FloatTensor', type=str)
|
||||||
parser.add_argument('--use_amp', dest='use_amp', action='store_true')
|
parser.add_argument('--use_amp', dest='use_amp', action='store_true')
|
||||||
parser.add_argument('--check_grad_nans', dest='check_grad_nans', action='store_true')
|
parser.add_argument('--check_grad_nans', dest='check_grad_nans', action='store_true')
|
||||||
parser.add_argument('--amp_level', default='O2',type=str)
|
parser.add_argument('--amp_level', default='O2', type=str)
|
||||||
|
|
||||||
|
|
||||||
# run on hpc
|
# run on hpc
|
||||||
parser.add_argument('--on_cluster', dest='on_cluster', action='store_true')
|
parser.add_argument('--on_cluster', dest='on_cluster', action='store_true')
|
||||||
|
|
||||||
# FAST training
|
# FAST training
|
||||||
# use these settings to make sure network has no bugs without running a full dataset
|
# use these settings to make sure network has no bugs without running a full dataset
|
||||||
parser.add_argument('--fast_dev_run', dest='fast_dev_run', default=False, action='store_true', help='runs validation after 1 tng step')
|
parser.add_argument('--fast_dev_run', dest='fast_dev_run', default=False, action='store_true',
|
||||||
parser.add_argument('--enable_tqdm', dest='enable_tqdm', default=False, action='store_true', help='false removes the prog bar')
|
help='runs validation after 1 tng step')
|
||||||
parser.add_argument('--overfit', default=-1, type=float, help='% of dataset to use with this option. float, or -1 for none')
|
parser.add_argument('--enable_tqdm', dest='enable_tqdm', default=False, action='store_true',
|
||||||
|
help='false removes the prog bar')
|
||||||
|
parser.add_argument('--overfit', default=-1, type=float,
|
||||||
|
help='% of dataset to use with this option. float, or -1 for none')
|
||||||
|
|
||||||
# debug args
|
# debug args
|
||||||
if rand_seed is not None:
|
if rand_seed is not None:
|
||||||
parser.add_argument('--random_seed', default=rand_seed, type=int)
|
parser.add_argument('--random_seed', default=rand_seed, type=int)
|
||||||
|
|
||||||
parser.add_argument('--interactive', dest='interactive', action='store_true', help='runs on gpu without cluster')
|
parser.add_argument('--interactive', dest='interactive', action='store_true',
|
||||||
parser.add_argument('--debug', dest='debug', action='store_true', help='enables/disables test tube')
|
help='runs on gpu without cluster')
|
||||||
parser.add_argument('--local', dest='local', action='store_true', help='enables local tng')
|
parser.add_argument('--debug', dest='debug', action='store_true',
|
||||||
|
help='enables/disables test tube')
|
||||||
|
parser.add_argument('--local', dest='local', action='store_true',
|
||||||
|
help='enables local tng')
|
||||||
|
|
||||||
# optimizer
|
# optimizer
|
||||||
parser.add_argument('--lr_scheduler_milestones', default=None, type=str)
|
parser.add_argument('--lr_scheduler_milestones', default=None, type=str)
|
||||||
@@ -1,5 +1,2 @@
|
|||||||
import pdb
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class MisconfigurationException(Exception):
|
class MisconfigurationException(Exception):
|
||||||
pass
|
pass
|
||||||
+2
-4
@@ -1,9 +1,7 @@
|
|||||||
coverage==4.5.3
|
|
||||||
mkdocs==1.0.4
|
|
||||||
pytest==5.0.1
|
|
||||||
scikit-learn==0.20.2
|
scikit-learn==0.20.2
|
||||||
tqdm==4.32.1
|
tqdm==4.32.1
|
||||||
twine==1.13.0
|
twine==1.13.0
|
||||||
numpy==1.16.4
|
numpy==1.16.4
|
||||||
torch>=1.1.0
|
torch>=1.1.0
|
||||||
torchvision==0.3.0
|
torchvision>=0.3.0
|
||||||
|
pandas
|
||||||
@@ -31,6 +31,8 @@ exclude_lines =
|
|||||||
print(traceback.print_exc())
|
print(traceback.print_exc())
|
||||||
return *
|
return *
|
||||||
raise Exception
|
raise Exception
|
||||||
|
raise *
|
||||||
|
except *
|
||||||
warnings
|
warnings
|
||||||
print
|
print
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
@@ -42,6 +44,7 @@ omit =
|
|||||||
pytorch_lightning/callbacks/pt_callbacks.py
|
pytorch_lightning/callbacks/pt_callbacks.py
|
||||||
tests/test_models.py
|
tests/test_models.py
|
||||||
pytorch_lightning/testing_models/lm_test_module.py
|
pytorch_lightning/testing_models/lm_test_module.py
|
||||||
|
pytorch_lightning/utilities/arg_parse.py
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = E731,W504,F401,F841
|
ignore = E731,W504,F401,F841
|
||||||
|
|||||||
@@ -1,29 +1,58 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Always prefer setuptools over distutils
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
# https://packaging.python.org/guides/single-sourcing-package-version/
|
# https://packaging.python.org/guides/single-sourcing-package-version/
|
||||||
|
|
||||||
# http://blog.ionelmc.ro/2014/05/25/python-packaging/
|
# http://blog.ionelmc.ro/2014/05/25/python-packaging/
|
||||||
|
|
||||||
|
# https://packaging.python.org/discussions/install-requires-vs-requirements /
|
||||||
|
# keep the meta-data here for simplicity in reading this file... it's not obvious
|
||||||
|
# what happens and to non-engineers they won't know to look in init...
|
||||||
|
# the goal of the project is simplicity for researchers, don't want to add too much
|
||||||
|
# engineer specific practices
|
||||||
setup(
|
setup(
|
||||||
name="pytorch-lightning",
|
name='pytorch-lightning',
|
||||||
version='0.3.6.7',
|
version='0.4.0',
|
||||||
description="The Keras for ML researchers using PyTorch",
|
description='The Keras for ML researchers using PyTorch',
|
||||||
author="William Falcon",
|
author='William Falcon',
|
||||||
author_email="waf2107@columbia.edu",
|
author_email='waf2107@columbia.edu',
|
||||||
url="https://github.com/williamFalcon/pytorch-lightning",
|
url='https://github.com/williamFalcon/pytorch-lightning',
|
||||||
download_url="https://github.com/williamFalcon/pytorch-lightning",
|
download_url='https://github.com/williamFalcon/pytorch-lightning',
|
||||||
license="MIT",
|
license='Apache-2',
|
||||||
keywords=["deep learning", "pytorch", "AI"],
|
|
||||||
python_requires=">=3.5",
|
|
||||||
install_requires=[
|
|
||||||
"torch>=1.1.0",
|
|
||||||
"tqdm",
|
|
||||||
"test-tube>=0.6.7.4",
|
|
||||||
],
|
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
long_description=open("README.md", encoding="utf-8").read(),
|
long_description=open('README.md', encoding='utf-8').read(),
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
keywords=['deep learning', 'pytorch', 'AI'],
|
||||||
|
python_requires='>=3.6',
|
||||||
|
install_requires=[
|
||||||
|
'torch==1.1.0',
|
||||||
|
'tqdm',
|
||||||
|
'test-tube>=0.6.7.6',
|
||||||
|
'pandas>=0.20.3',
|
||||||
|
],
|
||||||
|
classifiers=[
|
||||||
|
'Environment :: Console',
|
||||||
|
'Natural Language :: English',
|
||||||
|
# How mature is this project? Common values are
|
||||||
|
# 3 - Alpha, 4 - Beta, 5 - Production/Stable
|
||||||
|
'Development Status :: 4 - Beta',
|
||||||
|
# Indicate who your project is intended for
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
||||||
|
'Topic :: Scientific/Engineering :: Image Recognition',
|
||||||
|
'Topic :: Scientific/Engineering :: Information Analysis',
|
||||||
|
# Pick your license as you wish
|
||||||
|
'License :: OSI Approved :: BSD License',
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
# Specify the Python versions you support here. In particular, ensure
|
||||||
|
# that you indicate whether you support Python 2, Python 3 or both.
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
+8
-3
@@ -17,7 +17,7 @@ pip install -e .
|
|||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# run tests
|
# run tests
|
||||||
py.test
|
py.test -v
|
||||||
```
|
```
|
||||||
|
|
||||||
To test models that require GPU make sure to run the above command on a GPU machine.
|
To test models that require GPU make sure to run the above command on a GPU machine.
|
||||||
@@ -43,16 +43,21 @@ For each set up it also tests:
|
|||||||
5. simulated load from HPC signal.
|
5. simulated load from HPC signal.
|
||||||
|
|
||||||
## Running Coverage
|
## Running Coverage
|
||||||
|
Make sure to run coverage on a GPU machine with at least 2 GPUs and NVIDIA apex installed.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd pytorch-lightning
|
cd pytorch-lightning
|
||||||
|
|
||||||
# generate coverage
|
# generate coverage
|
||||||
pip install coverage
|
pip install coverage
|
||||||
coverage run tests/test_models.py
|
coverage run --source pytorch_lightning -m py.test pytorch_lightning tests examples -v --doctest-modules
|
||||||
|
|
||||||
# print coverage stats
|
# print coverage stats
|
||||||
coverage report -m
|
coverage report -m
|
||||||
|
|
||||||
|
# exporting resulys
|
||||||
|
coverage xml
|
||||||
|
codecov -t 17327163-8cca-4a5d-86c8-ca5f2ef700bc -v
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+11
-15
@@ -1,24 +1,19 @@
|
|||||||
import pytest
|
|
||||||
from pytorch_lightning import Trainer
|
from pytorch_lightning import Trainer
|
||||||
from pytorch_lightning.examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
from examples import LightningTemplateModel
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from test_tube import Experiment
|
from test_tube import Experiment
|
||||||
from pytorch_lightning.callbacks import ModelCheckpoint
|
from pytorch_lightning.callbacks import ModelCheckpoint
|
||||||
import numpy as np
|
|
||||||
import warnings
|
|
||||||
import torch
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import pdb
|
|
||||||
|
|
||||||
import pytorch_lightning as ptl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
from torch.nn import functional as F
|
from torch.nn import functional as F
|
||||||
from torch.utils.data import DataLoader
|
from torch.utils.data import DataLoader
|
||||||
from torchvision.datasets import MNIST
|
from torchvision.datasets import MNIST
|
||||||
|
|
||||||
|
|
||||||
class CoolModel(ptl.LightningModule):
|
class CoolModel(pl.LightningModule):
|
||||||
|
|
||||||
def __init(self):
|
def __init(self):
|
||||||
super(CoolModel, self).__init__()
|
super(CoolModel, self).__init__()
|
||||||
@@ -48,15 +43,15 @@ class CoolModel(ptl.LightningModule):
|
|||||||
def configure_optimizers(self):
|
def configure_optimizers(self):
|
||||||
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
return [torch.optim.Adam(self.parameters(), lr=0.02)]
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def tng_dataloader(self):
|
def tng_dataloader(self):
|
||||||
return DataLoader(MNIST('path/to/save', train=True), batch_size=32)
|
return DataLoader(MNIST('path/to/save', train=True), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def val_dataloader(self):
|
def val_dataloader(self):
|
||||||
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
|
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
|
||||||
|
|
||||||
@ptl.data_loader
|
@pl.data_loader
|
||||||
def test_dataloader(self):
|
def test_dataloader(self):
|
||||||
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
|
return DataLoader(MNIST('path/to/save', train=False), batch_size=32)
|
||||||
|
|
||||||
@@ -66,8 +61,8 @@ def get_model():
|
|||||||
root_dir = os.path.dirname(os.path.realpath(__file__))
|
root_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
hparams = Namespace(**{'drop_prob': 0.2,
|
hparams = Namespace(**{'drop_prob': 0.2,
|
||||||
'batch_size': 32,
|
'batch_size': 32,
|
||||||
'in_features': 28*28,
|
'in_features': 28 * 28,
|
||||||
'learning_rate': 0.001*8,
|
'learning_rate': 0.001 * 8,
|
||||||
'optimizer_name': 'adam',
|
'optimizer_name': 'adam',
|
||||||
'data_root': os.path.join(root_dir, 'mnist'),
|
'data_root': os.path.join(root_dir, 'mnist'),
|
||||||
'out_features': 10,
|
'out_features': 10,
|
||||||
@@ -112,7 +107,8 @@ def load_model(exp, save_dir):
|
|||||||
checkpoints = [x for x in os.listdir(save_dir) if '.ckpt' in x]
|
checkpoints = [x for x in os.listdir(save_dir) if '.ckpt' in x]
|
||||||
weights_dir = os.path.join(save_dir, checkpoints[0])
|
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)
|
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'
|
assert trained_model is not None, 'loading model failed'
|
||||||
|
|
||||||
@@ -137,7 +133,7 @@ def run_prediction(dataloader, trained_model):
|
|||||||
|
|
||||||
print(val_acc)
|
print(val_acc)
|
||||||
|
|
||||||
assert val_acc > 0.70, f'this model is expected to get > 0.7 in test set (it got {val_acc})'
|
assert val_acc > 0.70, 'this model is expected to get > 0.7 in test set (it got %f)' % val_acc
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
tox
|
||||||
|
coverage
|
||||||
|
codecov
|
||||||
|
pytest>=3.0.5
|
||||||
|
pytest-cov
|
||||||
|
flake8
|
||||||
|
check-manifest
|
||||||
|
test_tube
|
||||||
+173
-38
@@ -1,20 +1,22 @@
|
|||||||
import pytest
|
import os
|
||||||
from pytorch_lightning import Trainer
|
import shutil
|
||||||
from pytorch_lightning.examples.new_project_templates.lightning_module_template import LightningTemplateModel
|
import warnings
|
||||||
from pytorch_lightning.testing_models.lm_test_module import LightningTestModel
|
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import numpy as np
|
||||||
|
import torch
|
||||||
from test_tube import Experiment, SlurmCluster
|
from test_tube import Experiment, SlurmCluster
|
||||||
|
|
||||||
|
# sys.path += [os.path.abspath('..'), os.path.abspath('../..')]
|
||||||
|
from pytorch_lightning import Trainer
|
||||||
|
from pytorch_lightning.testing.lm_test_module import LightningTestModel
|
||||||
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping
|
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping
|
||||||
from pytorch_lightning.utils.debugging import MisconfigurationException
|
from pytorch_lightning.utilities.debugging import MisconfigurationException
|
||||||
from pytorch_lightning.root_module import memory
|
from pytorch_lightning.root_module import memory
|
||||||
from pytorch_lightning.models.trainer import reduce_distributed_output
|
from pytorch_lightning.models.trainer import reduce_distributed_output
|
||||||
from pytorch_lightning.root_module import model_saving
|
from pytorch_lightning.root_module import model_saving
|
||||||
import numpy as np
|
from examples import LightningTemplateModel
|
||||||
import warnings
|
|
||||||
import torch
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import pdb
|
|
||||||
|
|
||||||
SEED = 2334
|
SEED = 2334
|
||||||
torch.manual_seed(SEED)
|
torch.manual_seed(SEED)
|
||||||
@@ -24,16 +26,139 @@ np.random.seed(SEED)
|
|||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
# TESTS
|
# TESTS
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
def test_simple_cpu():
|
||||||
|
"""
|
||||||
|
Verify continue training session on CPU
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
hparams = get_hparams()
|
||||||
|
model = LightningTestModel(hparams)
|
||||||
|
|
||||||
|
save_dir = init_save_dir()
|
||||||
|
|
||||||
|
# exp file to get meta
|
||||||
|
trainer_options = dict(
|
||||||
|
max_nb_epochs=1,
|
||||||
|
val_percent_check=0.1,
|
||||||
|
train_percent_check=0.1,
|
||||||
|
)
|
||||||
|
|
||||||
|
# fit model
|
||||||
|
trainer = Trainer(**trainer_options)
|
||||||
|
result = trainer.fit(model)
|
||||||
|
|
||||||
|
# traning complete
|
||||||
|
assert result == 1, 'amp + ddp model failed to complete'
|
||||||
|
|
||||||
|
clear_save_dir()
|
||||||
|
|
||||||
|
|
||||||
|
def test_amp_single_gpu():
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
hparams = get_hparams()
|
||||||
|
model = LightningTestModel(hparams)
|
||||||
|
|
||||||
|
trainer_options = dict(
|
||||||
|
progress_bar=True,
|
||||||
|
max_nb_epochs=1,
|
||||||
|
gpus=[0],
|
||||||
|
distributed_backend='dp',
|
||||||
|
use_amp=True
|
||||||
|
)
|
||||||
|
|
||||||
|
run_gpu_model_test(trainer_options, model, hparams)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cpu_restore_training():
|
||||||
|
"""
|
||||||
|
Verify continue training session on CPU
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
hparams = get_hparams()
|
||||||
|
model = LightningTestModel(hparams)
|
||||||
|
|
||||||
|
save_dir = init_save_dir()
|
||||||
|
|
||||||
|
# exp file to get meta
|
||||||
|
test_exp_version = 10
|
||||||
|
exp = get_exp(False, version=test_exp_version)
|
||||||
|
exp.argparse(hparams)
|
||||||
|
exp.save()
|
||||||
|
|
||||||
|
trainer_options = dict(
|
||||||
|
max_nb_epochs=2,
|
||||||
|
val_check_interval=0.50,
|
||||||
|
val_percent_check=0.2,
|
||||||
|
train_percent_check=0.2,
|
||||||
|
experiment=exp,
|
||||||
|
checkpoint_callback=ModelCheckpoint(save_dir)
|
||||||
|
)
|
||||||
|
|
||||||
|
# fit model
|
||||||
|
trainer = Trainer(**trainer_options)
|
||||||
|
result = trainer.fit(model)
|
||||||
|
real_global_epoch = trainer.current_epoch
|
||||||
|
|
||||||
|
# traning complete
|
||||||
|
assert result == 1, 'amp + ddp model failed to complete'
|
||||||
|
|
||||||
|
# wipe-out trainer and model
|
||||||
|
# retrain with not much data... this simulates picking training back up after slurm
|
||||||
|
# we want to see if the weights come back correctly
|
||||||
|
new_exp = get_exp(False, version=test_exp_version)
|
||||||
|
trainer_options = dict(
|
||||||
|
max_nb_epochs=2,
|
||||||
|
val_check_interval=0.50,
|
||||||
|
val_percent_check=0.2,
|
||||||
|
train_percent_check=0.2,
|
||||||
|
experiment=new_exp,
|
||||||
|
checkpoint_callback=ModelCheckpoint(save_dir),
|
||||||
|
)
|
||||||
|
trainer = Trainer(**trainer_options)
|
||||||
|
model = LightningTestModel(hparams)
|
||||||
|
|
||||||
|
# set the epoch start hook so we can predict before the model does the full training
|
||||||
|
def assert_good_acc():
|
||||||
|
assert trainer.current_epoch == real_global_epoch and trainer.current_epoch > 0
|
||||||
|
|
||||||
|
# if model and state loaded correctly, predictions will be good even though we
|
||||||
|
# haven't trained with the new loaded model
|
||||||
|
trainer.model.eval()
|
||||||
|
run_prediction(trainer.val_dataloader, trainer.model)
|
||||||
|
|
||||||
|
model.on_sanity_check_start = assert_good_acc
|
||||||
|
|
||||||
|
# by calling fit again, we trigger training, loading weights from the cluster
|
||||||
|
# and our hook to predict using current model before any more weight updates
|
||||||
|
trainer.fit(model)
|
||||||
|
|
||||||
|
clear_save_dir()
|
||||||
|
|
||||||
|
|
||||||
def test_amp_gpu_ddp():
|
def test_amp_gpu_ddp():
|
||||||
"""
|
"""
|
||||||
Make sure DDP + AMP work
|
Make sure DDP + AMP work
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_amp_gpu_ddp cannot run.'
|
||||||
|
'Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
if not torch.cuda.device_count() > 1:
|
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')
|
warnings.warn('test_amp_gpu_ddp cannot run.'
|
||||||
|
'Rerun on a node with 2+ GPUs to run this test')
|
||||||
return
|
return
|
||||||
|
|
||||||
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
|
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
|
||||||
@@ -105,7 +230,8 @@ def test_cpu_slurm_save_load():
|
|||||||
# wipe-out trainer and model
|
# wipe-out trainer and model
|
||||||
# retrain with not much data... this simulates picking training back up after slurm
|
# retrain with not much data... this simulates picking training back up after slurm
|
||||||
# we want to see if the weights come back correctly
|
# we want to see if the weights come back correctly
|
||||||
continue_tng_hparams = get_hparams(continue_training=True, hpc_exp_number=cluster_a.hpc_exp_number)
|
continue_tng_hparams = get_hparams(continue_training=True,
|
||||||
|
hpc_exp_number=cluster_a.hpc_exp_number)
|
||||||
trainer_options = dict(
|
trainer_options = dict(
|
||||||
max_nb_epochs=1,
|
max_nb_epochs=1,
|
||||||
cluster=SlurmCluster(continue_tng_hparams),
|
cluster=SlurmCluster(continue_tng_hparams),
|
||||||
@@ -136,11 +262,9 @@ def test_cpu_slurm_save_load():
|
|||||||
def test_loading_meta_tags():
|
def test_loading_meta_tags():
|
||||||
hparams = get_hparams()
|
hparams = get_hparams()
|
||||||
|
|
||||||
save_dir = init_save_dir()
|
|
||||||
|
|
||||||
# save tags
|
# save tags
|
||||||
exp = get_exp(False)
|
exp = get_exp(False)
|
||||||
exp.tag({'some_str':'a_str', 'an_int': 1, 'a_float': 2.0})
|
exp.tag({'some_str': 'a_str', 'an_int': 1, 'a_float': 2.0})
|
||||||
exp.argparse(hparams)
|
exp.argparse(hparams)
|
||||||
exp.save()
|
exp.save()
|
||||||
|
|
||||||
@@ -221,7 +345,8 @@ def test_model_saving_loading():
|
|||||||
# load new model
|
# load new model
|
||||||
tags_path = exp.get_data_path(exp.name, exp.version)
|
tags_path = exp.get_data_path(exp.name, exp.version)
|
||||||
tags_path = os.path.join(tags_path, 'meta_tags.csv')
|
tags_path = os.path.join(tags_path, 'meta_tags.csv')
|
||||||
model_2 = LightningTestModel.load_from_metrics(weights_path=new_weights_path, tags_csv=tags_path, on_gpu=False)
|
model_2 = LightningTestModel.load_from_metrics(weights_path=new_weights_path,
|
||||||
|
tags_csv=tags_path, on_gpu=False)
|
||||||
model_2.eval()
|
model_2.eval()
|
||||||
|
|
||||||
# make prediction
|
# make prediction
|
||||||
@@ -232,8 +357,6 @@ def test_model_saving_loading():
|
|||||||
clear_save_dir()
|
clear_save_dir()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_model_freeze_unfreeze():
|
def test_model_freeze_unfreeze():
|
||||||
hparams = get_hparams()
|
hparams = get_hparams()
|
||||||
model = LightningTestModel(hparams)
|
model = LightningTestModel(hparams)
|
||||||
@@ -248,10 +371,12 @@ def test_amp_gpu_ddp_slurm_managed():
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_amp_gpu_ddp cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_amp_gpu_ddp cannot run.'
|
||||||
|
' Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
if not torch.cuda.device_count() > 1:
|
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')
|
warnings.warn('test_amp_gpu_ddp cannot run.'
|
||||||
|
' Rerun on a node with 2+ GPUs to run this test')
|
||||||
return
|
return
|
||||||
|
|
||||||
# simulate setting slurm flags
|
# simulate setting slurm flags
|
||||||
@@ -415,7 +540,8 @@ def test_single_gpu_model():
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_single_gpu_model cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_single_gpu_model cannot run.'
|
||||||
|
' Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
model, hparams = get_model()
|
model, hparams = get_model()
|
||||||
|
|
||||||
@@ -436,10 +562,12 @@ def test_multi_gpu_model_dp():
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_multi_gpu_model_dp cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_multi_gpu_model_dp cannot run.'
|
||||||
|
' Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
if not torch.cuda.device_count() > 1:
|
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')
|
warnings.warn('test_multi_gpu_model_dp cannot run.'
|
||||||
|
' Rerun on a node with 2+ GPUs to run this test')
|
||||||
return
|
return
|
||||||
model, hparams = get_model()
|
model, hparams = get_model()
|
||||||
trainer_options = dict(
|
trainer_options = dict(
|
||||||
@@ -462,10 +590,12 @@ def test_amp_gpu_dp():
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_amp_gpu_dp cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_amp_gpu_dp cannot run.'
|
||||||
|
' Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
if not torch.cuda.device_count() > 1:
|
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')
|
warnings.warn('test_amp_gpu_dp cannot run.'
|
||||||
|
' Rerun on a node with 2+ GPUs to run this test')
|
||||||
return
|
return
|
||||||
model, hparams = get_model()
|
model, hparams = get_model()
|
||||||
trainer_options = dict(
|
trainer_options = dict(
|
||||||
@@ -484,10 +614,12 @@ def test_multi_gpu_model_ddp():
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not torch.cuda.is_available():
|
if not torch.cuda.is_available():
|
||||||
warnings.warn('test_multi_gpu_model_ddp cannot run. Rerun on a GPU node to run this test')
|
warnings.warn('test_multi_gpu_model_ddp cannot run.'
|
||||||
|
' Rerun on a GPU node to run this test')
|
||||||
return
|
return
|
||||||
if not torch.cuda.device_count() > 1:
|
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')
|
warnings.warn('test_multi_gpu_model_ddp cannot run.'
|
||||||
|
' Rerun on a node with 2+ GPUs to run this test')
|
||||||
return
|
return
|
||||||
|
|
||||||
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
|
os.environ['MASTER_PORT'] = str(np.random.randint(12000, 19000, 1)[0])
|
||||||
@@ -504,7 +636,6 @@ def test_multi_gpu_model_ddp():
|
|||||||
run_gpu_model_test(trainer_options, model, hparams)
|
run_gpu_model_test(trainer_options, model, hparams)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_ddp_sampler_error():
|
def test_ddp_sampler_error():
|
||||||
"""
|
"""
|
||||||
Make sure DDP + AMP work
|
Make sure DDP + AMP work
|
||||||
@@ -589,8 +720,8 @@ def get_hparams(continue_training=False, hpc_exp_number=0):
|
|||||||
args = {
|
args = {
|
||||||
'drop_prob': 0.2,
|
'drop_prob': 0.2,
|
||||||
'batch_size': 32,
|
'batch_size': 32,
|
||||||
'in_features': 28*28,
|
'in_features': 28 * 28,
|
||||||
'learning_rate': 0.001*8,
|
'learning_rate': 0.001 * 8,
|
||||||
'optimizer_name': 'adam',
|
'optimizer_name': 'adam',
|
||||||
'data_root': os.path.join(root_dir, 'mnist'),
|
'data_root': os.path.join(root_dir, 'mnist'),
|
||||||
'out_features': 10,
|
'out_features': 10,
|
||||||
@@ -604,18 +735,22 @@ def get_hparams(continue_training=False, hpc_exp_number=0):
|
|||||||
return hparams
|
return hparams
|
||||||
|
|
||||||
|
|
||||||
def get_model():
|
def get_model(use_test_model=False):
|
||||||
# set up model with these hyperparams
|
# set up model with these hyperparams
|
||||||
hparams = get_hparams()
|
hparams = get_hparams()
|
||||||
model = LightningTemplateModel(hparams)
|
|
||||||
|
if use_test_model:
|
||||||
|
model = LightningTestModel(hparams)
|
||||||
|
else:
|
||||||
|
model = LightningTemplateModel(hparams)
|
||||||
|
|
||||||
return model, hparams
|
return model, hparams
|
||||||
|
|
||||||
|
|
||||||
def get_exp(debug=True):
|
def get_exp(debug=True, version=None):
|
||||||
# set up exp object without actually saving logs
|
# set up exp object without actually saving logs
|
||||||
root_dir = os.path.dirname(os.path.realpath(__file__))
|
root_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
exp = Experiment(debug=debug, save_dir=root_dir, name='tests_tt_dir')
|
exp = Experiment(debug=debug, save_dir=root_dir, name='tests_tt_dir', version=version)
|
||||||
return exp
|
return exp
|
||||||
|
|
||||||
|
|
||||||
@@ -675,13 +810,13 @@ def run_prediction(dataloader, trained_model):
|
|||||||
|
|
||||||
print(val_acc)
|
print(val_acc)
|
||||||
|
|
||||||
assert val_acc > 0.50, f'this model is expected to get > 0.50 in test set (it got {val_acc})'
|
assert val_acc > 0.50, 'this model is expected to get > 0.50 in test set (it got %f)' % val_acc
|
||||||
|
|
||||||
|
|
||||||
def assert_ok_acc(trainer):
|
def assert_ok_acc(trainer):
|
||||||
# this model should get 0.80+ acc
|
# this model should get 0.80+ acc
|
||||||
acc = trainer.tng_tqdm_dic['val_acc']
|
acc = trainer.tng_tqdm_dic['val_acc']
|
||||||
assert acc > 0.50, f'model failed to get expected 0.50 validation accuracy. Got: {acc}'
|
assert acc > 0.50, 'model failed to get expected 0.50 validation accuracy. Got: %f' % acc
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# this file is *not* meant to cover or endorse the use of tox or pytest or testing in general,
|
||||||
|
#
|
||||||
|
# It's meant to show the use of:
|
||||||
|
#
|
||||||
|
# - check-manifest
|
||||||
|
# confirm items checked into vcs are in your segdist
|
||||||
|
# - python setup.py check
|
||||||
|
# confirm required package meta-data in setup.py
|
||||||
|
# - readme_renderer (when using a ReStructuredText README)
|
||||||
|
# confirms your long_description will render correctly on PyPI.
|
||||||
|
#
|
||||||
|
# and also to help confirm pull requests to this project.
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py{35,36,37}
|
||||||
|
|
||||||
|
[pytest]
|
||||||
|
log_cli = 0
|
||||||
|
log_cli_level = CRITICAL
|
||||||
|
log_cli_format = %(message)s
|
||||||
|
log_file = pytest.log
|
||||||
|
log_file_level = DEBUG
|
||||||
|
log_file_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
|
||||||
|
log_file_date_format=%Y-%m-%d %H:%M:%S
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
basepython =
|
||||||
|
py35: python3.5
|
||||||
|
py36: python3.6
|
||||||
|
py37: python3.7
|
||||||
|
deps =
|
||||||
|
-r requirements.txt
|
||||||
|
-r ./tests/requirements.txt
|
||||||
|
commands =
|
||||||
|
check-manifest --ignore tox.ini
|
||||||
|
python setup.py check -m -s
|
||||||
|
coverage run --source pytorch_lightning -m py.test pytorch_lightning tests examples -v --doctest-modules
|
||||||
|
flake8 .
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude = .tox,*.egg,build,temp
|
||||||
|
select = E,W,F
|
||||||
|
doctests = True
|
||||||
|
verbose = 2
|
||||||
|
# https://pep8.readthedocs.io/en/latest/intro.html#error-codes
|
||||||
|
format = pylint
|
||||||
|
max-line-length = 100
|
||||||
Reference in New Issue
Block a user