| 1846 | } |
| 1847 | |
| 1848 | void TapeSetRecordOperation( |
| 1849 | PyObject* op_type, PyObject* input_tensors, PyObject* output_tensors, |
| 1850 | const std::vector<tensorflow::int64>& input_ids, |
| 1851 | const std::vector<tensorflow::DataType>& input_dtypes, |
| 1852 | const std::function<PyBackwardFunction*()>& backward_function_getter, |
| 1853 | const std::function<void(PyBackwardFunction*)>& backward_function_killer, |
| 1854 | const tensorflow::eager::ForwardFunction<PyObject>* forward_function) { |
| 1855 | std::vector<PyTapeTensor> output_info; |
| 1856 | tensorflow::Safe_PyObjectPtr output_seq(PySequence_Fast( |
| 1857 | output_tensors, "expected a sequence of integer tensor ids")); |
| 1858 | int output_len = PySequence_Size(output_tensors); |
| 1859 | if (PyErr_Occurred()) return; |
| 1860 | output_info.reserve(output_len); |
| 1861 | for (int i = 0; i < output_len; ++i) { |
| 1862 | output_info.push_back( |
| 1863 | TapeTensorFromTensor(PySequence_Fast_GET_ITEM(output_seq.get(), i))); |
| 1864 | if (PyErr_Occurred() != nullptr) { |
| 1865 | return; |
| 1866 | } |
| 1867 | } |
| 1868 | string op_type_str; |
| 1869 | if (PyBytes_Check(op_type)) { |
| 1870 | op_type_str = PyBytes_AsString(op_type); |
| 1871 | } else if (PyUnicode_Check(op_type)) { |
| 1872 | #if PY_MAJOR_VERSION >= 3 |
| 1873 | op_type_str = PyUnicode_AsUTF8(op_type); |
| 1874 | #else |
| 1875 | PyObject* py_str = PyUnicode_AsUTF8String(op_type); |
| 1876 | if (py_str == nullptr) return; |
| 1877 | op_type_str = PyBytes_AS_STRING(py_str); |
| 1878 | Py_DECREF(py_str); |
| 1879 | #endif |
| 1880 | } else { |
| 1881 | PyErr_SetString(PyExc_RuntimeError, "op_type should be a string."); |
| 1882 | return; |
| 1883 | } |
| 1884 | |
| 1885 | for (TFE_Py_Tape* tape : SafeTapeSet()) { |
| 1886 | tape->tape->RecordOperation(op_type_str, output_info, input_ids, |
| 1887 | input_dtypes, backward_function_getter, |
| 1888 | backward_function_killer); |
| 1889 | } |
| 1890 | |
| 1891 | auto accumulator_set = SafeAccumulatorSet(); |
| 1892 | if (!accumulator_set.empty()) { |
| 1893 | std::vector<PyTapeTensor> input_info; |
| 1894 | tensorflow::Safe_PyObjectPtr input_seq( |
| 1895 | PySequence_Fast(input_tensors, "expected a sequence of tensors")); |
| 1896 | if (input_seq == nullptr || PyErr_Occurred()) return; |
| 1897 | int input_len = PySequence_Size(input_tensors); |
| 1898 | input_info.reserve(input_len); |
| 1899 | for (int i = 0; i < input_len; ++i) { |
| 1900 | input_info.push_back( |
| 1901 | TapeTensorFromTensor(PySequence_Fast_GET_ITEM(input_seq.get(), i))); |
| 1902 | } |
| 1903 | for (int i = 0; i < output_len; ++i) { |
| 1904 | RegisterForwardAccumulatorCleanup( |
| 1905 | PySequence_Fast_GET_ITEM(output_seq.get(), i), |
no test coverage detected