| #include <Python.h> |
| #include <c10/util/irange.h> |
| #include <torch/csrc/autograd/functions/accumulate_grad.h> |
| #include <torch/csrc/autograd/functions/basic_ops.h> |
| #include <torch/csrc/autograd/functions/pybind.h> |
| #include <torch/csrc/autograd/functions/tensor.h> |
| #include <torch/csrc/autograd/generated/python_functions.h> |
| #include <torch/csrc/autograd/python_cpp_function.h> |
| #include <torch/csrc/autograd/python_variable.h> |
| #ifdef USE_DISTRIBUTED |
| #include <torch/csrc/distributed/autograd/functions/sendrpc_backward.h> |
| #endif |
| #include <torch/csrc/jit/python/python_tracer.h> |
| #include <torch/csrc/utils/pybind.h> |
| #include <torch/csrc/utils/python_numbers.h> |
| #include <torch/csrc/utils/python_strings.h> |
| |
| #include <utility> |
| |
| using namespace torch::autograd; |
| |
| struct DelayedErrorCtor { |
| DelayedError* operator()(PyObject* args) { |
| TORCH_CHECK( |
| PyTuple_GET_SIZE(args) == 2, |
| "Requires two arguments, got ", |
| PyTuple_GET_SIZE(args)); |
| auto arg1 = PyTuple_GET_ITEM(args, 0); |
| TORCH_CHECK(THPUtils_checkString(arg1), "argument 'msg' must be a string"); |
| std::string msg = THPUtils_unpackString(arg1); |
| auto arg2 = PyTuple_GET_ITEM(args, 1); |
| TORCH_CHECK( |
| THPUtils_checkLong(arg2), "argument 'num_inputs' must be an int"); |
| int num_inputs = THPUtils_unpackLong(arg2); |
| return new DelayedError(std::move(msg), num_inputs); |
| } |
| }; |
| |
| struct UndefinedGradCtor { |
| UndefinedGrad* operator()(PyObject* args) { |
| TORCH_CHECK( |
| PyTuple_GET_SIZE(args) == 0, |
| "Requires zero arguments, got ", |
| PyTuple_GET_SIZE(args)); |
| return new UndefinedGrad(); |
| } |
| }; |
| |
| struct NoCtor { |
| Node* operator()(PyObject* args) { |
| throw std::runtime_error("Cannot construct"); |
| } |
| }; |
| |
| template <typename C, typename T> |
| static void addClass( |
| PyObject* module, |
| PyTypeObject& type, |
| const char* name, |
| PyGetSetDef* function_properties = nullptr, |
| PyMethodDef* function_methods = nullptr) { |
| createForwardFunctionPyTypeObject<T>( |
| type, name, function_properties, function_methods); |
| Py_INCREF(&type); |
| PyModule_AddObject(module, name, (PyObject*)&type); |
| registerCppFunction(typeid(C), &type); |
| } |
| |
| template < |
| typename T, |
| typename ValueT, |
| typename ParamsT, |
| ValueT ParamsT::*ptr, |
| typename ConvertArgT, |
| PyObject* (*Convert)(ConvertArgT)> |
| PyObject* getTupleAttr(PyObject* obj, void* _unused) { |
| HANDLE_TH_ERRORS |
| THPCppFunction* self = (THPCppFunction*)obj; |
| auto& arr = ((T*)(self->cdata.get()))->*ptr; |
| auto num_elems = arr.size(); |
| THPObjectPtr py_tuple(PyTuple_New(num_elems)); |
| if (!py_tuple) |
| return nullptr; |
| for (const auto i : c10::irange(num_elems)) { |
| PyTuple_SET_ITEM(py_tuple.get(), i, Convert(arr[i])); |
| } |
| return py_tuple.release(); |
| END_HANDLE_TH_ERRORS |
| } |
| |
| template < |
| typename T, |
| typename ValueT, |
| typename ParamsT, |
| ValueT ParamsT::*ptr, |
| typename ConvertArgT, |
| PyObject* (*Convert)(ConvertArgT)> |
| PyObject* getValueAttr(PyObject* obj, void* _unused) { |
| HANDLE_TH_ERRORS |
| THPCppFunction* self = (THPCppFunction*)obj; |
| auto& val = ((T*)(self->cdata.get()))->*ptr; |
| return Convert(val); |
| END_HANDLE_TH_ERRORS |
| } |
| |
| static PyObject* accumulateGradVar(PyObject* _self, void* _unused) { |
| THPCppFunction* self = (THPCppFunction*)_self; |
| auto grad_acc = (AccumulateGrad*)self->cdata.get(); |
| return THPVariable_Wrap(grad_acc->variable); |
| } |
| |
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) |
| static struct PyGetSetDef accumulate_grad_properties[] = { |
| THP_FUNCTION_DEFAULT_PROPERTIES, |
| {(char*)"variable", accumulateGradVar, nullptr, nullptr, nullptr}, |
| {nullptr}}; |
| |
| void THPAutograd_initFunctions() { |
| THPObjectPtr module(PyModule_New("torch._C._functions")); |
| if (!module) |
| throw python_error(); |
| |
| static PyTypeObject AccumulateGradClass; |
| addClass<AccumulateGrad, NoCtor>( |
| module, |
| AccumulateGradClass, |
| "AccumulateGrad", |
| accumulate_grad_properties); |
| |
| static PyTypeObject ErrorClass; |
| addClass<Error, NoCtor>(module, ErrorClass, "Error"); |
| |
| static PyTypeObject NotImplementedClass; |
| addClass<NotImplemented, NoCtor>( |
| module, NotImplementedClass, "NotImplemented"); |
| |
| static PyTypeObject DelayedErrorClass; |
| addClass<DelayedError, DelayedErrorCtor>( |
| module, DelayedErrorClass, "DelayedError"); |
| |
| static PyTypeObject UndefinedGradBackwardClass; |
| addClass<UndefinedGradBackward, NoCtor>( |
| module, UndefinedGradBackwardClass, "UndefinedGradBackward"); |
| |
| static PyTypeObject UndefinedGradClass; |
| addClass<UndefinedGrad, UndefinedGradCtor>( |
| module, UndefinedGradClass, "UndefinedGrad"); |
| |
| static PyTypeObject CopyBackwardsClass; |
| addClass<CopyBackwards, NoCtor>(module, CopyBackwardsClass, "CopyBackwards"); |
| |
| #ifdef USE_DISTRIBUTED |
| static PyTypeObject SendRpcBackwardClass; |
| addClass<torch::distributed::autograd::SendRpcBackward, NoCtor>( |
| module, SendRpcBackwardClass, "SendRpcBackward"); |
| #endif |
| |
| static PyTypeObject CopySlicesClass; |
| addClass<CopySlices, NoCtor>(module, CopySlicesClass, "CopySlices"); |
| |
| generated::initialize_autogenerated_functions(module); |
| |
| auto c_module = THPObjectPtr(PyImport_ImportModule("torch._C")); |
| if (!c_module) |
| throw python_error(); |
| |
| Py_INCREF(module.get()); |
| if (PyModule_AddObject(c_module, "_functions", module) < 0) { |
| Py_DECREF(module.get()); |
| throw python_error(); |
| } |
| } |