# -*- coding: utf-8 -*- # MegEngine is Licensed under the Apache License, Version 2.0 (the "License") # # Copyright (c) 2014-2020 Megvii Inc. All rights reserved. # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import platform import pytest @pytest.mark.skipif( platform.system() == "Darwin", reason="do not imp GPU mode at macos now" ) @pytest.mark.skipif( platform.system() == "Windows", reason="do not imp GPU mode at Windows now" ) @pytest.mark.isolated_distributed def test_syncbn(): import numpy as np import multiprocessing as mp from megengine.distributed.group import Server from megengine.core._trace_option import use_tensor_shape if use_tensor_shape(): # XXX: fix sync bn if use_tensor_shape return nr_chan = 8 nr_ranks = 4 data_shape = (3, nr_chan, 4, nr_ranks * 8) momentum = 0.9 eps = 1e-5 running_mean = np.zeros((1, nr_chan, 1, 1), dtype=np.float32) running_var = np.ones((1, nr_chan, 1, 1), dtype=np.float32) steps = 4 server = Server(0) port = server.py_server_port def worker(rank, data, yv_expect, running_mean, running_var): import megengine as mge import megengine.distributed as dist from megengine import tensor from megengine.module import SyncBatchNorm from megengine.distributed.group import Group from megengine.test import assertTensorClose if mge.get_device_count("gpu") < nr_ranks: return dist.init_process_group("localhost", port, nr_ranks, rank, rank) group = Group([i for i in range(nr_ranks)]) bn = SyncBatchNorm(nr_chan, eps=eps, momentum=momentum, group=group) data_tensor = None for i in range(steps): if data_tensor is None: data_tensor = tensor(data[i], device=f"gpu{rank}:0") else: data_tensor.set_value(data[i]) yv = bn(data_tensor) assertTensorClose(yv_expect, yv.numpy(), max_err=5e-6) assertTensorClose(running_mean, bn.running_mean.numpy(), max_err=5e-6) assertTensorClose(running_var, bn.running_var.numpy(), max_err=5e-6) xv = [] for i in range(steps): xv.append(np.random.normal(loc=2.3, size=data_shape).astype(np.float32)) xv_transposed = np.transpose(xv[i], [0, 2, 3, 1]).reshape( (data_shape[0] * data_shape[2] * data_shape[3], nr_chan) ) mean = np.mean(xv_transposed, axis=0).reshape(1, nr_chan, 1, 1) var_biased = np.var(xv_transposed, axis=0).reshape((1, nr_chan, 1, 1)) sd = np.sqrt(var_biased + eps) var_unbiased = np.var(xv_transposed, axis=0, ddof=1).reshape((1, nr_chan, 1, 1)) running_mean = running_mean * momentum + mean * (1 - momentum) running_var = running_var * momentum + var_unbiased * (1 - momentum) yv_expect = (xv[i] - mean) / sd data = [] for i in range(nr_ranks): data.append([]) for j in range(steps): data[i].append(xv[j][:, :, :, i * 8 : i * 8 + 8]) procs = [] for rank in range(nr_ranks): p = mp.Process( target=worker, args=( rank, data[rank], yv_expect[:, :, :, rank * 8 : rank * 8 + 8], running_mean, running_var, ), ) p.start() procs.append(p) for p in procs: p.join(10) assert p.exitcode == 0 def test_module_conv2d(): from megengine.module.conv import Conv2d conv = Conv2d(2, 3, 1)