Skip to content

feat(template): add dcgan template #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 17, 2021
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
restore-keys: |
pnpm-and-pip-cache-

- run: pip install "black==20.8b1" "isort==5.7.0"
- run: pip install -Uq pip wheel && pip install -Uq "black==20.8b1" "isort==5.7.0"
- run: npm i -g pnpm
- run: pnpm i --frozen-lockfile --color
- run: pnpm lint
Expand Down
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ To contribute to Code-Generator App, you will need Nodejs LTS v14.16.x, VSCode,

- Install pnpm from https://pnpm.io/installation. Use standalone script if there is a root issue with installing with npm.

- Install the dependencies with `pnpm install` in the project root directory. This might take a while to install.
- Install the dependencies with `pnpm install` and `bash .github/run_code_style.sh install` in the project root directory. This might take a while to install.

- Run `pnpm run dev` to start local development server and starts editing the codes in the `src` directory. Changes will be updated on the app.

Expand Down Expand Up @@ -68,6 +68,8 @@ To add a new template,

8. For the `utils.py`, copy the starter code from the `src/template-common/utils.py`.

9. You can check if the copied codes needed are up-to-date with the base codes with: `python scripts/check_copies.py`

## Pull Request Guidelines

- Checkout a topic branch from a base branch, e.g. `v1` (currently).
Expand Down
48 changes: 22 additions & 26 deletions scripts/check_copies.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,40 @@
from pathlib import Path


def check_utils():
def check(fname):
red = "\033[31m"
green = "\033[32m"
reset = "\033[0m"

with open("./src/templates/template-common/utils.py", "r") as f:
common_utils = f.read()
with open(f"./src/templates/template-common/{fname}", "r") as f:
common = f.readlines()

path = Path("./src/templates/")

for file in path.rglob("**/utils.py"):
utils = file.read_text("utf-8")
if utils.find(common_utils) > -1:
print(green, "Matched", file, reset)
for file in path.rglob(f"**/{fname}"):
if str(file).find("common") > -1:
continue
else:
print(red, "Unmatched", file, reset)
template = file.read_text("utf-8")

match = []
for c in common:
match.append(template.find(c) > -1)

def check_readme():
red = "\033[31m"
green = "\033[32m"
reset = "\033[0m"

with open("./src/templates/template-common/README.md", "r") as f:
common_utils = f.read()

path = Path("./src/templates/")

for file in path.rglob("**/README.md"):
utils = file.read_text("utf-8")
if utils.find(common_utils) > -1:
print(green, "Matched", file, reset)
else:
print(red, "Unmatched", file, reset)
if all(match):
print(green, "Matched", file, reset)
else:
print(red, "Unmatched", file, reset)
exit(1)


if __name__ == "__main__":
check_utils()
check("config.yaml")
print()
check("main.py")
print()
check("README.md")
print()
check_readme()
check("requirements.txt")
print()
check("utils.py")
52 changes: 52 additions & 0 deletions src/templates/template-common/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
backend: null
seed: 666
data_path: ./
train_batch_size: 4
eval_batch_size: 8
num_workers: 2
max_epochs: 2
train_epoch_length: 4
eval_epoch_length: 4
lr: 0.0001
use_amp: false
verbose: false

#::: if (it.dist === 'spawn') { :::#
# distributed spawn
nproc_per_node: #:::= it.nproc_per_node :::#
#::: if (it.nnodes) { :::#
# distributed multi node spawn
nnodes: #:::= it.nnodes :::#
node_rank: 0
master_addr: #:::= it.master_addr :::#
master_port: #:::= it.master_port :::#
#::: } :::#
#::: } :::#

#::: if (it.filename_prefix) { :::#
filename_prefix: #:::= it.filename_prefix :::#
#::: } :::#

#::: if (it.n_saved) { :::#
n_saved: #:::= it.n_saved :::#
#::: } :::#

#::: if (it.save_every_iters) { :::#
save_every_iters: #:::= it.save_every_iters :::#
#::: } :::#

#::: if (it.patience) { :::#
patience: #:::= it.patience :::#
#::: } :::#

#::: if (it.limit_sec) { :::#
limit_sec: #:::= it.limit_sec :::#
#::: } :::#

#::: if (it.output_dir) { :::#
output_dir: #:::= it.output_dir :::#
#::: } :::#

#::: if (it.log_every_iters) { :::#
log_every_iters: #:::= it.log_every_iters :::#
#::: } :::#
57 changes: 57 additions & 0 deletions src/templates/template-common/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
ckpt_handler_train, ckpt_handler_eval, timer = setup_handlers(
trainer, evaluator, config, to_save_train, to_save_eval
)

#::: if (it.save_training || it.save_evaluation || it.patience || it.terminate_on_nan || it.timer || it.limit_sec) { :::#
if timer is not None:
logger.info("Time per batch: %.4f seconds", timer.value())
timer.reset()
#::: } :::#

