Skip to content
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

Can I use nbla::Array in a extenstion created by C Python API? #1247

Open
twmht opened this issue Feb 2, 2024 · 1 comment
Open

Can I use nbla::Array in a extenstion created by C Python API? #1247

twmht opened this issue Feb 2, 2024 · 1 comment
Assignees

Comments

@twmht
Copy link

twmht commented Feb 2, 2024

Hi,

How to create nbla::Array in the c extension and return it to python side?

for example with numpy we can do

#include <Python.h>
#include <numpy/arrayobject.h>

static PyObject* create_numpy_array(PyObject* self, PyObject* args) {
    // Parse arguments if needed

    // Initialize Python and NumPy
    Py_Initialize();
    import_array();

    // Create a NumPy array
    npy_intp dims[2] = {3, 3};  // dimensions of the 2D array
    PyObject* myArray = PyArray_SimpleNew(2, dims, NPY_DOUBLE);

    // Access the array data
    double* data = (double*)PyArray_DATA(myArray);

    // Fill the array with some data
    for (npy_intp i = 0; i < dims[0]; ++i) {
        for (npy_intp j = 0; j < dims[1]; ++j) {
            data[i * dims[1] + j] = i + j;
        }
    }

    // Return the NumPy array
    return myArray;
}

static PyMethodDef methods[] = {
    {"create_numpy_array", create_numpy_array, METH_NOARGS, "Create and return a NumPy array"},
    {NULL, NULL, 0, NULL} // Sentinel
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    "my_module", // Module name
    NULL,        // Module documentation, may be NULL
    -1,          // Size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
    methods
};

PyMODINIT_FUNC PyInit_my_module(void) {
    import_array();  // Must be called before PyModule_Create

    return PyModule_Create(&module);
}

but nbla::Array python interface is created by Cython, I am not sure how to use that in my c extension.

Any idea?

@TomonobuTsujikawa TomonobuTsujikawa self-assigned this Feb 4, 2024
@TomonobuTsujikawa
Copy link
Contributor

Our internal developer provided the following example.

Here is the sample how to export nd_array to python as numpy array:

#include <Python.h>
#include <numpy/arrayobject.h>
#include <nbla/nd_array.hpp>


static PyObject* create_numpy_array_from_nbla_array(PyObject* self, PyObject* args)
{
    // Parse arguments if needed

    // Initialize Python and NumPy
    Py_Initialize();
    import_array();

    //Suppose we have an NdArray
    nbla::Context cpu_ctx{{"cpu:float"}, "CpuCachedArray", "0"};
    nbla::Shape_t shape = {3, 3};
    nbla::NdArrayPtr nd_ptr = nbla::NdArray::create(shape);
    nbla::Array * array = nd_ptr->cast(nbla::get_dtype<double>(), cpu_ctx, false/*write_only*/);

    //Suppose we assigned in some place.
    double *p = array->pointer<double>();
    for (int i = 0; i < shape[0]; ++i) {
        for (int j = 0; j < shape[1]; ++j) {
            p[i * shape[1] + j] = i + j;
        }
    }

    //Suppose we read it in another place
    const nbla::Array *r_array = nd_ptr->get(nbla::get_dtype<double>(), cpu_ctx);
    const double *rp = r_array->const_pointer<double>();
    PyObject* myArray = PyArray_SimpleNewFromData(
        shape.size(),
        shape.data(),
        NPY_DOUBLE,
        (void*)rp);

    // Return the NumPy array
    return myArray;
}


static PyObject* create_numpy_array(PyObject* self, PyObject* args) {
    // Parse arguments if needed

    // Initialize Python and NumPy
    Py_Initialize();
    import_array();

    // Create a NumPy array
    npy_intp dims[2] = {3, 3};  // dimensions of the 2D array
    PyObject* myArray = PyArray_SimpleNew(2, dims, NPY_DOUBLE);

    // Access the array data
    double* data = (double*)PyArray_DATA(myArray);

    // Fill the array with some data
    for (npy_intp i = 0; i < dims[0]; ++i) {
        for (npy_intp j = 0; j < dims[1]; ++j) {
            data[i * dims[1] + j] = i + j;
        }
    }

    // Return the NumPy array
    return myArray;
}

static PyMethodDef methods[] = {
    {"create_numpy_array", create_numpy_array, METH_NOARGS, "Create and return a NumPy array"},
    {"create_numpy_array_from_nbla_array", create_numpy_array_from_nbla_array, METH_NOARGS, "Create and return a NumPy array from nd_array"},
    {NULL, NULL, 0, NULL} // Sentinel
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    "my_module", // Module name
    NULL,        // Module documentation, may be NULL
    -1,          // Size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
    methods
};

PyMODINIT_FUNC PyInit_my_module(void) {
    import_array();  // Must be called before PyModule_Create

    return PyModule_Create(&module);
}

Here is CMakeLists.txt used to build above cpp file.

cmake_minimum_required(VERSION 3.14)
project(YourExtensionModule)

# Find the Python interpreter, libraries, and include directories
find_package(PythonLibs 3.2 REQUIRED)
find_package(PythonInterp 3.2 REQUIRED)

# Find NumPy headers
message(${PYTHON_EXECUTABLE})
execute_process(
  COMMAND "${PYTHON_EXECUTABLE}" -c "import numpy; print(numpy.get_include())"
  OUTPUT_VARIABLE NUMPY_INCLUDE_DIR
  OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Include directories for Python and NumPy
include_directories(${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIR})

# Your source file(s). If you have more, add them here.
set(SOURCE_FILES pyarray.cpp)

# Enable C++11 (or another version if needed)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories("your_nnabla_include/nnabla/include")
link_directories("your_nnabla_sharedlib/nnabla/build/lib")

# Create a shared library that can be imported by Python
add_library(my_module MODULE ${SOURCE_FILES})

# Remove the 'lib' prefix from the output name to adhere to Python's naming convention
set_target_properties(my_module PROPERTIES PREFIX "")

# Link against Python libraries
target_link_libraries(my_module ${PYTHON_LIBRARIES} nnabla nnabla_utils)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants