diff --git a/gluonfr/model_zoo/attention_net.py b/gluonfr/model_zoo/attention_net.py index 627b85a..b8115f6 100644 --- a/gluonfr/model_zoo/attention_net.py +++ b/gluonfr/model_zoo/attention_net.py @@ -327,7 +327,7 @@ def get_attention_net(classes, num_layers, **kwargs): ptr, modules = attention_net_spec[num_layers] assert len(ptr) == len(modules) == 3 p, t, r = ptr - net = AttentionNet(classes, modules, p, t, r, **kwargs) + net = AttentionNetFace(classes, modules, p, t, r, **kwargs) return net diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..ab16469 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,4 @@ +# This is Gluon-Face test module. + +We use pytest as our test runner +and will use Jenkins+Github as CI. \ No newline at end of file diff --git a/tests/unittests/common.py b/tests/unittests/common.py new file mode 100644 index 0000000..2c2d2a6 --- /dev/null +++ b/tests/unittests/common.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) + + +import mxnet as mx +import functools + + +def try_gpu(gpu_id=0): + """Try execute on gpu, if not fallback to cpu""" + + def test_helper(orig_test): + @functools.wraps(orig_test) + def test_wapper(*args, **kwargs): + try: + a = mx.nd.zeros((1,), ctx=mx.gpu(gpu_id)) + ctx = mx.gpu(gpu_id) + except Exception: + ctx = mx.cpu() + with ctx: + orig_test(*args, **kwargs) + + return test_wapper + + return test_helper + + +def try_cpu(cpu_id=0): + """Try execute on gpu, if not fallback to cpu""" + + def test_helper(orig_test): + @functools.wraps(orig_test) + def test_wapper(*args, **kwargs): + try: + a = mx.nd.zeros((1,), ctx=mx.cpu(cpu_id)) + ctx = mx.gpu(cpu_id) + except Exception: + ctx = mx.cpu(0) + with ctx: + orig_test(*args, **kwargs) + + return test_wapper + + return test_helper diff --git a/tests/unittests/test_basic_block.py b/tests/unittests/test_basic_block.py new file mode 100644 index 0000000..cd89d46 --- /dev/null +++ b/tests/unittests/test_basic_block.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) + +import pytest +import mxnet as mx +from mxnet import nd +from mxnet.gluon import nn +from gluonfr.nn.basic_blocks import FrBase +from tests.unittests.common import try_gpu + + +class Model(FrBase): + def __init__(self, embedding_size=1, weight_norm=False, feature_norm=False, + need_cls_layer=True): + super(Model, self).__init__(1, embedding_size, weight_norm, feature_norm, need_cls_layer) + self.features = nn.HybridSequential() + self.features.add( + nn.Conv2D(16, 3, 1, 1, use_bias=False), + nn.BatchNorm(), + nn.Dense(embedding_size, use_bias=False), + nn.BatchNorm(center=False, scale=False), + ) + + +@pytest.fixture(params=[[16, False, False, False], + [16, True, True, False], + [16, True, True, True]]) +def get_model(request): + return Model(*request.param) + + +@try_gpu(0) +def test_model(get_model): + ctx = mx.context.current_context() + x = nd.random.normal(shape=(2, 3, 112, 112), ctx=ctx) + model = get_model + model.initialize(ctx=ctx) + model(x) diff --git a/tests/unittests/test_data_dataloader.py b/tests/unittests/test_data_dataloader.py new file mode 100644 index 0000000..845a3bf --- /dev/null +++ b/tests/unittests/test_data_dataloader.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) + +"""No additional Dataloader to test""" +pass diff --git a/tests/unittests/test_data_dataset.py b/tests/unittests/test_data_dataset.py deleted file mode 100644 index 7fd27f1..0000000 --- a/tests/unittests/test_data_dataset.py +++ /dev/null @@ -1,55 +0,0 @@ -# MIT License -# -# Copyright (c) 2018 Haoxintong -# -# 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. -"""""" -import mxnet as mx -import numpy as np -from unittest import TestCase -from gluonfr.data.dataset import FRValDataset -from mxnet.gluon.data import DataLoader - -targets = 'lfw,calfw,cplfw,cfp_fp,agedb_30,cfp_ff,vgg2_fp' - - -class TestDataset(TestCase): - # def setUpClass(cls): - - def test_val_dataset(self): - for target in targets.split(","): - val_set = FRValDataset(target) - for _ in range(10): - index = np.random.randint(0, len(val_set)) - _ = val_set[index] - - def test_load_data(self): - for target in targets.split(","): - loader = DataLoader(FRValDataset(target), batch_size=8) - for i, batch in enumerate(loader): - data = batch[0] - issame = batch[1] - print(data[0].shape) - print(issame) - # assert isinstance(data, (mx.nd.NDArray, mx.nd.NDArray)) - # assert isinstance(issame, mx.nd.NDArray) - # assert data[0].shape == data[1].shape == (8, 3, 112, 112) - # assert issame.shape == (8,) - if i > 0: - break diff --git a/tests/unittests/test_data_datasets.py b/tests/unittests/test_data_datasets.py new file mode 100644 index 0000000..891e8db --- /dev/null +++ b/tests/unittests/test_data_datasets.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) + +import pytest +import numpy as np +from gluonfr.data.dataset import FRValDataset, FRTrainRecordDataset + +train_sets = ['vgg', 'webface', 'emore'] +val_sets = ['agedb_30', 'calfw', 'cfp_ff', 'cfp_fp', 'cplfw', 'lfw'] + + +def parse_sets(datasets): + return [[dataset] for dataset in datasets] + + +@pytest.fixture(params=parse_sets(train_sets)) +def get_train_datasets(request): + dt = FRTrainRecordDataset(*request.param) + return dt + + +@pytest.fixture(params=parse_sets(val_sets)) +def get_val_datasets(request): + dt = FRValDataset(*request.param) + return dt + + +def test_train_datasets(get_train_datasets): + dt = get_train_datasets + for _ in range(10): + index = np.random.randint(0, len(dt)) + img, label = dt[index] + assert img.shape == (112, 112, 3) + assert type(label) is float + + +def test_val_datasets(get_val_datasets): + dt = get_val_datasets + for _ in range(10): + index = np.random.randint(0, len(dt)) + imgs, label = dt[index] + assert imgs[0].shape == imgs[1].shape == (112, 112, 3) + assert label in (0, 1) diff --git a/tests/unittests/test_loss.py b/tests/unittests/test_loss.py new file mode 100644 index 0000000..af0a8d5 --- /dev/null +++ b/tests/unittests/test_loss.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) +"""loss test please look at our examples.""" +pass diff --git a/tests/unittests/test_model_zoo.py b/tests/unittests/test_model_zoo.py new file mode 100644 index 0000000..ffe9712 --- /dev/null +++ b/tests/unittests/test_model_zoo.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# @Author : PistonYang(pistonyang@gmail.com) + +import mxnet as mx +from gluonfr.model_zoo.model_zoo import * +from tests.unittests.common import try_gpu + + +@try_gpu(0) +def test_model_zoo(): + ctx = mx.context.current_context() + models = get_model_list() + data = mx.random.normal(shape=(2, 3, 112, 112), ctx=ctx) + for model_name in models: + model = get_model(model_name, classes=10, weight_norm=True, feature_norm=True) + model.initialize(ctx=ctx) + model(data) + mx.nd.waitall()