Gradient for concat op. Args: op: An operation. grad: `Tensor` or `IndexedSlices` representing the gradients with respect to each output of the op. start_value_index: An integer index of the first value in the op.inputs. end_value_index: An integer index of the last value in
(op, grad, start_value_index, end_value_index, dim_index)
| 50 | |
| 51 | |
| 52 | def _ConcatGradHelper(op, grad, start_value_index, end_value_index, dim_index): |
| 53 | """Gradient for concat op. |
| 54 | |
| 55 | Args: |
| 56 | op: An operation. |
| 57 | grad: `Tensor` or `IndexedSlices` representing the gradients with respect |
| 58 | to each output of the op. |
| 59 | start_value_index: An integer index of the first value in the op.inputs. |
| 60 | end_value_index: An integer index of the last value in the op.inputs. |
| 61 | dim_index: An interger index of concat_dim or axis parameter in op.inputs. |
| 62 | |
| 63 | Returns: |
| 64 | Tensors representing the partial gradients with respect to each input |
| 65 | of the op. |
| 66 | |
| 67 | Raises: |
| 68 | ValueError: if concat_dim/axis is not statically known. |
| 69 | """ |
| 70 | |
| 71 | def _CreateDenseMaskAndBegin(sizes, concat_dim): |
| 72 | """Create variables for iteratively slicing a dense gradients tensor.""" |
| 73 | # Since shape is 1-D, shape_of_shape = [rank-of-inputs] |
| 74 | shape_of_shape = array_ops.shape(sizes[0]) |
| 75 | # Make a vector of length equal to the input's dimensions, |
| 76 | # with 0's everywhere and 1 in the concat dim position. |
| 77 | # Note: Can't use sparse_to_dense since it isn't GPU-capable (for now) |
| 78 | mask = array_ops.concat([ |
| 79 | array_ops.fill(array_ops.expand_dims(concat_dim, 0), 0), [1], |
| 80 | array_ops.fill(shape_of_shape - concat_dim - 1, 0) |
| 81 | ], 0) |
| 82 | begin = array_ops.fill(shape_of_shape, 0) |
| 83 | return mask, begin |
| 84 | |
| 85 | def _ExtractInputShapes(inputs): |
| 86 | """Extract the shapes of a set of input tensors.""" |
| 87 | if context.executing_eagerly(): |
| 88 | return array_ops.shape_n(inputs) |
| 89 | sizes = [] |
| 90 | fully_known = True |
| 91 | for x in inputs: |
| 92 | input_shape = array_ops.shape(x) |
| 93 | if not isinstance(input_shape, |
| 94 | ops.Tensor) or input_shape.op.type != "Const": |
| 95 | fully_known = False |
| 96 | break |
| 97 | sizes.append(input_shape) |
| 98 | |
| 99 | if fully_known: |
| 100 | return sizes |
| 101 | else: |
| 102 | return array_ops.shape_n(inputs) |
| 103 | |
| 104 | # Degenerate concatenation, just return grad. |
| 105 | if len(op.inputs) == 2: |
| 106 | return grad + [None] if end_value_index <= dim_index else [None] + grad |
| 107 | |
| 108 | concat_dim = op.inputs[dim_index] |
| 109 | input_values = op.inputs[start_value_index:end_value_index] |
no test coverage detected