Open twmht opened 9 months ago
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)
Hi,
How to create nbla::Array in the c extension and return it to python side?
for example with numpy we can do
but nbla::Array python interface is created by Cython, I am not sure how to use that in my c extension.
Any idea?