| 1123 | } |
| 1124 | |
| 1125 | tensorflow::Status CallBackwardFunction( |
| 1126 | PyBackwardFunction* backward_function, |
| 1127 | const std::vector<tensorflow::int64>& unneeded_gradients, |
| 1128 | tensorflow::gtl::ArraySlice<PyObject*> output_gradients, |
| 1129 | std::vector<PyObject*>* result) const final { |
| 1130 | PyObject* grads = PyTuple_New(output_gradients.size()); |
| 1131 | for (size_t i = 0; i < output_gradients.size(); ++i) { |
| 1132 | if (output_gradients[i] == nullptr) { |
| 1133 | Py_INCREF(Py_None); |
| 1134 | PyTuple_SET_ITEM(grads, i, Py_None); |
| 1135 | } else { |
| 1136 | PyTuple_SET_ITEM(grads, i, |
| 1137 | reinterpret_cast<PyObject*>(output_gradients[i])); |
| 1138 | } |
| 1139 | } |
| 1140 | PyObject* py_result = (*backward_function)(grads, unneeded_gradients); |
| 1141 | Py_DECREF(grads); |
| 1142 | if (py_result == nullptr) { |
| 1143 | return tensorflow::errors::Internal("gradient function threw exceptions"); |
| 1144 | } |
| 1145 | result->clear(); |
| 1146 | PyObject* seq = |
| 1147 | PySequence_Fast(py_result, "expected a sequence of gradients"); |
| 1148 | if (seq == nullptr) { |
| 1149 | return tensorflow::errors::InvalidArgument( |
| 1150 | "gradient function did not return a list"); |
| 1151 | } |
| 1152 | int len = PySequence_Fast_GET_SIZE(seq); |
| 1153 | VLOG(1) << "Gradient length is " << len; |
| 1154 | result->reserve(len); |
| 1155 | for (int i = 0; i < len; ++i) { |
| 1156 | PyObject* item = PySequence_Fast_GET_ITEM(seq, i); |
| 1157 | if (item == Py_None) { |
| 1158 | result->push_back(nullptr); |
| 1159 | } else { |
| 1160 | Py_INCREF(item); |
| 1161 | result->push_back(item); |
| 1162 | } |
| 1163 | } |
| 1164 | Py_DECREF(seq); |
| 1165 | Py_DECREF(py_result); |
| 1166 | return tensorflow::Status::OK(); |
| 1167 | } |
| 1168 | |
| 1169 | void DeleteGradient(PyObject* tensor) const final { Py_XDECREF(tensor); } |
| 1170 | |