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.

DistGCN_15d.py 6.5 kB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. from __future__ import absolute_import
  2. from .Node import Op
  3. import math
  4. from .. import ndarray
  5. import numpy as np
  6. from ctypes import *
  7. def row_num(node_count, rank, size):
  8. n_per_proc = math.ceil(float(node_count) / size)
  9. if (node_count % size == 0):
  10. return int(node_count / size)
  11. if (rank < size - 1):
  12. return int(n_per_proc)
  13. else:
  14. return int(node_count % n_per_proc)
  15. def broad_func(node_count, adj_matrix, inputs, rank, size, replication, row_groups, col_groups, ctx, comm=None, stream_handle=None):
  16. assert size % (replication ** 2) == 0
  17. n_per_proc = math.ceil(float(node_count) / (size // replication))
  18. proc_node_count = row_num(
  19. node_count, rank//replication, size // replication)
  20. z_loc = ndarray.empty((proc_node_count, inputs.shape[1]), ctx=ctx)
  21. tmp = ndarray.empty((proc_node_count, inputs.shape[1]), ctx=ctx)
  22. inputs_recv = ndarray.empty((int(n_per_proc), inputs.shape[1]), ctx=ctx)
  23. rank_c = rank // replication
  24. rank_col = rank % replication
  25. stages = size // (replication ** 2)
  26. node_count_col = stages * n_per_proc
  27. if rank_col == replication - 1:
  28. stages = (size // replication) - (replication - 1) * stages
  29. node_count_col = node_count - (replication - 1) * node_count_col
  30. start_pos = list(range(0, int(node_count_col), int(n_per_proc)))
  31. end_pos = start_pos[1:]+[int(node_count_col)]
  32. for i in range(stages):
  33. q = (rank_col * (size // (replication ** 2)) + i) * \
  34. replication + rank_col
  35. q_c = q // replication
  36. if q_c == size // replication - 1:
  37. inputs_recv = ndarray.empty((row_num(
  38. node_count, size//replication - 1, size//replication), inputs.shape[1]), ctx=ctx)
  39. if q == rank:
  40. inputs.copyto(inputs_recv)
  41. from ..communicator.mpi_nccl_comm import ncclDataType_t, ncclRedOp_t
  42. if replication > 1:
  43. col_groups[rank_col].dlarrayBroadcast(
  44. inputs_recv, inputs_recv, ncclDataType_t.ncclFloat32, q)
  45. else:
  46. comm.dlarrayBroadcast(inputs_recv, inputs_recv,
  47. ncclDataType_t.ncclFloat32, q)
  48. from ..gpu_links import CuSparse_Csrmm, matrix_elementwise_add
  49. CuSparse_Csrmm(adj_matrix, False, inputs_recv, False, tmp,
  50. stream=stream_handle, start_pos=int(start_pos[i]), end_pos=int(end_pos[i]))
  51. matrix_elementwise_add(z_loc, tmp, z_loc, stream_handle)
  52. if replication > 1:
  53. row_groups[rank_c].dlarrayNcclAllReduce(
  54. z_loc, z_loc, ncclDataType_t.ncclFloat32, reduceop=ncclRedOp_t.ncclSum)
  55. return z_loc
  56. class DistGCN_15dOp(Op):
  57. def __init__(self, node_A, node_B, node_C, node_Count_Self, node_Count_All, size, replication, device_id, comm, comm_groups=[None, None], need_W=True):
  58. super().__init__(DistGCN_15dOp, [
  59. node_A, node_B, node_C], ctx=ndarray.gpu(device_id))
  60. self.need_W = need_W
  61. self.node_Count_Self = node_Count_Self
  62. self.node_Count_All = node_Count_All
  63. self.replication = replication
  64. self.size = size
  65. self.comm = comm
  66. self.comm_groups = comm_groups
  67. self.device_id = device_id
  68. def compute(self, input_vals, output_val, stream_handle=None):
  69. adj_matrix = input_vals[0]
  70. inputs_H = input_vals[1]
  71. weight = input_vals[2]
  72. node_count = self.node_Count_All
  73. comm = self.comm
  74. rank = comm.localRank.value
  75. ctx = ndarray.gpu(self.device_id)
  76. if weight.shape[1] < inputs_H.shape[1]:
  77. HW = ndarray.empty((inputs_H.shape[0], weight.shape[1]), ctx=ctx)
  78. if (self.need_W == True):
  79. from ..gpu_links import matrix_multiply
  80. matrix_multiply(inputs_H, False, weight,
  81. False, HW, stream_handle)
  82. else:
  83. HW = inputs_H
  84. z = broad_func(node_count, adj_matrix, HW, rank, self.size, self.replication,
  85. row_groups=self.comm_groups[0], col_groups=self.comm_groups[1], ctx=ctx, comm=comm, stream_handle=stream_handle)
  86. z.copyto(output_val)
  87. else:
  88. AH = broad_func(node_count, adj_matrix, inputs_H, rank, self.size, self.replication,
  89. row_groups=self.comm_groups[0], col_groups=self.comm_groups[1], ctx=ctx, comm=comm, stream_handle=stream_handle)
  90. z = ndarray.empty((AH.shape[0], weight.shape[1]), ctx=ctx)
  91. if (self.need_W == True):
  92. from ..gpu_links import matrix_multiply
  93. matrix_multiply(AH, False, weight, False, z, stream_handle)
  94. else:
  95. z = AH
  96. z.copyto(output_val)
  97. def gradient(self, output_grad):
  98. adj_matrix = self.inputs[0]
  99. inputs_H = self.inputs[1]
  100. weight = self.inputs[2]
  101. node_Count_Self = self.node_Count_Self
  102. node_Count_All = self.node_Count_All
  103. comm = self.comm
  104. rank = comm.localRank.value
  105. ag = distgcn_15d_op(adj_matrix, output_grad, weight, node_Count_Self, node_Count_All,
  106. self.size, self.replication, self.device_id, comm, self.comm_groups, need_W=False)
  107. from . import matmul_op
  108. grad_A = None
  109. grad_H = matmul_op(ag, weight, trans_B=True)
  110. grad_weight = matmul_op(inputs_H, ag, trans_A=True)
  111. from . import groupallreduceCommunicate_op
  112. if self.replication > 1:
  113. weight_groups = self.comm_groups[1]
  114. if len(self.comm_groups) == 3:
  115. weight_groups = self.comm_groups[2]
  116. grad_W = groupallreduceCommunicate_op(
  117. grad_weight, weight_groups[rank % self.replication])
  118. else:
  119. grad_W = groupallreduceCommunicate_op(grad_weight, comm)
  120. return [grad_A, grad_H, grad_W]
  121. def infer_shape(self, input_shapes):
  122. assert len(input_shapes) == 3
  123. H = input_shapes[1]
  124. W = input_shapes[2]
  125. shape_H = H[1]
  126. shape_W = W[1]
  127. if (self.need_W == True):
  128. return (self.node_Count_Self, shape_W)
  129. else:
  130. return (self.node_Count_Self, shape_H)
  131. def distgcn_15d_op(node_A, node_B, node_C, node_Count_Self, node_Count_All, size, replication, device_id, comm, comm_groups=[None, None], need_W=True):
  132. return DistGCN_15dOp(node_A, node_B, node_C, node_Count_Self, node_Count_All, size, replication, device_id, comm, comm_groups, need_W=need_W)