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.

Broadcast.py 3.2 kB

5 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. from __future__ import absolute_import
  2. import numpy as np
  3. from .Node import Op
  4. from .ReduceSum import reduce_sum_op
  5. from ..gpu_links import broadcast_shape_simple
  6. from .. import ndarray
  7. class BroadcastToOp(Op):
  8. def __init__(self, node_A, node_B, ctx=None):
  9. super().__init__(BroadcastToOp, [node_A, node_B], ctx)
  10. def compute(self, input_vals, output_val, stream_handle=None):
  11. if self.on_cpu:
  12. input_shape = list(input_vals[1].shape)
  13. output_val[:] = np.broadcast_to(
  14. input_vals[0].asnumpy(), input_shape)
  15. else:
  16. if self.inplace:
  17. input_vals[0].broadcast_to(input_vals[1].shape, output_val)
  18. else:
  19. # broadcast_shape(input_vals[0], output_val, None, stream_handle)
  20. broadcast_shape_simple(
  21. input_vals[0], output_val, self.out_strides, self.in_dims, stream_handle)
  22. def gradient(self, output_grad):
  23. self.grad_node = reduce_sum_op(
  24. output_grad, None, None, ctx=self.raw_ctx)
  25. return [self.grad_node, None]
  26. def infer_shape(self, input_shapes):
  27. assert len(input_shapes) == 2
  28. input_shape = list(input_shapes[0])
  29. output_shape = list(input_shapes[1])
  30. output_ndim = len(output_shape)
  31. assert len(input_shape) <= output_ndim
  32. diff = output_ndim - len(input_shape)
  33. axes = list(range(diff))
  34. keepdims = [False] * diff
  35. input_shape = [1] * diff + input_shape
  36. for i in range(output_ndim):
  37. assert output_shape[i] > 0 and isinstance(output_shape[i], int)
  38. assert input_shape[i] == 1 or input_shape[i] == output_shape[i]
  39. if i >= diff and input_shape[i] == 1 and output_shape[i] > 1:
  40. axes.append(i)
  41. keepdims.append(True)
  42. if hasattr(self, 'grad_node'):
  43. self.grad_node.axes = axes
  44. self.grad_node.keepdims = keepdims
  45. # here we save the output strides and input dimensions for GPU computation
  46. if self.on_gpu and not self.inplace:
  47. input_shape = list(input_shapes[0])
  48. out_strides = [0 for _ in range(output_ndim)]
  49. temp_size = 1
  50. for i in range(output_ndim - 1, -1, -1):
  51. out_strides[i] = temp_size
  52. temp_size *= output_shape[i]
  53. in_dims = [1 for _ in range(diff)] + input_shape
  54. self.out_strides = ndarray.array(
  55. out_strides, self.ctx, data_type=np.int32)
  56. self.in_dims = ndarray.array(in_dims, self.ctx, data_type=np.int32)
  57. return input_shapes[1]
  58. def backward_hook(self, config):
  59. self.inplace = config.enable_lazy and self not in config.eval_node_list
  60. def broadcastto_op(node_A, node_B, ctx=None):
  61. """Creates a node that represents np.broadcast_to(node_A, node_B.shape).
  62. Parameters:
  63. ----
  64. node_a : Node
  65. The Node to be broadcast.
  66. node_b : Node
  67. Another Node with the target shape.
  68. Returns:
  69. ----
  70. A new Node instance created by Op.
  71. """
  72. return BroadcastToOp(node_A, node_B, ctx=ctx)