#::: if (it.logger) { :::#
if rank == 0:
from ignite.contrib.handlers.wandb_logger import WandBLogger

if isinstance(exp_logger, WandBLogger):
# why handle differently for wandb?
# See: https://github.com/pytorch/ignite/issues/1894
exp_logger.finish()
elif exp_logger:
exp_logger.close()
#::: } :::#

#::: if (it.save_training || it.save_evaluation || it.patience || it.terminate_on_nan || it.timer || it.limit_sec) { :::#
if ckpt_handler_train is not None:
logger.info(
"Last training checkpoint name - %s",
ckpt_handler_train.last_checkpoint,
)

if ckpt_handler_eval is not None:
logger.info(
"Last evaluation checkpoint name - %s",
ckpt_handler_eval.last_checkpoint,
)
#::: } :::#

# main entrypoint
@hydra.main(config_name="config")
def main(config):
#::: if (it.dist === 'spawn') { :::#
#::: if (it.nproc_per_node && it.nnodes && it.master_addr && it.master_port) { :::#
kwargs = {
"nproc_per_node": config.nproc_per_node,
"nnodes": config.nnodes,
"node_rank": config.node_rank,
"master_addr": config.master_addr,
"master_port": config.master_port,
}
#::: } else if (it.nproc_per_node) { :::#
kwargs = {"nproc_per_node": config.nproc_per_node}
#::: } :::#
with idist.Parallel(config.backend, **kwargs) as p:
p.run(run, config=config)
#::: } else { :::#
with idist.Parallel(config.backend) as p:
p.run(run, config=config)
#::: } :::#
14 changes: 14 additions & 0 deletions src/templates/template-common/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
torch>=1.8.0
torchvision>=0.9.0
pytorch-ignite>=0.4.4
hydra-core>=1.0.0

#::: if (['neptune', 'polyaxon'].includes(it.logger)) { :::#

#:::= it.logger + '-client' :::#

#::: } else { :::#

#:::= it.logger :::#

#::: } :::#
137 changes: 137 additions & 0 deletions src/templates/template-vision-dcgan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Template by Code-Generator

## Getting Started

Install the dependencies with `pip`:

```sh
pip install -r requirements.txt --progress-bar off -U
```

## Training

#::: if (it.dist === 'launch') { :::#
#::: if (it.nproc_per_node) { :::#
#::: if (it.nnodes && it.master_addr && it.master_port) { :::#

### Multi Node, Multi GPU Training (`torch.distributed.launch`) (recommended)

- Execute on master node

```sh
python -m torch.distributed.launch \
--nproc_per_node #:::= nproc_per_node :::# \
--nnodes #:::= it.nnodes :::# \
--node_rank 0 \
--master_addr #:::= it.master_addr :::# \
--master_port #:::= it.master_port :::# \
--use_env main.py backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

- Execute on worker nodes

```sh
python -m torch.distributed.launch \
--nproc_per_node #:::= nproc_per_node :::# \
--nnodes #:::= it.nnodes :::# \
--node_rank <node_rank> \
--master_addr #:::= it.master_addr :::# \
--master_port #:::= it.master_port :::# \
--use_env main.py backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

#::: } else { :::#

### Multi GPU Training (`torch.distributed.launch`) (recommended)

```sh
python -m torch.distributed.launch \
--nproc_per_node #:::= it.nproc_per_node :::# \
--use_env main.py backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

#::: } :::#
#::: } :::#
#::: } :::#

#::: if (it.dist === 'spawn') { :::#
#::: if (it.nproc_per_node) { :::#
#::: if (it.nnodes && it.master_addr && it.master_port) { :::#

### Multi Node, Multi GPU Training (`torch.multiprocessing.spawn`)

- Execute on master node

```sh
python main.py \
nproc_per_node=#:::= nproc_per_node :::# \
nnodes=#:::= it.nnodes :::# \
node_rank=0 \
master_addr=#:::= it.master_addr :::# \
master_port=#:::= it.master_port :::# \
backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

- Execute on worker nodes

```sh
python main.py \
nproc_per_node=#:::= nproc_per_node :::# \
nnodes=#:::= it.nnodes :::# \
node_rank=<node_rank> \
master_addr=#:::= it.master_addr :::# \
master_port=#:::= it.master_port :::# \
backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

#::: } else { :::#

### Multi GPU Training (`torch.multiprocessing.spawn`)

```sh
python main.py \
nproc_per_node=#:::= it.nproc_per_node :::# \
backend=nccl \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

#::: } :::#
#::: } :::#
#::: } :::#

#::: if (!it.nproc_per_node) { :::#

### 1 GPU Training

```sh
python main.py \
hydra.run.dir=. \
hydra.output_subdir=null \
hydra/job_logging=disabled \
hydra/hydra_logging=disabled
```

#::: } :::#
Loading