File: | build/../torch/csrc/autograd/python_function.cpp |
Warning: | line 100, column 11 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include <torch/csrc/autograd/python_function.h> | ||||
2 | |||||
3 | #include <torch/csrc/python_headers.h> | ||||
4 | #include <structmember.h> | ||||
5 | #include <ATen/ATen.h> | ||||
6 | #include <ATen/SequenceNumber.h> | ||||
7 | #include <c10/util/irange.h> | ||||
8 | #include <pybind11/pybind11.h> | ||||
9 | |||||
10 | #include <torch/csrc/THP.h> | ||||
11 | #include <torch/csrc/autograd/grad_mode.h> | ||||
12 | #include <torch/csrc/autograd/functions/accumulate_grad.h> | ||||
13 | #include <torch/csrc/autograd/functions/basic_ops.h> | ||||
14 | #include <torch/csrc/autograd/functions/utils.h> | ||||
15 | #include <torch/csrc/autograd/python_cpp_function.h> | ||||
16 | #include <torch/csrc/autograd/python_hook.h> | ||||
17 | #include <torch/csrc/autograd/saved_variable.h> | ||||
18 | #include <torch/csrc/autograd/python_anomaly_mode.h> | ||||
19 | #include <torch/csrc/jit/frontend/tracer.h> | ||||
20 | #include <torch/csrc/jit/ir/ir.h> | ||||
21 | #include <torch/csrc/jit/python/python_tracer.h> | ||||
22 | #include <torch/csrc/jit/python/pybind_utils.h> | ||||
23 | #include <torch/csrc/utils/python_strings.h> | ||||
24 | #include <torch/csrc/DynamicTypes.h> | ||||
25 | #include <torch/csrc/Exceptions.h> | ||||
26 | |||||
27 | #include <exception> | ||||
28 | #include <functional> | ||||
29 | #include <memory> | ||||
30 | #include <stdexcept> | ||||
31 | #include <string> | ||||
32 | #include <tuple> | ||||
33 | #include <unordered_map> | ||||
34 | #include <unordered_set> | ||||
35 | #include <utility> | ||||
36 | #include <vector> | ||||
37 | |||||
38 | using namespace torch; | ||||
39 | using namespace torch::autograd; | ||||
40 | using namespace torch::jit; | ||||
41 | using at::Tensor; | ||||
42 | |||||
43 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||
44 | PyObject *THPFunctionClass = nullptr; | ||||
45 | |||||
46 | #define THPFunction_assert(condition, ...)if (!(condition)) { THPUtils_setError(...); throw python_error (); } \ | ||||
47 | if (!(condition)) { THPUtils_setError(__VA_ARGS__); throw python_error(); } | ||||
48 | |||||
49 | namespace torch { namespace autograd { | ||||
50 | |||||
51 | void PyNode::throw_python_error() { | ||||
52 | python_error err; | ||||
53 | err.persist(); | ||||
54 | throw err; | ||||
55 | } | ||||
56 | |||||
57 | // NOTE: this function is written in a way that assumes it's only called for backward; | ||||
58 | // it's used by engine.cpp. This is responsible for forwarding a call from | ||||
59 | // C++'s Node::apply to a Python method "apply". | ||||
60 | auto PyNode::apply(variable_list&& inputs) -> variable_list { | ||||
61 | pybind11::gil_scoped_acquire gil; | ||||
62 | at::OptionalDeviceGuard _device_guard; | ||||
63 | THPFunction* py_fn = (THPFunction*)obj; | ||||
64 | |||||
65 | // Massage a C++ variable_list into a Python arguments tuple | ||||
66 | auto num_inputs = inputs.size(); | ||||
67 | THPObjectPtr pyInputs(PyTuple_New(num_inputs)); | ||||
68 | if (!pyInputs) throw_python_error(); | ||||
| |||||
69 | auto& output_info = py_fn->output_info; | ||||
70 | for (const auto i : c10::irange(num_inputs)) { | ||||
71 | // NOLINTNEXTLINE(cppcoreguidelines-init-variables) | ||||
72 | PyObject* input; | ||||
73 | if (inputs[i].defined() || !py_fn->materialize_grads) { | ||||
74 | input = THPVariable_Wrap(inputs[i]); | ||||
75 | } else { | ||||
76 | input = THPVariable_Wrap(output_info[i].zeros(_device_guard)); | ||||
77 | } | ||||
78 | if (!input) throw_python_error(); | ||||
79 | PyTuple_SET_ITEM(pyInputs.get(), i, input)PyTuple_SetItem(pyInputs.get(), i, input); | ||||
80 | } | ||||
81 | |||||
82 | THPObjectPtr apply_fn(PyObject_GetAttrString(obj, "apply")); | ||||
83 | if (!apply_fn) throw_python_error(); | ||||
84 | THPObjectPtr r(PyObject_CallObject(apply_fn, pyInputs.get())); | ||||
85 | if (!r) throw_python_error(); | ||||
86 | ensure_tuple(r); | ||||
87 | |||||
88 | auto& is_variable_input = py_fn->is_variable_input; | ||||
89 | int num_outputs = PyTuple_GET_SIZE(r.get())(((PyVarObject*)(((PyTupleObject *)(r.get()))))->ob_size); | ||||
90 | int num_forward_inputs = is_variable_input.size(); | ||||
91 | // Returning too many results is ok, but only as long as they're all None. | ||||
92 | // Truncate the result tuple in that case. | ||||
93 | if (num_outputs > num_forward_inputs) { | ||||
94 | bool all_none = true; | ||||
95 | for (const auto i : c10::irange(num_forward_inputs, num_outputs)) { | ||||
96 | all_none &= PyTuple_GET_ITEM(r.get(), i)(((PyTupleObject *)(r.get()))->ob_item[i]) == Py_None(&_Py_NoneStruct); | ||||
97 | } | ||||
98 | if (all_none
| ||||
99 | num_outputs = num_forward_inputs; | ||||
100 | r = PyTuple_GetSlice(r.get(), 0, num_forward_inputs); | ||||
| |||||
101 | if (!r) throw_python_error(); | ||||
102 | } | ||||
103 | } | ||||
104 | |||||
105 | // Now the number of gradients should match | ||||
106 | if (num_outputs
| ||||
107 | std::string msg("function "); | ||||
108 | msg += name() + " returned an incorrect number of gradients (expected "; | ||||
109 | msg += std::to_string(num_forward_inputs) + ", got " ; | ||||
110 | msg += std::to_string(num_outputs) + ")"; | ||||
111 | throw std::runtime_error(msg); | ||||
112 | } | ||||
113 | |||||
114 | // Massage the Python results tuple back into a C++ variable_list | ||||
115 | variable_list results; | ||||
116 | results.reserve(num_outputs); | ||||
117 | for (int i = 0; i != num_outputs; ++i) { | ||||
118 | PyObject* output = PyTuple_GET_ITEM(r.get(), i)(((PyTupleObject *)(r.get()))->ob_item[i]); | ||||
119 | bool was_variable = is_variable_input[i]; | ||||
120 | if (!was_variable
| ||||
121 | if (output != Py_None(&_Py_NoneStruct)) { | ||||
122 | std::string msg("function "); | ||||
123 | msg += name() + " returned a gradient different than None at position "; | ||||
124 | msg += std::to_string(i + 1) + ", but the corresponding forward input was not a Variable"; | ||||
125 | throw std::runtime_error(msg); | ||||
126 | } | ||||
127 | continue; | ||||
128 | } | ||||
129 | if (output == Py_None(&_Py_NoneStruct)) { | ||||
130 | results.emplace_back(); | ||||
131 | } else { | ||||
132 | if (!THPVariable_Check(output)) { | ||||
133 | std::string msg("expected Variable or None (got "); | ||||
134 | msg += THPUtils_typename(output)((((PyObject*)(output))->ob_type)->tp_name); | ||||
135 | msg += ")"; | ||||
136 | throw std::runtime_error(msg); | ||||
137 | } | ||||
138 | results.emplace_back(THPVariable_Unpack(output)); | ||||
139 | } | ||||
140 | } | ||||
141 | |||||
142 | return results; | ||||
143 | } | ||||
144 | |||||
145 | auto PyNode::is_traceable() -> bool { | ||||
146 | pybind11::gil_scoped_acquire gil; | ||||
147 | THPObjectPtr forward_class {PyObject_GetAttrString(obj, "_forward_cls")}; | ||||
148 | if (!forward_class) throw_python_error(); | ||||
149 | THPObjectPtr traceable_py_bool {PyObject_GetAttrString(forward_class, "is_traceable")}; | ||||
150 | if (!traceable_py_bool) throw_python_error(); | ||||
151 | return traceable_py_bool == Py_True((PyObject *) &_Py_TrueStruct); | ||||
152 | } | ||||
153 | |||||
154 | auto PyNode::release_variables() -> void { | ||||
155 | pybind11::gil_scoped_acquire gil; | ||||
156 | auto f = (THPFunction*) obj; | ||||
157 | f->saved_variables.clear(); | ||||
158 | f->has_freed_buffers = 1; | ||||
159 | } | ||||
160 | |||||
161 | auto PyNode::name() const -> std::string { | ||||
162 | pybind11::gil_scoped_acquire gil; | ||||
163 | auto f = (THPFunction*) obj; | ||||
164 | auto name = std::string(Py_TYPE(f)(((PyObject*)(f))->ob_type)->tp_name); | ||||
165 | return name; | ||||
166 | } | ||||
167 | |||||
168 | }} // namespace torch::autograd | ||||
169 | |||||
170 | // Traverse and clear are required for supporting Python's GC cycle handling. | ||||
171 | static int THPFunction_traverse(THPFunction *self, visitproc visit, void *arg) | ||||
172 | { | ||||
173 | // cdata could be null if the PyNode has already gone out of scope | ||||
174 | // by the time we're GC'ing this THPFunction (e.g., the user saved grad_fn only). | ||||
175 | // | ||||
176 | // TODO: I'm not really sure if we're actually obligated to traverse PyObject | ||||
177 | // that is stored in PyNode, since we don't really own that C++ object. | ||||
178 | if (auto cdata = self->cdata.lock()) { | ||||
179 | for (const auto& hook : cdata->pre_hooks()) { | ||||
180 | if (auto pyhook = dynamic_cast<PyFunctionPreHook*>(hook.get())) { | ||||
181 | Py_VISIT(pyhook->dict)do { if (pyhook->dict) { int vret = visit(((PyObject*)(pyhook ->dict)), arg); if (vret) return vret; } } while (0); | ||||
182 | } | ||||
183 | } | ||||
184 | for (const auto& hook : cdata->post_hooks()) { | ||||
185 | if (auto pyhook = dynamic_cast<PyFunctionPostHook*>(hook.get())) { | ||||
186 | Py_VISIT(pyhook->dict)do { if (pyhook->dict) { int vret = visit(((PyObject*)(pyhook ->dict)), arg); if (vret) return vret; } } while (0); | ||||
187 | } | ||||
188 | } | ||||
189 | } | ||||
190 | Py_VISIT(self->to_save)do { if (self->to_save) { int vret = visit(((PyObject*)(self ->to_save)), arg); if (vret) return vret; } } while (0); | ||||
191 | Py_VISIT(self->non_differentiable)do { if (self->non_differentiable) { int vret = visit(((PyObject *)(self->non_differentiable)), arg); if (vret) return vret ; } } while (0); | ||||
192 | Py_VISIT(self->dirty_tensors)do { if (self->dirty_tensors) { int vret = visit(((PyObject *)(self->dirty_tensors)), arg); if (vret) return vret; } } while (0); | ||||
193 | return 0; | ||||
194 | } | ||||
195 | |||||
196 | static int THPFunction_clear(THPFunction *self) | ||||
197 | { | ||||
198 | // Note that the cdata might not be expired yet in the case where this | ||||
199 | // object is part of a cycle and the GC happens to tp_clear this PyObject | ||||
200 | // before the other ones that trigger the de-allocation of the cdata | ||||
201 | |||||
202 | Py_CLEAR(self->needs_input_grad)do { PyObject *_py_tmp = ((PyObject*)(self->needs_input_grad )); if (_py_tmp != __null) { (self->needs_input_grad) = __null ; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0); | ||||
203 | |||||
204 | Py_CLEAR(self->to_save)do { PyObject *_py_tmp = ((PyObject*)(self->to_save)); if ( _py_tmp != __null) { (self->to_save) = __null; _Py_DECREF( ((PyObject*)(_py_tmp))); } } while (0); | ||||
205 | Py_CLEAR(self->non_differentiable)do { PyObject *_py_tmp = ((PyObject*)(self->non_differentiable )); if (_py_tmp != __null) { (self->non_differentiable) = __null ; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0); | ||||
206 | Py_CLEAR(self->dirty_tensors)do { PyObject *_py_tmp = ((PyObject*)(self->dirty_tensors) ); if (_py_tmp != __null) { (self->dirty_tensors) = __null ; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0); | ||||
207 | |||||
208 | self->output_info.clear(); | ||||
209 | self->input_info.clear(); | ||||
210 | self->saved_variables.clear(); | ||||
211 | self->is_variable_input.clear(); | ||||
212 | |||||
213 | return 0; | ||||
214 | } | ||||
215 | |||||
216 | static void THPFunction_dealloc(THPFunction* self) | ||||
217 | { | ||||
218 | // Why is this guaranteed to be true? Suppose that self->cdata is non-null | ||||
219 | // (otherwise the condition is trivially true). Then there is a PyNode | ||||
220 | // which contains an owning reference to this object. But we are only | ||||
221 | // allowed to clear if all owning references are gone! Contradiction. | ||||
222 | // | ||||
223 | // However, note that THPFunction_clear is typically called in the shared_ptr | ||||
224 | // destructor of PyNode; in that case, per | ||||
225 | // https://cplusplus.github.io/LWG/lwg-active.html#2751 it's not currently | ||||
226 | // specified in the standard that this is guaranteed. If you see this | ||||
227 | // assert triggering in the wild, feel free to comment it out. They're | ||||
228 | // likely to standardize that you ARE guaranteed to see the weak pointers | ||||
229 | // as expired in the destructor in the future, so we'll keep this for now. | ||||
230 | TORCH_INTERNAL_ASSERT(self->cdata.expired())if ((__builtin_expect(static_cast<bool>(!(self->cdata .expired())), 0))) { ::c10::detail::torchInternalAssertFail( __func__ , "../torch/csrc/autograd/python_function.cpp", static_cast< uint32_t>(230), "self->cdata.expired()" "INTERNAL ASSERT FAILED at " "\"../torch/csrc/autograd/python_function.cpp\"" ":" "230" ", please report a bug to PyTorch. " , c10::str()); }; | ||||
231 | |||||
232 | PyObject_GC_UnTrack(self); | ||||
233 | THPFunction_clear(self); | ||||
234 | self->cdata.~weak_ptr<PyNode>(); | ||||
235 | self->output_info.~vector(); | ||||
236 | self->input_info.~vector(); | ||||
237 | self->saved_variables.~vector(); | ||||
238 | self->is_variable_input.~vector(); | ||||
239 | Py_TYPE(self)(((PyObject*)(self))->ob_type)->tp_free((PyObject*)self); | ||||
240 | } | ||||
241 | |||||
242 | PyObject *THPFunction_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) | ||||
243 | { | ||||
244 | PyObject* obj = type->tp_alloc(type, 0); | ||||
245 | if (!obj) return nullptr; | ||||
246 | // Python zero-initializes the object memory, so there's no need to initialize | ||||
247 | // most fields | ||||
248 | THPFunction* self = (THPFunction*)obj; | ||||
249 | // Setup the PyNode later; we can't keep it live here | ||||
250 | new (&self->cdata) std::weak_ptr<PyNode>(); | ||||
251 | new (&self->output_info) std::vector<VariableInfo>(); | ||||
252 | new (&self->input_info) std::vector<VariableInfo>(); | ||||
253 | new (&self->saved_variables) std::vector<SavedVariable>(); | ||||
254 | new (&self->is_variable_input) std::vector<bool>(); | ||||
255 | self->materialize_grads = true; | ||||
256 | return obj; | ||||
257 | } | ||||
258 | |||||
259 | //////////////////////////////////////////////////////////////////////////////// | ||||
260 | // Forward | ||||
261 | //////////////////////////////////////////////////////////////////////////////// | ||||
262 | |||||
263 | // Bump the counters of all recorded dirty input tensors, adding each of them | ||||
264 | // into dirty_inputs. Also does some sanity checking. | ||||
265 | static std::unordered_set<at::TensorImpl*> _mark_dirty(THPFunction *self) | ||||
266 | { | ||||
267 | // Increase versions of modified tensors | ||||
268 | std::unordered_set<at::TensorImpl*> dirty_inputs; | ||||
269 | if (!self->dirty_tensors) return dirty_inputs; | ||||
270 | |||||
271 | THPFunction_assert(PyTuple_Check(self->dirty_tensors), "autograd "if (!(((((((PyObject*)(self->dirty_tensors))->ob_type)) ->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: dirty_tensors attribute is expected to be a tuple " "but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type )->tp_name)); throw python_error(); } | ||||
272 | "internal error: dirty_tensors attribute is expected to be a tuple "if (!(((((((PyObject*)(self->dirty_tensors))->ob_type)) ->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: dirty_tensors attribute is expected to be a tuple " "but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type )->tp_name)); throw python_error(); } | ||||
273 | "but is %s", THPUtils_typename(self->dirty_tensors))if (!(((((((PyObject*)(self->dirty_tensors))->ob_type)) ->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: dirty_tensors attribute is expected to be a tuple " "but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type )->tp_name)); throw python_error(); }; | ||||
274 | Py_ssize_t num_dirty = PyTuple_GET_SIZE(self->dirty_tensors)(((PyVarObject*)(((PyTupleObject *)(self->dirty_tensors))) )->ob_size); | ||||
275 | dirty_inputs.reserve(num_dirty); | ||||
276 | for(const auto i : c10::irange(num_dirty)) { | ||||
277 | PyObject *obj = PyTuple_GET_ITEM(self->dirty_tensors, i)(((PyTupleObject *)(self->dirty_tensors))->ob_item[i]); | ||||
278 | THPFunction_assert(THPVariable_Check(obj), "mark_dirty can "if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can " "only accept variables, but argument %d is of type %s", i, ( (((PyObject*)(obj))->ob_type)->tp_name)); throw python_error (); } | ||||
279 | "only accept variables, but argument %d is of type %s", i,if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can " "only accept variables, but argument %d is of type %s", i, ( (((PyObject*)(obj))->ob_type)->tp_name)); throw python_error (); } | ||||
280 | THPUtils_typename(obj))if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can " "only accept variables, but argument %d is of type %s", i, ( (((PyObject*)(obj))->ob_type)->tp_name)); throw python_error (); }; | ||||
281 | |||||
282 | const auto& tensor = THPVariable_Unpack(obj); | ||||
283 | dirty_inputs.insert(tensor.unsafeGetTensorImpl()); | ||||
284 | torch::autograd::impl::bump_version(tensor); | ||||
285 | } | ||||
286 | // We're not going to ever need this so let's remove references now | ||||
287 | Py_CLEAR(self->dirty_tensors)do { PyObject *_py_tmp = ((PyObject*)(self->dirty_tensors) ); if (_py_tmp != __null) { (self->dirty_tensors) = __null ; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0); | ||||
288 | return dirty_inputs; | ||||
289 | } | ||||
290 | |||||
291 | static std::unordered_set<at::TensorImpl*> _parse_non_differentiable(THPFunction *self); | ||||
292 | |||||
293 | // Given a Python tuple of raw output tensors (raw_output), set each of | ||||
294 | // the corresponding entries in a different Python tuple (outputs) with | ||||
295 | // these tensors wrapped with variables. We save the gradient function (self) | ||||
296 | // to the variable if the output requires grad. | ||||
297 | // | ||||
298 | // There is a considerable amount of complexity to handle if the operation | ||||
299 | // that produced these output tensors is inplace. A mapping of *input* | ||||
300 | // tensors to variables (t2var) is used to test if this occurred, and | ||||
301 | // the set of dirty tensors (dirty_inputs) is used to figure out what to | ||||
302 | // do in this case. After this method is run, t2var is extended with | ||||
303 | // mappings for output tensors as well. | ||||
304 | static void _wrap_outputs(const std::shared_ptr<PyNode>& cdata, THPFunction *self, | ||||
305 | const variable_list &input_vars, PyObject *raw_output, PyObject *outputs, bool is_executable) | ||||
306 | { | ||||
307 | auto cdata_if_executable = is_executable ? cdata : nullptr; | ||||
308 | Py_ssize_t num_outputs = PyTuple_GET_SIZE(raw_output)(((PyVarObject*)(((PyTupleObject *)(raw_output))))->ob_size ); | ||||
309 | if (is_executable) { | ||||
310 | self->output_info.clear(); | ||||
311 | self->output_info.reserve(num_outputs); | ||||
312 | } | ||||
313 | |||||
314 | auto non_differentiable = _parse_non_differentiable(self); | ||||
315 | auto dirty_inputs = _mark_dirty(self); | ||||
316 | |||||
317 | std::vector<c10::optional<Variable>> raw_output_vars; | ||||
318 | raw_output_vars.reserve(num_outputs); | ||||
319 | for (const auto i : c10::irange(num_outputs)) { | ||||
320 | PyObject* obj = PyTuple_GET_ITEM(raw_output, i)(((PyTupleObject *)(raw_output))->ob_item[i]); | ||||
321 | // Only process tensors as outputs for autograd purposes. | ||||
322 | if (THPVariable_Check(obj)) { | ||||
323 | raw_output_vars.emplace_back(THPVariable_Unpack(obj)); | ||||
324 | } else { | ||||
325 | raw_output_vars.emplace_back(); | ||||
326 | } | ||||
327 | } | ||||
328 | |||||
329 | // Wrap only the tensor outputs. | ||||
330 | auto wrapped_outputs = _wrap_outputs(input_vars, non_differentiable, dirty_inputs, raw_output_vars, cdata_if_executable); | ||||
331 | |||||
332 | for(const auto i : c10::irange(num_outputs)) { | ||||
333 | PyObject* obj = PyTuple_GetItem(raw_output, i); | ||||
334 | // Keep the non-tensor outputs as is. | ||||
335 | if (!THPVariable_Check(obj)) { | ||||
336 | if (is_executable) { | ||||
337 | self->output_info.emplace_back(); | ||||
338 | } | ||||
339 | Py_INCREF(obj)_Py_INCREF(((PyObject*)(obj))); | ||||
340 | PyTuple_SetItem(outputs, i, obj); | ||||
341 | } else { | ||||
342 | if (is_executable) { | ||||
343 | self->output_info.emplace_back(*wrapped_outputs[i]); | ||||
344 | } | ||||
345 | PyTuple_SetItem(outputs, i, THPVariable_Wrap(*wrapped_outputs[i])); | ||||
346 | } | ||||
347 | } | ||||
348 | } | ||||
349 | |||||
350 | // Save any variables that requested by to_save | ||||
351 | static void _save_variables(const std::shared_ptr<PyNode>& cdata_ptr, THPFunction* self) | ||||
352 | { | ||||
353 | if (!self->to_save) return; | ||||
354 | |||||
355 | THPFunction_assert(PyTuple_Check(self->to_save), "autograd internal "if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal " "error: to_save attribute is expected to be a tuple but is %s" , ((((PyObject*)(self->to_save))->ob_type)->tp_name) ); throw python_error(); } | ||||
356 | "error: to_save attribute is expected to be a tuple but is %s",if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal " "error: to_save attribute is expected to be a tuple but is %s" , ((((PyObject*)(self->to_save))->ob_type)->tp_name) ); throw python_error(); } | ||||
357 | THPUtils_typename(self->to_save))if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal " "error: to_save attribute is expected to be a tuple but is %s" , ((((PyObject*)(self->to_save))->ob_type)->tp_name) ); throw python_error(); }; | ||||
358 | Py_ssize_t num_saved = PyTuple_GET_SIZE(self->to_save)(((PyVarObject*)(((PyTupleObject *)(self->to_save))))-> ob_size); | ||||
359 | self->saved_variables.clear(); | ||||
360 | self->saved_variables.reserve(num_saved); | ||||
361 | for(const auto i : c10::irange(num_saved)) { | ||||
362 | PyObject *obj = PyTuple_GET_ITEM(self->to_save, i)(((PyTupleObject *)(self->to_save))->ob_item[i]); | ||||
363 | if (obj == Py_None(&_Py_NoneStruct)) { | ||||
364 | self->saved_variables.emplace_back(); | ||||
365 | continue; | ||||
366 | } else if (THPVariable_Check(obj)) { | ||||
367 | const auto& tensor = THPVariable_Unpack(obj); | ||||
368 | bool is_output = tensor.grad_fn().get() == cdata_ptr.get(); | ||||
369 | self->saved_variables.emplace_back(tensor, is_output); | ||||
370 | } else { | ||||
371 | throw torch::TypeError( | ||||
372 | "save_for_backward can only save variables, but argument %ld is of " | ||||
373 | "type %s", i, Py_TYPE(obj)(((PyObject*)(obj))->ob_type)->tp_name); | ||||
374 | } | ||||
375 | } | ||||
376 | // Free .to_save | ||||
377 | Py_CLEAR(self->to_save)do { PyObject *_py_tmp = ((PyObject*)(self->to_save)); if ( _py_tmp != __null) { (self->to_save) = __null; _Py_DECREF( ((PyObject*)(_py_tmp))); } } while (0); | ||||
378 | } | ||||
379 | |||||
380 | // Mark requires_grad = 0 on non-differentiable variables (as per non_differentiable) | ||||
381 | static std::unordered_set<at::TensorImpl*> | ||||
382 | _parse_non_differentiable(THPFunction *self) | ||||
383 | { | ||||
384 | std::unordered_set<at::TensorImpl*> set; | ||||
385 | if (!self->non_differentiable) return set; | ||||
386 | |||||
387 | THPFunction_assert(PyTuple_Check(self->non_differentiable), "autograd "if (!(((((((PyObject*)(self->non_differentiable))->ob_type ))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: non_differentiable attribute is expected to be a " "tuple but is %s", ((((PyObject*)(self->non_differentiable ))->ob_type)->tp_name)); throw python_error(); } | ||||
388 | "internal error: non_differentiable attribute is expected to be a "if (!(((((((PyObject*)(self->non_differentiable))->ob_type ))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: non_differentiable attribute is expected to be a " "tuple but is %s", ((((PyObject*)(self->non_differentiable ))->ob_type)->tp_name)); throw python_error(); } | ||||
389 | "tuple but is %s", THPUtils_typename(self->non_differentiable))if (!(((((((PyObject*)(self->non_differentiable))->ob_type ))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError ("autograd " "internal error: non_differentiable attribute is expected to be a " "tuple but is %s", ((((PyObject*)(self->non_differentiable ))->ob_type)->tp_name)); throw python_error(); }; | ||||
390 | Py_ssize_t num_nondiff = PyTuple_GET_SIZE(self->non_differentiable)(((PyVarObject*)(((PyTupleObject *)(self->non_differentiable ))))->ob_size); | ||||
391 | set.reserve(num_nondiff); | ||||
392 | for(const auto i : c10::irange(num_nondiff)) { | ||||
393 | PyObject *t = PyTuple_GET_ITEM(self->non_differentiable, i)(((PyTupleObject *)(self->non_differentiable))->ob_item [i]); | ||||
394 | THPFunction_assert(THPVariable_Check(t), "mark_non_differentiable "if (!(THPVariable_Check(t))) { THPUtils_setError("mark_non_differentiable " "only accepts variable arguments, but got %s", ((((PyObject* )(t))->ob_type)->tp_name)); throw python_error(); } | ||||
395 | "only accepts variable arguments, but got %s", THPUtils_typename(t))if (!(THPVariable_Check(t))) { THPUtils_setError("mark_non_differentiable " "only accepts variable arguments, but got %s", ((((PyObject* )(t))->ob_type)->tp_name)); throw python_error(); }; | ||||
396 | set.insert(THPVariable_Unpack(t).unsafeGetTensorImpl()); | ||||
397 | } | ||||
398 | Py_CLEAR(self->non_differentiable)do { PyObject *_py_tmp = ((PyObject*)(self->non_differentiable )); if (_py_tmp != __null) { (self->non_differentiable) = __null ; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0); | ||||
399 | return set; | ||||
400 | } | ||||
401 | |||||
402 | struct UnpackedInput { | ||||
403 | THPObjectPtr input_tuple; | ||||
404 | variable_list input_vars; | ||||
405 | }; | ||||
406 | |||||
407 | struct InputFlags { | ||||
408 | bool is_executable = false; | ||||
409 | edge_list next_edges; | ||||
410 | THPObjectPtr needs_input_grad; | ||||
411 | std::vector<bool> is_variable_input; | ||||
412 | }; | ||||
413 | |||||
414 | template<bool enforce_variables> | ||||
415 | std::pair<UnpackedInput, InputFlags> unpack_input(PyObject *args) { | ||||
416 | UnpackedInput unpacked; | ||||
417 | InputFlags flags; | ||||
418 | |||||
419 | auto num_args = PyTuple_GET_SIZE(args)(((PyVarObject*)(((PyTupleObject *)(args))))->ob_size); | ||||
420 | unpacked.input_tuple = PyTuple_New(num_args); | ||||
421 | flags.needs_input_grad = PyTuple_New(num_args); | ||||
422 | for(const auto i : c10::irange(num_args)) { | ||||
423 | PyObject *arg = PyTuple_GET_ITEM(args, i)(((PyTupleObject *)(args))->ob_item[i]); | ||||
424 | |||||
425 | bool is_variable = THPVariable_Check(arg); | ||||
426 | flags.is_variable_input.push_back(is_variable); | ||||
427 | if (!is_variable) { | ||||
428 | // TODO: remove this code path once Variable and Tensor are merged in Python | ||||
429 | if (enforce_variables) { | ||||
430 | THPUtils_setError("expected a Tensor argument, but got %s", | ||||
431 | THPUtils_typename(arg)((((PyObject*)(arg))->ob_type)->tp_name)); | ||||
432 | throw python_error(); | ||||
433 | } | ||||
434 | Py_INCREF(Py_False)_Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct))) ); | ||||
435 | PyTuple_SET_ITEM(flags.needs_input_grad.get(), i, Py_False)PyTuple_SetItem(flags.needs_input_grad.get(), i, ((PyObject * ) &_Py_FalseStruct)); | ||||
436 | } else { | ||||
437 | const auto& tensor = THPVariable_Unpack(arg); | ||||
438 | unpacked.input_vars.push_back(tensor); | ||||
439 | PyObject* needs_grad = tensor.requires_grad() ? Py_True((PyObject *) &_Py_TrueStruct) : Py_False((PyObject *) &_Py_FalseStruct); | ||||
440 | Py_INCREF(needs_grad)_Py_INCREF(((PyObject*)(needs_grad))); | ||||
441 | PyTuple_SET_ITEM(flags.needs_input_grad.get(), i, needs_grad)PyTuple_SetItem(flags.needs_input_grad.get(), i, needs_grad); | ||||
442 | } | ||||
443 | Py_INCREF(arg)_Py_INCREF(((PyObject*)(arg))); | ||||
444 | PyTuple_SET_ITEM(unpacked.input_tuple.get(), i, arg)PyTuple_SetItem(unpacked.input_tuple.get(), i, arg); | ||||
445 | } | ||||
446 | |||||
447 | flags.is_executable = GradMode::is_enabled() && any_variable_requires_grad(unpacked.input_vars); | ||||
448 | flags.next_edges = (flags.is_executable ? collect_next_edges(unpacked.input_vars) : edge_list()); | ||||
449 | return std::make_pair(std::move(unpacked), std::move(flags)); | ||||
450 | } | ||||
451 | |||||
452 | static torch::jit::Node* _trace_pre_record( | ||||
453 | PyObject* op_obj, | ||||
454 | PyObject *input_objects, | ||||
455 | const variable_list& input_vars) { | ||||
456 | if (!jit::tracer::isTracing()) { | ||||
457 | return nullptr; | ||||
458 | } | ||||
459 | |||||
460 | // Save scalar args and the calling convention | ||||
461 | auto num_args = PyTuple_GET_SIZE(input_objects)(((PyVarObject*)(((PyTupleObject *)(input_objects))))->ob_size ); | ||||
462 | pyobj_list scalar_args; | ||||
463 | std::string arg_types; | ||||
464 | arg_types.reserve(num_args); | ||||
465 | scalar_args.reserve(num_args); | ||||
466 | for(const auto i : c10::irange(num_args)) { | ||||
467 | PyObject *arg_object = PyTuple_GET_ITEM(input_objects, i)(((PyTupleObject *)(input_objects))->ob_item[i]); | ||||
468 | if (THPVariable_Check(arg_object)) { | ||||
469 | arg_types.push_back('d'); | ||||
470 | } else { | ||||
471 | arg_types.push_back('c'); | ||||
472 | Py_INCREF(arg_object)_Py_INCREF(((PyObject*)(arg_object))); | ||||
473 | scalar_args.emplace_back(arg_object); | ||||
474 | } | ||||
475 | } | ||||
476 | |||||
477 | Py_INCREF(op_obj)_Py_INCREF(((PyObject*)(op_obj))); | ||||
478 | auto pyobj = THPObjectPtr(op_obj); | ||||
479 | return jit::tracer::preRecordPythonTrace( | ||||
480 | std::move(pyobj), arg_types, input_vars, std::move(scalar_args)); | ||||
481 | } | ||||
482 | |||||
483 | static void _trace_post_record( | ||||
484 | torch::jit::Node* node, | ||||
485 | PyObject* op_obj, | ||||
486 | const variable_list& input_vars, | ||||
487 | PyObject *output_objects, | ||||
488 | bool is_inplace, | ||||
489 | bool unpack_output) { | ||||
490 | if (!jit::tracer::isTracing()) { | ||||
491 | return; | ||||
492 | } | ||||
493 | |||||
494 | node->i_(jit::attr::inplace, is_inplace); | ||||
495 | |||||
496 | // Isolate C variable ptrs in a vector | ||||
497 | int num_outputs = PyTuple_GET_SIZE(output_objects)(((PyVarObject*)(((PyTupleObject *)(output_objects))))->ob_size ); | ||||
498 | auto graph = node->owningGraph(); | ||||
499 | node->addOutput(); | ||||
500 | if (!unpack_output) { | ||||
501 | std::vector<TypePtr> tuple_values(num_outputs, TensorType::get()); | ||||
502 | TypePtr tuple_type = TupleType::create(std::move(tuple_values)); | ||||
503 | node->output()->setType(tuple_type); | ||||
504 | auto unpacked = graph->createTupleUnpack(node->output())->insertAfter(node); | ||||
505 | node = unpacked; | ||||
506 | } | ||||
507 | for (const auto i : c10::irange(num_outputs)) { | ||||
508 | PyObject* obj = PyTuple_GET_ITEM(output_objects, i)(((PyTupleObject *)(output_objects))->ob_item[i]); | ||||
509 | if (THPVariable_Check(obj)) { | ||||
510 | Value* value = node->outputs()[i]; | ||||
511 | const auto& tensor = THPVariable_Unpack(obj); | ||||
512 | if (tensor.defined()) { | ||||
513 | value->inferTypeFrom(tensor); | ||||
514 | jit::tracer::setValueTrace(tensor, value); | ||||
515 | } | ||||
516 | } | ||||
517 | } | ||||
518 | } | ||||
519 | |||||
520 | PyObject* process_outputs(PyObject *op_obj, const std::shared_ptr<PyNode>& cdata, | ||||
521 | THPFunction* grad_fn, const UnpackedInput& unpacked, | ||||
522 | PyObject *inputs, THPObjectPtr&& raw_output, bool is_executable, | ||||
523 | torch::jit::Node* node) { | ||||
524 | bool unpack_output = ensure_tuple(raw_output); | ||||
525 | |||||
526 | auto num_outputs = PyTuple_GET_SIZE(raw_output.get())(((PyVarObject*)(((PyTupleObject *)(raw_output.get()))))-> ob_size); | ||||
527 | |||||
528 | THPObjectPtr outputs(PyTuple_New(num_outputs)); | ||||
529 | if (!outputs) throw python_error(); | ||||
530 | |||||
531 | cdata->clear_input_metadata(); | ||||
532 | |||||
533 | // Record type, device, and size information about inputs | ||||
534 | if (is_executable) { | ||||
535 | grad_fn->input_info.clear(); | ||||
536 | grad_fn->input_info.reserve(unpacked.input_vars.size()); | ||||
537 | for (auto& var : unpacked.input_vars) { | ||||
538 | grad_fn->input_info.emplace_back(var); | ||||
539 | } | ||||
540 | } | ||||
541 | |||||
542 | bool is_inplace = static_cast<bool>(grad_fn->dirty_tensors); | ||||
543 | _wrap_outputs(cdata, grad_fn, unpacked.input_vars, raw_output, outputs, is_executable); | ||||
544 | _trace_post_record(node, op_obj, unpacked.input_vars, outputs, is_inplace, unpack_output); | ||||
545 | if (is_executable) { | ||||
546 | _save_variables(cdata, grad_fn); | ||||
547 | } else { | ||||
548 | // Remove unnecessary attributes | ||||
549 | Py_XDECREF(grad_fn->to_save)_Py_XDECREF(((PyObject*)(grad_fn->to_save))); | ||||
550 | grad_fn->to_save = nullptr; | ||||
551 | Py_XDECREF(grad_fn->non_differentiable)_Py_XDECREF(((PyObject*)(grad_fn->non_differentiable))); | ||||
552 | grad_fn->non_differentiable = nullptr; | ||||
553 | } | ||||
554 | |||||
555 | // Unpack the output, unless .forward() returned a tuple | ||||
556 | if (unpack_output) { | ||||
557 | PyObject *output = PyTuple_GET_ITEM(outputs.get(), 0)(((PyTupleObject *)(outputs.get()))->ob_item[0]); | ||||
558 | Py_INCREF(output)_Py_INCREF(((PyObject*)(output))); | ||||
559 | return output; | ||||
560 | } | ||||
561 | |||||
562 | return outputs.release(); | ||||
563 | } | ||||
564 | |||||
565 | PyObject* THPFunction_name(PyObject *self, PyObject* noargs) { | ||||
566 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
567 | auto cdata = ((THPFunction*)self)->cdata.lock(); | ||||
568 | TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
569 | "Attribute 'name' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
570 | "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
571 | "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
572 | "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
573 | "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); }; | ||||
574 | return THPUtils_packString(cdata->name()); | ||||
575 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
576 | } | ||||
577 | |||||
578 | PyObject *THPFunction_apply(PyObject *cls, PyObject *inputs) | ||||
579 | { | ||||
580 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
581 | RECORD_FUNCTION(at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard .isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject *)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number ::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name , at::sequence_number::peek()); } } | ||||
582 | ((PyTypeObject*)cls)->tp_name,at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard .isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject *)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number ::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name , at::sequence_number::peek()); } } | ||||
583 | std::vector<c10::IValue>(),at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard .isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject *)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number ::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name , at::sequence_number::peek()); } } | ||||
584 | at::sequence_number::peek())at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard .isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject *)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number ::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name , at::sequence_number::peek()); } }; | ||||
585 | |||||
586 | THPObjectPtr backward_cls(PyObject_GetAttrString(cls, "_backward_cls")); | ||||
587 | if (!backward_cls) return nullptr; | ||||
588 | THPObjectPtr ctx_obj(PyObject_CallFunctionObjArgs(backward_cls, nullptr)); | ||||
589 | if (!ctx_obj) return nullptr; | ||||
590 | THPFunction* ctx = (THPFunction*)ctx_obj.get(); | ||||
591 | |||||
592 | auto cdata = std::shared_ptr<PyNode>(new PyNode(std::move(ctx_obj)), deleteNode); | ||||
593 | ctx->cdata = cdata; | ||||
594 | |||||
595 | // Prepare inputs and allocate context (grad fn) | ||||
596 | auto info_pair = unpack_input<false>(inputs); | ||||
597 | UnpackedInput& unpacked_input = info_pair.first; | ||||
598 | InputFlags& input_info = info_pair.second; | ||||
599 | |||||
600 | // Record input nodes if tracing | ||||
601 | auto* node = _trace_pre_record(cls, inputs, unpacked_input.input_vars); | ||||
602 | |||||
603 | // Initialize backward function (and ctx) | ||||
604 | bool is_executable = input_info.is_executable; | ||||
605 | cdata->set_next_edges(std::move(input_info.next_edges)); | ||||
606 | ctx->needs_input_grad = input_info.needs_input_grad.release(); | ||||
607 | ctx->is_variable_input = std::move(input_info.is_variable_input); | ||||
608 | |||||
609 | // Prepend ctx to input_tuple, in preparation for static method call | ||||
610 | auto num_args = PyTuple_GET_SIZE(inputs)(((PyVarObject*)(((PyTupleObject *)(inputs))))->ob_size); | ||||
611 | THPObjectPtr ctx_input_tuple(PyTuple_New(num_args + 1)); | ||||
612 | if (!ctx_input_tuple) return nullptr; | ||||
613 | Py_INCREF(ctx)_Py_INCREF(((PyObject*)(ctx))); | ||||
614 | PyTuple_SET_ITEM(ctx_input_tuple.get(), 0, (PyObject*)ctx)PyTuple_SetItem(ctx_input_tuple.get(), 0, (PyObject*)ctx); | ||||
615 | for (const auto i : c10::irange(num_args)) { | ||||
616 | PyObject *arg = PyTuple_GET_ITEM(unpacked_input.input_tuple.get(), i)(((PyTupleObject *)(unpacked_input.input_tuple.get()))->ob_item [i]); | ||||
617 | Py_INCREF(arg)_Py_INCREF(((PyObject*)(arg))); | ||||
618 | PyTuple_SET_ITEM(ctx_input_tuple.get(), i + 1, arg)PyTuple_SetItem(ctx_input_tuple.get(), i + 1, arg); | ||||
619 | } | ||||
620 | |||||
621 | // Call forward | ||||
622 | THPObjectPtr tensor_outputs; | ||||
623 | { | ||||
624 | AutoGradMode grad_mode(false); | ||||
625 | THPObjectPtr forward_fn(PyObject_GetAttrString(cls, "forward")); | ||||
626 | if (!forward_fn) return nullptr; | ||||
627 | tensor_outputs = PyObject_CallObject(forward_fn, ctx_input_tuple); | ||||
628 | if (!tensor_outputs) return nullptr; | ||||
629 | } | ||||
630 | |||||
631 | return process_outputs(cls, cdata, ctx, unpacked_input, inputs, std::move(tensor_outputs), | ||||
632 | is_executable, node); | ||||
633 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
634 | } | ||||
635 | |||||
636 | |||||
637 | //////////////////////////////////////////////////////////////////////////////// | ||||
638 | // Other methods / attributes | ||||
639 | //////////////////////////////////////////////////////////////////////////////// | ||||
640 | |||||
641 | PyObject* THPFunction__register_hook_dict(PyObject *_self, PyObject *_var) | ||||
642 | { | ||||
643 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
644 | THPUtils_assert(THPVariable_Check(_var), "_register_hook_dict expected a Tensor")if ((__builtin_expect((!(THPVariable_Check(_var))), (0)))) { THPUtils_setError ("_register_hook_dict expected a Tensor"); return nullptr; }; | ||||
645 | THPVariable* var = reinterpret_cast<THPVariable*>(_var); | ||||
646 | const auto& tensor = THPVariable_Unpack(var); | ||||
647 | std::unique_ptr<FunctionPreHook> hook(new PyFunctionPreHook( | ||||
648 | var->backward_hooks, tensor.output_nr())); | ||||
649 | auto self = (THPFunction*)_self; | ||||
650 | auto cdata = self->cdata.lock(); | ||||
651 | TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
652 | "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
653 | "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
654 | "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
655 | "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
656 | "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); }; | ||||
657 | cdata->add_pre_hook(std::move(hook)); | ||||
658 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | ||||
659 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
660 | } | ||||
661 | |||||
662 | PyObject* THPFunction_register_hook(PyObject *_self, PyObject *hook) | ||||
663 | { | ||||
664 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
665 | auto self= (THPFunction*)_self; | ||||
666 | auto cdata = self->cdata.lock(); | ||||
667 | TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
668 | "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
669 | "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
670 | "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
671 | "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
672 | "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); }; | ||||
673 | return torch::autograd::registerFunctionHook(*cdata, hook); | ||||
674 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
675 | } | ||||
676 | |||||
677 | int THPFunction_set_materialize_grads(THPFunction *self, PyObject *value, void *unused) | ||||
678 | { | ||||
679 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
680 | if (!PyBool_Check(value)((((PyObject*)(value))->ob_type) == &PyBool_Type)) { | ||||
681 | THPUtils_invalidArguments(value, nullptr, "set_materialize_grads", 1, "(bool)"); | ||||
682 | return -1; | ||||
683 | } | ||||
684 | self->materialize_grads = (value == Py_True((PyObject *) &_Py_TrueStruct)); | ||||
685 | return 0; | ||||
686 | END_HANDLE_TH_ERRORS_RET(-1)} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return -1; } catch (const c10::IndexError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_IndexError , torch::processErrorMsg(msg)); return -1; } catch (const c10 ::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return -1; } catch (const c10 ::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return -1; } catch (const c10 ::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return -1; } catch (const c10 ::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return -1; } catch (torch::PyTorchError & e) { auto msg = torch::processErrorMsg(e.what()); PyErr_SetString (e.python_type(), msg); return -1; } catch (const std::exception & e) { auto msg = torch::processErrorMsg(e.what()); PyErr_SetString (PyExc_RuntimeError, msg); return -1; } | ||||
687 | } | ||||
688 | |||||
689 | static PyObject *unpack_saved_variables( | ||||
690 | THPFunction *self, | ||||
691 | const std::function<PyObject*(const Variable&)>& unpack_fn) | ||||
692 | { | ||||
693 | THPUtils_assert(!self->has_freed_buffers, ERR_BACKWARD_TWICE)if ((__builtin_expect((!(!self->has_freed_buffers)), (0))) ) { THPUtils_setError(ERR_BACKWARD_TWICE); return nullptr; }; | ||||
694 | auto& saved_variables = self->saved_variables; | ||||
695 | if (saved_variables.empty()) | ||||
696 | return PyTuple_New(0); | ||||
697 | |||||
698 | int num_saved = saved_variables.size(); | ||||
699 | THPObjectPtr saved(PyTuple_New(num_saved)); | ||||
700 | if (!saved) | ||||
701 | return nullptr; | ||||
702 | auto saved_for = self->cdata.lock(); | ||||
703 | // This is really a true assert, because we've already tested for the | ||||
704 | // self->has_freed_buffers case at the beginning of this function: | ||||
705 | // buffers are freed when PyNode dies; if the buffers are not freed, | ||||
706 | // PyNode must be live. (Note that the buffers could be freed | ||||
707 | // even though the PyNode is live, but that doesn't matter here | ||||
708 | // because we will never hit this line of code if the buffers are freed-- | ||||
709 | // and in any case saved_for will be non-NULL.) | ||||
710 | TORCH_INTERNAL_ASSERT(saved_for)if ((__builtin_expect(static_cast<bool>(!(saved_for)), 0 ))) { ::c10::detail::torchInternalAssertFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(710), "saved_for" "INTERNAL ASSERT FAILED at " "\"../torch/csrc/autograd/python_function.cpp\"" ":" "710" ", please report a bug to PyTorch. " , c10::str()); }; | ||||
711 | for(const auto i : c10::irange(num_saved)) { | ||||
712 | auto unpacked_var = saved_variables[i].unpack(saved_for); | ||||
713 | THPObjectPtr value; | ||||
714 | if (!unpacked_var.defined()) { | ||||
715 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | ||||
716 | value = Py_None(&_Py_NoneStruct); | ||||
717 | } else { | ||||
718 | value = unpack_fn(unpacked_var); | ||||
719 | } | ||||
720 | PyTuple_SET_ITEM(saved.get(), i, value.release())PyTuple_SetItem(saved.get(), i, value.release()); | ||||
721 | } | ||||
722 | return saved.release(); | ||||
723 | } | ||||
724 | |||||
725 | PyObject *THPFunction_saved_tensors(THPFunction *self, void *_unused) | ||||
726 | { | ||||
727 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
728 | return unpack_saved_variables(self, [](const Variable& var) { | ||||
729 | return THPVariable_Wrap(var); | ||||
730 | }); | ||||
731 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
732 | } | ||||
733 | |||||
734 | PyObject *THPFunction_saved_variables(THPFunction *self, void *_unused) | ||||
735 | { | ||||
736 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
737 | auto r = PyErr_WarnEx(PyExc_DeprecationWarning, | ||||
738 | "'saved_variables' is deprecated; use 'saved_tensors'", 0); | ||||
739 | if (r != 0) throw python_error(); | ||||
740 | return unpack_saved_variables(self, [](const Variable& var) { | ||||
741 | return THPVariable_Wrap(var); | ||||
742 | }); | ||||
743 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
744 | } | ||||
745 | |||||
746 | PyObject *THPFunction_next_functions(THPFunction *self, void *_unused) | ||||
747 | { | ||||
748 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
749 | auto cdata = self->cdata.lock(); | ||||
750 | TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
751 | "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
752 | "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
753 | "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
754 | "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); } | ||||
755 | "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. " "Accessing this attribute directly on an instance of autograd.Function is a legacy " "access pattern that is no longer supported. For examples on how to use new-style " "autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function " ))); }; | ||||
756 | const auto num_outputs = cdata->num_outputs(); | ||||
757 | THPObjectPtr result(PyTuple_New(num_outputs)); | ||||
758 | if (!result) | ||||
759 | return nullptr; | ||||
760 | for (const auto i : c10::irange(num_outputs)) { | ||||
761 | THPObjectPtr fn_tuple(PyTuple_New(2)); | ||||
762 | if (!fn_tuple) return nullptr; | ||||
763 | const auto& edge = cdata->next_edge(i); | ||||
764 | PyObject* fn = functionToPyObject(edge.function); | ||||
765 | if (!fn) return nullptr; | ||||
766 | PyTuple_SET_ITEM(fn_tuple.get(), 0, fn)PyTuple_SetItem(fn_tuple.get(), 0, fn); | ||||
767 | PyTuple_SET_ITEM(fn_tuple.get(), 1, THPUtils_packInt64(edge.input_nr))PyTuple_SetItem(fn_tuple.get(), 1, THPUtils_packInt64(edge.input_nr )); | ||||
768 | PyTuple_SET_ITEM(result.get(), i, fn_tuple.release())PyTuple_SetItem(result.get(), i, fn_tuple.release()); | ||||
769 | } | ||||
770 | return result.release(); | ||||
771 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
772 | } | ||||
773 | |||||
774 | PyObject *THPFunction_metadata(THPFunction *self, void *_unused) | ||||
775 | { | ||||
776 | HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try { | ||||
777 | auto cdata = self->cdata.lock(); | ||||
778 | // The correct way to solve this problem is to stop exposing grad_fn | ||||
779 | // of PyFunctions as THPFunction; instead, we should use THPCppFunction | ||||
780 | // like everyone else. But this is a BC-breaking change as it would | ||||
781 | // mean that you no longer get the property that grad_fn is a subclass | ||||
782 | // of the autograd function class that you defined in the custom case, | ||||
783 | // so I didn't fix it here. | ||||
784 | TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
785 | "You attempted to access the anomaly metadata of a custom autograd function "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
786 | "but the underlying PyNode has already been deallocated. The most likely "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
787 | "reason this occurred is because you assigned x.grad_fn to a local variable "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
788 | "and then let the original variable get deallocated. Don't do that! If "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
789 | "you really have no way of restructuring your code so this is the case, "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); } | ||||
790 | "please file an issue reporting that you are affected by this.")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0))) { ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp" , static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl ( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, " "please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function " "but the underlying PyNode has already been deallocated. The most likely " "reason this occurred is because you assigned x.grad_fn to a local variable " "and then let the original variable get deallocated. Don't do that! If " "you really have no way of restructuring your code so this is the case, " "please file an issue reporting that you are affected by this." ))); }; | ||||
791 | auto metadata = static_cast<PyAnomalyMetadata*>(cdata->metadata())->dict(); | ||||
792 | |||||
793 | Py_INCREF(metadata)_Py_INCREF(((PyObject*)(metadata))); | ||||
794 | return metadata; | ||||
795 | END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw ; } } catch (python_error & e) { e.restore(); return nullptr ; } catch (const c10::IndexError& e) { auto msg = torch:: get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace (); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg( msg)); return nullptr; } catch (const c10::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError , torch::processErrorMsg(msg)); return nullptr; } catch (const c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled () ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError , torch::processErrorMsg(msg)); return nullptr; } catch (torch ::PyTorchError & e) { auto msg = torch::processErrorMsg(e .what()); PyErr_SetString(e.python_type(), msg); return nullptr ; } catch (const std::exception& e) { auto msg = torch::processErrorMsg (e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr ; } | ||||
796 | } | ||||
797 | |||||
798 | typedef PyObject *(*getter)(PyObject *, void *); | ||||
799 | typedef int (*setter)(PyObject *, PyObject *, void *); | ||||
800 | |||||
801 | namespace { | ||||
802 | |||||
803 | template<PyObject* THPFunction::*ptr> | ||||
804 | PyObject* getObject(PyObject* obj, void* _unused) { | ||||
805 | auto self = (THPFunction*)obj; | ||||
806 | PyObject* value = self->*ptr; | ||||
807 | if (!value) { | ||||
808 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | ||||
809 | } | ||||
810 | Py_INCREF(value)_Py_INCREF(((PyObject*)(value))); | ||||
811 | return value; | ||||
812 | } | ||||
813 | |||||
814 | template<PyObject* THPFunction::*ptr> | ||||
815 | int setObject(PyObject* obj, PyObject* value, void* _unused) { | ||||
816 | auto self = (THPFunction*)obj; | ||||
817 | if (value == Py_None(&_Py_NoneStruct)) { | ||||
818 | value = nullptr; | ||||
819 | } | ||||
820 | Py_XDECREF((self->*ptr))_Py_XDECREF(((PyObject*)((self->*ptr)))); | ||||
821 | Py_XINCREF(value)_Py_XINCREF(((PyObject*)(value))); | ||||
822 | self->*ptr = value; | ||||
823 | return 0; | ||||
824 | } | ||||
825 | |||||
826 | template<typename M, M THPFunction::*ptr, PyObject* (*Convert)(long)> | ||||
827 | PyObject* getMember(PyObject* obj, void* _unused) { | ||||
828 | auto self = (THPFunction*)obj; | ||||
829 | return Convert(self->*ptr); | ||||
830 | } | ||||
831 | |||||
832 | template<typename M, M autograd::Node::*ptr, PyObject* (*Convert)(long)> | ||||
833 | PyObject* getImplMember(PyObject* obj, void* _unused) { | ||||
834 | auto self = (THPFunction*)obj; | ||||
835 | return Convert(self->cdata.*ptr); | ||||
836 | } | ||||
837 | |||||
838 | PyObject* getRequiresGrad(PyObject* obj, void* _unused) { | ||||
839 | Py_RETURN_TRUEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct )))), ((PyObject *) &_Py_TrueStruct); | ||||
840 | } | ||||
841 | |||||
842 | } | ||||
843 | |||||
844 | // NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-non-const-global-variables) | ||||
845 | static struct PyGetSetDef THPFunction_properties[] = { | ||||
846 | {"saved_tensors", (getter)THPFunction_saved_tensors, nullptr, nullptr, nullptr}, | ||||
847 | {"saved_variables", (getter)THPFunction_saved_variables, nullptr, nullptr, nullptr}, | ||||
848 | {"next_functions", (getter)THPFunction_next_functions, nullptr, nullptr, nullptr}, | ||||
849 | {"to_save", &getObject<&THPFunction::to_save>, &setObject<&THPFunction::to_save>, nullptr, nullptr}, | ||||
850 | {"non_differentiable", &getObject<&THPFunction::non_differentiable>, &setObject<&THPFunction::non_differentiable>, nullptr, nullptr}, | ||||
851 | {"dirty_tensors", &getObject<&THPFunction::dirty_tensors>, &setObject<&THPFunction::dirty_tensors>, nullptr, nullptr}, | ||||
852 | {"needs_input_grad", &getObject<&THPFunction::needs_input_grad>, nullptr, nullptr, nullptr}, | ||||
853 | {"requires_grad", getRequiresGrad, nullptr, nullptr, nullptr}, | ||||
854 | {"metadata", (getter)THPFunction_metadata, nullptr, nullptr, nullptr}, | ||||
855 | {"materialize_grads", nullptr, (setter)THPFunction_set_materialize_grads, nullptr, nullptr}, | ||||
856 | {nullptr} | ||||
857 | }; | ||||
858 | |||||
859 | // NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-non-const-global-variables) | ||||
860 | static struct PyMethodDef THPFunction_methods[] = { | ||||
861 | {(char*)"name", THPFunction_name, METH_NOARGS0x0004, nullptr}, | ||||
862 | {(char*)"apply", THPFunction_apply, METH_CLASS0x0010 | METH_VARARGS0x0001, nullptr}, | ||||
863 | {(char*)"_register_hook_dict", THPFunction__register_hook_dict, METH_O0x0008, nullptr}, | ||||
864 | {(char*)"register_hook", THPFunction_register_hook, METH_O0x0008, nullptr}, | ||||
865 | {nullptr} | ||||
866 | }; | ||||
867 | |||||
868 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||
869 | PyTypeObject THPFunctionType = { | ||||
870 | PyVarObject_HEAD_INIT(nullptr, 0){ { 1, nullptr }, 0 }, | ||||
871 | "torch._C._FunctionBase", /* tp_name */ | ||||
872 | sizeof(THPFunction), /* tp_basicsize */ | ||||
873 | 0, /* tp_itemsize */ | ||||
874 | (destructor)THPFunction_dealloc, /* tp_dealloc */ | ||||
875 | // NOLINTNEXTLINE(modernize-use-nullptr) | ||||
876 | 0, /* tp_vectorcall_offset */ | ||||
877 | nullptr, /* tp_getattr */ | ||||
878 | nullptr, /* tp_setattr */ | ||||
879 | nullptr, /* tp_reserved */ | ||||
880 | nullptr, /* tp_repr */ | ||||
881 | nullptr, /* tp_as_number */ | ||||
882 | nullptr, /* tp_as_sequence */ | ||||
883 | nullptr, /* tp_as_mapping */ | ||||
884 | nullptr, /* tp_hash */ | ||||
885 | nullptr, /* tp_call */ | ||||
886 | nullptr, /* tp_str */ | ||||
887 | nullptr, /* tp_getattro */ | ||||
888 | nullptr, /* tp_setattro */ | ||||
889 | nullptr, /* tp_as_buffer */ | ||||
890 | Py_TPFLAGS_DEFAULT( 0 | (1UL << 18) | 0) | Py_TPFLAGS_BASETYPE(1UL << 10) | Py_TPFLAGS_HAVE_GC(1UL << 14), /* tp_flags */ | ||||
891 | nullptr, /* tp_doc */ | ||||
892 | (traverseproc)THPFunction_traverse, /* tp_traverse */ | ||||
893 | (inquiry)THPFunction_clear, /* tp_clear */ | ||||
894 | nullptr, /* tp_richcompare */ | ||||
895 | 0, /* tp_weaklistoffset */ | ||||
896 | nullptr, /* tp_iter */ | ||||
897 | nullptr, /* tp_iternext */ | ||||
898 | THPFunction_methods, /* tp_methods */ | ||||
899 | nullptr, /* tp_members */ | ||||
900 | THPFunction_properties, /* tp_getset */ | ||||
901 | nullptr, /* tp_base */ | ||||
902 | nullptr, /* tp_dict */ | ||||
903 | nullptr, /* tp_descr_get */ | ||||
904 | nullptr, /* tp_descr_set */ | ||||
905 | 0, /* tp_dictoffset */ | ||||
906 | nullptr, /* tp_init */ | ||||
907 | nullptr, /* tp_alloc */ | ||||
908 | THPFunction_new /* tp_new */ | ||||
909 | }; | ||||
910 | |||||
911 | bool THPFunction_initModule(PyObject *module) | ||||
912 | { | ||||
913 | if (PyType_Ready(&THPFunctionType) < 0) | ||||
914 | return false; | ||||
915 | Py_INCREF(&THPFunctionType)_Py_INCREF(((PyObject*)(&THPFunctionType))); | ||||
916 | PyModule_AddObject(module, "_FunctionBase", (PyObject *)&THPFunctionType); | ||||
917 | return true; | ||||
918 | } |
1 | #ifndef PyTuple_GetSlice |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyTuple_GetSlice is defined as a macro." |
10 | #endif |