File: | .cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow/tensorflow/python/lib/core/ndarray_tensor.cc |
Warning: | line 352, column 5 Calling function '_Py_DECREF' with a PyObject argument whose ownership has been released (with stolen reference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. | |||
2 | ||||
3 | Licensed under the Apache License, Version 2.0 (the "License"); | |||
4 | you may not use this file except in compliance with the License. | |||
5 | You may obtain a copy of the License at | |||
6 | ||||
7 | http://www.apache.org/licenses/LICENSE-2.0 | |||
8 | ||||
9 | Unless required by applicable law or agreed to in writing, software | |||
10 | distributed under the License is distributed on an "AS IS" BASIS, | |||
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
12 | See the License for the specific language governing permissions and | |||
13 | limitations under the License. | |||
14 | ==============================================================================*/ | |||
15 | ||||
16 | #include "tensorflow/python/lib/core/ndarray_tensor.h" | |||
17 | ||||
18 | #include <cstring> | |||
19 | #include <optional> | |||
20 | ||||
21 | #include "tensorflow/c/eager/tfe_context_internal.h" | |||
22 | #include "tensorflow/c/tf_tensor_internal.h" | |||
23 | #include "tensorflow/core/lib/core/coding.h" | |||
24 | #include "tensorflow/core/lib/core/errors.h" | |||
25 | #include "tensorflow/core/lib/gtl/inlined_vector.h" | |||
26 | #include "tensorflow/core/platform/types.h" | |||
27 | #include "tensorflow/python/lib/core/bfloat16.h" | |||
28 | #include "tensorflow/python/lib/core/ndarray_tensor_bridge.h" | |||
29 | #include "tensorflow/python/lib/core/numpy.h" | |||
30 | ||||
31 | namespace tensorflow { | |||
32 | namespace { | |||
33 | ||||
34 | char const* numpy_type_name(int numpy_type) { | |||
35 | switch (numpy_type) { | |||
36 | #define TYPE_CASE(s)case s: return "s" \ | |||
37 | case s: \ | |||
38 | return #s | |||
39 | ||||
40 | TYPE_CASE(NPY_BOOL)case NPY_BOOL: return "NPY_BOOL"; | |||
41 | TYPE_CASE(NPY_BYTE)case NPY_BYTE: return "NPY_BYTE"; | |||
42 | TYPE_CASE(NPY_UBYTE)case NPY_UBYTE: return "NPY_UBYTE"; | |||
43 | TYPE_CASE(NPY_SHORT)case NPY_SHORT: return "NPY_SHORT"; | |||
44 | TYPE_CASE(NPY_USHORT)case NPY_USHORT: return "NPY_USHORT"; | |||
45 | TYPE_CASE(NPY_INT)case NPY_INT: return "NPY_INT"; | |||
46 | TYPE_CASE(NPY_UINT)case NPY_UINT: return "NPY_UINT"; | |||
47 | TYPE_CASE(NPY_LONG)case NPY_LONG: return "NPY_LONG"; | |||
48 | TYPE_CASE(NPY_ULONG)case NPY_ULONG: return "NPY_ULONG"; | |||
49 | TYPE_CASE(NPY_LONGLONG)case NPY_LONGLONG: return "NPY_LONGLONG"; | |||
50 | TYPE_CASE(NPY_ULONGLONG)case NPY_ULONGLONG: return "NPY_ULONGLONG"; | |||
51 | TYPE_CASE(NPY_FLOAT)case NPY_FLOAT: return "NPY_FLOAT"; | |||
52 | TYPE_CASE(NPY_DOUBLE)case NPY_DOUBLE: return "NPY_DOUBLE"; | |||
53 | TYPE_CASE(NPY_LONGDOUBLE)case NPY_LONGDOUBLE: return "NPY_LONGDOUBLE"; | |||
54 | TYPE_CASE(NPY_CFLOAT)case NPY_CFLOAT: return "NPY_CFLOAT"; | |||
55 | TYPE_CASE(NPY_CDOUBLE)case NPY_CDOUBLE: return "NPY_CDOUBLE"; | |||
56 | TYPE_CASE(NPY_CLONGDOUBLE)case NPY_CLONGDOUBLE: return "NPY_CLONGDOUBLE"; | |||
57 | TYPE_CASE(NPY_OBJECT)case NPY_OBJECT: return "NPY_OBJECT"; | |||
58 | TYPE_CASE(NPY_STRING)case NPY_STRING: return "NPY_STRING"; | |||
59 | TYPE_CASE(NPY_UNICODE)case NPY_UNICODE: return "NPY_UNICODE"; | |||
60 | TYPE_CASE(NPY_VOID)case NPY_VOID: return "NPY_VOID"; | |||
61 | TYPE_CASE(NPY_DATETIME)case NPY_DATETIME: return "NPY_DATETIME"; | |||
62 | TYPE_CASE(NPY_TIMEDELTA)case NPY_TIMEDELTA: return "NPY_TIMEDELTA"; | |||
63 | TYPE_CASE(NPY_HALF)case NPY_HALF: return "NPY_HALF"; | |||
64 | TYPE_CASE(NPY_NTYPES)case NPY_NTYPES: return "NPY_NTYPES"; | |||
65 | TYPE_CASE(NPY_NOTYPE)case NPY_NOTYPE: return "NPY_NOTYPE"; | |||
66 | TYPE_CASE(NPY_CHAR)case NPY_CHAR: return "NPY_CHAR"; | |||
67 | TYPE_CASE(NPY_USERDEF)case NPY_USERDEF: return "NPY_USERDEF"; | |||
68 | default: | |||
69 | return "not a numpy type"; | |||
70 | } | |||
71 | } | |||
72 | ||||
73 | Status PyArrayDescr_to_TF_DataType(PyArray_Descr* descr, | |||
74 | TF_DataType* out_tf_datatype) { | |||
75 | PyObject* key; | |||
76 | PyObject* value; | |||
77 | Py_ssize_t pos = 0; | |||
78 | ||||
79 | // Return an error if the fields attribute is null. | |||
80 | // Occurs with an improper conversion attempt to resource. | |||
81 | if (descr->fields == nullptr) { | |||
82 | return errors::Internal("Unexpected numpy data type"); | |||
83 | } | |||
84 | ||||
85 | if (PyDict_Next(descr->fields, &pos, &key, &value)) { | |||
86 | // In Python 3, the keys of numpy custom struct types are unicode, unlike | |||
87 | // Python 2, where the keys are bytes. | |||
88 | const char* key_string = | |||
89 | PyBytes_Check(key)((((((PyObject*)(key))->ob_type))->tp_flags & ((1UL << 27))) != 0) ? PyBytes_AsString(key) | |||
90 | : PyBytes_AsString(PyUnicode_AsASCIIString(key)); | |||
91 | if (!key_string) { | |||
92 | return errors::Internal("Corrupt numpy type descriptor"); | |||
93 | } | |||
94 | tensorflow::string key = key_string; | |||
95 | // The typenames here should match the field names in the custom struct | |||
96 | // types constructed in test_util.py. | |||
97 | // TODO(mrry,keveman): Investigate Numpy type registration to replace this | |||
98 | // hard-coding of names. | |||
99 | if (key == "quint8") { | |||
100 | *out_tf_datatype = TF_QUINT8; | |||
101 | } else if (key == "qint8") { | |||
102 | *out_tf_datatype = TF_QINT8; | |||
103 | } else if (key == "qint16") { | |||
104 | *out_tf_datatype = TF_QINT16; | |||
105 | } else if (key == "quint16") { | |||
106 | *out_tf_datatype = TF_QUINT16; | |||
107 | } else if (key == "qint32") { | |||
108 | *out_tf_datatype = TF_QINT32; | |||
109 | } else if (key == "resource") { | |||
110 | *out_tf_datatype = TF_RESOURCE; | |||
111 | } else { | |||
112 | return errors::Internal("Unsupported numpy data type"); | |||
113 | } | |||
114 | return Status::OK(); | |||
115 | } | |||
116 | return errors::Internal("Unsupported numpy data type"); | |||
117 | } | |||
118 | ||||
119 | Status PyArray_TYPE_to_TF_DataType(PyArrayObject* array, | |||
120 | TF_DataType* out_tf_datatype) { | |||
121 | int pyarray_type = PyArray_TYPE(array); | |||
122 | PyArray_Descr* descr = PyArray_DESCR(array); | |||
123 | switch (pyarray_type) { | |||
124 | case NPY_FLOAT16NPY_HALF: | |||
125 | *out_tf_datatype = TF_HALF; | |||
126 | break; | |||
127 | case NPY_FLOAT32NPY_FLOAT: | |||
128 | *out_tf_datatype = TF_FLOAT; | |||
129 | break; | |||
130 | case NPY_FLOAT64NPY_DOUBLE: | |||
131 | *out_tf_datatype = TF_DOUBLE; | |||
132 | break; | |||
133 | case NPY_INT32NPY_INT: | |||
134 | *out_tf_datatype = TF_INT32; | |||
135 | break; | |||
136 | case NPY_UINT8NPY_UBYTE: | |||
137 | *out_tf_datatype = TF_UINT8; | |||
138 | break; | |||
139 | case NPY_UINT16NPY_USHORT: | |||
140 | *out_tf_datatype = TF_UINT16; | |||
141 | break; | |||
142 | case NPY_UINT32NPY_UINT: | |||
143 | *out_tf_datatype = TF_UINT32; | |||
144 | break; | |||
145 | case NPY_UINT64NPY_ULONG: | |||
146 | *out_tf_datatype = TF_UINT64; | |||
147 | break; | |||
148 | case NPY_INT8NPY_BYTE: | |||
149 | *out_tf_datatype = TF_INT8; | |||
150 | break; | |||
151 | case NPY_INT16NPY_SHORT: | |||
152 | *out_tf_datatype = TF_INT16; | |||
153 | break; | |||
154 | case NPY_INT64NPY_LONG: | |||
155 | *out_tf_datatype = TF_INT64; | |||
156 | break; | |||
157 | case NPY_BOOL: | |||
158 | *out_tf_datatype = TF_BOOL; | |||
159 | break; | |||
160 | case NPY_COMPLEX64NPY_CFLOAT: | |||
161 | *out_tf_datatype = TF_COMPLEX64; | |||
162 | break; | |||
163 | case NPY_COMPLEX128NPY_CDOUBLE: | |||
164 | *out_tf_datatype = TF_COMPLEX128; | |||
165 | break; | |||
166 | case NPY_OBJECT: | |||
167 | case NPY_STRING: | |||
168 | case NPY_UNICODE: | |||
169 | *out_tf_datatype = TF_STRING; | |||
170 | break; | |||
171 | case NPY_VOID: | |||
172 | // Quantized types are currently represented as custom struct types. | |||
173 | // PyArray_TYPE returns NPY_VOID for structs, and we should look into | |||
174 | // descr to derive the actual type. | |||
175 | // Direct feeds of certain types of ResourceHandles are represented as a | |||
176 | // custom struct type. | |||
177 | return PyArrayDescr_to_TF_DataType(descr, out_tf_datatype); | |||
178 | default: | |||
179 | if (pyarray_type == Bfloat16NumpyType()) { | |||
180 | *out_tf_datatype = TF_BFLOAT16; | |||
181 | break; | |||
182 | } else if (pyarray_type == NPY_ULONGLONG) { | |||
183 | // NPY_ULONGLONG is equivalent to NPY_UINT64, while their enum values | |||
184 | // might be different on certain platforms. | |||
185 | *out_tf_datatype = TF_UINT64; | |||
186 | break; | |||
187 | } else if (pyarray_type == NPY_LONGLONG) { | |||
188 | // NPY_LONGLONG is equivalent to NPY_INT64, while their enum values | |||
189 | // might be different on certain platforms. | |||
190 | *out_tf_datatype = TF_INT64; | |||
191 | break; | |||
192 | } else if (pyarray_type == NPY_INT) { | |||
193 | // NPY_INT is equivalent to NPY_INT32, while their enum values might be | |||
194 | // different on certain platforms. | |||
195 | *out_tf_datatype = TF_INT32; | |||
196 | break; | |||
197 | } else if (pyarray_type == NPY_UINT) { | |||
198 | // NPY_UINT is equivalent to NPY_UINT32, while their enum values might | |||
199 | // be different on certain platforms. | |||
200 | *out_tf_datatype = TF_UINT32; | |||
201 | break; | |||
202 | } | |||
203 | return errors::Internal("Unsupported numpy type: ", | |||
204 | numpy_type_name(pyarray_type)); | |||
205 | } | |||
206 | return Status::OK(); | |||
207 | } | |||
208 | ||||
209 | Status PyObjectToString(PyObject* obj, const char** ptr, Py_ssize_t* len, | |||
210 | PyObject** ptr_owner) { | |||
211 | *ptr_owner = nullptr; | |||
212 | if (PyBytes_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 27))) != 0)) { | |||
213 | char* buf; | |||
214 | if (PyBytes_AsStringAndSize(obj, &buf, len) != 0) { | |||
215 | return errors::Internal("Unable to get element as bytes."); | |||
216 | } | |||
217 | *ptr = buf; | |||
218 | return Status::OK(); | |||
219 | } else if (PyUnicode_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 28))) != 0)) { | |||
220 | #if (PY_MAJOR_VERSION3 > 3 || (PY_MAJOR_VERSION3 == 3 && PY_MINOR_VERSION8 >= 3)) | |||
221 | *ptr = PyUnicode_AsUTF8AndSize(obj, len); | |||
222 | if (*ptr != nullptr) return Status::OK(); | |||
223 | #else | |||
224 | PyObject* utemp = PyUnicode_AsUTF8String(obj); | |||
225 | char* buf; | |||
226 | if (utemp != nullptr && PyBytes_AsStringAndSize(utemp, &buf, len) != -1) { | |||
227 | *ptr = buf; | |||
228 | *ptr_owner = utemp; | |||
229 | return Status::OK(); | |||
230 | } | |||
231 | Py_XDECREF(utemp)_Py_XDECREF(((PyObject*)(utemp))); | |||
232 | #endif | |||
233 | return errors::Internal("Unable to convert element to UTF-8"); | |||
234 | } else { | |||
235 | return errors::Internal("Unsupported object type ", obj->ob_type->tp_name); | |||
236 | } | |||
237 | } | |||
238 | ||||
239 | // Iterate over the string array 'array', extract the ptr and len of each string | |||
240 | // element and call f(ptr, len). | |||
241 | template <typename F> | |||
242 | Status PyBytesArrayMap(PyArrayObject* array, F f) { | |||
243 | Safe_PyObjectPtr iter = tensorflow::make_safe( | |||
244 | PyArray_IterNew(*(PyObject * (*)(PyObject *)) _tensorflow_numpy_api[98])(reinterpret_cast<PyObject*>(array))); | |||
245 | while (PyArray_ITER_NOTDONE(iter.get())(((PyArrayIterObject *)(iter.get()))->index < ((PyArrayIterObject *)(iter.get()))->size)) { | |||
246 | auto item = tensorflow::make_safe(PyArray_GETITEM( | |||
247 | array, static_cast<char*>(PyArray_ITER_DATA(iter.get())((void *)(((PyArrayIterObject *)(iter.get()))->dataptr))))); | |||
248 | if (!item) { | |||
249 | return errors::Internal("Unable to get element from the feed - no item."); | |||
250 | } | |||
251 | Py_ssize_t len; | |||
252 | const char* ptr; | |||
253 | PyObject* ptr_owner = nullptr; | |||
254 | TF_RETURN_IF_ERROR(PyObjectToString(item.get(), &ptr, &len, &ptr_owner))do { ::tensorflow::Status _status = (PyObjectToString(item.get (), &ptr, &len, &ptr_owner)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0); | |||
255 | f(ptr, len); | |||
256 | Py_XDECREF(ptr_owner)_Py_XDECREF(((PyObject*)(ptr_owner))); | |||
257 | PyArray_ITER_NEXT(iter.get())do { ((PyArrayIterObject *)(iter.get()))->index++; if (((PyArrayIterObject *)(iter.get()))->nd_m1 == 0) { do { (((PyArrayIterObject * )(iter.get())))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iter.get()))))->strides[0]; (((PyArrayIterObject *)(iter .get())))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iter.get()))->contiguous) ((PyArrayIterObject *)(iter. get()))->dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter .get()))->ao)->elsize; else if (((PyArrayIterObject *)( iter.get()))->nd_m1 == 1) { do { if ((((PyArrayIterObject * )(iter.get())))->coordinates[1] < (((PyArrayIterObject * )(iter.get())))->dims_m1[1]) { (((PyArrayIterObject *)(iter .get())))->coordinates[1]++; (((PyArrayIterObject *)(iter. get())))->dataptr += (((PyArrayIterObject *)(iter.get()))) ->strides[1]; } else { (((PyArrayIterObject *)(iter.get()) ))->coordinates[1] = 0; (((PyArrayIterObject *)(iter.get() )))->coordinates[0]++; (((PyArrayIterObject *)(iter.get()) ))->dataptr += (((PyArrayIterObject *)(iter.get())))->strides [0] - (((PyArrayIterObject *)(iter.get())))->backstrides[1 ]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iter.get()))->nd_m1; __npy_i >= 0; __npy_i--) { if ( ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] < ((PyArrayIterObject *)(iter.get()))->dims_m1[__npy_i]) { ( (PyArrayIterObject *)(iter.get()))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iter.get()))->dataptr += ((PyArrayIterObject *)(iter.get()))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iter.get()))->dataptr -= ((PyArrayIterObject *)(iter.get ()))->backstrides[__npy_i]; } } } } while (0); | |||
258 | } | |||
259 | return Status::OK(); | |||
260 | } | |||
261 | ||||
262 | // Encode the strings in 'array' into a contiguous buffer and return the base of | |||
263 | // the buffer. The caller takes ownership of the buffer. | |||
264 | Status EncodePyBytesArray(PyArrayObject* array, int64_t nelems, size_t* size, | |||
265 | void** buffer) { | |||
266 | // Encode all strings. | |||
267 | *size = nelems * sizeof(tensorflow::tstring); | |||
268 | std::unique_ptr<tensorflow::tstring[]> base_ptr( | |||
269 | new tensorflow::tstring[nelems]); | |||
270 | tensorflow::tstring* dst = base_ptr.get(); | |||
271 | ||||
272 | TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0) | |||
273 | PyBytesArrayMap(array, [&dst](const char* ptr, Py_ssize_t len) {do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0) | |||
274 | dst->assign(ptr, len);do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0) | |||
275 | dst++;do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0) | |||
276 | }))do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0); | |||
277 | *buffer = base_ptr.release(); | |||
278 | return Status::OK(); | |||
279 | } | |||
280 | ||||
281 | Status CopyTF_TensorStringsToPyArray(const TF_Tensor* src, uint64 nelems, | |||
282 | PyArrayObject* dst) { | |||
283 | const void* tensor_data = TF_TensorData(src); | |||
284 | DCHECK(tensor_data != nullptr)while (false && (tensor_data != nullptr)) ::tensorflow ::internal::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 284); | |||
285 | DCHECK_EQ(TF_STRING, TF_TensorType(src))while (false && ((void)(TF_STRING), (void)(TF_TensorType (src)), 0)) ::tensorflow::internal::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 285); | |||
286 | ||||
287 | const tstring* tstr = static_cast<const tstring*>(tensor_data); | |||
288 | ||||
289 | std::unique_ptr<TF_Status, decltype(&TF_DeleteStatus)> status( | |||
290 | TF_NewStatus(), TF_DeleteStatus); | |||
291 | auto iter = make_safe(PyArray_IterNew(*(PyObject * (*)(PyObject *)) _tensorflow_numpy_api[98])(reinterpret_cast<PyObject*>(dst))); | |||
292 | for (int64_t i = 0; i < static_cast<int64_t>(nelems); ++i) { | |||
293 | const tstring& tstr_i = tstr[i]; | |||
294 | auto py_string = | |||
295 | make_safe(PyBytes_FromStringAndSize(tstr_i.data(), tstr_i.size())); | |||
296 | if (py_string == nullptr) { | |||
297 | return errors::Internal( | |||
298 | "failed to create a python byte array when converting element #", i, | |||
299 | " of a TF_STRING tensor to a numpy ndarray"); | |||
300 | } | |||
301 | ||||
302 | if (PyArray_SETITEM(dst, static_cast<char*>(PyArray_ITER_DATA(iter.get())((void *)(((PyArrayIterObject *)(iter.get()))->dataptr))), | |||
303 | py_string.get()) != 0) { | |||
304 | return errors::Internal("Error settings element #", i, | |||
305 | " in the numpy ndarray"); | |||
306 | } | |||
307 | PyArray_ITER_NEXT(iter.get())do { ((PyArrayIterObject *)(iter.get()))->index++; if (((PyArrayIterObject *)(iter.get()))->nd_m1 == 0) { do { (((PyArrayIterObject * )(iter.get())))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iter.get()))))->strides[0]; (((PyArrayIterObject *)(iter .get())))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iter.get()))->contiguous) ((PyArrayIterObject *)(iter. get()))->dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter .get()))->ao)->elsize; else if (((PyArrayIterObject *)( iter.get()))->nd_m1 == 1) { do { if ((((PyArrayIterObject * )(iter.get())))->coordinates[1] < (((PyArrayIterObject * )(iter.get())))->dims_m1[1]) { (((PyArrayIterObject *)(iter .get())))->coordinates[1]++; (((PyArrayIterObject *)(iter. get())))->dataptr += (((PyArrayIterObject *)(iter.get()))) ->strides[1]; } else { (((PyArrayIterObject *)(iter.get()) ))->coordinates[1] = 0; (((PyArrayIterObject *)(iter.get() )))->coordinates[0]++; (((PyArrayIterObject *)(iter.get()) ))->dataptr += (((PyArrayIterObject *)(iter.get())))->strides [0] - (((PyArrayIterObject *)(iter.get())))->backstrides[1 ]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iter.get()))->nd_m1; __npy_i >= 0; __npy_i--) { if ( ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] < ((PyArrayIterObject *)(iter.get()))->dims_m1[__npy_i]) { ( (PyArrayIterObject *)(iter.get()))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iter.get()))->dataptr += ((PyArrayIterObject *)(iter.get()))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iter.get()))->dataptr -= ((PyArrayIterObject *)(iter.get ()))->backstrides[__npy_i]; } } } } while (0); | |||
308 | } | |||
309 | return Status::OK(); | |||
310 | } | |||
311 | ||||
312 | // Determine the dimensions of a numpy ndarray to be created to represent an | |||
313 | // output Tensor. | |||
314 | Status GetPyArrayDimensionsForTensor(const TF_Tensor* tensor, | |||
315 | gtl::InlinedVector<npy_intp, 4>* dims, | |||
316 | int64_t* nelems) { | |||
317 | dims->clear(); | |||
318 | const int ndims = TF_NumDims(tensor); | |||
319 | if (TF_TensorType(tensor) == TF_RESOURCE) { | |||
320 | if (ndims != 0) { | |||
321 | return errors::InvalidArgument( | |||
322 | "Fetching of non-scalar resource tensors is not supported."); | |||
323 | } | |||
324 | dims->push_back(TF_TensorByteSize(tensor)); | |||
325 | *nelems = dims->back(); | |||
326 | } else { | |||
327 | *nelems = 1; | |||
328 | for (int i = 0; i < ndims; ++i) { | |||
329 | dims->push_back(TF_Dim(tensor, i)); | |||
330 | *nelems *= dims->back(); | |||
331 | } | |||
332 | } | |||
333 | return Status::OK(); | |||
334 | } | |||
335 | ||||
336 | // Determine the type description (PyArray_Descr) of a numpy ndarray to be | |||
337 | // created to represent an output Tensor. | |||
338 | Status GetPyArrayDescrForTensor(const TF_Tensor* tensor, | |||
339 | PyArray_Descr** descr) { | |||
340 | if (TF_TensorType(tensor) == TF_RESOURCE) { | |||
341 | PyObject* field = PyTuple_New(3); | |||
342 | #if PY_MAJOR_VERSION3 < 3 | |||
343 | PyTuple_SetItem(field, 0, PyBytes_FromString("resource")); | |||
344 | #else | |||
345 | PyTuple_SetItem(field, 0, PyUnicode_FromString("resource")); | |||
346 | #endif | |||
347 | PyTuple_SetItem(field, 1, PyArray_TypeObjectFromType(*(PyObject * (*)(int)) _tensorflow_numpy_api[46])(NPY_UBYTE)); | |||
348 | PyTuple_SetItem(field, 2, PyLong_FromLong(1)); | |||
349 | PyObject* fields = PyList_New(1); | |||
350 | PyList_SetItem(fields, 0, field); | |||
351 | int convert_result = PyArray_DescrConverter(*(int (*)(PyObject *, PyArray_Descr **)) _tensorflow_numpy_api [174])(fields, descr); | |||
352 | Py_CLEAR(field)do { PyObject *_py_tmp = ((PyObject*)(field)); if (_py_tmp != __null) { (field) = __null; _Py_DECREF(((PyObject*)(_py_tmp) )); } } while (0); | |||
| ||||
353 | Py_CLEAR(fields)do { PyObject *_py_tmp = ((PyObject*)(fields)); if (_py_tmp != __null) { (fields) = __null; _Py_DECREF(((PyObject*)(_py_tmp ))); } } while (0); | |||
354 | if (convert_result != 1) { | |||
355 | return errors::Internal("Failed to create numpy array description for ", | |||
356 | "TF_RESOURCE-type tensor"); | |||
357 | } | |||
358 | } else { | |||
359 | int type_num = -1; | |||
360 | TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (TF_DataType_to_PyArray_TYPE (TF_TensorType(tensor), &type_num)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0) | |||
361 | TF_DataType_to_PyArray_TYPE(TF_TensorType(tensor), &type_num))do { ::tensorflow::Status _status = (TF_DataType_to_PyArray_TYPE (TF_TensorType(tensor), &type_num)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0); | |||
362 | *descr = PyArray_DescrFromType(*(PyArray_Descr * (*)(int)) _tensorflow_numpy_api[45])(type_num); | |||
363 | } | |||
364 | ||||
365 | return Status::OK(); | |||
366 | } | |||
367 | ||||
368 | inline void FastMemcpy(void* dst, const void* src, size_t size) { | |||
369 | // clang-format off | |||
370 | switch (size) { | |||
371 | // Most compilers will generate inline code for fixed sizes, | |||
372 | // which is significantly faster for small copies. | |||
373 | case 1: memcpy(dst, src, 1); break; | |||
374 | case 2: memcpy(dst, src, 2); break; | |||
375 | case 3: memcpy(dst, src, 3); break; | |||
376 | case 4: memcpy(dst, src, 4); break; | |||
377 | case 5: memcpy(dst, src, 5); break; | |||
378 | case 6: memcpy(dst, src, 6); break; | |||
379 | case 7: memcpy(dst, src, 7); break; | |||
380 | case 8: memcpy(dst, src, 8); break; | |||
381 | case 9: memcpy(dst, src, 9); break; | |||
382 | case 10: memcpy(dst, src, 10); break; | |||
383 | case 11: memcpy(dst, src, 11); break; | |||
384 | case 12: memcpy(dst, src, 12); break; | |||
385 | case 13: memcpy(dst, src, 13); break; | |||
386 | case 14: memcpy(dst, src, 14); break; | |||
387 | case 15: memcpy(dst, src, 15); break; | |||
388 | case 16: memcpy(dst, src, 16); break; | |||
389 | #if defined(PLATFORM_GOOGLE) || defined(PLATFORM_POSIX) && \ | |||
390 | !defined(IS_MOBILE_PLATFORM) | |||
391 | // On Linux, memmove appears to be faster than memcpy for | |||
392 | // large sizes, strangely enough. | |||
393 | default: memmove(dst, src, size); break; | |||
394 | #else | |||
395 | default: memcpy(dst, src, size); break; | |||
396 | #endif | |||
397 | } | |||
398 | // clang-format on | |||
399 | } | |||
400 | ||||
401 | } // namespace | |||
402 | ||||
403 | // TODO(slebedev): revise TF_TensorToPyArray usages and switch to the | |||
404 | // aliased version where appropriate. | |||
405 | Status TF_TensorToMaybeAliasedPyArray(Safe_TF_TensorPtr tensor, | |||
406 | PyObject** out_ndarray) { | |||
407 | auto dtype = TF_TensorType(tensor.get()); | |||
408 | if (dtype == TF_STRING || dtype == TF_RESOURCE) { | |||
409 | return TF_TensorToPyArray(std::move(tensor), out_ndarray); | |||
410 | } | |||
411 | ||||
412 | TF_Tensor* moved = tensor.release(); | |||
413 | int64_t nelems = -1; | |||
414 | gtl::InlinedVector<npy_intp, 4> dims; | |||
415 | TF_RETURN_IF_ERROR(GetPyArrayDimensionsForTensor(moved, &dims, &nelems))do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (moved, &dims, &nelems)); if ((__builtin_expect(!_status .ok(), 0))) return _status; } while (0); | |||
416 | return ArrayFromMemory( | |||
417 | dims.size(), dims.data(), TF_TensorData(moved), | |||
418 | static_cast<DataType>(dtype), [moved] { TF_DeleteTensor(moved); }, | |||
419 | out_ndarray); | |||
420 | } | |||
421 | ||||
422 | // Converts the given TF_Tensor to a numpy ndarray. | |||
423 | // If the returned status is OK, the caller becomes the owner of *out_array. | |||
424 | Status TF_TensorToPyArray(Safe_TF_TensorPtr tensor, PyObject** out_ndarray) { | |||
425 | // A fetched operation will correspond to a null tensor, and a None | |||
426 | // in Python. | |||
427 | if (tensor == nullptr) { | |||
428 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
429 | *out_ndarray = Py_None(&_Py_NoneStruct); | |||
430 | return Status::OK(); | |||
431 | } | |||
432 | int64_t nelems = -1; | |||
433 | gtl::InlinedVector<npy_intp, 4> dims; | |||
434 | TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (tensor.get(), &dims, &nelems)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0) | |||
435 | GetPyArrayDimensionsForTensor(tensor.get(), &dims, &nelems))do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (tensor.get(), &dims, &nelems)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0); | |||
436 | ||||
437 | // If the type is neither string nor resource we can reuse the Tensor memory. | |||
438 | TF_Tensor* original = tensor.get(); | |||
439 | TF_Tensor* moved = TF_TensorMaybeMove(tensor.release()); | |||
440 | if (moved != nullptr) { | |||
441 | if (ArrayFromMemory( | |||
442 | dims.size(), dims.data(), TF_TensorData(moved), | |||
443 | static_cast<DataType>(TF_TensorType(moved)), | |||
444 | [moved] { TF_DeleteTensor(moved); }, out_ndarray) | |||
445 | .ok()) { | |||
446 | return Status::OK(); | |||
447 | } | |||
448 | } | |||
449 | tensor.reset(original); | |||
450 | ||||
451 | // Copy the TF_TensorData into a newly-created ndarray and return it. | |||
452 | PyArray_Descr* descr = nullptr; | |||
453 | TF_RETURN_IF_ERROR(GetPyArrayDescrForTensor(tensor.get(), &descr))do { ::tensorflow::Status _status = (GetPyArrayDescrForTensor (tensor.get(), &descr)); if ((__builtin_expect(!_status.ok (), 0))) return _status; } while (0); | |||
454 | Safe_PyObjectPtr safe_out_array = | |||
455 | tensorflow::make_safe(PyArray_Empty(*(PyObject * (*)(int, npy_intp const *, PyArray_Descr *, int )) _tensorflow_numpy_api[184])(dims.size(), dims.data(), descr, 0)); | |||
456 | if (!safe_out_array) { | |||
457 | return errors::Internal("Could not allocate ndarray"); | |||
458 | } | |||
459 | PyArrayObject* py_array = | |||
460 | reinterpret_cast<PyArrayObject*>(safe_out_array.get()); | |||
461 | if (TF_TensorType(tensor.get()) == TF_STRING) { | |||
462 | Status s = CopyTF_TensorStringsToPyArray(tensor.get(), nelems, py_array); | |||
463 | if (!s.ok()) { | |||
464 | return s; | |||
465 | } | |||
466 | } else if (static_cast<size_t>(PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array)))) != | |||
467 | TF_TensorByteSize(tensor.get())) { | |||
468 | return errors::Internal("ndarray was ", PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array))), | |||
469 | " bytes but TF_Tensor was ", | |||
470 | TF_TensorByteSize(tensor.get()), " bytes"); | |||
471 | } else { | |||
472 | FastMemcpy(PyArray_DATA(py_array), TF_TensorData(tensor.get()), | |||
473 | PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array)))); | |||
474 | } | |||
475 | ||||
476 | *out_ndarray = safe_out_array.release(); | |||
477 | return Status::OK(); | |||
478 | } | |||
479 | ||||
480 | Status NdarrayToTensor(TFE_Context* ctx, PyObject* ndarray, | |||
481 | Safe_TF_TensorPtr* ret) { | |||
482 | DCHECK(ret != nullptr)while (false && (ret != nullptr)) ::tensorflow::internal ::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 482); | |||
483 | ||||
484 | // Make sure we dereference this array object in case of error, etc. | |||
485 | Safe_PyObjectPtr array_safe(make_safe( | |||
486 | PyArray_FromAny(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _tensorflow_numpy_api[69])(ndarray, nullptr, 0, 0, NPY_ARRAY_CARRAY_RO(0x0001 | 0x0100), nullptr))); | |||
487 | if (!array_safe) return errors::InvalidArgument("Not a ndarray."); | |||
488 | PyArrayObject* array = reinterpret_cast<PyArrayObject*>(array_safe.get()); | |||
489 | ||||
490 | // Convert numpy dtype to TensorFlow dtype. | |||
491 | TF_DataType dtype = TF_FLOAT; | |||
492 | TF_RETURN_IF_ERROR(PyArray_TYPE_to_TF_DataType(array, &dtype))do { ::tensorflow::Status _status = (PyArray_TYPE_to_TF_DataType (array, &dtype)); if ((__builtin_expect(!_status.ok(), 0) )) return _status; } while (0); | |||
493 | ||||
494 | int64_t nelems = 1; | |||
495 | gtl::InlinedVector<int64_t, 4> dims; | |||
496 | for (int i = 0; i < PyArray_NDIM(array); ++i) { | |||
497 | dims.push_back(PyArray_SHAPE(array)[i]); | |||
498 | nelems *= dims[i]; | |||
499 | } | |||
500 | ||||
501 | // Create a TF_Tensor based on the fed data. In the case of non-string data | |||
502 | // type, this steals a reference to array, which will be relinquished when | |||
503 | // the underlying buffer is deallocated. For string, a new temporary buffer | |||
504 | // is allocated into which the strings are encoded. | |||
505 | if (dtype == TF_RESOURCE) { | |||
506 | size_t size = PyArray_NBYTES(array)(PyArray_ITEMSIZE(array) * (*(npy_intp (*)(npy_intp const *, int )) _tensorflow_numpy_api[158])(PyArray_DIMS(array), PyArray_NDIM (array))); | |||
507 | array_safe.release(); | |||
508 | ||||
509 | if (ctx) { | |||
510 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
511 | static_cast<tensorflow::DataType>(dtype), {}, 0, PyArray_DATA(array), | |||
512 | size, &DelayedNumpyDecref, array)}); | |||
513 | } else { | |||
514 | *ret = make_safe(TF_NewTensor(dtype, {}, 0, PyArray_DATA(array), size, | |||
515 | &DelayedNumpyDecref, array)); | |||
516 | } | |||
517 | ||||
518 | } else if (dtype != TF_STRING) { | |||
519 | size_t size = PyArray_NBYTES(array)(PyArray_ITEMSIZE(array) * (*(npy_intp (*)(npy_intp const *, int )) _tensorflow_numpy_api[158])(PyArray_DIMS(array), PyArray_NDIM (array))); | |||
520 | array_safe.release(); | |||
521 | if (ctx) { | |||
522 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
523 | static_cast<tensorflow::DataType>(dtype), dims.data(), dims.size(), | |||
524 | PyArray_DATA(array), size, &DelayedNumpyDecref, array)}); | |||
525 | } else { | |||
526 | *ret = make_safe(TF_NewTensor(dtype, dims.data(), dims.size(), | |||
527 | PyArray_DATA(array), size, | |||
528 | &DelayedNumpyDecref, array)); | |||
529 | } | |||
530 | ||||
531 | } else { | |||
532 | size_t size = 0; | |||
533 | void* encoded = nullptr; | |||
534 | TF_RETURN_IF_ERROR(EncodePyBytesArray(array, nelems, &size, &encoded))do { ::tensorflow::Status _status = (EncodePyBytesArray(array , nelems, &size, &encoded)); if ((__builtin_expect(!_status .ok(), 0))) return _status; } while (0); | |||
535 | if (ctx) { | |||
536 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
537 | static_cast<tensorflow::DataType>(dtype), dims.data(), dims.size(), | |||
538 | encoded, size, | |||
539 | [](void* data, size_t len, void* arg) { | |||
540 | delete[] reinterpret_cast<tensorflow::tstring*>(data); | |||
541 | }, | |||
542 | nullptr)}); | |||
543 | } else { | |||
544 | *ret = make_safe(TF_NewTensor( | |||
545 | dtype, dims.data(), dims.size(), encoded, size, | |||
546 | [](void* data, size_t len, void* arg) { | |||
547 | delete[] reinterpret_cast<tensorflow::tstring*>(data); | |||
548 | }, | |||
549 | nullptr)); | |||
550 | } | |||
551 | } | |||
552 | ||||
553 | return Status::OK(); | |||
554 | } | |||
555 | ||||
556 | Status TF_TensorToTensor(const TF_Tensor* src, Tensor* dst); | |||
557 | TF_Tensor* TF_TensorFromTensor(const tensorflow::Tensor& src, Status* status); | |||
558 | ||||
559 | Status NdarrayToTensor(PyObject* obj, Tensor* ret) { | |||
560 | Safe_TF_TensorPtr tf_tensor = make_safe(static_cast<TF_Tensor*>(nullptr)); | |||
561 | Status s = NdarrayToTensor(nullptr /*ctx*/, obj, &tf_tensor); | |||
562 | if (!s.ok()) { | |||
563 | return s; | |||
564 | } | |||
565 | return TF_TensorToTensor(tf_tensor.get(), ret); | |||
566 | } | |||
567 | ||||
568 | Status TensorToNdarray(const Tensor& t, PyObject** ret) { | |||
569 | Status status; | |||
570 | Safe_TF_TensorPtr tf_tensor = make_safe(TF_TensorFromTensor(t, &status)); | |||
571 | if (!status.ok()) { | |||
| ||||
572 | return status; | |||
573 | } | |||
574 | return TF_TensorToMaybeAliasedPyArray(std::move(tf_tensor), ret); | |||
575 | } | |||
576 | ||||
577 | } // namespace tensorflow |
1 | #ifndef PyTuple_New |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyTuple_New(Py_ssize_t len) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyTuple_New is defined as a macro." |
10 | #endif |
1 | #ifndef PyList_SetItem |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | void clang_analyzer_PyObject_Steal_Reference(const void *); |
5 | int clang_analyzer_noimpl_conjure_int(); |
6 | int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *o) { |
7 | clang_analyzer_PyObject_Steal_Reference(o); |
8 | return clang_analyzer_noimpl_conjure_int(); |
9 | } |
10 | #else |
11 | #warning "API PyList_SetItem is defined as a macro." |
12 | #endif |