如何访问ConstantNode的数值?假设已知:const ConstantNode *cnode;
ConstantNode类含有public类型的NDArray data,cnode->data就是runtime::NDArray类。
class ConstantNode : public ExprNode {
public:
/*! \brief The data of the tensor */
runtime::NDArray data;
NDArray包含protected Container data
protected:
/*! \brief Internal Data content */
Container* data_{nullptr};
所以,通过ConstantNode类对象无法直接访问该data
但是,NDArray提供了operator->()操作符,可以访问该data
inline const DLTensor* NDArray::operator->() const {
return &(data_->dl_tensor);
}
Container包含DLTensor dl_tensor;
class NDArray::Container {
public:
// NOTE: the first part of this structure is the same as
// DLManagedTensor, note that, however, the deleter
// is only called when the reference counter goes to 0
/*!
* \brief The corresponding dl_tensor field.
* \note it is important that the first field is DLTensor
* So that this data structure is DLTensor compatible.
* The head ptr of this struct can be viewed as DLTensor*.
*/
DLTensor dl_tensor;
DLTensor结构体定义如下:
typedef struct {
/*!
* \brief The opaque data pointer points to the allocated data. This will be
* CUDA device pointer or cl_mem handle in OpenCL. This pointer is always
* aligns to 256 bytes as in CUDA.
*
* For given DLTensor, the size of memory required to store the contents of
* data is calculated as follows:
*
* \code{.c}
* static inline size_t GetDataSize(const DLTensor* t) {
* size_t size = 1;
* for (tvm_index_t i = 0; i < t->ndim; ++i) {
* size *= t->shape[i];
* }
* size *= (t->dtype.bits * t->dtype.lanes + 7) / 8;
* return size;
* }
* \endcode
*/
void* data;
/*! \brief The device context of the tensor */
DLContext ctx;
/*! \brief Number of dimensions */
int ndim;
/*! \brief The data type of the pointer*/
DLDataType dtype;
/*! \brief The shape of the tensor */
int64_t* shape;
/*!
* \brief strides of the tensor,
* can be NULL, indicating tensor is compact.
*/
int64_t* strides;
/*! \brief The offset in bytes to the beginning pointer to data */
uint64_t byte_offset;
} DLTensor;
所以,假设给定一个ConstantNode类指针对象:
ConstantNode* cnode;
NDArray nd= **cnode->data;
那么nd.operator->()表示一个DLTensor指针类
所以,nd->data就能直接访问**DLTensor的data
注意,通过如下方式可以获取DLTensor的总大小(字节数)和数据个数
static inline size_t GetDataSize(const DLTensor* t) {
size_t size = 1;
for (tvm_index_t i = 0; i < t->ndim; ++i) {
size *= t->shape[i];
}
size *= (t->dtype.bits * t->dtype.lanes + 7) / 8;
return size;
}
static inline size_t GetDataNumber(const DLTensor* t) {
size_t size = 1;
for (tvm_index_t i = 0; i < t->ndim; ++i) {
size *= t->shape[i];
}
size *= (t->dtype.bits * t->dtype.lanes + 7) / 8;
return size;
}
if (const ConstantNode* rhs = other.as<ConstantNode>()) {
return NDArrayEqual(lhs->data, rhs->data);//此处,rhs->data就是指向NDArray *
}
示例:
Expr ExpandConstantNode(const ConstantNode* const_node, std::string layout_name) {
runtime::NDArray src_ret = const_node->data;
TensorType tensor_type = const_node->tensor_type();
int64_t OC, IC;
std::vector<int64_t> src_shape;
Array<IndexExpr> tensor_shape = tensor_shape;
for (size_t i = 0; i < tensor_shape.size(); ++i) {
int64_t sz_i = *as_const_int(tensor_shape[i]);
src_shape.push_back(sz_i);
}
OC = src_shape[0];
IC = src_shape[1];
std::vector<int64_t> dst_shape;
dst_shape.assign(src_shape.begin(), src_shape.end());
dst_shape[0] = OC * 2; // duble the OC
dst_shape[1] = IC;
auto dst_ndarray = runtime::NDArray::Empty(
dst_shape, tensor_type->dtype.operator DLDataType(), {kDLCPU, 0});
DLTensor* dst = const_cast<DLTensor*>(dst_ndarray.operator->());
SimpleDataType data_type = GetSimpleDataType(tensor_type->dtype);
if (data_type == DATA_FP16) {
// FP16
ExpandWeight<uint16_t>(src_ret.operator->(), dst, src_shape, dst_shape, layout_name);
} else if (data_type == DATA_FLOAT) {
// FP32 for testing
ExpandWeight<float>(src_ret.operator->(), dst, src_shape, dst_shape, layout_name);
} else {
// INT8
ExpandWeight<char>(src_ret.operator->(), dst, src_shape, dst_shape, layout_name);
}
auto new_constant = ConstantNode::make(dst_ndarray);
return new_constant;
}
};