Gradients for the dense tensor in the SparseTensorDenseMatMul op. If either input is complex, no gradient is provided. Args: op: the SparseTensorDenseMatMul op grad: the incoming gradient Returns: Gradient for each of the 4 input tensors: (sparse_indices, sparse_values, sp
(op, grad)
| 147 | |
| 148 | @ops.RegisterGradient("SparseTensorDenseMatMul") |
| 149 | def _SparseTensorDenseMatMulGrad(op, grad): |
| 150 | """Gradients for the dense tensor in the SparseTensorDenseMatMul op. |
| 151 | |
| 152 | If either input is complex, no gradient is provided. |
| 153 | |
| 154 | Args: |
| 155 | op: the SparseTensorDenseMatMul op |
| 156 | grad: the incoming gradient |
| 157 | |
| 158 | Returns: |
| 159 | Gradient for each of the 4 input tensors: |
| 160 | (sparse_indices, sparse_values, sparse_shape, dense_tensor) |
| 161 | The gradients for indices and shape are None. |
| 162 | |
| 163 | Raises: |
| 164 | TypeError: When the two operands don't have the same type. |
| 165 | """ |
| 166 | a_indices, a_values, a_shape = op.inputs[:3] |
| 167 | b = op.inputs[3] |
| 168 | adj_a = op.get_attr("adjoint_a") |
| 169 | adj_b = op.get_attr("adjoint_b") |
| 170 | |
| 171 | a_type = a_values.dtype.base_dtype |
| 172 | b_type = b.dtype.base_dtype |
| 173 | if a_type != b_type: |
| 174 | raise TypeError("SparseTensorDenseMatMul op received operands with " |
| 175 | "different types: ", a_type, " and ", b_type) |
| 176 | if a_type in (ops.dtypes.complex64, ops.dtypes.complex128): |
| 177 | raise NotImplementedError("SparseTensorDenseMatMul op does not support " |
| 178 | "complex gradients.") |
| 179 | |
| 180 | # gradient w.r.t. dense |
| 181 | b_grad = gen_sparse_ops.sparse_tensor_dense_mat_mul( |
| 182 | a_indices, a_values, a_shape, grad, adjoint_a=not adj_a) |
| 183 | if adj_b: |
| 184 | b_grad = array_ops.transpose(b_grad) |
| 185 | |
| 186 | # gradient w.r.t. sparse values |
| 187 | rows = a_indices[:, 0] |
| 188 | cols = a_indices[:, 1] |
| 189 | |
| 190 | # TODO(zongheng, ebrevdo): add conjugates in the right places when complex |
| 191 | # values are allowed. |
| 192 | # TODO(zongheng): these gather calls could potentially duplicate rows/cols in |
| 193 | # memory. If there is a need, we should look into implementing this more |
| 194 | # intelligently to avoid duplicating data. |
| 195 | parts_a = array_ops.gather(grad, rows if not adj_a else cols) |
| 196 | parts_b = array_ops.gather(b if not adj_b else array_ops.transpose(b), |
| 197 | cols if not adj_a else rows) |
| 198 | a_values_grad = math_ops.reduce_sum(parts_a * parts_b, axis=1) |
| 199 | |
| 200 | # gradients w.r.t. (a_indices, a_values, a_shape, b) |
| 201 | return (None, a_values_grad, None, b_grad) |
| 202 | |
| 203 | |
| 204 | @ops.RegisterGradient("SparseDenseCwiseAdd") |
nothing calls this directly
no test coverage detected