通过 pybind11 返回 numpy 数组

2023-12-24

我有一个 C++ 函数计算一个大张量,我想通过它作为 NumPy 数组返回到 Pythonpybind11 https://github.com/pybind/pybind11.

从 pybind11 的文档来看,似乎使用STL unique_ptr http://en.cppreference.com/w/cpp/memory/unique_ptr是可取的。 在下面的示例中,注释掉的版本可以工作,而给定的版本可以编译但在运行时失败(“无法将函数返回值转换为 Python 类型!”)。

为什么智能指针版本失败?创建和返回 NumPy 数组的规范方法是什么?

PS:由于程序结构和数组的大小,最好不要复制内存,而是从给定的指针创建数组。内存所有权应该由 Python 获取。

typedef typename py::array_t<double, py::array::c_style | py::array::forcecast> py_cdarray_t;

// py_cd_array_t _test()
std::unique_ptr<py_cdarray_t> _test()
{
    double * memory = new double[3]; memory[0] = 11; memory[1] = 12; memory[2] = 13;
    py::buffer_info bufinfo (
        memory,                                   // pointer to memory buffer
        sizeof(double),                           // size of underlying scalar type
        py::format_descriptor<double>::format(),  // python struct-style format descriptor
        1,                                        // number of dimensions
        { 3 },                                    // buffer dimensions
        { sizeof(double) }                        // strides (in bytes) for each index
    );

    //return py_cdarray_t(bufinfo);
    return std::unique_ptr<py_cdarray_t>( new py_cdarray_t(bufinfo) );
}

一些评论(然后是一个有效的实现)。

  • pybind11 的 C++ 对象包装器围绕 Python 类型(例如pybind11::object, pybind11::list,并且,在这种情况下,pybind11::array_t<T>)实际上只是底层 Python 对象指针的包装器。在这方面,已经承担了共享指针包装器的角色,因此将其包装在unique_ptr: 返回py::array_t<T>直接对象本质上已经只是返回一个美化的指针。
  • pybind11::array_t可以直接从数据指针构造,因此您可以跳过py::buffer_info中间步骤,只需将形状和步幅直接提供给pybind11::array_t构造函数。以这种方式构造的 numpy 数组不会拥有自己的数据,它只会引用它(即 numpyowndata标志将被设置为 false)。
  • 内存所有权可以与 Python 对象的生命周期联系在一起,但您仍然需要正确地进行释放。 Pybind11 提供了py::capsule课程来帮助你做到这一点。您想要做的是将 numpy 数组指定为base论证array_t。这将使 numpy 数组引用它,只要数组本身还活着,它就保持活动状态,并在不再引用它时调用清理函数。
  • The c_style旧版本(2.2 之前)中的 flag 仅对新数组有效,即在不传递值指针时。这个问题在 2.2 版本中得到了修复,如果您仅指定形状而不指定步幅,也会影响自动步幅。如果您自己直接指定步幅(就像我在下面的示例中所做的那样),它根本没有任何效果。

因此,将各个部分放在一起,此代码是一个完整的 pybind11 模块,它演示了如何完成您正在寻找的内容(并包含一些 C++ 输出以证明确实工作正常):

#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

PYBIND11_PLUGIN(numpywrap) {
    py::module m("numpywrap");
    m.def("f", []() {
        // Allocate and initialize some data; make this big so
        // we can see the impact on the process memory use:
        constexpr size_t size = 100*1000*1000;
        double *foo = new double[size];
        for (size_t i = 0; i < size; i++) {
            foo[i] = (double) i;
        }

        // Create a Python object that will free the allocated
        // memory when destroyed:
        py::capsule free_when_done(foo, [](void *f) {
            double *foo = reinterpret_cast<double *>(f);
            std::cerr << "Element [0] = " << foo[0] << "\n";
            std::cerr << "freeing memory @ " << f << "\n";
            delete[] foo;
        });

        return py::array_t<double>(
            {100, 1000, 1000}, // shape
            {1000*1000*8, 1000*8, 8}, // C-style contiguous strides for double
            foo, // the data pointer
            free_when_done); // numpy array references this parent
    });
    return m.ptr();
}

编译它并从 Python 调用它表明它可以工作:

>>> import numpywrap
>>> z = numpywrap.f()
>>> # the python process is now taking up a bit more than 800MB memory
>>> z[1,1,1]
1001001.0
>>> z[0,0,100]
100.0
>>> z[99,999,999]
99999999.0
>>> z[0,0,0] = 3.141592
>>> del z
Element [0] = 3.14159
freeing memory @ 0x7fd769f12010
>>> # python process memory size has dropped back down
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 pybind11 返回 numpy 数组 的相关文章

