Я нашел хакерский способ добиться этого.Вот небольшой пример.
from ctypes import *
import numpy as np
import mxnet as mx
m = mx.ndarray.zeros((4,4))
m.wait_to_read() # make sure the data is allocated
c_uint64_p = POINTER(c_uint64)
handle= cast(m.handle, c_uint64_p) # NDArray*
ptr_ = cast(handle[0], c_uint64_p) # shared_ptr<Chunk>
dptr = cast(ptr_[0], POINTER(c_float)) # shandle.dptr
n = np.ctypeslib.as_array(dptr, shape=(4,4)) # m and n will share buffer
Я вывел приведенный выше код, взглянув на исходный код MxNet C ++.Некоторое объяснение:
Сначала обратите внимание на атрибут NDArray.handle
.Это c_void_p
.Прочитайте исходный код Python, вы узнаете, что это NDArrayHandle
.Теперь погрузитесь в код src/c_api/c_api_ndarray.cc
, он будет интерпретирован как NDArray*
.
В дереве исходного кода перейдите к include/mxnet/ndarray.h
и найдите класс NDArray
.Первое поле:
/*! \brief internal data of NDArray */
std::shared_ptr<Chunk> ptr_{nullptr};
Проверка Chunk
, которая является структурой, определенной внутри NDArray
, мы видим:
/*! \brief the real data chunk that backs NDArray */
// shandle is used to store the actual values in the NDArray
// aux_handles store the aux data(such as indices) if it's needed by non-default storage.
struct Chunk {
/*! \brief storage handle from storage engine.
for non-default storage, shandle stores the data(value) array.
*/
Storage::Handle shandle;
Наконец, shandle
определено в include/mxnet/storage.h
:
struct Handle {
/*!
* \brief Pointer to the data.
*/
void* dptr{nullptr};
Написание небольшой программы показывает, что sizeof(shared_ptr<some_type>)
равно 16. Основываясь на этом вопросе, мы можем предположить, что shared_ptr
состоит из двух указателей.Нетрудно понять, что первый указатель - это указатель на данные.Собрав все воедино, все, что нужно, - это разыменование двух указателей.
На нижнем сайте этот метод нельзя использовать в производственной среде или в крупных проектах.Он может сломаться в будущем выпуске или привести к серьезным ошибкам и дырам в безопасности.