GitOrigin-RevId: a5fe25be8c
tags/v1.0.0
| @@ -17,13 +17,114 @@ import numpy as np | |||
| from megengine.autodiff.grad_manager import GradManager, get_backwarding_grad_manager | |||
| from megengine.device import get_default_device, get_device_count | |||
| from ..functional.param_pack import get_offsets, pack_allreduce_split | |||
| from ..core.ops.builtin import ParamPackConcat, ParamPackSplit | |||
| from ..core.tensor.core import apply | |||
| from ..functional.utils import copy | |||
| from ..tensor import Tensor | |||
| from ..utils.future import Future | |||
| from .functional import all_reduce_sum, broadcast | |||
| from .group import WORLD, Group, group_barrier, is_distributed | |||
| def param_pack_split(inp: Tensor, offsets: list, shapes: list): | |||
| r""" | |||
| Returns split tensor to tensor list as offsets and shapes described, | |||
| only used for ``parampack``. | |||
| :param inp: input tensor. | |||
| :param offsets: offsets of outputs, length of `2 * n`, | |||
| while n is tensor nums you want to split, | |||
| format `[begin0, end0, begin1, end1]`. | |||
| :param shapes: tensor shapes of outputs. | |||
| :return: splitted tensors. | |||
| Examples: | |||
| .. testcode:: | |||
| import numpy as np | |||
| from megengine import tensor | |||
| from megengine.distributed.helper import param_pack_split | |||
| a = tensor(np.ones((10,), np.int32)) | |||
| b, c = param_pack_split(a, [0, 1, 1, 10], [(1,), (3, 3)]) | |||
| print(b.numpy()) | |||
| print(c.numpy()) | |||
| Outputs: | |||
| .. testoutput:: | |||
| [1] | |||
| [[1 1 1] | |||
| [1 1 1] | |||
| [1 1 1]] | |||
| """ | |||
| op = ParamPackSplit() | |||
| op.offsets = offsets | |||
| op.shapes = shapes | |||
| return apply(op, inp) | |||
| def param_pack_concat(inps: list, offsets: Tensor, offsets_val: list): | |||
| r""" | |||
| Returns concated tensor, only used for ``parampack``. | |||
| :param inps: input tensors. | |||
| :param offsets: device value of offsets. | |||
| :param offsets_val: offsets of inputs, length of `2 * n`, | |||
| format `[begin0, end0, begin1, end1]`. | |||
| :return: concated tensor. | |||
| Examples: | |||
| .. testcode:: | |||
| import numpy as np | |||
| from megengine import tensor | |||
| from megengine.distributed.helper import param_pack_concat | |||
| a = tensor(np.ones((1,), np.int32)) | |||
| b = tensor(np.ones((3, 3), np.int32)) | |||
| offsets_val = [0, 1, 1, 10] | |||
| offsets = tensor(offsets_val, np.int32) | |||
| c = param_pack_concat([a, b], offsets, offsets_val) | |||
| print(c.numpy()) | |||
| Outputs: | |||
| .. testoutput:: | |||
| [1 1 1 1 1 1 1 1 1 1] | |||
| """ | |||
| op = ParamPackConcat() | |||
| op.offsets = offsets_val | |||
| return apply(op, *inps, offsets)[0] | |||
| def get_offsets(shapes): | |||
| offsets = [] | |||
| offset = 0 | |||
| for shape in shapes: | |||
| offsets.append(offset) | |||
| offset += int(np.prod(shape)) | |||
| offsets.append(offset) | |||
| return offsets | |||
| def pack_allreduce_split(pack_list, shapes, group, reduce_method): | |||
| offsets_val = get_offsets(shapes) | |||
| offsets = Tensor(offsets_val) | |||
| packed_grads = param_pack_concat(pack_list, offsets, offsets_val) | |||
| packed_grads = all_reduce_sum(packed_grads, group, group.comp_node) | |||
| if reduce_method == "mean": | |||
| packed_grads /= group.size | |||
| grads = param_pack_split(packed_grads, offsets_val, shapes) | |||
| return grads | |||
| class TensorFuture(Future): | |||
| def device(self): | |||
| raise "Sorry, this tensor is not ready" | |||
| @@ -1,34 +0,0 @@ | |||
| # -*- 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 numpy as np | |||
| from ..tensor import Tensor | |||
| from .distributed import all_reduce_sum | |||
| from .tensor import param_pack_concat, param_pack_split | |||
| def get_offsets(shapes): | |||
| offsets = [] | |||
| offset = 0 | |||
| for shape in shapes: | |||
| offsets.append(offset) | |||
| offset += int(np.prod(shape)) | |||
| offsets.append(offset) | |||
| return offsets | |||
| def pack_allreduce_split(pack_list, shapes, group, reduce_method): | |||
| offsets_val = get_offsets(shapes) | |||
| offsets = Tensor(offsets_val) | |||
| packed_grads = param_pack_concat(pack_list, offsets, offsets_val) | |||
| packed_grads = all_reduce_sum(packed_grads, group, group.comp_node) | |||
| if reduce_method == "mean": | |||
| packed_grads /= group.size | |||
| grads = param_pack_split(packed_grads, offsets_val, shapes) | |||
| return grads | |||
| @@ -46,8 +46,6 @@ __all__ = [ | |||
| "linspace", | |||
| "ones", | |||
| "ones_like", | |||
| "param_pack_concat", | |||
| "param_pack_split", | |||
| "reshape", | |||
| "split", | |||
| "squeeze", | |||
| @@ -975,81 +973,3 @@ def arange( | |||
| if np.dtype(dtype) == np.int32: | |||
| return result.astype(dtype) | |||
| return result | |||
| def param_pack_split(inp: Tensor, offsets: List, shapes: List) -> Tensor: | |||
| r""" | |||
| Returns split tensor to tensor list as offsets and shapes described, | |||
| only used for ``parampack``. | |||
| :param inp: input tensor. | |||
| :param offsets: offsets of outputs, length of `2 * n`, | |||
| while n is tensor nums you want to split, | |||
| format `[begin0, end0, begin1, end1]`. | |||
| :param shapes: tensor shapes of outputs. | |||
| :return: splitted tensors. | |||
| Examples: | |||
| .. testcode:: | |||
| import numpy as np | |||
| import megengine.functional as F | |||
| from megengine import tensor | |||
| a = tensor(np.ones((10,), np.int32)) | |||
| b, c = F.param_pack_split(a, [0, 1, 1, 10], [(1,), (3, 3)]) | |||
| print(b.numpy()) | |||
| print(c.numpy()) | |||
| Outputs: | |||
| .. testoutput:: | |||
| [1] | |||
| [[1 1 1] | |||
| [1 1 1] | |||
| [1 1 1]] | |||
| """ | |||
| op = builtin.ParamPackSplit() | |||
| op.offsets = offsets | |||
| op.shapes = shapes | |||
| return apply(op, inp) | |||
| def param_pack_concat(inps: List, offsets: Tensor, offsets_val: List) -> Tensor: | |||
| r""" | |||
| Returns concated tensor, only used for ``parampack``. | |||
| :param inps: input tensors. | |||
| :param offsets: device value of offsets. | |||
| :param offsets_val: offsets of inputs, length of `2 * n`, | |||
| format `[begin0, end0, begin1, end1]`. | |||
| :return: concated tensor. | |||
| Examples: | |||
| .. testcode:: | |||
| import numpy as np | |||
| import megengine.functional as F | |||
| from megengine import tensor | |||
| a = tensor(np.ones((1,), np.int32)) | |||
| b = tensor(np.ones((3, 3), np.int32)) | |||
| offsets_val = [0, 1, 1, 10] | |||
| offsets = tensor(offsets_val, np.int32) | |||
| c = F.param_pack_concat([a, b], offsets, offsets_val) | |||
| print(c.numpy()) | |||
| Outputs: | |||
| .. testoutput:: | |||
| [1 1 1 1 1 1 1 1 1 1] | |||
| """ | |||
| op = builtin.ParamPackConcat() | |||
| op.offsets = offsets_val | |||
| return apply(op, *inps, offsets)[0] | |||
| @@ -10,12 +10,17 @@ import multiprocessing as mp | |||
| import platform | |||
| import queue | |||
| import numpy as np | |||
| import pytest | |||
| import megengine as mge | |||
| import megengine.distributed as dist | |||
| from megengine.core.ops.builtin import CollectiveComm, ParamPackConcat, ParamPackSplit | |||
| from megengine.distributed.helper import get_device_count_by_fork | |||
| from megengine.distributed.helper import ( | |||
| get_device_count_by_fork, | |||
| param_pack_concat, | |||
| param_pack_split, | |||
| ) | |||
| def _assert_q_empty(q): | |||
| @@ -195,3 +200,19 @@ def test_oprmm_hashable(): | |||
| rhs = (CollectiveComm(), ParamPackConcat(), ParamPackSplit()) | |||
| assert lhs == rhs | |||
| assert hash(lhs) == hash(rhs) | |||
| def test_param_pack_split(): | |||
| a = mge.Tensor(np.ones((10,), np.int32)) | |||
| b, c = param_pack_split(a, [0, 1, 1, 10], [(1,), (3, 3)]) | |||
| assert np.allclose(b.numpy(), a.numpy()[1]) | |||
| assert np.allclose(c.numpy(), a.numpy()[1:].reshape(3, 3)) | |||
| def test_param_pack_concat(): | |||
| a = mge.Tensor(np.ones((1,), np.int32)) | |||
| b = mge.Tensor(np.ones((3, 3), np.int32)) | |||
| offsets_val = [0, 1, 1, 10] | |||
| offsets = mge.Tensor(offsets_val, np.int32) | |||
| c = param_pack_concat([a, b], offsets, offsets_val) | |||
| assert np.allclose(np.concatenate([a.numpy(), b.numpy().flatten()]), c.numpy()) | |||
| @@ -359,19 +359,3 @@ def test_copy_d2h(): | |||
| def test_copy_d2d(): | |||
| copy_test("gpu0", "gpu1") | |||
| copy_test("gpu0:0", "gpu0:1") | |||
| def test_param_pack_split(): | |||
| a = tensor(np.ones((10,), np.int32)) | |||
| b, c = F.param_pack_split(a, [0, 1, 1, 10], [(1,), (3, 3)]) | |||
| assert np.allclose(b.numpy(), a.numpy()[1]) | |||
| assert np.allclose(c.numpy(), a.numpy()[1:].reshape(3, 3)) | |||
| def test_param_pack_concat(): | |||
| a = tensor(np.ones((1,), np.int32)) | |||
| b = tensor(np.ones((3, 3), np.int32)) | |||
| offsets_val = [0, 1, 1, 10] | |||
| offsets = tensor(offsets_val, np.int32) | |||
| c = F.param_pack_concat([a, b], offsets, offsets_val) | |||
| assert np.allclose(np.concatenate([a.numpy(), b.numpy().flatten()]), c.numpy()) | |||