随机推荐

  • 长度示例中“List a”中的“a”是什么?

    我想知道在哪里可以找到有关 a 用在长度示例 http elm lang org examples length 似乎是某种类型 1 2 3 is a List Int 只能与整数列表一起使用的函数必须具有List Int在他们的类型签名中
  • __init__ 的目的

    我读了一些书 但无法像我想的那样完全理解这一点 我正在从 LPTHW 教程中制作一个 选择你自己的冒险 小游戏 这是完整的脚本 http codepad org YWVUlHnU http codepad org YWVUlHnU 我不明白
  • 在Python中计算modbus的CRC16

    首先 抱歉 我是初学者 我在 modbus 上得到以下字节序列 01 04 08 00 00 00 09 00 00 00 00f8 0c 该字节序列上粗体的 CRC 是正确的 但是 要检查 创建 CRC 我必须遵循设备规范 其中规定 错误
  • 什么是段以及如何在 8086 模式下寻址它们?

    自从我开始使用 8086 汇编语言编程以来 我一直在思考这些段和段寄存器 我面临的问题是 我无法对脑海中的片段有一个直观的图像 因此我不清楚这些概念 谁能帮我理解这个概念将其与现实世界场景联系起来 我还有以下问题 问题一 据我了解 在启用2
  • ColdFusion jvm 垃圾收集不

    我有一个 cfc 方法 它循环遍历列表并通过 cfhttp 进行一系列 SOAP 调用 然后将结果插入数据库 该过程本身工作得很好 问题是java内存慢慢填满 最终 取决于返回的记录中的元素数量 停止工作 没有错误或任何可见的东西它就停止了
  • 打开 pdf 时出现 MUPDF UnsupportedOperationException

    我正在将 MUPDF 用于 Android 项目 但一些 Android 用户遇到了问题 我得到的报告如下 java lang UnsupportedOperationException Not supported E AndroidRun
  • Matlab - 周围元素的总和

    我想计算矩阵中给定元素周围元素的总和 到目前为止 我已经编写了以下几行代码 for i 1 m rij 1 n 0 for j 1 n alive tijdelijk i 1 j tijdelijk i 1 j tijdelijk i 1
  • 创建一个只有两个圆角边缘的矩形

    我可以创建一个所有边缘均为圆形的矩形形状 然而 我想要的是一个矩形 只有两个边缘是圆形的 这可能吗 我本质上是在拼凑一个 ListView 它看起来像一个带有圆形边缘的气泡 我希望添加一个两个顶部边缘呈圆形的页眉和一个两个底部边缘呈圆形的页
  • jQuery 日期选择器首先选择年份,然后选择月份

    需要进行哪些更改才能首先显示 年份 下拉列表 然后将 月份 下拉列表显示为 jQuery 中的第二个字段 以便用户可以选择自己的出生年份 然后选择该年的月份 我们仍然希望限制日历不能显示大于今天的日期 如果用户选择 2011 年 则不应允许
  • 如何计算bigquery数组字段中元素的频率

    我有一个看起来像这样的表 我正在寻找一个表 该表给出字段中元素的频率计数l 0 l 1 l 2 l 3 例如 输出应如下所示 author id year l o name l 0 count l1 name l1 count l2 nam
  • 来自 java android 的图像序列的视频编码[重复]

    这个问题在这里已经有答案了 我想仅在我当前的 android 项目中使用 java 对图像序列中的视频进行编码 我的意思是不使用任何外部工具 例如 NDK 另外 是否有可用的 java 库用于从图像序列编码视频 您可以使用名为 JCodec
  • 在哪里可以找到可用于扫描和 OCR 文档的免费 .Net (C#) 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个免费的 Net C 库 我可以使用该库从文档扫描仪进行扫描 然后对文档进行 OCR 这样我就可以从中获取文本并将其保存在数据
  • 如何在不使用 SQL 查询表的情况下选择过去 12 个月的名称和年份?

    我如何使用当前时间选择最近 12 个月的名称 不使用任何表格 如果当前月份是十月那么我想要的结果是 month year oct 2011 nov 2011 dec 2011 jan 2012 feb 2012 mar 2012 apr 2
  • Android - 无法执行 dex:定义了多个 dex 文件

    我尝试运行我的 Android 应用程序 但收到此错误 2014 03 11 11 21 34 Dex Loader Unable to execute dex Multiple dex files define Lorg apache c
  • CSS 级联顺序 - 作者与用户[重复]

    这个问题在这里已经有答案了 按优先级升序排列 用户代理声明 用户正常声明 作者正常声明 作者重要声明 用户重要声明 CSS 规范定义author and user as Author 作者根据文档语言的约定为源文档指定样式表 例如 在 HT
  • 如何使用 API 删除 GitHub 存储库

    我正在熟悉 GitHub APIhttp developer github com v3 http developer github com v3 我正在尝试使用 Firefox 的 RESTClient 插件和curl 命令行工具 我已经
  • 连接 JS 客户端和 Python 服务器

    我对 JS 和 Python 比较陌生 所以这可能是一个初学者的问题 我正在尝试将字符串从 JS 客户端发送到 Python 服务器 然后将该字符串发送到另一个 Python 客户端 这是我的代码 JS客户端 var socket io c
  • 如何检测客户端机器是否已经安装了JRE版本?

    在应用程序中 我们为客户端提供选择是否使用 JRE 下载我们的应用程序的功能 如果可以检测客户端系统是否已经配置了 JRE 则可以以更加用户友好的方式提供此功能 如果您想限制测试以检查是否安装了 JREand在路径上 只需检查环境变量PAT
  • Laravel 调用未定义方法 App\\ Model ::mapInto()、vendor\\laravel\\framework\\src\\Illuminate\\Support\\Traits\\ForwardsCalls.php

    我试图 public function show Product product return ProductDetailResource collection product 调用未定义的方法App Model mapInto 异常 Ba
  • 通过 pybind11 返回 numpy 数组

    我有一个 C 函数计算一个大张量 我想通过它作为 NumPy 数组返回到 Pythonpybind11 https github com pybind pybind11 从 pybind11 的文档来看 似乎使用STL unique ptr