You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

parampack.py 5.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # -*- coding: utf-8 -*-
  2. # MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  3. #
  4. # Copyright (c) 2014-2020 Megvii Inc. All rights reserved.
  5. #
  6. # Unless required by applicable law or agreed to in writing,
  7. # software distributed under the License is distributed on an
  8. # "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. import collections
  10. from typing import Iterable, Optional
  11. import numpy as np
  12. from .._internal.opr import param_pack_split
  13. from ..core import Parameter, Tensor
  14. from .module import Module
  15. class ParamPack(Module):
  16. r"""Pack module's parameters
  17. :param model: the module you want to pack parameters.
  18. :param nr_ignore_first: how many parameters will be unpacked at first.
  19. :param max_size_per_group: upper bound of packed parameters' size in MB.
  20. :param max_nr_params_per_group: upper bound of the number of parameters of each group.
  21. """
  22. def __init__(
  23. self,
  24. model: Module,
  25. nr_ignore_first: int = 8,
  26. max_size_per_group: int = 10,
  27. max_nr_params_per_group: int = 100,
  28. ):
  29. super().__init__()
  30. self._model = model
  31. self._nr_ignore_first = nr_ignore_first
  32. self._max_size_per_group = max_size_per_group
  33. self._max_nr_params_per_group = max_nr_params_per_group
  34. self._grouped_params = []
  35. self._packed_params = []
  36. params = model.parameters()
  37. self._pack_params(params)
  38. def parameters(self, requires_grad: Optional[bool] = None) -> Iterable[Parameter]:
  39. for param in self._packed_params:
  40. if requires_grad is None or param.requires_grad == requires_grad:
  41. yield param
  42. def _pack_params(self, params: Iterable[Parameter]):
  43. groups = collections.defaultdict(list)
  44. ignored = 0
  45. param_id = 0
  46. for param in params:
  47. if self._nr_ignore_first > ignored:
  48. ignored += 1
  49. self._grouped_params.append([{"tensor": param, "id": param_id}])
  50. self._packed_params.append(param)
  51. else:
  52. key = (param.dtype, param.device, param.requires_grad)
  53. groups[key].append({"tensor": param, "id": param_id})
  54. param_id += 1
  55. for (dtype, device, requires_grad) in groups.keys():
  56. dtype_sz = np.dtype(dtype).itemsize
  57. align = device.mem_align
  58. if align < dtype_sz:
  59. align = 1
  60. else:
  61. assert align % dtype_sz == 0
  62. align //= dtype_sz
  63. group = groups[(dtype, device, requires_grad)]
  64. while group:
  65. aligned_pos = []
  66. offset = 0
  67. params = []
  68. idx = 0
  69. while idx < len(group):
  70. param = group[idx]
  71. assert param["tensor"].device == device
  72. padding = (align - (offset & (align - 1))) & (align - 1)
  73. offset += padding
  74. aligned_pos.append(offset)
  75. params.append(param)
  76. offset += int(np.prod(param["tensor"].shape))
  77. idx += 1
  78. if (
  79. offset * dtype_sz >= self._max_size_per_group * 1024 * 1024
  80. or idx >= self._max_nr_params_per_group
  81. ):
  82. break
  83. group = group[idx:]
  84. if idx == 1:
  85. # ignore param packs with only one item
  86. self._packed_params.append(params[0]["tensor"])
  87. self._grouped_params.append(params)
  88. continue
  89. packed_value = np.zeros((offset,), dtype=dtype)
  90. for param, pos in zip(params, aligned_pos):
  91. val = param["tensor"].numpy()
  92. packed_value[pos : pos + val.size] = val.flatten()
  93. new_param = Parameter(
  94. value=packed_value,
  95. device=device,
  96. dtype=dtype,
  97. requires_grad=requires_grad,
  98. )
  99. self._packed_params.append(new_param)
  100. self._grouped_params.append(params)
  101. def forward(self, *args, **kwargs):
  102. replace_param = dict()
  103. for i in range(len(self._packed_params)):
  104. packed_param = self._packed_params[i]
  105. grouped_params = self._grouped_params[i]
  106. if len(grouped_params) == 1:
  107. continue
  108. split = param_pack_split(
  109. packed_param._symvar, [i["tensor"].shape for i in grouped_params]
  110. )
  111. split = [
  112. Parameter(Tensor(i, requires_grad=packed_param.requires_grad))
  113. for i in split
  114. ]
  115. for j in range(len(split)):
  116. replace_param[grouped_params[j]["id"]] = split[j]
  117. self._model.replace_param(replace_param, 0)
  118. return self._model.forward(*args, **kwargs)

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台

Contributors (1)