How to pybind FloatC and FloatD
Closed this issue · 17 comments
I am rendering a gradient image using enoki CUDA array. Is there any suggestion on how to store the c++ cuda array FloatC and FloatD (or vector) into python so I can call backward in python for optimization? I didn't see there is a binding for that in enoki/python.h
You can compile extensive Python bindings for both, including automatic convertion to PyTorch/NumPy. See the 'refactor' branch which contains considerable additional work to this end. The enoki/python.h
file is only applicable to simple CPU-only arrays.
In particular, look at ENOKI_CUDA, ENOKI_AUTODIFF, and ENOKI_PYTHON in CMake.
File "", line 1, in
TypeError: Unable to convert function return value to a Python type! The signature was
(self: xxxx.Render) -> enoki::DiffArray<enoki::CUDAArray >
the c++ code is something like this...
struct Render {
FloatD m_bitmap_d;
Render();
FloatD &run();
const FloatD &run() const { return m_bitmap_d; }
void config_print();
~Render() {};
};
Right. You'll need to load the Enoki python module so that its return value converter knows what to do with these types. So simply run import enoki
in your Python code before calling Render::run
. Let me say again that you will probably get a lot more out of the bindings in the refactor
branch of Enoki. For that branch, you will need to run import enoki.cuda_autodiff
.
And FWIW what enoki/python.h
does is to convert C++ Enoki types into corresponding Python types (NumPy arrays) by copying them. That's not really a good way of interfacing between C++ <-> Python when a GPU is involved and the arrays are potentially very big.
You can also take a look at the following list:
https://pybind11.readthedocs.io/en/stable/advanced/cast/index.html.
The header enoki/python.h
corresponds to variant #3, and in Mitsuba 2 and Enoki's refactor
branch we have now completely switched over to variant #1 for doing conversions.
I tried these code and the problem still occur...
C++:
NAMESPACE_BEGIN(xxxx)
struct Render {
Render();
FloatC run(); // return a FloatC
~Render() {};
};
NAMESPACE_END(xxxx)
// pybind
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/complex.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <enoki/python.h>
#include <enoki/stl.h>
#include <enoki/cuda.h>
#include <enoki/autodiff.h>
...
pybind11::class_xxxx::Render(m, "Render")
.def(pybind11::init<>())
.def("run", &xxxx::Render::run);
Python:
import enoki
import xxxx
r = xxxx.Render()
r.run()
TypeError: Unable to convert function return value to a Python type! The signature was
(self: xxxx.Render) -> enoki::CUDAArray
Issue 1: You are likely compiling Enoki & your own project with different compilers (G++ vs Clang, or different versions of them). In this case, pybind11 keeps classes in different namespaces to prevent ABI incompatibilities.
Issue 2: Can you try again with the latest refactor branch?
Can you give Clang a try?
sudo apt install clang-9 lldb-9 clang-tools-9 clang clangd lldb clang-tools \
libc++abi1-9 libc++abi-9-dev libc++1-9 libc++-9-dev \
I fixed the GCC issue you reported just now. Generally, I would still recommend using Clang. I've run into so many issues with miscompilations with GCC in the last 2 years that I have completely lost trust in it.
ok, also should i write pybind11::module::import("enoki"); in my c++ code?
Yes, that's probably a good idea.
So just to clarify: you can compile Enoki including its Python bindings using both GCC and Clang? But returning a CUDAArray<float>
from pybind11-bound code does not work?
IMO there are only two possibilities for this:
-
Your project and Enoki were compiled with different settings. You have to be careful about the following: use the same version of Clang or GCC. Second (important!) use the same C++ standard library. When compiling Enoki with clang, it uses -stdlib=libc++, which means that your project also has to use -stdlib=libc++.
-
You did not import the Enoki python module that contains the type you are using. Note that there was a change here for the
refactor
branch: onmaster
, it is enough to writeimport enoki
. On therefactor
branch, you need to write:import enoki.autodiff_cuda
(or cuda_autodiff, I don't remember). Note that all the mathematical functions remain inenoki
, so one would typically do computations as follows:
from enoki.autodiff_cuda import Float32, UInt32, ...
import enoki as ek
x = ek.linspace(Float32, -1, 1, 100)
y = ek.select(x > 0, ek.asin(x), ek.acos(x))
...
Thanks, it works