TIM-VX/samples/nbg_runner/nbg_runner_main.cc

246 lines
9.6 KiB
C++

/****************************************************************************
*
* Copyright (c) 2020 Vivante Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#include "tim/vx/context.h"
#include "tim/vx/graph.h"
#include "tim/vx/ops/nbg.h"
#include "tim/vx/types.h"
#include "tim/utils/nbg_parser/nbg_parser.h"
#include "tim/utils/nbg_parser/gc_vip_nbg_format.h"
#include <fstream>
#include <iostream>
#include <assert.h>
#include <vector>
#include <map>
#ifdef __linux__
#include <time.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
using namespace std;
static uint64_t get_perf_count()
{
#if defined(__linux__) || defined(__ANDROID__) || defined(__QNX__) || defined(__CYGWIN__)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)((uint64_t)ts.tv_nsec + (uint64_t)ts.tv_sec * 1000000000);
#elif defined(_WIN32) || defined(UNDER_CE)
LARGE_INTEGER ln;
QueryPerformanceCounter(&ln);
return (uint64_t)ln.QuadPart;
#endif
}
static map<_nbg_buffer_quantize_format_e, tim::vx::QuantType> QMap = {
{NBG_BUFFER_QUANTIZE_NONE, tim::vx::QuantType::NONE},
{NBG_BUFFER_QUANTIZE_AFFINE_ASYMMETRIC, tim::vx::QuantType::ASYMMETRIC},
};
static map<tim::vx::QuantType, string> QNameMap = {
{tim::vx::QuantType::NONE, "NONE"},
{tim::vx::QuantType::ASYMMETRIC, "ASYMMETRIC_PER_TENSOR"},
{tim::vx::QuantType::SYMMETRIC_PER_CHANNEL, "SYMMETRIC_PER_CHANNEL"},
};
static map<_nbg_buffer_format_e, tim::vx::DataType> DMap = {
{NBG_BUFFER_FORMAT_FP32, tim::vx::DataType::FLOAT32},
{NBG_BUFFER_FORMAT_FP16, tim::vx::DataType::FLOAT16},
{NBG_BUFFER_FORMAT_UINT8, tim::vx::DataType::UINT8},
{NBG_BUFFER_FORMAT_INT8, tim::vx::DataType::INT8},
{NBG_BUFFER_FORMAT_UINT16, tim::vx::DataType::UINT16},
{NBG_BUFFER_FORMAT_INT16, tim::vx::DataType::INT16},
{NBG_BUFFER_FORMAT_UINT32, tim::vx::DataType::UINT32},
{NBG_BUFFER_FORMAT_INT32, tim::vx::DataType::INT32},
};
static map<tim::vx::DataType, string> DNameMap = {
{tim::vx::DataType::FLOAT32, "FLOAT32"},
{tim::vx::DataType::FLOAT16, "FLOAT16"},
{tim::vx::DataType::UINT8, "UINT8"},
{tim::vx::DataType::INT8, "INT8"},
{tim::vx::DataType::UINT16, "UINT16"},
{tim::vx::DataType::INT16, "INT16"},
{tim::vx::DataType::UINT32, "UINT32"},
{tim::vx::DataType::INT32, "INT32"},
};
int main(int argc, char** argv) {
if (argc != 2) {
std::cout<< "usage: ./nbg_runner network.nb" << std::endl;
return -1;
}
ifstream nbg_file((const char*)argv[1]);
assert(nbg_file);
nbg_file.seekg(0, ios::end);
int nbg_size = nbg_file.tellg();
std::vector<char> nbg_buf(nbg_size);
nbg_file.seekg(0, ios::beg);
nbg_file.read( nbg_buf.data(), nbg_size );
nbg_file.close();
nbg_parser_data nbg = NBG_NULL;
nbg_parser_init(nbg_buf.data(), nbg_size, &nbg);
// Get Inputs
int input_count = 0;
nbg_parser_query_network(nbg, NBG_PARSER_NETWORK_INPUT_COUNT, &input_count,
sizeof(input_count));
printf("Number of Inputs: %d\n", input_count);
vector<tim::vx::TensorSpec> input_list;
for (int i = 0; i < input_count; i++) {
printf(" Input: %d\n", i);
// Get type of input, only support tensor for now
_nbg_buffer_type_e data_type;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_DATA_TYPE, &data_type,
sizeof(data_type));
assert( data_type == NBG_BUFFER_TYPE_TENSOR );
// Get Shape
unsigned int dim_count;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_NUM_OF_DIMENSION,
&dim_count, sizeof(dim_count));
assert( dim_count <= MAX_NUM_DIMS );
unsigned int dim_size[MAX_NUM_DIMS];
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_DIMENSIONS, dim_size,
sizeof(dim_size) * dim_count);
tim::vx::ShapeType input_shape;
printf("\tShape: { ");
for (unsigned int j=0 ; j<dim_count; j++) {
input_shape.push_back(dim_size[j]);
printf("%u ", input_shape[j]);
}
printf("}\n");
// Get Quantization Format
_nbg_buffer_quantize_format_e quant_format;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_QUANT_FORMAT,
&quant_format, sizeof(quant_format));
float tf_scale;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_SCALE, &tf_scale,
sizeof(tf_scale));
int tf_zerop;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_ZERO_POINT, &tf_zerop,
sizeof(tf_zerop));
tim::vx::Quantization input_quant(QMap[quant_format], tf_scale, tf_zerop);
// Get Data Format
_nbg_buffer_format_e data_format;
nbg_parser_query_input(nbg, i, NBG_PARSER_BUFFER_PROP_DATA_FORMAT, &data_format,
sizeof(data_format));
printf("\tFormat: %s - ", DNameMap[DMap[data_format]].c_str());
printf("%s(%f, %d)\n", QNameMap[QMap[quant_format]].c_str(), tf_scale, tf_zerop);
tim::vx::TensorSpec input_tensor(DMap[data_format], input_shape, tim::vx::TensorAttribute::INPUT, input_quant);
input_list.push_back(input_tensor);
}
// Get Outtputs
int output_count = 0;
nbg_parser_query_network(nbg, NBG_PARSER_NETWORK_OUTPUT_COUNT, &output_count,
sizeof(output_count));
printf("Number of Outputs: %d\n", output_count);
vector<tim::vx::TensorSpec> output_list;
for (int i = 0; i < output_count; i++) {
printf(" Output: %d\n", i);
// Get type of output, only support tensor for now
_nbg_buffer_type_e data_type;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_DATA_TYPE, &data_type,
sizeof(data_type));
assert( data_type == NBG_BUFFER_TYPE_TENSOR );
// Get Shape
unsigned int dim_count;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_NUM_OF_DIMENSION,
&dim_count, sizeof(dim_count));
assert( dim_count <= MAX_NUM_DIMS );
unsigned int dim_size[MAX_NUM_DIMS];
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_DIMENSIONS, dim_size,
sizeof(dim_size) * dim_count);
tim::vx::ShapeType output_shape;
printf("\tShape: { ");
for (unsigned int j=0 ; j<dim_count; j++) {
output_shape.push_back(dim_size[j]);
printf("%u ", output_shape[j]);
}
printf("}\n");
// Get Quantization Format
_nbg_buffer_quantize_format_e quant_format;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_QUANT_FORMAT,
&quant_format, sizeof(quant_format));
float tf_scale;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_SCALE, &tf_scale,
sizeof(tf_scale));
int tf_zerop;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_ZERO_POINT, &tf_zerop,
sizeof(tf_zerop));
tim::vx::Quantization output_quant(QMap[quant_format], tf_scale, tf_zerop);
// Get Data Format
_nbg_buffer_format_e data_format;
nbg_parser_query_output(nbg, i, NBG_PARSER_BUFFER_PROP_DATA_FORMAT, &data_format,
sizeof(data_format));
printf("\tFormat: %s - ", DNameMap[DMap[data_format]].c_str());
printf("%s(%f, %d)\n", QNameMap[QMap[quant_format]].c_str(), tf_scale, tf_zerop);
tim::vx::TensorSpec output_tensor(DMap[data_format], output_shape, tim::vx::TensorAttribute::OUTPUT, output_quant);
output_list.push_back(output_tensor);
}
auto ctx = tim::vx::Context::Create();
auto graph = ctx->CreateGraph();
auto nbg_node = graph->CreateOperation<tim::vx::ops::NBG>(
nbg_buf.data(), input_count, output_count);
for(int i=0; i<input_count; i++) {
auto input = graph->CreateTensor(input_list[i]);
(*nbg_node).BindInput(input);
}
for(int i=0; i<output_count; i++) {
auto output = graph->CreateTensor(output_list[i]);
(*nbg_node).BindOutput(output);
}
uint64_t tmS, tmE;
tmS = get_perf_count();
assert(graph->Compile());
tmE = get_perf_count();
printf("Compile Time: %ldus\n", (tmE - tmS)/1000);
tmS = get_perf_count();
assert(graph->Run());
tmE = get_perf_count();
printf("Run Time: %ldus\n", (tmE - tmS)/1000);
}