/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*! * \file ndarray.h * \brief definition of ndarray * \author Chuntao Hong, Zhang Chen */ #ifndef MXNET_CPP_NDARRAY_H_ #define MXNET_CPP_NDARRAY_H_ #include #include #include #include #include #include "mxnet-cpp/base.h" #include "mxnet-cpp/shape.h" namespace mxnet { namespace cpp { enum DeviceType { kCPU = 1, kGPU = 2, kCPUPinned = 3 }; /*! * \brief Context interface */ class Context { public: /*! * \brief Context constructor * \param type type of the device * \param id id of the device */ Context(const DeviceType& type, int id) : type_(type), id_(id) {} /*! * \return the type of the device */ DeviceType GetDeviceType() const { return type_; } /*! * \return the id of the device */ int GetDeviceId() const { return id_; } /*! * \brief Return a GPU context * \param device_id id of the device * \return the corresponding GPU context */ static Context gpu(int device_id = 0) { return Context(DeviceType::kGPU, device_id); } /*! * \brief Return a CPU context * \param device_id id of the device. this is not needed by CPU * \return the corresponding CPU context */ static Context cpu(int device_id = 0) { return Context(DeviceType::kCPU, device_id); } private: DeviceType type_; int id_; }; /*! * \brief struct to store NDArrayHandle */ struct NDBlob { public: /*! * \brief default constructor */ NDBlob() : handle_(nullptr) {} /*! * \brief construct with a NDArrayHandle * \param handle NDArrayHandle to store */ explicit NDBlob(NDArrayHandle handle) : handle_(handle) {} /*! * \brief destructor, free the NDArrayHandle */ ~NDBlob() { MXNDArrayFree(handle_); } /*! * \brief the NDArrayHandle */ NDArrayHandle handle_; private: NDBlob(const NDBlob&); NDBlob& operator=(const NDBlob&); }; /*! * \brief NDArray interface */ class NDArray { public: /*! * \brief construct with a none handle */ NDArray(); /*! * \brief construct with a NDArrayHandle */ explicit NDArray(const NDArrayHandle& handle); /*! * \brief construct a new dynamic NDArray * \param shape the shape of array * \param context context of NDArray * \param delay_alloc whether delay the allocation * \param dtype data type of NDArray */ NDArray(const std::vector& shape, const Context& context, bool delay_alloc = true, int dtype = 0); /*! * \brief construct a new dynamic NDArray * \param shape the shape of array * \param constext context of NDArray * \param delay_alloc whether delay the allocation * \param dtype data type of NDArray */ NDArray(const Shape& shape, const Context& context, bool delay_alloc = true, int dtype = 0); NDArray(const mx_float* data, size_t size); /*! * \brief construct a new dynamic NDArray * \param data the data to create NDArray from * \param shape the shape of array * \param constext context of NDArray */ NDArray(const mx_float* data, const Shape& shape, const Context& context); /*! * \brief construct a new dynamic NDArray * \param data the data to create NDArray from * \param shape the shape of array * \param constext context of NDArray */ NDArray(const std::vector& data, const Shape& shape, const Context& context); explicit NDArray(const std::vector& data); NDArray operator+(mx_float scalar); NDArray operator-(mx_float scalar); NDArray operator*(mx_float scalar); NDArray operator/(mx_float scalar); NDArray operator%(mx_float scalar); NDArray operator+(const NDArray&); NDArray operator-(const NDArray&); NDArray operator*(const NDArray&); NDArray operator/(const NDArray&); NDArray operator%(const NDArray&); /*! * \brief set all the elements in ndarray to be scalar * \param scalar the scalar to set * \return reference of self */ NDArray& operator=(mx_float scalar); /*! * \brief elementwise add to current space * this mutate the current NDArray * \param scalar the data to add * \return reference of self */ NDArray& operator+=(mx_float scalar); /*! * \brief elementwise subtract from current ndarray * this mutate the current NDArray * \param scalar the data to subtract * \return reference of self */ NDArray& operator-=(mx_float scalar); /*! * \brief elementwise multiplication to current ndarray * this mutate the current NDArray * \param scalar the data to subtract * \return reference of self */ NDArray& operator*=(mx_float scalar); /*! * \brief elementwise division from current ndarray * this mutate the current NDArray * \param scalar the data to subtract * \return reference of self */ NDArray& operator/=(mx_float scalar); /*! * \brief elementwise modulo from current ndarray * this mutate the current NDArray * \param scalar the data to subtract * \return reference of self */ NDArray& operator%=(mx_float scalar); /*! * \brief elementwise add to current space * this mutate the current NDArray * \param src the data to add * \return reference of self */ NDArray& operator+=(const NDArray& src); /*! * \brief elementwise subtract from current ndarray * this mutate the current NDArray * \param src the data to subtract * \return reference of self */ NDArray& operator-=(const NDArray& src); /*! * \brief elementwise multiplication to current ndarray * this mutate the current NDArray * \param src the data to subtract * \return reference of self */ NDArray& operator*=(const NDArray& src); /*! * \brief elementwise division from current ndarray * this mutate the current NDArray * \param src the data to subtract * \return reference of self */ NDArray& operator/=(const NDArray& src); /*! * \brief elementwise modulo from current ndarray * this mutate the current NDArray * \param src the data to subtract * \return reference of self */ NDArray& operator%=(const NDArray& src); NDArray ArgmaxChannel(); /*! * \brief Do a synchronize copy from a contiguous CPU memory region. * * This function will call WaitToWrite before the copy is performed. * This is useful to copy data from existing memory region that are * not wrapped by NDArray(thus dependency not being tracked). * * \param data the data source to copy from. * \param size the memory size we want to copy from. */ void SyncCopyFromCPU(const mx_float* data, size_t size); /*! * \brief Do a synchronize copy from a contiguous CPU memory region. * * This function will call WaitToWrite before the copy is performed. * This is useful to copy data from existing memory region that are * not wrapped by NDArray(thus dependency not being tracked). * * \param data the data source to copy from, int the form of mx_float vector */ void SyncCopyFromCPU(const std::vector& data); /*! * \brief Do a synchronize copy to a contiguous CPU memory region. * * This function will call WaitToRead before the copy is performed. * This is useful to copy data from existing memory region that are * not wrapped by NDArray(thus dependency not being tracked). * * \param data the data source to copyinto. * \param size the memory size we want to copy into. Defualt value is Size() */ void SyncCopyToCPU(mx_float* data, size_t size = 0); /*! * \brief Do a synchronize copy to a contiguous CPU memory region. * * This function will call WaitToRead before the copy is performed. * This is useful to copy data from existing memory region that are * not wrapped by NDArray(thus dependency not being tracked). * * \param data the data source to copyinto. * \param size the memory size we want to copy into. Defualt value is Size() */ void SyncCopyToCPU(std::vector* data, size_t size = 0); /*! * \brief copy the content of current array to a target array. * \param other the target NDArray * \return the target NDarray */ NDArray CopyTo(NDArray* other) const; /*! * \brief return a new copy to this NDArray * \param Context the new context of this NDArray * \return the new copy */ NDArray Copy(const Context&) const; /*! * \brief return offset of the element at (h, w) * \param h height position * \param w width position * \return offset of two dimensions array */ size_t Offset(size_t h = 0, size_t w = 0) const; /*! * \brief return offset of three dimensions array * \param c channel position * \param h height position * \param w width position * \return offset of three dimensions array */ size_t Offset(size_t c, size_t h, size_t w) const; /*! * \brief return value of the element at (index) * \param index position * \return value of one dimensions array */ mx_float At(size_t index) const; /*! * \brief return value of the element at (h, w) * \param h height position * \param w width position * \return value of two dimensions array */ mx_float At(size_t h, size_t w) const; /*! * \brief return value of three dimensions array * \param c channel position * \param h height position * \param w width position * \return value of three dimensions array */ mx_float At(size_t c, size_t h, size_t w) const; /*! * \brief Slice a NDArray * \param begin begin index in first dim * \param end end index in first dim * \return sliced NDArray */ NDArray Slice(mx_uint begin, mx_uint end) const; /*! * \brief Return a reshaped NDArray that shares memory with current one * \param new_shape the new shape * \return reshaped NDarray */ NDArray Reshape(const Shape& new_shape) const; /*! * \brief Block until all the pending write operations with respect * to current NDArray are finished, and read can be performed. */ void WaitToRead() const; /*! * \brief Block until all the pending read/write operations with respect * to current NDArray are finished, and write can be performed. */ void WaitToWrite(); /*! * \brief Block until all the pending read/write operations with respect * to current NDArray are finished, and read/write can be performed. */ static void WaitAll(); /*! * \brief Sample gaussian distribution for each elements of out. * \param mu mean of gaussian distribution. * \param sigma standard deviation of gaussian distribution. * \param out output NDArray. */ static void SampleGaussian(mx_float mu, mx_float sigma, NDArray* out); /*! * \brief Sample uniform distribution for each elements of out. * \param begin lower bound of distribution. * \param end upper bound of distribution. * \param out output NDArray. */ static void SampleUniform(mx_float begin, mx_float end, NDArray* out); /*! * \brief Load NDArrays from binary file. * \param file_name name of the binary file. * \param array_list a list of NDArrays returned, do not fill the list if * nullptr is given. * \param array_map a map from names to NDArrays returned, do not fill the map * if nullptr is given or no names is stored in binary file. */ static void Load(const std::string& file_name, std::vector* array_list = nullptr, std::map* array_map = nullptr); /*! * \brief Load map of NDArrays from binary file. * \param file_name name of the binary file. * \return a list of NDArrays. */ static std::map LoadToMap(const std::string& file_name); /*! * \brief Load list of NDArrays from binary file. * \param file_name name of the binary file. * \return a map from names to NDArrays. */ static std::vector LoadToList(const std::string& file_name); /*! * \brief Load NDArrays from buffer. * \param buffer Pointer to buffer. (ie contents of param file) * \param size Size of buffer * \param array_list a list of NDArrays returned, do not fill the list if * nullptr is given. * \param array_map a map from names to NDArrays returned, do not fill the map * if nullptr is given or no names is stored in binary file. */ static void LoadFromBuffer(const void* buffer, size_t size, std::vector* array_list = nullptr, std::map* array_map = nullptr); /*! * \brief Load map of NDArrays from buffer. * \param buffer Pointer to buffer. (ie contents of param file) * \param size Size of buffer * \return a list of NDArrays. */ static std::map LoadFromBufferToMap(const void* buffer, size_t size); /*! * \brief Load list of NDArrays from buffer. * \param buffer Pointer to buffer. (ie contents of param file) * \param size Size of buffer * \return a map from names to NDArrays. */ static std::vector LoadFromBufferToList(const void* buffer, size_t size); /*! * \brief save a map of string->NDArray to binary file. * \param file_name name of the binary file. * \param array_map a map from names to NDArrays. */ static void Save(const std::string& file_name, const std::map& array_map); /*! * \brief save a list of NDArrays to binary file. * \param file_name name of the binary file. * \param array_list a list of NDArrays. */ static void Save(const std::string& file_name, const std::vector& array_list); /*! * \return the size of current NDArray, a.k.a. the production of all shape dims */ size_t Size() const; /*! * \return the shape of current NDArray, in the form of mx_uint vector */ std::vector GetShape() const; /*! * \return the data type of current NDArray */ int GetDType() const; /*! * \brief Get the pointer to data (IMPORTANT: The ndarray should not be in GPU) * \return the data pointer to the current NDArray */ const mx_float* GetData() const; /*! * \return the context of NDArray */ Context GetContext() const; /*! * \return the NDArrayHandle of the current NDArray */ NDArrayHandle GetHandle() const { return blob_ptr_->handle_; } private: std::shared_ptr blob_ptr_; }; std::ostream& operator<<(std::ostream& out, const NDArray& ndarray); } // namespace cpp } // namespace mxnet #endif // MXNET_CPP_NDARRAY_H_