#include <functional>
/** @brief the binded data manipulation function */
-typedef std::function<void (void*, void*, size_t)> dataManipFunc;
+typedef std::function<size_t (void*, void*, size_t)> dataManipFunc;
/** @brief communication plugin: singleton */
class CommPlugin {
*/
int extractGenericBuffer (const generic_buffer *buf, void *data,
dataManipFunc func = nullptr, size_t offset = 0, size_t size = 0) {
+ size_t count = 0;
+
if (buf == nullptr || data == nullptr)
return -EINVAL;
if (buf->size == 0)
if (size == 0)
size = buf->size;
- /** Note that npu-engine supports data manipulation only for the BUFFER_MAPPED.
- * Thus, for other types, user need to ensure that the data format in the dmabuf
- * is compatible with the device. */
+ /** Note that npu-engine does not support data manipulation for the BUFFER_DMABUF.
+ * In this case, ensure that the data format is compatible with the device. */
if (buf->type == BUFFER_FILE) {
std::ifstream ifs (buf->filepath, std::ios::binary);
if (ifs.good()) {
ifs.seekg(offset);
- ifs.read(static_cast<char *>(data), size);
- size_t count = ifs.gcount();
- ifs.close();
+ if (func != nullptr) {
+ char * tmp = new char [size];
- if (count == size)
- return 0;
+ ifs.read(tmp, size);
+ func (data, tmp, size);
+
+ delete [] tmp;
+ } else {
+ ifs.read(static_cast<char *>(data), size);
+ }
+ count = ifs.gcount();
+ ifs.close();
}
} else if (buf->type == BUFFER_MAPPED) {
if (buf->addr == nullptr)
return -EINVAL;
- if (func != nullptr)
- func (data, static_cast<char*>(buf->addr) + offset, size);
- else
+ if (func != nullptr) {
+ count = func (data, static_cast<char*>(buf->addr) + offset, size);
+ } else {
memcpy (data, static_cast<char*>(buf->addr) + offset, size);
+ count = size;
+ }
+ }
+ /** BUFFER_DMABUF enables zero-copy: it's impossible to manipulate data */
+ if (count == size)
return 0;
- }
- /** BUFFER_DMABUF enables zero-copy, which means it's impossible to manipulate data */
return -EINVAL;
}
*/
#include "ne-handler.h"
+#include "ne-data.h"
#include <libnpuhost.h>
#include <npubinfmt.h>
return -EINVAL;
}
+ const_cast<Model *>(model)->updateDataInfo ();
+
Buffer *buffer = prepareInputBuffers (model->getMetadata(), input);
if (buffer == nullptr) {
logerr (TAG, "Failed to extract buffer instance\n");
TrinityVision2::prepareSegmentTable (const Model *model, const input_buffers *input,
const output_buffers *output)
{
- if (model == nullptr) {
- logerr (TAG, "Invalid arguments provided\n");
- return nullptr;
- }
-
const Metadata *meta = model->getMetadata ();
if (meta == nullptr || (input != nullptr &&
meta->getInputNum() != input->num_buffers)) {
if (opmode != NPUINPUT_HOST)
return -EINVAL;
- if (input == nullptr || input->num_buffers == 0)
+ if (input == nullptr || input->num_buffers == 0 || model == nullptr)
return -EINVAL;
+ const_cast<Model *>(model)->updateDataInfo ();
+
/** this device uses segment table */
SegmentTable * segt = prepareSegmentTable (model, input);
if (segt == nullptr) {
/** extract input data */
for (uint32_t idx = 0; idx < input->num_buffers; idx++) {
- size_t max_seg_size = segt->getInputSegment(idx)->getSize();
- uint32_t seg_offset = segt->getInputSegmentOffset(idx);
-
- if (input->bufs[idx].size + seg_offset > max_seg_size) {
- logerr (TAG, "Too large input data provided: max segment size (%zu)\n",
- max_seg_size);
- return -ERANGE;
- }
-
if (!segt->getInputSegment(idx)->isExternal ()) {
+ uint32_t seg_offset = segt->getInputSegmentOffset(idx);
auto func = std::bind (TrinityVision2::manipulateData, model, idx, true,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
int status = comm_.extractGenericBuffer (
#ifdef ENABLE_MANIP
-#define do_quantized_memcpy(type) do {\
- idx = 0;\
- if (quant) {\
- while (idx < num_elems) {\
- val = ((type *) src)[idx];\
- val = val / _scale;\
- val += _zero_point;\
- val = (val > 255.0) ? 255.0 : 0.0;\
- ((uint8_t *) dst)[idx++] = (uint8_t) val;\
- }\
- } else {\
- while (idx < num_elems) {\
- val = *(uint8_t *) src;\
- val -= _zero_point;\
- val *= _scale;\
- ((type *) dst)[idx++] = (type) val;\
- dst = (void*)(((uint8_t *) dst) + data_size);\
- src = (void*)(((uint8_t *) src) + 1);\
- }\
- }\
- } while (0)
-
-/**
- * @brief memcpy during quantization
- */
-static void memcpy_with_quant (bool quant, data_type type, float scale, uint32_t zero_point,
- void *dst, const void *src, uint32_t num_elems)
-{
- double _scale = (double) scale;
- double _zero_point = (double) zero_point;
- double val;
- uint32_t data_size = get_data_size (type);
- uint32_t idx;
-
- switch (type) {
- case DATA_TYPE_INT8:
- do_quantized_memcpy (int8_t);
- break;
- case DATA_TYPE_UINT8:
- do_quantized_memcpy (uint8_t);
- break;
- case DATA_TYPE_INT16:
- do_quantized_memcpy (int16_t);
- break;
- case DATA_TYPE_UINT16:
- do_quantized_memcpy (uint16_t);
- break;
- case DATA_TYPE_INT32:
- do_quantized_memcpy (int32_t);
- break;
- case DATA_TYPE_UINT32:
- do_quantized_memcpy (uint32_t);
- break;
- case DATA_TYPE_INT64:
- do_quantized_memcpy (int64_t);
- break;
- case DATA_TYPE_UINT64:
- do_quantized_memcpy (uint64_t);
- break;
- case DATA_TYPE_FLOAT32:
- do_quantized_memcpy (float);
- break;
- case DATA_TYPE_FLOAT64:
- do_quantized_memcpy (double);
- break;
- default:
- logerr (TAG, "Unsupported datatype %d\n", type);
- }
-}
-
/**
* @brief perform data manipulation
* @param[in] model model instance
void *dst, void *src, size_t size)
{
const Metadata *meta = model->getMetadata();
- const tensor_data_info* info;
- const uint32_t *dims;
- uint32_t zero_point;
- float scale;
+ DataConverter converter (is_input);
+
+ converter.setData (src, dst, size);
- /** extract required information from the metadata */
if (is_input) {
- if (idx >= meta->getInputNum()) {
- logerr (TAG, "Wrong information for input tensors in metadata\n");
+ const tensor_data_info* info = model->getInputDataInfo (idx);
+ if (info == nullptr)
return 0;
- }
- info = model->getInputDataInfo (idx);
- dims = meta->getInputDims (idx);
- zero_point = meta->getInputQuantZero (idx);
- scale = meta->getInputQuantScale (idx);
+ converter.setDataLayout (info->layout, DATA_LAYOUT_SRNPU);
+ converter.setDataType (info->type, DATA_TYPE_SRNPU);
+ converter.setDataDims (meta->getInputDims (idx));
+ converter.setQuantZero (meta->getInputQuantZero (idx));
+ converter.setQuantScale (meta->getInputQuantScale (idx));
} else {
- if (idx >= meta->getOutputNum()) {
- logerr (TAG, "Wrong information for output tensors in metadata\n");
+ const tensor_data_info* info = model->getOutputDataInfo (idx);
+ if (info == nullptr)
return 0;
- }
-
- info = model->getOutputDataInfo (idx);
- dims = meta->getOutputDims (idx);
- zero_point = meta->getOutputQuantZero (idx);
- scale = meta->getOutputQuantScale (idx);
- }
-
- if (info == nullptr) {
- logerr (TAG, "Unmatched tensors info\n");
- return 0;
- }
-
- uint32_t batch = dims[0];
- uint32_t height = dims[1];
- uint32_t width = dims[2];
- uint32_t depth = dims[3];
- uint32_t data_size = get_data_size (info->type);
- if (data_size == 0) {
- logerr (TAG, "Invalid data size\n");
- return 0;
+ converter.setDataLayout (DATA_LAYOUT_SRNPU, info->layout);
+ converter.setDataType (DATA_TYPE_SRNPU, info->type);
+ converter.setDataDims (meta->getOutputDims (idx));
+ converter.setQuantZero (meta->getOutputQuantZero (idx));
+ converter.setQuantScale (meta->getOutputQuantScale (idx));
}
- bool need_quantization = false;
- /**
- * note that we assume DATA_TYPE_SRNPU is the smallest data type that we consider.
- * Also, DATA_TYPE_SRNPU and uint8_t may be regarded as the same in the view of apps.
- */
- if (info->type != DATA_TYPE_SRNPU) {
- assert (data_size >= get_data_size (DATA_TYPE_SRNPU));
+ return converter.perform ();
+}
- if (data_size > get_data_size (DATA_TYPE_SRNPU) ||
- !(zero_point == default_quant_zero && scale == default_quant_scale))
- need_quantization = true;
- }
+/**
+ * @brief perform data manipulation
+ * @param[in] model model instance
+ * @param[in] idx tensor index
+ * @param[in] is_input indicate it's input manipulation
+ * @param[out] dst destination buffer
+ * @param[in] src source buffer (feature map)
+ * @param[in] size size to be copied
+ * @return size of memory copy if no error, otherwise zero
+ *
+ * @note the input data format should be NHWC
+ *
+ * @detail Feature map data in TRIV2, (x, y, z) = (width, height, depth)
+ *
+ * 1) Image input (depth == 1 or depth == 3)
+ * Addr(x,y,z) = Addr(0,0,0) + z + depth * x + ymod * y
+ *
+ * 2) Common cases
+ * Addr(x,y,z) = Addr(0,0,0) + (z % 64) + (64 * x) + ymod * y + zmod * (z / 64)
+ */
+size_t
+TrinityVision2::manipulateData (const Model *model, uint32_t idx, bool is_input,
+ void *dst, void *src, size_t size)
+{
+ const Metadata *meta = model->getMetadata();
+ DataConverter converter (is_input);
- /** check data manipulation is required */
- if (depth != 3 && depth != 64 && info->layout != DATA_LAYOUT_SRNPU) {
- uint32_t MPA_L = DATA_GRANULARITY;
- uint32_t n, h, w, d;
- uint32_t std_offset; /* standard offset in NHWC data format */
- uint32_t npu_offset; /* npu offset in NPU HW data format*/
- uint32_t src_offset;
- uint32_t dst_offset;
- uint32_t slice_size;
+ converter.setData (src, dst, size);
- /* @todo we currently support only NHWC */
- if (info->layout != DATA_LAYOUT_NHWC) {
- logerr (TAG, "data manipulation is supported for NHWC only\n");
+ if (is_input) {
+ const tensor_data_info* info = model->getInputDataInfo (idx);
+ if (info == nullptr)
return 0;
- }
- for (n = 0; n < batch; n++) {
- for (h = 0; h < height; h++) {
- for (w = 0; w < width; w++) {
- for (d = 0; d < depth; d += MPA_L) {
- std_offset = d + depth * (w + width * (h + n * height));
- npu_offset = MPA_L * (w + width * (h + (n + d / MPA_L) * height));
- slice_size = (depth - d >= MPA_L) ? MPA_L : depth - d;
-
- if (is_input) {
- src_offset = std_offset * data_size;
- dst_offset = npu_offset;
- } else {
- src_offset = npu_offset;
- dst_offset = std_offset * data_size;
- }
-
- /* if depth is not a multiple of MPA_L, add zero paddings (not exact values) */
- if (need_quantization) {
- memcpy_with_quant (is_input, info->type, scale, zero_point,
- static_cast<char*>(dst) + dst_offset,
- static_cast<char*>(src) + src_offset,
- slice_size);
- } else {
- memcpy (
- static_cast<char*>(dst) + dst_offset,
- static_cast<char*>(src) + src_offset,
- slice_size);
- }
- }
- }
- }
- }
- } else if (need_quantization) {
- /** depth == 3 || depth == 64; special cases which can directly copy input tensor data */
- memcpy_with_quant (is_input, info->type, scale, zero_point,
- dst, src, is_input ? size / data_size : size);
+ converter.setDataLayout (info->layout, DATA_LAYOUT_TRIV2);
+ converter.setDataType (info->type, meta->getInputQuantType (idx));
+ converter.setDataDims (meta->getInputDims (idx));
+ converter.setQuantZero (meta->getInputQuantZero (idx));
+ converter.setQuantScale (meta->getInputQuantScale (idx));
} else {
- memcpy (dst, src, size);
+ const tensor_data_info* info = model->getOutputDataInfo (idx);
+ if (info == nullptr)
+ return 0;
+
+ converter.setDataLayout (DATA_LAYOUT_TRIV2, info->layout);
+ converter.setDataType (meta->getOutputQuantType (idx), info->type);
+ converter.setDataDims (meta->getOutputDims (idx));
+ converter.setQuantZero (meta->getOutputQuantZero (idx));
+ converter.setQuantScale (meta->getOutputQuantScale (idx));
}
- return size;
+ return converter.perform ();
}
#else
return size;
}
-#endif
-
-/** other device types don't have data manip impl. yet */
-
size_t
TrinityVision2::manipulateData (const Model *model, uint32_t idx, bool is_input,
void *dst, void *src, size_t size)
return size;
}
+#endif
+
+/** other device types don't have data manip impl. yet */
+
size_t
TrinityAsr::manipulateData (const Model *model, uint32_t idx, bool is_input,
void *dst, void *src, size_t size)
return 0;
}
+void
+Model::updateDataInfo ()
+{
+ for (uint32_t idx = 0; idx < in_.num_info; idx++) {
+ if (in_.info[idx].layout == DATA_LAYOUT_MODEL) {
+ if (meta_->getVersion () < 3)
+ in_.info[idx].layout = DATA_LAYOUT_TRIV;
+ else
+ in_.info[idx].layout = DATA_LAYOUT_TRIV2;
+ }
+ if (in_.info[idx].type == DATA_TYPE_MODEL)
+ in_.info[idx].type = meta_->getInputQuantType (idx);
+ }
+
+ for (uint32_t idx = 0; idx < out_.num_info; idx++) {
+ if (out_.info[idx].layout == DATA_LAYOUT_MODEL) {
+ if (meta_->getVersion () < 3)
+ out_.info[idx].layout = DATA_LAYOUT_TRIV;
+ else
+ out_.info[idx].layout = DATA_LAYOUT_TRIV2;
+ }
+ if (out_.info[idx].type == DATA_TYPE_MODEL)
+ out_.info[idx].type = meta_->getOutputQuantType (idx);
+ }
+}
+
/**
* @brief extract and set the metadata
* @param[in] data raw-data of model binary
if (this->meta_.get() == nullptr)
return -EINVAL;
+ in_.num_info = getInputTensorNum ();
+ for (uint32_t idx = 0; idx < getInputTensorNum (); idx++) {
+ in_.info[idx].layout = DATA_LAYOUT_MODEL;
+ in_.info[idx].type = DATA_TYPE_MODEL;
+ }
+
+ out_.num_info = getOutputTensorNum ();
+ for (uint32_t idx = 0; idx < getOutputTensorNum (); idx++) {
+ out_.info[idx].layout = DATA_LAYOUT_MODEL;
+ out_.info[idx].type = DATA_TYPE_MODEL;
+ }
+
return 0;
}
#include <assert.h>
/** default data layout and type */
-static const data_type default_data_type = DATA_TYPE_SRNPU;
-static const data_layout default_data_layout = DATA_LAYOUT_SRNPU;
+static const data_type default_data_type = DATA_TYPE_MODEL;
+static const data_layout default_data_layout = DATA_LAYOUT_MODEL;
/** this assumes uint8 zero quantization */
static const uint32_t default_quant_zero = 127;
static const float default_quant_scale = 1.0;
virtual uint32_t getInputSegmentOffset (uint32_t idx) const { return 0; }
virtual uint32_t getOutputSegmentOffset (uint32_t idx) const { return 0; }
+ virtual uint32_t getInputEmodY (uint32_t idx) const { return 0; }
+ virtual uint32_t getInputEmodZ (uint32_t idx) const { return 0; }
+
+ virtual uint32_t getOutputEmodY (uint32_t idx) const { return 0; }
+ virtual uint32_t getOutputEmodZ (uint32_t idx) const { return 0; }
+
uint64_t getSize () const { return meta_->size; }
uint64_t getProgramSize () const { return meta_->program_size; }
uint64_t getWeightSize () const { return meta_->weight_size; }
return output_dims[idx];
}
+ data_type getInputQuantType (uint32_t idx) const override {
+ return DATA_TYPE_SRNPU;
+ }
+
+ data_type getOutputQuantType (uint32_t idx) const override {
+ return DATA_TYPE_SRNPU;
+ }
private:
Metadata_v1 (npubin_meta *meta);
return meta_->output_quant_s[idx];
}
+ data_type getInputQuantType (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
+ return DATA_TYPE_SRNPU;
+ }
+
+ data_type getOutputQuantType (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
+ return DATA_TYPE_SRNPU;
+ }
+
private:
Metadata_v2 (npubin_meta *meta);
};
return meta_->output_seg_dims[idx];
}
+ uint32_t getInputEmodY (uint32_t idx) const override {
+ assert (idx < getInputNum ());
+ return meta_->input_seg_emod_y[idx];
+ }
+ uint32_t getInputEmodZ (uint32_t idx) const override {
+ assert (idx < getInputNum ());
+ return meta_->input_seg_emod_z[idx];
+ }
+
+ uint32_t getOutputEmodY (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
+ return meta_->output_seg_emod_y[idx];
+ }
+ uint32_t getOutputEmodZ (uint32_t idx) const override {
+ assert (idx < getOutputNum ());
+ return meta_->output_seg_emod_z[idx];
+ }
+
uint32_t getInputQuantZero (uint32_t idx) const override {
assert (idx < getInputNum ());
return meta_->input_seg_quant_z[idx];
void setProgramData (HWmem *data) { program_data_ = data; }
void setInternalID (uint64_t id) { internal_id_ = id; }
+ void updateDataInfo ();
+
const Metadata *getMetadata () const { return meta_.get(); }
uint32_t getID () const { return model_id_; }
}
}
- void set_async (int async) {
- async_ = (async == 1);
+ void set_async () {
+ async_ = true;
}
void set_repeat (const std::string repeat_str) {
std::cerr << " -i <arg> \t Set output notimode [intr|polling]\n";
std::cerr << " -n <arg> \t Set number of repetition\n";
std::cerr << " -a \t\t Set async mode\n";
+ std::cerr << " -h \t\t Show help messages\n";
}
/** @brief apptest main */
optind = 0;
opterr = 0;
- while ((c = getopt (argc, argv, "an:i:")) != -1) {
+ while ((c = getopt (argc, argv, "ahn:i:")) != -1) {
switch (c) {
case 'a':
- tester.set_async (1);
+ tester.set_async ();
break;
case 'n':
tester.set_repeat (optarg);
else
std::cerr << "Unknown flag: " << c;
std::cerr << std::endl;
-
+ // no-break
+ case 'h':
print_usage(argv[0]);
+ return 0;
}
}
EXPECT_EQ (&plugin, &plugin2);
}
-static void test_manip (char *data, size_t size)
+static size_t test_manip (char *data, size_t size)
{
for (size_t i = 0; i < size; i++)
data[i] = 'b';
+
+ return size;
}
/**
if (val > 255.0)
val = 255.0;
- else
+ else if (val < 0.0)
val = 0.0;
- EXPECT_DOUBLE_EQ (val, (double)((uint8_t *) each_data_ptr)[j]);
+ EXPECT_EQ ((uint8_t) val, ((uint8_t *) each_data_ptr)[j]);
}
}
}
if (val > 255.0)
val = 255.0;
- else
+ else if (val < 0.0)
val = 0.0;
- EXPECT_DOUBLE_EQ (val, (double)((uint8_t *) each_data_ptr)[j % 32 + 64 * (j / 32)]);
+ EXPECT_EQ ((uint8_t) val, ((uint8_t *) each_data_ptr)[j % 32 + 64 * (j / 32)]);
+ }
+ }
+ }
+
+ destroy_input_buffers (input_buf);
+ destroy_model_buffer (model_buf);
+}
+
+/**
+ * @brief test TRIV's dequantization during data manipulation
+ */
+TEST (ne_core_handler_test, triv_dequantization)
+{
+ std::unique_ptr<Device> device (Device::createInstance (NPUCOND_TRIV_CONN_SOCIP, 0));
+ EXPECT_NE (device.get (), nullptr);
+
+ srand (time (NULL));
+
+ /* metadata version 2 */
+ generic_buffer model_buf;
+ create_model_buffer_v2 (model_buf);
+
+ /* setup for input tensors */
+ input_buffers input_buf;
+ create_input_buffers (input_buf);
+
+ uint32_t num_tensors = 4;
+ uint32_t size_tensor = 4096;
+
+ tensors_data_info info;
+ info.num_info = num_tensors;
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ info.info[i].layout = DATA_LAYOUT_NHWC; /* need manipulation */
+ info.info[i].type = DATA_TYPE_FLOAT32; /* need quantization */
+ }
+
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ /* fill any data */
+ for (uint32_t j = 0; j < size_tensor / sizeof (float); j++) {
+ ((float *) input_buf.bufs[i].addr)[j] = i * j;
+ }
+ }
+
+ npubin_meta *meta = static_cast<npubin_meta *> (model_buf.addr);
+
+ /* case 1: no data manipulation (depth == 64) */
+ meta->input_num = num_tensors;
+ meta->buffer_size = size_tensor / sizeof (float); /** 32bit -> 8bit */
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ meta->input_offsets[i] = 0;
+ meta->input_elem_size[i] = sizeof (float); /* float */
+ meta->input_dims[i][0] = 1;
+ meta->input_dims[i][1] = 4;
+ meta->input_dims[i][2] = 4;
+ meta->input_dims[i][3] = 64;
+
+ meta->input_quant_s[i] = 10.0;
+ meta->input_quant_z[i] = 127;
+
+ meta->output_offsets[i] = 0;
+ meta->output_elem_size[i] = sizeof (float); /* float */
+ meta->output_dims[i][0] = 1;
+ meta->output_dims[i][1] = 4;
+ meta->output_dims[i][2] = 4;
+ meta->output_dims[i][3] = 64;
+
+ meta->output_quant_s[i] = 10.0;
+ meta->output_quant_z[i] = 127;
+ }
+
+ Model *model = nullptr;
+ EXPECT_EQ (device->setModel (&model_buf, &model), 0);
+ EXPECT_EQ (model->setDataInfo (&info, &info), 0);
+
+ {
+ std::unique_ptr<uint8_t []> output_data (new uint8_t [meta->buffer_size]);
+ std::unique_ptr<float []> output_dequant_data (new float [meta->buffer_size]);
+
+ double zero_point, scale;
+ void *each_data_ptr;
+
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ EXPECT_EQ (TrinityVision::manipulateData (model, i, true,
+ output_data.get (), input_buf.bufs[i].addr, size_tensor), size_tensor);
+
+ zero_point = (double) meta->input_quant_z[i];
+ scale = (double) meta->input_quant_s[i];
+ each_data_ptr = (char *) output_data.get ();
+
+ for (uint32_t j = 0; j < size_tensor / sizeof(float); j++) {
+ double val = (double)((float *) input_buf.bufs[i].addr)[j];
+
+ val = val / scale;
+ val = val + zero_point;
+
+ if (val > 255.0)
+ val = 255.0;
+ else if (val < 0.0)
+ val = 0.0;
+
+ EXPECT_EQ ((uint8_t) val, ((uint8_t *) each_data_ptr)[j]);
+ }
+
+ EXPECT_EQ (TrinityVision::manipulateData (model, i, false,
+ output_dequant_data.get (), output_data.get (), size_tensor / sizeof (float)),
+ size_tensor / sizeof (float));
+
+ zero_point = (double) meta->output_quant_z[i];
+ scale = (double) meta->output_quant_s[i];
+ each_data_ptr = (char *) output_dequant_data.get ();
+
+ for (uint32_t j = 0; j < size_tensor / sizeof(float); j++) {
+ double val = (double)((uint8_t *) output_data.get ())[j];
+
+ val = val - zero_point;
+ val = val * scale;
+
+ ASSERT_DOUBLE_EQ (val, (double)((float *) each_data_ptr)[j]);
+ }
+ }
+ }
+
+ /* case 2: data manipulation (depth == 32) */
+ meta->input_num = num_tensors;
+ meta->buffer_size = size_tensor / sizeof (float) * 2; /** 32bit -> 8bit but need zero padding */
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ meta->input_offsets[i] = 0;
+ meta->input_elem_size[i] = sizeof (float); /* float */
+ meta->input_dims[i][0] = 1;
+ meta->input_dims[i][1] = 8;
+ meta->input_dims[i][2] = 4;
+ meta->input_dims[i][3] = 32;
+
+ meta->input_quant_s[i] = 10.0;
+ meta->input_quant_z[i] = 127;
+
+ meta->output_offsets[i] = 0;
+ meta->output_elem_size[i] = sizeof (float); /* float */
+ meta->output_dims[i][0] = 1;
+ meta->output_dims[i][1] = 8;
+ meta->output_dims[i][2] = 4;
+ meta->output_dims[i][3] = 32;
+
+ meta->output_quant_s[i] = 10.0;
+ meta->output_quant_z[i] = 127;
+ }
+
+ EXPECT_EQ (device->setModel (&model_buf, &model), 0);
+ EXPECT_EQ (model->setDataInfo (&info, &info), 0);
+
+ {
+ std::unique_ptr<uint8_t []> output_data (new uint8_t [meta->buffer_size]);
+ std::unique_ptr<float []> output_dequant_data (new float [meta->buffer_size]);
+
+ double zero_point, scale;
+ void *each_data_ptr;
+
+ for (uint32_t i = 0; i < num_tensors; i++) {
+ EXPECT_EQ (TrinityVision::manipulateData (model, i, true,
+ output_data.get (), input_buf.bufs[i].addr, size_tensor), size_tensor);
+
+ zero_point = (double) meta->input_quant_z[i];
+ scale = (double) meta->input_quant_s[i];
+ each_data_ptr = (char *) output_data.get ();
+
+ for (uint32_t j = 0; j < size_tensor / sizeof(float); j++) {
+ double val = (double)((float *) input_buf.bufs[i].addr)[j];
+
+ val = val / scale;
+ val = val + zero_point;
+
+ if (val > 255.0)
+ val = 255.0;
+ else if (val < 0.0)
+ val = 0.0;
+
+ EXPECT_EQ ((uint8_t) val, ((uint8_t *) each_data_ptr)[j % 32 + 64 * (j / 32)]);
+ }
+
+ EXPECT_EQ (TrinityVision::manipulateData (model, i, false,
+ output_dequant_data.get (), output_data.get (), size_tensor / sizeof (float) * 2),
+ size_tensor / sizeof (float) * 2);
+
+ zero_point = (double) meta->output_quant_z[i];
+ scale = (double) meta->output_quant_s[i];
+ each_data_ptr = (char *) output_dequant_data.get ();
+
+ for (uint32_t j = 0; j < size_tensor / sizeof(float); j++) {
+ double val = (double)((uint8_t *) output_data.get ())[j % 32 + 64 * (j / 32)];
+
+ val = val - zero_point;
+ val = val * scale;
+
+ EXPECT_DOUBLE_EQ (val, (double)((float *) each_data_ptr)[j]);
}
}
}
EXPECT_EQ (meta->getOutputQuantZero (0), default_quant_zero);
EXPECT_FLOAT_EQ (meta->getInputQuantScale (0), default_quant_scale);
EXPECT_FLOAT_EQ (meta->getOutputQuantScale (0), default_quant_scale);
- EXPECT_EQ (meta->getInputQuantType (0), default_data_type);
- EXPECT_EQ (meta->getOutputQuantType (0), default_data_type);
+ EXPECT_EQ (meta->getInputQuantType (0), DATA_TYPE_SRNPU);
+ EXPECT_EQ (meta->getOutputQuantType (0), DATA_TYPE_SRNPU);
EXPECT_EQ (meta->getSegmentsNum (), (uint32_t) 0);
EXPECT_EQ (meta->getSegmentSize (0), (uint32_t) 0);