• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 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 #ifndef TENSORFLOW_PYTHON_EAGER_PYWRAP_TFE_H_
17 #define TENSORFLOW_PYTHON_EAGER_PYWRAP_TFE_H_
18 
19 // Place `<locale>` before <Python.h> to avoid build failure in macOS.
20 #include <locale>
21 
22 // The empty line above is on purpose as otherwise clang-format will
23 // automatically move <Python.h> before <locale>.
24 #include <Python.h>
25 
26 #include "tensorflow/c/eager/c_api.h"
27 #include "tensorflow/core/framework/types.pb.h"
28 #include "tensorflow/core/lib/core/status.h"
29 #include "tensorflow/core/lib/gtl/inlined_vector.h"
30 #include "tensorflow/python/lib/core/safe_pyobject_ptr.h"
31 
32 typedef tensorflow::gtl::InlinedVector<TFE_TensorHandle*, 4>
33     TFE_InputTensorHandles;
34 typedef tensorflow::gtl::InlinedVector<TFE_TensorHandle*, 2>
35     TFE_OutputTensorHandles;
36 
37 // Execute a TensorFlow operation.
38 //
39 // 'device_name': Name of the device on which to execute the operation, or NULL
40 //                for automatic selection.
41 // 'op_name': Name of the TensorFlow op to execute.
42 // 'inputs': An array of TFE_TensorHandle*'s of size 'num_inputs'. These tensors
43 //           will be provided as input to the operation.
44 // 'attrs': A Python tuple alternating names and attr values.
45 // 'outputs': A pointer to a TFE_OutputTensorHandles in which outputs will
46 //            placed. On success, its elements will be filled in and the
47 //            caller takes ownership of each returned TFE_TensorHandle.
48 //            'outputs' MUST be sized to be at least as large as the number
49 //            of tensors produced by the operation and will be resized to
50 //            the actual number of tensors produced.
51 void TFE_Py_Execute(TFE_Context* ctx, const char* device_name,
52                     const char* op_name, TFE_InputTensorHandles* inputs,
53                     PyObject* attrs, TFE_OutputTensorHandles* outputs,
54                     TF_Status* out_status);
55 
56 // Execute a cancelable TensorFlow operation.
57 //
58 // Arguments as above (for TFE_Py_Execute), with the addition of:
59 // 'cancellation_manager': A pointer to a TFE_CancellationManager that can be
60 //                         used to cancel execution of the given operation.
61 typedef struct TFE_CancellationManager TFE_CancellationManager;
62 void TFE_Py_ExecuteCancelable(TFE_Context* ctx, const char* device_name,
63                               const char* op_name,
64                               TFE_InputTensorHandles* inputs, PyObject* attrs,
65                               TFE_CancellationManager* cancellation_manager,
66                               TFE_OutputTensorHandles* outputs,
67                               TF_Status* out_status);
68 
69 // Registers e as the Exception class for handling not ok Status. Returns
70 // Py_None if registration succeeds, else throws a TypeError and returns NULL.
71 //
72 // This function is not thread-safe.
73 PyObject* TFE_Py_RegisterExceptionClass(PyObject* e);
74 
75 // Registers e as the VSpace to use.
76 // `vspace` must be a imperative_grad.py:VSpace named tuple.
77 PyObject* TFE_Py_RegisterVSpace(PyObject* e);
78 
79 // Registers e as the Exception to be raised when the conditions of
80 // TFE_Py_FastPathExecute_C have not been met. When this exception is set, it
81 // is a signal to the calling code that it should fall back to the safer (and
82 // more complete) code path.
83 //
84 // This function is not thread-safe.
85 PyObject* TFE_Py_RegisterFallbackExceptionClass(PyObject* e);
86 
87 // Registers e as the gradient_function.
88 // The registered function takes
89 // (op_name, attrs, num_inputs, inputs, outputs, output_gradients) and returns
90 // the input gradients. This function will not correctly be able to generate
91 // gradients for functional ops - the gradients for those ops are calculated
92 // through a different codepath (see function.py for additional information).
93 //
94 // This function is not thread-safe.
95 PyObject* TFE_Py_RegisterGradientFunction(PyObject* e);
96 
97 // Registers e as the forward_gradient_function.  The registered function takes
98 // (op_name, attrs, inputs, outputs, tangents) and returns the output
99 // tangents. This function is used only for operations, not for custom gradients
100 // or functional ops.
101 //
102 // This function is not thread-safe.
103 PyObject* TFE_Py_RegisterJVPFunction(PyObject* e);
104 
105 // Returns 0 if 'status' is TF_OK. Otherwise, raises an exception (using
106 // `exception` if not nullptr, else using the class registered via
107 // TFE_Py_RegisterExceptionClass), and returns -1.
108 int MaybeRaiseExceptionFromTFStatus(TF_Status* status, PyObject* exception);
109 
110 // Returns 0 if 'status' is ok. Otherwise, raises an exception (using
111 // `exception` if not nullptr, else using the class registered via
112 // TFE_Py_RegisterExceptionClass), and returns -1.
113 int MaybeRaiseExceptionFromStatus(const tensorflow::Status& status,
114                                   PyObject* exception);
115 
116 // Returns the string associated with the passed-in python object.
117 const char* TFE_GetPythonString(PyObject* o);
118 
119 // Returns a unique id on each call.
120 int64_t get_uid();
121 
122 // Wraps the output of get_uid as a Python Long object. Ownership is passed to
123 // the caller.
124 PyObject* TFE_Py_UID();
125 
126 // Deleter for Context objects, called from the Capsule that owns it.
127 void TFE_DeleteContextCapsule(PyObject* context);
128 
129 // Returns true if o is an instance of EagerTensor, but not a subclass. Else
130 // returns false.
131 bool EagerTensor_CheckExact(const PyObject* o);
132 
133 // Helper function to construct a new EagerTensor from a TFE_TensorHandle.
134 PyObject* EagerTensorFromHandle(TFE_TensorHandle* handle,
135                                 const bool is_packed = false);
136 
137 // Extracts the handle inside EagerTensor object `o`. Returns nullptr on error.
138 TFE_TensorHandle* EagerTensor_Handle(const PyObject* o);
139 
140 // Creates the `EagerTensor` class by subclassing `base_class` and returns the
141 // newly created type, or nullptr on error.
142 PyObject* TFE_Py_InitEagerTensor(PyObject* base_class);
143 
144 // Sets `profiler` as the current profiler to receive callbacks about events
145 // on eager tensors. Currently, the only reported event is creation.
146 // `profiler` is expected to have a `created(self, eager_tensor)` method that
147 // takes the created tensor as its single argument.
148 // Previous profiler, if any, is unset and will not receive any more
149 // callbacks.
150 // To unset the profiler, pass Py_None as the value of `profiler`.
151 PyObject* TFE_Py_SetEagerTensorProfiler(PyObject* profiler);
152 
153 // Creates a new tape and adds it to the active set. `persistent` and
154 // `watch_accessed_variables` must be `PyBool_Type` (`Py_True` or `Py_False`).
155 PyObject* TFE_Py_TapeSetNew(PyObject* persistent,
156                             PyObject* watch_accessed_variables);
157 
158 // Removes the passed tape from the set of active tapes.
159 void TFE_Py_TapeSetRemove(PyObject* tape);
160 
161 // Adds the passed tape to the set of active tapes.
162 void TFE_Py_TapeSetAdd(PyObject* tape);
163 
164 // Returns true if the tape stack is empty.
165 PyObject* TFE_Py_TapeSetIsEmpty();
166 
167 // Check if any backward tape should record an operation given inputs.
168 //
169 // Does not take forward accumulators into account.
170 PyObject* TFE_Py_TapeSetShouldRecordBackprop(PyObject* tensors);
171 
172 // Determine possible gradient types, taking forward accumulators into account.
173 //   - 0 if no tape will record (implies TFE_Py_TapeSetShouldRecordBackprop
174 //     is false and no forward accumulator is watching)
175 //   - 1 if first-order gradients may be requested
176 //   - 2 if higher-order gradients may be requested
177 PyObject* TFE_Py_TapeSetPossibleGradientTypes(PyObject* tensors);
178 
179 void TFE_Py_TapeWatch(PyObject* tape, PyObject* tensor);
180 void TFE_Py_TapeSetDeleteTrace(tensorflow::int64 tensor_id);
181 
182 // Stops any gradient recording on the current thread.
183 //
184 // Includes forward accumulators.
185 void TFE_Py_TapeSetStopOnThread();
186 
187 // Restarts gradient recording on the current thread.
188 void TFE_Py_TapeSetRestartOnThread();
189 
190 // Checks whether gradient recording is stopped on the current thread.
191 PyObject* TFE_Py_TapeSetIsStopped();
192 
193 // Records an operation for the purpose of gradient computation.
194 //
195 // Arguments:
196 //  - op_type is a string for the operation type, used in the backprop code
197 //  - output_tensors are a list of Python Tensor objects output by the operation
198 //  - input_tensors are a list of input Tensors to the recorded operation
199 //  - backward_function is the function to be called during backprop or
200 //    forwardprop to, given the gradients of the output tensors, produce the
201 //    gradients of the input tensors. This function is automatically transposed
202 //    during forwardprop.
203 //  - forward_function is an optional special-case for forwardprop, taking input
204 //    jvps and returning output jvps.
205 //
206 // Records an operation both for backprop (gradient tape) and forwardprop
207 // (forward accumulator). Equivalent to calling both
208 // TFE_Py_TapeSetRecordOperationBackprop and
209 // TFE_Py_TapeSetRecordOperationForwardprop.
210 PyObject* TFE_Py_TapeSetRecordOperation(PyObject* op_type,
211                                         PyObject* output_tensors,
212                                         PyObject* input_tensors,
213                                         PyObject* backward_function,
214                                         PyObject* forward_function);
215 
216 // Records an operation only for backprop (gradient tapes).
217 //
218 // Same arguments as TFE_Py_TapeSetRecordOperation.
219 PyObject* TFE_Py_TapeSetRecordOperationBackprop(PyObject* op_type,
220                                                 PyObject* output_tensors,
221                                                 PyObject* input_tensors,
222                                                 PyObject* backward_function);
223 
224 // Records an operation only for forwardprop (forward accumulators).
225 //
226 // Arguments:
227 //  - op_type is a string for the operation type, used in the backprop code
228 //  - output_tensors are a list of Python Tensor objects output by the operation
229 //  - input_tensors are a list of input Tensors to the recorded operation
230 //  - backward_function is the function to be called to, given the gradients of
231 //    the output tensors, produce the gradients of the input tensors. This
232 //    function is automatically transposed to produce output gradients given
233 //    input gradients.
234 //  - forwardprop_output_indices indicates any output_tensors which contain
235 //    JVPs. Typically these will have come from TFE_Py_PackJVPs. May
236 //    be None or an empty sequence if there are no JVP outputs from the
237 //    operation.
238 PyObject* TFE_Py_TapeSetRecordOperationForwardprop(
239     PyObject* op_type, PyObject* output_tensors, PyObject* input_tensors,
240     PyObject* backward_function, PyObject* forwardprop_output_indices);
241 
242 // Notifies all tapes that a variable has been accessed.
243 void TFE_Py_TapeVariableAccessed(PyObject* variable);
244 
245 // Watches the given variable object on the given tape.
246 void TFE_Py_TapeWatchVariable(PyObject* tape, PyObject* variable);
247 
248 // Computes a gradient based on information recorded on the tape.`tape` must
249 // have been produced by TFE_Py_NewTape. `target` and `sources` must be python
250 // lists of Tensor objects. `output_gradients` is either None or a python list
251 // of either Tensor or None, and if not None should have the same length as
252 // target.
253 PyObject* TFE_Py_TapeGradient(PyObject* tape, PyObject* target,
254                               PyObject* sources, PyObject* output_gradients,
255                               PyObject* sources_raw,
256                               PyObject* unconnected_gradients,
257                               TF_Status* status);
258 
259 // Execute a tensorflow operation assuming that all provided inputs are
260 // correctly formatted (i.e. EagerTensors). If it doesn't find EagerTensors,
261 // it will simply fail with a NotImplementedError.
262 //
263 // The "args" PyObject* is meant to be a tuple with the following structure:
264 //  Item 1: The Python eager Context object
265 //  Item 2: op_name: Name of the TensorFlow op to execute.
266 //  Item 3: name: An optional name for the operation.
267 //  Item 4 onwards: inputs - This is a list of inputs followed by a list of
268 //        attrs. It is not necessary for type attrs to be present.
269 //
270 // Note: the device_name and op_callbacks, which were previously passed
271 // as arguments, are now read via GetEagerContextThreadLocalData().
272 //
273 // This is named _C since there doesn't seem to be any way to make it visible
274 // in the SWIG interface without renaming due to the use of the %native
275 // directive.
276 PyObject* TFE_Py_FastPathExecute_C(PyObject* args);
277 
278 // Record the gradient for a given op.
279 PyObject* TFE_Py_RecordGradient(PyObject* op_name, PyObject* inputs,
280                                 PyObject* attrs, PyObject* results,
281                                 PyObject* forward_pass_name_scope);
282 
283 // Returns all variables watched by the given tape in the order those variables
284 // were created.
285 PyObject* TFE_Py_TapeWatchedVariables(PyObject* tape);
286 
287 // Creates a new forward accumulator. Does not add it to the active set.
288 PyObject* TFE_Py_ForwardAccumulatorNew(bool use_batch);
289 
290 // Adds a ForwardAccumulator to the active set, meaning it will watch executed
291 // operations. It must not already be in the active set.
292 PyObject* TFE_Py_ForwardAccumulatorSetAdd(PyObject* accumulator);
293 // Removes a forward accumulator from the active set, meaning it will no longer
294 // be watching operations.
295 void TFE_Py_ForwardAccumulatorSetRemove(PyObject* accumulator);
296 
297 // Tell the forward accumulator `accumulator` to watch `tensor`, with a Tensor
298 // tangent vector `tangent` of matching shape and dtype.
299 void TFE_Py_ForwardAccumulatorWatch(PyObject* accumulator, PyObject* tensor,
300                                     PyObject* tangent);
301 
302 // Looks up the Jacobian-vector product of `tensor` in the forward accumulator
303 // `accumulator`. Returns None if no JVP is available.
304 PyObject* TFE_Py_ForwardAccumulatorJVP(PyObject* accumulator, PyObject* tensor);
305 
306 // Temporarily push or pop transient state for accumulators in the active set.
307 //
308 // Allows an accumulator which is currently processing an operation to
309 // temporarily reset its state. This is useful when building forwardprop
310 // versions of functions, where an accumulator will trigger function building
311 // and then must process captured symbolic tensors while building it. Without
312 // pushing and popping, accumulators ignore operations executed as a direct
313 // result of their own jvp computations.
314 PyObject* TFE_Py_ForwardAccumulatorPushState();
315 PyObject* TFE_Py_ForwardAccumulatorPopState();
316 
317 // Collects state from all current forward accumulators related to `tensors`.
318 //
319 // This is useful for packing JVPs as function inputs before executing a
320 // function which computes primals and JVPs at the same time.
321 //
322 // Does not include accumulators which are currently in the process of computing
323 // a jvp (and so appear somewhere on the current execution stack) or any
324 // accumulators more deeply nested.
325 //
326 // Includes JVPs for `tensors` and any higher-order JVPs for those
327 // (recursively). Returns a two-element tuple (indices, jvps):
328 //   indices: A sequence of sequences of two-element tuples. Each forward
329 //       accumulator is represented as a sequence of tuples with (primal_index,
330 //       jvp_index). Both integers index into the concatenated `tensors + jvps`
331 //       array.
332 //   jvps: A flat list of Tensors. Best interpreted as a sequence to be
333 //       appended to `tensors`.
334 PyObject* TFE_Py_PackJVPs(PyObject* tensors);
335 
336 // Variable Watcher methods.
337 
338 // Creates a new variable watcher and adds it to the set of active variable
339 // watchers.
340 PyObject* TFE_Py_VariableWatcherNew();
341 
342 // Removes the passed variable watcher from the set of active variable watchers.
343 void TFE_Py_VariableWatcherRemove(PyObject* variable_watcher);
344 
345 // Notifies all variable watchers that a variable has been accessed.
346 void TFE_Py_VariableWatcherVariableAccessed(PyObject* variable);
347 
348 // Returns all variables watched by the given variable_watcher in the order
349 // those variables were created.
350 PyObject* TFE_Py_VariableWatcherWatchedVariables(PyObject* variable_watcher);
351 
352 // Returns an EagerTensor of dimension [len(`tensors`)] containing
353 // the `slice_dim`'th dimension of each tensor in `tensors`. In other words,
354 // TFE_Py_TensorShapeSlice takes a slice of dimensions of tensors in
355 // `tensors`. For example, if `tensors` contains tensors of with shapes
356 // [1, 2, 3], [4, 5], [6, 7, 8, 9], TFE_Py_TensorShapeSlice called with
357 // `slice_dim` equal to 1 will return [2, 5, 7].
358 // On error, returns nullptr and sets python exception.
359 // REQUIRES: `tensors` is a python list/tuple of EagerTensors
360 // REQUIRES: `slice_dim` is non-negative and smaller than the rank of all
361 //   tensors in `tensors`.
362 PyObject* TFE_Py_TensorShapeSlice(PyObject* tensors, int slice_dim);
363 
364 // Returns the shape of this tensor's on-device representation.
365 // The shape is represented as a Python tuple of integers.
366 PyObject* TFE_Py_TensorShapeOnDevice(PyObject* tensor);
367 
368 // Encodes the object as a tuple that is meant to be used as part of the key
369 // for the defun function cache.  If `include_tensor_ranks_only` is true,
370 // then the encoding only stores tensor ranks, and the key is
371 // agnostic to dimension sizes.  Otherwise, full tensor shape encodings are
372 // returned.
373 PyObject* TFE_Py_EncodeArg(PyObject*, bool include_tensor_ranks_only);
374 
375 void TFE_Py_EnableInteractivePythonLogging();
376 
377 // Sets `python_context` as the current eager Context object (defined
378 // in eager/context.py). This function must be called at least once before
379 // eager tensors are created.
380 // If an error is encountered, sets python error and returns NULL. Else, returns
381 // Py_None.
382 //
383 // This function is not thread-safe.
384 PyObject* TFE_Py_SetEagerContext(PyObject* py_context);
385 
386 // Returns the current eager Context object (defined in eager/context.py)
387 // that was last set using TFE_Py_SetEagerContext.
388 // If an error is encountered, sets python error and returns NULL.
389 // The returned PyObject is "new", i.e. the caller must call Py_DECREF on it at
390 // some point.
391 PyObject* GetPyEagerContext();
392 
393 // These are exposed since there is SWIG code that calls these.
394 // Returns a pre-allocated status if it exists.
395 TF_Status* GetStatus();
396 // Returns the pre-allocated status to the code.
397 void ReturnStatus(TF_Status* status);
398 
399 namespace tensorflow {
400 
401 // Returns the DataType for the specified tensor.  Returns DT_INVALID if
402 // PyObject is not a tensor.
403 DataType PyTensor_DataType(PyObject* tensor);
404 
405 // Thread-local data associated with a Python eager Context object.
406 //
407 // TODO(edloper): Consider changing device_name and scope_name to a const char*
408 // (with nullptr used for None). However, note that existing code (e.g.
409 // TFE_TensorHandleCache::Lookup) assumes that the lifetime of these strings
410 // extends beyond the point where their value is changed; so we'd need to make
411 // sure that the strings stay alive (maybe using PyUnicode_InternInPlace?)
412 struct EagerContextThreadLocalData {
413   bool is_eager = false;
414   bool invoking_op_callbacks = false;
415   tensorflow::Safe_PyObjectPtr device_name;
416   tensorflow::Safe_PyObjectPtr scope_name;
417   tensorflow::Safe_PyObjectPtr device_spec;
418   tensorflow::Safe_PyObjectPtr function_call_options;
419   tensorflow::Safe_PyObjectPtr executor;
420   tensorflow::Safe_PyObjectPtr op_callbacks;
421 };
422 
423 // Create a thread-local-data structure associated with py_eager_context.
424 // `is_eager` and `device_spec` are used to supply default values for those
425 // fields whenever a new thread-local instance is created for py_eager_tensor.
426 //
427 // This function assumes that the Python GIL is held (and does not perform its
428 // own locking).
429 void MakeEagerContextThreadLocalData(PyObject* py_eager_context,
430                                      PyObject* is_eager,
431                                      PyObject* device_spec);
432 
433 // Returns the thread-local instance of EagerContextThreadLocalData that is
434 // associated with the given Python Context object.  If an instance has not
435 // yet been created for `py_eager_context` in this thread, then a new one is
436 // created, and initialized with the default values specified in
437 // MakeEagerContextThreadLocalData.
438 EagerContextThreadLocalData* GetEagerContextThreadLocalData(
439     PyObject* py_eager_context);
440 
441 // Free data structures used to track py_eager_context.
442 //
443 // This frees global state associated with py_eager_context, as well as thread-
444 // local state associated with py_eager_context and the current thread. If you
445 // wish to destroy thread-local state associated with a single py_eager_context
446 // for multiple threads, then you must call this method from each thread.
447 //
448 // Thread-local state assocaited with eager contexts is also automatically
449 // cleaned up when the thread is destroyed.
450 //
451 // This function assumes that the Python GIL is held (and does not perform its
452 // own locking).
453 void DestroyEagerContextThreadLocalData(PyObject* py_eager_context);
454 
455 }  // namespace tensorflow
456 
457 #endif  // TENSORFLOW_PYTHON_EAGER_PYWRAP_TFE_H_
458