pybind 11-将任意numpy数组转换为向量

mznpcxlj  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(154)

我正在尝试使用pybind 11编写一个python插件,并在将数据从numpy转换为std::vector类型时遇到了问题。python函数的调用是通过以下形式的字典实现的:{"varname": numpy_array}我所有的试验都以一个类似RuntimeError: Unable to cast Python instance of type <class 'numpy.ndarray'> to C++ type 'std::vector<float, std::allocator<float> >'的投射错误的变体结束
解析函数如下所示:

std::vector<float> Plg::process(py::dict &inputs)
{
  std::vector<std::string> keys;
  //len(data) == len(keys)
  std::vector<std::vector<std::vector<float>>> data; //!!! does not work
  for (auto item : inputs)
  {
    std::string k = py::cast<std::string>(item.first);
    keys.push_back(k);
    std::vector<std::vector<float>> d = py::cast<std::vector<std::vector<float>>>(item.second);
    data.push_back(d);
  }
  //_process(data); - call to actual function, replace with dummy:
  std::vector<float> results;
  results.push_back(10.2);
  return results;
}

item对象的类型是pybind 11::handle,我似乎找不到它的成员的明确列表。在正常情况下我只会让我的函数接受py::array_t,但遗憾的是,输入必须是一个带有字符串键和半任意numpy数组的字典:

std::vector<float> Plg::doit(py::array_t<float, py::array::c_style | py::array::forcecast> 
                                &input_vector)
    {
        std::vector<float> array_vector(input_vector.size());
        std::memcpy(array_vector.data(), input_vector.data()
                        , input_vector.size()*sizeof(float));
        std::vector<float> results = _process(array_vector);
        return results;
    }

然而,上面的方法只适用于在Python中预先转换为数组的数据(平面numpy数组)。我发现的所有线程都在处理一个相反的问题--从vector到numpy,这不是我的情况。
我的问题是双重的,首先
1.如何解压缩任意numpy数组并将其放入平面std::vector中?
1.有没有更聪明的方法不需要memcpy?
我相信有一个简单的解决方案,我只是不知道,将大大感谢帮助

更新

我的问题来自于numpy容忍的不同输入大小--输入的数据可以是维度为(10,10,2)或(200,)甚至(2,)的数组--它最终应该都是内部的float向量--py::array_t似乎处理得很好

nvbavucw

nvbavucw1#

拆包有点简单,但我不确定它的效率。技巧是使用py::array_t的属性以及它如何处理任意numpy数组。问题是,**buffer对象没有有效的end()**方法(开始()返回正确的值,end()返回null)

std::vector<float> Plg::proc(py::dict &inputs)
{
    std::vector<std::string> keys;
    std::vector<std::vector<float>> data;
    for(auto item : inputs)
    {
            std::string k = py::cast<std::string>(item.first);
            keys.push_back(k);  // string part is trivial
    // create a storage element using pyarray cast defining it from second element of the map:
            auto buffer = py::array_t<float, py::array::c_style | py::array::forcecast>::ensure(item.second);
            if(!buffer)
            {
                std::cout << "no buffer loaded!" << std::endl;
            }
            else
            {
    // put raw data into a float vector. This relies on numpy arrays being contigeuous and contineous in memory. The previous problem came from buffer.end() being null so constructing from begin() and end() is doomed to fail!. Calculate item size using bytes in the buffer and item size.
                std::vector<float> d(buffer.data(), buffer.data()+buffer.nbytes()/buffer.itemsize());
                data.push_back(d);
            }
        
    }
    do_stuff(data, keys);
}

如果pybind附带更深入的示例就更好了,但总的来说,这是一个很棒的库。

相关问题