-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
register c++ half-precision floating point as numpy.float16 #1776
Comments
I'm not sure what your above code would do if it were just focusing on From looking at the question marks in your repro, I think what you need is to tell your C++ translation unit about Example specialization for pybind11/include/pybind11/numpy.h Line 1026 in 9bb3313
It's not succinctly documented, but I think you just need to define |
I also work with fp16 in my C++ libraries but I have to wrote a lot of lambda functions (for getter/setter from/to fp32 conversion for example)... |
Can you post a link to your code that requires conversions to/from fp32? And have you tried implementing the |
I can post a code if it's really needed but it can be confusing due to the architecture... But the idea is MyClass has a function myClassHalf.def(
"set_arg"
[](MyClass<half> &myclass, std::vector<float> &arr ) {
std::vector<half> new_arg(arr.size());
std::copy(arr.begin(), arr.end(), new_arg.begin());
myclass.set_arg(new_arg);
},
py::arg("arr")
); It's not elegant but it works. I didn't try the |
Aye, yeah, your manual inline type caster will do the trick for ya if you're on a tight deadline. Another alternative, that's somewhere between your inline workaround and the While the examples there use the direct Python C API, you could instead use Here's a quick 3-min hack that might address your usage (though I haven't tested it): namespace pybind11 { namespace detail {
template <> struct type_caster<half> {
public:
PYBIND11_TYPE_CASTER(half, _("half"));
using float_caster = type_caster<float>;
bool load(handle src, bool convert) {
float_caster caster;
if (caster.load(src, convert)) {
this->value = half(float(caster)); // Implicit cast defined by `type_caster`.
return true;
}
return false;
}
static handle cast(half src, return_value_policy policy, handle parent) {
return float_caster::cast(float(src), policy, parent);
}
};
}} // namespace pybind11::detail Then you can just directly bind any APIs that use myClassHalf.def("set_arg", &MyClass<half>::set_arg, py::arg("arr")); |
Actually, got curious / overly invested, made a solution that should work for you in #1785: |
Thanks for your help, it's really appreciated. I will try it in the next days |
Welcome! And, er, brain fart: The solution related to #1785 would only work if you successfully register |
@eacousineau Thanks a lot. However with #include <pybind11/pybind11.h>
#include <half.h>
using half = half_float::half;
namespace pybind11 { namespace detail {
template <> struct type_caster<half> {
public:
PYBIND11_TYPE_CASTER(half, _("half"));
using float_caster = type_caster<float>;
bool load(handle src, bool convert) {
float_caster caster;
if (caster.load(src, convert)) {
this->value = half(float(caster)); // Implicit cast defined by `type_caster`.
return true;
}
return false;
}
static handle cast(half src, return_value_policy policy, handle parent) {
return float_caster::cast(float(src), policy, parent);
}
};
}} // namespace pybind11::detail
PYBIND11_MODULE(bind_half_np_pybind, m) {
m.def("overload", [](float16 x) { return "float16"; });
} py-side >>> from bind_half_np_pybind import overload
>>> overload(np.float16(1.0))
u'float16'
>>> overload(np.int(1))
u'float16'
>>> overload(np.float64(1.0))
u'float16' That's not the exact same thing what we want.
Another working on your test code. Same error |
That's the whole point of it being a short-term workaround ;) It's not terribly efficient.
Er, I have no idea what you actually want... Can you post what you expect the output to be? You've only provided one C++ overload, so you'll only get one type. Do you want it to overload for multiple types? (If so, why?)
You've convinced me to do it for ya :P (just because the NumPy stuff is a bit esoteric haha). Here's the working code: Related header for |
@eacousineau Thanks so much. you save my life. Another question with refactoring ur code Code. m.def("make_array", []() {
py::array_t<float16> x{2};
x.mutable_at(0) = float16{1.};
x.mutable_at(1) = float16{10.};
return x;
});
m.def("make_scalar", []() { return float16{2.}; });
m.def("return_array", [](py::array_t<float16> x, int sz) {
py::buffer_info buf = x.request();
float16 *ptr = (float16 *)buf.ptr;
for (int i = 0; i < sz; ++i) {
ptr[i] += (float16)(i);
}
});
m.def("return_array", [](py::array_t<float> x, int sz) {
py::buffer_info buf = x.request();
float *ptr = (float *)buf.ptr;
for (int i = 0; i < sz; ++i) {
ptr[i] *= (float)(i);
}
}); in py-side >>> import numpy as np
>>> a = np.array([1.0, 2.0, 3.0], dtype=np.float16)
>>> b = np.array([1.0, 2.0, 3.0], dtype=np.float32)
>>> c = np.array([1, 2, 3], dtype=np.int)
>>> d = np.array(['x', 'b'])
>>>
>>> return_array(a, a.size)
array([1., 3., 5.], dtype=float16) # the right
>>> return_array(b, b.size)
array([0., 2., 6.], dtype=float32) # the right
>>> return_array(c, c.size)
array([1., 2., 3.], dtype=int) # should it raise an TypeError like the following?
>>> return_array(d, d.size)
Traceback (most recent call last):
File "<input>", line 1, in <module>
return_array(d, d.size)
TypeError: return_array(): incompatible function arguments. Th
e following argument types are supported:
1. (arg0: numpy.ndarray[float16], arg1: int) -> None
2. (arg0: numpy.ndarray[float32], arg1: int) -> None
Invoked with: array(['x', 'b'], dtype='|S1'), 2 When calling func without definitions for a given type of the parameters, it should raise an exception. However, as showing in the pyside code, calling with dtype=int,no exceptions raised |
Meta: If you have an issue, can you be more explicit about what the problem is, rather than just posting code + errors with no text? (Sorry, I'm picky about these things!) Also, this looks like an entirely different question; if I covered your main question about And can you either reformulate this issue to have an action, like "Update docs to show example of [...]", or mebbe close it if it's resolved? |
I get it work ! Thanks a lot but I have to make some changes on
// Kinda following: https://github.com/pybind/pybind11/blob/9bb3313162c0b856125e481ceece9d8faa567716/include/pybind11/numpy.h#L1000
template <>
struct npy_format_descriptor<float16> {
static pybind11::dtype dtype() {
handle ptr = npy_api::get().PyArray_DescrFromType_(NPY_FLOAT16);
return reinterpret_borrow<pybind11::dtype>(ptr);
}
static std::string format() {
// following: https://docs.python.org/3/library/struct.html#format-characters
return "e";
}
static constexpr auto name() {
return _("float16");
}
}; |
Thanks very much mainly solved my problem |
Issue description
how could I pass numpy.float16 into c++ (in c++, I used the half.hpp as the float16 type)? ( what is the right way to bind numpy.float16 and half float defined in half.hpp)
Reproducible example code
depend on half.hpp
in test_half_pybind.cc:
in python side
any help or reference will be highly appreciated.
The text was updated successfully, but these errors were encountered: