You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -241,15 +278,74 @@ matters (importing in the wrong order will lead to an error).
241
278
242
279
To use the custom operator with hybrid Python/C++ registrations, we must
243
280
first load the C++ library that holds the custom operator definition
244
-
and then call the ``torch.library`` registration APIs. This can happen in one
245
-
of two ways:
281
+
and then call the ``torch.library`` registration APIs. This can happen in
282
+
three ways:
283
+
284
+
285
+
1. The first way to load the C++ library that holds the custom operator definition
286
+
is to define a dummy Python module for _C. Then, in Python, when you import the
287
+
module with ``import _C``, the ``.so``s corresponding to the extension will be
288
+
loaded and the ``TORCH_LIBRARY`` and ``TORCH_LIBRARY_IMPL`` static initializers
289
+
will run. One can create a dummy Python module with ``PYBIND11_MODULE`` like below,
290
+
but you will notice that this does not compile with ``Py_LIMITED_API``, because
291
+
``pybind11`` does not promise to only use the stable limited CPython API! With
292
+
the below code, you sadly cannot build a CPython agnostic wheel for your extension!
293
+
(Foreshadowing: I wonder what the second way is ;)).
294
+
295
+
.. code-block:: cpp
296
+
// in, say, not_agnostic/csrc/extension_BAD.cpp
297
+
#include <pybind11/pybind11.h>
246
298
299
+
PYBIND11_MODULE("_C", m) {}
247
300
248
-
1. In this tutorial, our C++ custom operator is located in a shared library object,
249
-
and we use ``torch.ops.load_library("/path/to/library.so")`` to load it. This
250
-
is the blessed path for Python agnosticism, and you will not have a Python C
251
-
extension module to import. See our `extension_cpp/__init__.py <https://github.com/pytorch/extension-cpp/blob/e4c4eb822889ea67f191071fa627d750e04bf047/extension_cpp/__init__.py>`_
252
-
for an example:
301
+
.. code-block:: python
302
+
303
+
# in, say, extension/__init__.py
304
+
from . import _C
305
+
306
+
2. In this tutorial, because we value being able to build a single wheel across multiple
307
+
CPython versions, we will replace the unstable ``PYBIND11`` call with stable API calls.
308
+
The below code compiles with ``-DPy_LIMITED_API=0x03090000`` and successfully creates
309
+
a dummy Python module for our ``_C`` extension so that it can be imported from Python.
310
+
See `extension_cpp/__init__.py <https://github.com/pytorch/extension-cpp/blob/master/extension_cpp/__init__.py>`_
311
+
and `extension_cpp/csrc/muladd.cpp <https://github.com/pytorch/extension-cpp/blob/master/extension_cpp/csrc/muladd.cpp>`_
312
+
for more details:
313
+
314
+
.. code-block:: cpp
315
+
#include <Python.h>
316
+
317
+
extern "C" {
318
+
/* Creates a dummy empty _C module that can be imported from Python.
319
+
The import from Python will load the .so consisting of this file
320
+
in this extension, so that the TORCH_LIBRARY static initializers
321
+
below are run. */
322
+
PyObject* PyInit__C(void)
323
+
{
324
+
static struct PyModuleDef module_def = {
325
+
PyModuleDef_HEAD_INIT,
326
+
"_C", /* name of module */
327
+
NULL, /* module documentation, may be NULL */
328
+
-1, /* size of per-interpreter state of the module,
329
+
or -1 if the module keeps state in global variables. */
330
+
NULL, /* methods */
331
+
};
332
+
return PyModule_Create(&module_def);
333
+
}
334
+
}
335
+
336
+
.. code-block:: python
337
+
338
+
# in, say, extension/__init__.py
339
+
from . import _C
340
+
341
+
3. If you want to avoid ``Python.h`` entirely in your C++ custom operator, you may
342
+
use ``torch.ops.load_library("/path/to/library.so")`` in Python to load the ``.so``
343
+
file(s) compiled from the extension. Note that, with this method, there is no ``_C``
344
+
Python module created for the extension so you cannot call ``import _C`` from Python.
345
+
Instead of relying on the import statement to trigger the custom operators to be
346
+
registered, ``torch.ops.load_library("/path/to/library.so")`` will do the trick.
347
+
The challenge then is shifted towards understanding where the ``.so`` files are
348
+
located so that you can load them, which is not always trivial:
253
349
254
350
.. code-block:: python
255
351
@@ -265,22 +361,6 @@ of two ways:
265
361
from . import ops
266
362
267
363
268
-
2. You may also see other custom extensions importing the Python C extension module.
269
-
The module would be created in C++ and then imported in Python, like the code below.
270
-
This code is not guaranteed to use the stable limited CPython API and would block
271
-
your extension from building a Python-agnostic wheel! AVOID the following:
272
-
273
-
.. code-block:: cpp
274
-
275
-
// in, say, not_agnostic/csrc/extension_BAD.cpp
276
-
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {}
277
-
278
-
.. code-block:: python
279
-
280
-
# in, say, extension_BAD/__init__.py
281
-
from . import _C
282
-
283
-
284
364
Adding training (autograd) support for an operator
0 commit comments