使用Pybind11将Eigen :: Tensor暴露给Python [英] Exposing Eigen::Tensor To Python Using Pybind11

查看:346
本文介绍了使用Pybind11将Eigen :: Tensor暴露给Python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用pybind11将本征张量暴露给python。我可以编译所有内容,并且可以成功将其导入python。但是,数据无法转换为python类型。我尝试了两种方法。一种是直接公开数据,第二种是使用映射。两者都在python环境中失败。

I am trying to expose an Eigen tensor to python using pybind11. I can compile everything with no issue and can successfully import it to python. However, the data cannot be converted to a python type. I tried two methods. One is directly exposing the data and second using mapping. Both fail in python environment.

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>
#include <unsupported/Eigen/CXX11/Tensor>

class myclass{

    myclass(){
        m_data = new float[m_dim1*m_dim2*m_dim3]; // Contiguous data that represents a three dimensional array
        for(int i = 0; i<m_dim1*m_dim2*m_dim3; i++)
            m_data[i] = i;

        m_tensor = Eigen::TensorMap<Eigen::Tensor<float, 3>>(m_data, m_dim1, m_dim2, m_dim3);
    }

    Eigen::TensorMap<Eigen::Tensor<float, 3>>& getDataUsingMapping() { Eigen::TensorMap<Eigen::Tensor<float, 3>> temp(m_data, m_dim1, m_dim2, m_dim3);  return temp; }
    Eigen::Tensor<float, 3>& getDataWithoutUsingMapping() { return m_tensor};


private:
    Eigen::Tensor<float, 3> m_tensor;
    // In fact, m_data, m_dim1, m_dim2, m_dim3 all are
    // read from a data file but for this example let's 
    // assume some values.
    float* m_data; 
    int m_dim1 = 2, m_dim2 = 5, m_dim3 = 10;
}


PYBIND11_MODULE(example, m) {
    py::class_<myclass>(m, "myclass")
        .def(py::init<>())
        .def("getDataUsingMapping", &myClass::getDataUsingMapping, py::return_value_policy::reference)
        .def("getDataWithoutUsingMapping", &myClass::getDataWithoutUsingMapping, py::return_value_policy::reference);
}

我希望能够使用其维数在python中处理此3D数组信息(m_dim1,m_dim2,m_dim3)

I would like to be able to process this 3D array in python with its dimensional information (m_dim1, m_dim2, m_dim3).

以下是我尝试获取python中的数据后收到的错误消息。

Here are the error messages I get after trying to get the data in python.

>>> import example
>>> d = example()
>>>
>>> DataInPython = d.getDataUsingMapping()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Unable to convert function return value to a Python type! The signature was
        (self: example) -> Eigen::TensorMap<Eigen::Tensor<float,3,0,__int64>,0,Eigen::MakePointer>
>>>
>>>
>>> DataInPython = d.getDataWithoutUsingMapping()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Unable to convert function return value to a Python type! The signature was
        (self: example) -> Eigen::Tensor<std::complex<float>,3,0,__int64>

Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.

我尝试包括所有pybdin11 include文件,但没有解决问题。有人可以帮我吗?

I tried including all pybdin11 include files but did not fix the problem. Could someone kindly help me?

推荐答案

该C ++代码无法编译,并且该python代码可能无法按发布的方式运行,但是在修复了这些问题并进行了逻辑上的更改之后,结论仍然是pybind11不支持来自 unsupported / Eigen / CXX11 / Tensor的TensorMap,因为该类没有提供与其他Eigen映射类相同的接口。

That C++ code does not compile and that python code can not possibly have run as posted, but after fixing those and making the logical changes, the conclusion is still that pybind11 does not support TensorMap from "unsupported/Eigen/CXX11/Tensor" as that class does not provide the same interface as other Eigen mapping classes.

我希望mapper脚轮的特殊化能够自动工作,但是要明确地这样做:

I would have expected a specialization of the mapper caster to work automatically, but doing so explicitly:

template<>
struct py::detail::type_caster<Eigen::TensorMap<Eigen::Tensor<float, 3>>, void>
    : py::detail::eigen_map_caster<Eigen::TensorMap<Eigen::Tensor<float, 3>>> {};

无法实例化pybind11 :: detail :: EigenProps,b / c TensorMap不提供其尺寸与cols /行/步幅。这样,SFINAE会阻止自动生成Caster。

fails the instantiation of pybind11::detail::EigenProps, b/c TensorMap does not provide its dimensions with cols/rows/stride. Thus, SFINAE prevents automatic generation of the caster.

除了使用名为 unsupported的目录中的标头之外,没有其他选择吗?如果不是,最好的选择是将TensorMap的内容复制到一个numpy数组中,并以 getDataUsingMapping 的自定义方式返回该数组:有几个这样的示例,有或没有复制。 (除非您愿意展平张量,否则EigenProps的专业化将不起作用,但是您可以将其用作为TensorMap编写新的通用类型转换程序的示例。)

Is there no other option than to use headers from a directory named "unsupported"? If not, your best bet is to copy the TensorMap's contents to a numpy array and to return that in a customization of getDataUsingMapping: there are several examples of how to do that on SO, with and without copying. (Specialization of EigenProps would not work unless you're willing to flatten the tensor, but you could use it as an example to write a new generic type caster for TensorMap.)

这篇关于使用Pybind11将Eigen :: Tensor暴露给Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