From 7983f74b2e417a2cdf81318fcd3d0b6d207e0406 Mon Sep 17 00:00:00 2001 From: ydcjeff <32727188+ydcjeff@users.noreply.github.com> Date: Tue, 25 May 2021 15:39:05 +0630 Subject: [PATCH 01/12] test: add user tests --- .../template-common/requirements.txt | 4 ++ .../requirements.txt | 4 ++ .../test_all.py | 70 ++++++++++++++++++ .../template-vision-dcgan/requirements.txt | 4 ++ .../template-vision-dcgan/test_all.py | 72 +++++++++++++++++++ .../requirements.txt | 4 ++ .../template-vision-segmentation/test_all.py | 70 ++++++++++++++++++ 7 files changed, 228 insertions(+) create mode 100644 src/templates/template-vision-classification/test_all.py create mode 100644 src/templates/template-vision-dcgan/test_all.py create mode 100644 src/templates/template-vision-segmentation/test_all.py diff --git a/src/templates/template-common/requirements.txt b/src/templates/template-common/requirements.txt index 4bbe4290..52dc19aa 100644 --- a/src/templates/template-common/requirements.txt +++ b/src/templates/template-common/requirements.txt @@ -12,3 +12,7 @@ pyyaml #:::= it.logger :::# #::: } :::# + +#::: if (it.include_tests) { :::# +pytest +#::: } :::# diff --git a/src/templates/template-vision-classification/requirements.txt b/src/templates/template-vision-classification/requirements.txt index 4bbe4290..52dc19aa 100644 --- a/src/templates/template-vision-classification/requirements.txt +++ b/src/templates/template-vision-classification/requirements.txt @@ -12,3 +12,7 @@ pyyaml #:::= it.logger :::# #::: } :::# + +#::: if (it.include_tests) { :::# +pytest +#::: } :::# diff --git a/src/templates/template-vision-classification/test_all.py b/src/templates/template-vision-classification/test_all.py new file mode 100644 index 00000000..a130e1c7 --- /dev/null +++ b/src/templates/template-vision-classification/test_all.py @@ -0,0 +1,70 @@ +import os +from argparse import Namespace +from numbers import Number +from typing import Iterable + +import ignite.distributed as idist +import pytest +import torch +from datasets import get_datasets +from ignite.contrib.handlers.param_scheduler import ParamScheduler +from ignite.engine import Engine +from torch import nn, optim +from torch.functional import Tensor +from torch.optim.lr_scheduler import _LRScheduler +from torch.utils.data import Dataset +from trainers import evaluate_function +from utils import initialize + + +def set_up(): + model = nn.Linear(1, 1) + optimizer = optim.Adam(model.parameters()) + device = idist.device() + loss_fn = nn.MSELoss() + batch = [torch.tensor([1.0]), torch.tensor([1.0])] + + return model, optimizer, device, loss_fn, batch + + +@pytest.mark.skipif(os.getenv("RUN_SLOW_TESTS", 0) == 0, reason="Skip slow tests") +def test_get_datasets(tmp_path): + train_ds, eval_ds = get_datasets(tmp_path) + + assert isinstance(train_ds, Dataset) + assert isinstance(eval_ds, Dataset) + train_batch = next(iter(train_ds)) + assert isinstance(train_batch, Iterable) + assert isinstance(train_batch[0], Tensor) + assert isinstance(train_batch[1], Number) + assert train_batch[0].ndim == 3 + eval_batch = next(iter(eval_ds)) + assert isinstance(eval_batch, Iterable) + assert isinstance(eval_batch[0], Tensor) + assert isinstance(eval_batch[1], Number) + assert eval_batch[0].ndim == 3 + + +def test_evaluate_fn(): + model, _, device, _, batch = set_up() + engine = Engine(lambda e, b: 1) + config = Namespace(use_amp=False) + output = evaluate_function(config, engine, batch, model, device) + assert isinstance(output, tuple) + + +def test_initialize(): + config = Namespace( + model="squeezenet1_0", + lr=1e-3, + momentum=0.9, + weight_decay=1e-4, + num_iters_per_epoch=1, + num_warmup_epochs=1, + max_epochs=1, + ) + model, optimizer, loss_fn, lr_scheduler = initialize(config) + assert isinstance(model, nn.Module) + assert isinstance(optimizer, optim.Optimizer) + assert isinstance(loss_fn, nn.Module) + assert isinstance(lr_scheduler, (_LRScheduler, ParamScheduler)) diff --git a/src/templates/template-vision-dcgan/requirements.txt b/src/templates/template-vision-dcgan/requirements.txt index 4bbe4290..52dc19aa 100644 --- a/src/templates/template-vision-dcgan/requirements.txt +++ b/src/templates/template-vision-dcgan/requirements.txt @@ -12,3 +12,7 @@ pyyaml #:::= it.logger :::# #::: } :::# + +#::: if (it.include_tests) { :::# +pytest +#::: } :::# diff --git a/src/templates/template-vision-dcgan/test_all.py b/src/templates/template-vision-dcgan/test_all.py new file mode 100644 index 00000000..a65ecf98 --- /dev/null +++ b/src/templates/template-vision-dcgan/test_all.py @@ -0,0 +1,72 @@ +import os +from argparse import Namespace +from numbers import Number +from typing import Iterable + +import ignite.distributed as idist +import pytest +import torch +from datasets import get_datasets +from ignite.engine import Engine +from models import Discriminator, Generator +from torch import nn, optim +from torch.functional import Tensor +from torch.utils.data import Dataset +from trainers import train_function + + +def set_up(): + model = nn.Linear(1, 1) + optimizer = optim.Adam(model.parameters()) + device = idist.device() + loss_fn = nn.MSELoss() + batch = [torch.tensor([1.0]), torch.tensor([1.0])] + + return model, optimizer, device, loss_fn, batch + + +@pytest.mark.skipif(os.getenv("RUN_SLOW_TESTS", 0) == 0, reason="Skip slow tests") +def test_get_datasets(tmp_path): + dataset, _ = get_datasets("cifar10", tmp_path) + + assert isinstance(dataset, Dataset) + batch = next(iter(dataset)) + assert isinstance(batch, Iterable) + assert isinstance(batch[0], Tensor) + assert isinstance(batch[1], Number) + assert batch[0].ndim == 3 + + +def test_models(): + model_G = Generator(100, 64, 3) + model_D = Discriminator(3, 64) + x = torch.rand([1, 100, 32, 32]) + y = model_G(x) + y.sum().backward() + z = model_D(y) + assert y.shape == torch.Size([1, 3, 560, 560]) + assert z.shape == torch.Size([1024]) + assert isinstance(model_D, nn.Module) + assert isinstance(model_G, nn.Module) + + +def test_train_fn(): + model, optimizer, device, loss_fn, batch = set_up() + real_labels = torch.ones(2, device=device) + fake_labels = torch.zeros(2, device=device) + engine = Engine(lambda e, b: 1) + config = Namespace(use_amp=False, batch_size=2, z_dim=100) + output = train_function( + config, + engine, + batch, + model, + model, + loss_fn, + optimizer, + optimizer, + device, + real_labels, + fake_labels, + ) + assert isinstance(output, dict) diff --git a/src/templates/template-vision-segmentation/requirements.txt b/src/templates/template-vision-segmentation/requirements.txt index 22d3c3d5..054bac44 100644 --- a/src/templates/template-vision-segmentation/requirements.txt +++ b/src/templates/template-vision-segmentation/requirements.txt @@ -14,3 +14,7 @@ image_dataset_viz #:::= it.logger :::# #::: } :::# + +#::: if (it.include_tests) { :::# +pytest +#::: } :::# diff --git a/src/templates/template-vision-segmentation/test_all.py b/src/templates/template-vision-segmentation/test_all.py new file mode 100644 index 00000000..a130e1c7 --- /dev/null +++ b/src/templates/template-vision-segmentation/test_all.py @@ -0,0 +1,70 @@ +import os +from argparse import Namespace +from numbers import Number +from typing import Iterable + +import ignite.distributed as idist +import pytest +import torch +from datasets import get_datasets +from ignite.contrib.handlers.param_scheduler import ParamScheduler +from ignite.engine import Engine +from torch import nn, optim +from torch.functional import Tensor +from torch.optim.lr_scheduler import _LRScheduler +from torch.utils.data import Dataset +from trainers import evaluate_function +from utils import initialize + + +def set_up(): + model = nn.Linear(1, 1) + optimizer = optim.Adam(model.parameters()) + device = idist.device() + loss_fn = nn.MSELoss() + batch = [torch.tensor([1.0]), torch.tensor([1.0])] + + return model, optimizer, device, loss_fn, batch + + +@pytest.mark.skipif(os.getenv("RUN_SLOW_TESTS", 0) == 0, reason="Skip slow tests") +def test_get_datasets(tmp_path): + train_ds, eval_ds = get_datasets(tmp_path) + + assert isinstance(train_ds, Dataset) + assert isinstance(eval_ds, Dataset) + train_batch = next(iter(train_ds)) + assert isinstance(train_batch, Iterable) + assert isinstance(train_batch[0], Tensor) + assert isinstance(train_batch[1], Number) + assert train_batch[0].ndim == 3 + eval_batch = next(iter(eval_ds)) + assert isinstance(eval_batch, Iterable) + assert isinstance(eval_batch[0], Tensor) + assert isinstance(eval_batch[1], Number) + assert eval_batch[0].ndim == 3 + + +def test_evaluate_fn(): + model, _, device, _, batch = set_up() + engine = Engine(lambda e, b: 1) + config = Namespace(use_amp=False) + output = evaluate_function(config, engine, batch, model, device) + assert isinstance(output, tuple) + + +def test_initialize(): + config = Namespace( + model="squeezenet1_0", + lr=1e-3, + momentum=0.9, + weight_decay=1e-4, + num_iters_per_epoch=1, + num_warmup_epochs=1, + max_epochs=1, + ) + model, optimizer, loss_fn, lr_scheduler = initialize(config) + assert isinstance(model, nn.Module) + assert isinstance(optimizer, optim.Optimizer) + assert isinstance(loss_fn, nn.Module) + assert isinstance(lr_scheduler, (_LRScheduler, ParamScheduler)) From 2acd7939429cb495d8d93205d11093f15cb98524 Mon Sep 17 00:00:00 2001 From: ydcjeff <32727188+ydcjeff@users.noreply.github.com> Date: Tue, 25 May 2021 16:16:11 +0630 Subject: [PATCH 02/12] test: refactor tests, add `include_test` checkbox - add CI - add checks in generating zip tests ref #103 --- .github/workflows/ci.yml | 10 +-- __tests__/vision-classification.spec.js | 3 + __tests__/vision-dcgan.spec.js | 3 + __tests__/vision-segmentation.spec.js | 3 + scripts/requirements.txt | 1 + scripts/run_tests.sh | 1 + src/components/TabTemplates.vue | 9 ++- src/store.js | 6 +- .../test_all.py | 61 +++++++----------- .../template-vision-dcgan/test_all.py | 63 +++++++++---------- .../template-vision-segmentation/test_all.py | 61 +++++++----------- src/templates/templates.json | 3 + 12 files changed, 107 insertions(+), 117 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7422e483..9da60704 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,8 @@ on: jobs: tests: runs-on: ${{ matrix.os }} + env: + RUN_SLOW_TESTS: 1 strategy: fail-fast: false matrix: @@ -59,14 +61,14 @@ jobs: - run: pnpm test:ci - run: sh ./scripts/run_tests.sh unzip - - name: Run simple - run: sh ./scripts/run_tests.sh simple - if: github.event_name != 'schedule' - - name: Run all run: sh ./scripts/run_tests.sh all if: github.event_name != 'schedule' + - name: Run simple + run: sh ./scripts/run_tests.sh simple + if: github.event_name != 'schedule' + - name: Run launch run: sh ./scripts/run_tests.sh launch if: github.event_name == 'schedule' diff --git a/__tests__/vision-classification.spec.js b/__tests__/vision-classification.spec.js index 13cdfc73..c2c59b2b 100644 --- a/__tests__/vision-classification.spec.js +++ b/__tests__/vision-classification.spec.js @@ -43,6 +43,9 @@ test('vision classification simple', async () => { test('vision classification all', async () => { await page.selectOption('select', 'template-vision-classification') + await page.check('#include_test-checkbox') + expect(await page.isChecked('#include_test-checkbox')).toBeTruthy() + await page.waitForSelector('text=README.md') await page.click(':nth-match(:text("Training"), 2)') diff --git a/__tests__/vision-dcgan.spec.js b/__tests__/vision-dcgan.spec.js index 81753a2e..127458f2 100644 --- a/__tests__/vision-dcgan.spec.js +++ b/__tests__/vision-dcgan.spec.js @@ -43,6 +43,9 @@ test('vision dcgan simple', async () => { test('vision dcgan all', async () => { await page.selectOption('select', 'template-vision-dcgan') + await page.check('#include_test-checkbox') + expect(await page.isChecked('#include_test-checkbox')).toBeTruthy() + await page.waitForSelector('text=README.md') await page.click(':nth-match(:text("Training"), 2)') diff --git a/__tests__/vision-segmentation.spec.js b/__tests__/vision-segmentation.spec.js index 84ab3e10..ef7c2fff 100644 --- a/__tests__/vision-segmentation.spec.js +++ b/__tests__/vision-segmentation.spec.js @@ -43,6 +43,9 @@ test('vision segmentation simple', async () => { test('vision segmentation all', async () => { await page.selectOption('select', 'template-vision-segmentation') + await page.check('#include_test-checkbox') + expect(await page.isChecked('#include_test-checkbox')).toBeTruthy() + await page.waitForSelector('text=README.md') await page.click(':nth-match(:text("Training"), 2)') diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 7a659699..e0c29e52 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -4,3 +4,4 @@ pytorch-ignite>=0.4.2 pyyaml albumentations image_dataset_viz +pytest diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 84eeee1e..19385ad7 100644 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -27,6 +27,7 @@ run_all() { for dir in $(find ./dist-tests/*-all -type d) do cd $dir + pytest -vra --color=yes --tb=short test_*.py python main.py --data_path ~/data cd $CWD done diff --git a/src/components/TabTemplates.vue b/src/components/TabTemplates.vue index c6f298f8..d0847c83 100644 --- a/src/components/TabTemplates.vue +++ b/src/components/TabTemplates.vue @@ -10,16 +10,23 @@ @change.prevent="downloadTemplates" /> +
+ +