// for device
constexpr char DeviceModelFileOpt[] = "model_file";
+constexpr char DeviceModelDataTypeOpt[] = "model_dtype";
constexpr char DeviceImagePathOpt[] = "image_path";
constexpr char DeviceOutputLabelsOpt[] = "output_labels";
constexpr char DeviceReqIPOpt[] = "edge_ip";
constexpr char DeviceReqPortOpt[] = "req_port";
constexpr char DeviceRepPortOpt[] = "rep_port";
-// mobilenet v1
+// Imagenet(ILSVRC-2012-CLS) classification with MobileNet V1
const int MOBILENETV1_HEIGHT = 224;
const int MOBILENETV1_WIDTH = 224;
const int OUTPUT_LABELS_NUM = 1001;
+const int UINT8_BYTES = 1;
+const int FLOAT32_BYTES = 4;
const int IMG_HEIGHT = 100;
const int IMG_WIDTH = 100;
ImageClassification()
: edge_ip_("127.0.0.1")
, peer_name_(BEYOND_PLUGIN_PEER_NN_NAME)
+ , model_dtype_("uint8")
, req_port_(3000)
, rep_port_(3001)
, service_port_(3000)
, use_config_(0)
, discovered_(0)
+ , num_bytes_per_channel_(UINT8_BYTES)
, target_(TargetMode::UNKNOWN)
, session_h_(nullptr)
, evt_h_(nullptr)
std::string output_label_path_;
std::string edge_ip_;
std::string peer_name_;
+ std::string model_dtype_;
unsigned short req_port_;
unsigned short rep_port_;
unsigned short service_port_;
int use_config_;
int discovered_;
+ int num_bytes_per_channel_;
TargetMode target_;
std::vector<std::string> image_labels_;
Option::CreateOption(UseConfigOpt, &use_config_,
"Peer configuration On:1, Off:0 (default: 0)\n"),
Option::CreateOption(DeviceModelFileOpt, &model_file_path_,
- "Path to tflite model file"),
+ "Path to tflite model file(Imagenet classification with MobileNet V1)"),
+ Option::CreateOption(DeviceModelDataTypeOpt, &model_dtype_,
+ "Model data type(`uint8` or `float32` default: uint8)"),
Option::CreateOption(DeviceImagePathOpt, &input_image_path_,
"Path to input image file that will be evaluated"),
Option::CreateOption(DeviceOutputLabelsOpt, &output_label_path_,
if (LoadLabels() == false) {
printf("Failed to load labels\n");
}
+ if (model_dtype_.compare("float32") == 0) {
+ num_bytes_per_channel_ = FLOAT32_BYTES;
+ } else if (model_dtype_.compare("uint8") == 0) {
+ num_bytes_per_channel_ = UINT8_BYTES;
+ } else {
+ printf("Unsupported data type : %s\n", model_dtype_.c_str());
+ result = false;
+ }
if (result == true) {
printf("------------------------------\n");
printf("Target : %s \n", run_as_.c_str());
- printf("Model File : %s \n", model_file_path_.c_str());
+ printf("Model : %s (data type %s)\n", model_file_path_.c_str(), model_dtype_.c_str());
printf("Input Image File : %s \n", input_image_path_.c_str());
printf("Output Label File : %s \n", output_label_path_.c_str());
printf("Edge IP Address : %s \n", edge_ip_.c_str());
}
if (use_config_ == 1) {
+ const char *trans_mode;
+ const char *trans_opt;
+ if (num_bytes_per_channel_ == 4) {
+ trans_mode = "arithmetic";
+ trans_opt = "typecast:float32,add:-127.5,div:127.5";
+ } else {
+ trans_mode = "typecast";
+ trans_opt = "uint8";
+ }
struct beyond_input_image_config image_config = {
.format = "BGR",
.width = IMG_WIDTH,
.convert_format = "RGB",
.convert_width = MOBILENETV1_WIDTH,
.convert_height = MOBILENETV1_HEIGHT,
- .transform_mode = "typecast",
- .transform_option = "uint8"
+ .transform_mode = trans_mode,
+ .transform_option = trans_opt
};
struct beyond_input_config input_config;
input_config.input_type = BEYOND_INPUT_TYPE_IMAGE;
while (std::getline(stream, line)) {
image_labels_.push_back(line);
}
+
+ int loaded = image_labels_.size();
+ if (OUTPUT_LABELS_NUM != loaded) {
+ printf("Failed to get label from output(loaded %d)\n", loaded);
+ return false;
+ }
+
return true;
}
return false;
}
- if (use_config_ == 1) {
- // NO implementation yet for service config
- struct beyond_config config = { 's', nullptr };
- ret = beyond_peer_configure(peer_h_, &config);
- if (ret < 0) {
- printf("Failed to config input : %d\n", ret);
- return false;
- }
- }
-
struct beyond_peer_info info = {
.name = const_cast<char *>("name"),
.host = const_cast<char *>("0.0.0.0"),
cv::resize(inputImage, resizedImage,
cv::Size(IMG_WIDTH, IMG_HEIGHT));
} else {
- cv::resize(inputImage, resizedImage,
- cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
- cv::cvtColor(resizedImage, resizedImage, cv::COLOR_BGR2RGB);
+ if (num_bytes_per_channel_ == FLOAT32_BYTES) {
+ cv::Mat temp;
+ cv::resize(inputImage, temp,
+ cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
+ cv::cvtColor(temp, temp, cv::COLOR_BGR2RGB);
+ temp.convertTo(resizedImage, CV_32FC3, 1/255.0);
+ }
+ else {
+ cv::resize(inputImage, resizedImage,
+ cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
+ cv::cvtColor(resizedImage, resizedImage, cv::COLOR_BGR2RGB);
+ }
}
- int size_in_byte = resizedImage.size().width * resizedImage.size().height * resizedImage.channels() * sizeof(unsigned char);
-
- // configure tensor_info, tensor (by user for a tempoerary) ?
- // input tensor
const struct beyond_tensor_info *input_info;
int num_inputs;
if (beyond_inference_get_input_tensor_info(inference_h_, &input_info, &num_inputs)) {
beyond_tensor *beyond_tensors = BEYOND_TENSOR(in_tensor_h);
auto &in = beyond_tensors[0];
- in.type = BEYOND_TENSOR_TYPE_UINT8;
- in.size = size_in_byte;
- memcpy(in.data, resizedImage.data, size_in_byte);
+ if (DEBUG == true) {
+ printf("model input (type : 0x%.2X, size : %d )\n", in.type, in.size);
+ }
+ memcpy(in.data, resizedImage.data, in.size);
// invoke
if (beyond_inference_do(inference_h_, in_tensor_h, nullptr) < 0) {
bool ImageClassification::PrintResult()
{
beyond_tensor_h out_tensor_h;
- int count; // dummy: Could not get count in this api beyond_inference_get_output
+ int count;
+ int index = -1;
+ int copy_bytes = OUTPUT_LABELS_NUM * num_bytes_per_channel_;
+
if (beyond_inference_get_output(inference_h_, &out_tensor_h, &count) < 0) {
printf("Failed beyond_inference_get_output\n");
return false;
}
+ if ((out_tensor_h == nullptr) || (count <= 0)) {
+ printf("Invalid out_tensor_h:%p, count: %d\n", out_tensor_h, count);
+ return false;
+ }
beyond_tensor *tensors = BEYOND_TENSOR(out_tensor_h);
- if ((tensors[0].type != BEYOND_TENSOR_TYPE_UINT8) ||
- (tensors[0].size != OUTPUT_LABELS_NUM)) {
- printf("incorrect output( type : %d, size : %d)\n", tensors[0].type, tensors[0].size);
- printf("expected result( type : %d, size : %d)\n", BEYOND_TENSOR_TYPE_UINT8, OUTPUT_LABELS_NUM);
+ if (DEBUG == true) {
+ printf("model output (type : 0x%.2X, size : %d )\n", tensors[0].type, tensors[0].size);
}
- uint8_t max_score = 0;
- uint8_t scores[OUTPUT_LABELS_NUM];
- int index = -1;
- int loaded = image_labels_.size();
+ if (tensors[0].size != copy_bytes) {
+ printf("incorrect size( %d, but expected : %d)\n", tensors[0].size, copy_bytes);
+ return false;
+ }
- memcpy(&scores, tensors[0].data, tensors[0].size);
+ if (num_bytes_per_channel_ == UINT8_BYTES) {
+ if (tensors[0].type != BEYOND_TENSOR_TYPE_UINT8) {
+ printf("incorrect type( 0x%.2X, but expected : %d )\n", tensors[0].type, BEYOND_TENSOR_TYPE_UINT8);
+ return false;
+ }
+ uint8_t max_score = 0;
+ uint8_t scores[OUTPUT_LABELS_NUM];
- for (int i = 0; i < tensors[0].size; i++) {
- if (scores[i] > 0 && scores[i] > max_score) {
- index = i;
- max_score = scores[i];
+ memcpy(&scores, tensors[0].data, copy_bytes);
+
+ for (int i = 0; i < OUTPUT_LABELS_NUM; i++) {
+ if (scores[i] > 0 && scores[i] > max_score) {
+ index = i;
+ max_score = scores[i];
+ }
}
+ } else if (num_bytes_per_channel_ == FLOAT32_BYTES) {
+ if (tensors[0].type != BEYOND_TENSOR_TYPE_FLOAT32) {
+ printf("incorrect type( %d, but expected : %d )\n", tensors[0].type, BEYOND_TENSOR_TYPE_FLOAT32);
+ return false;
+ }
+ float max_score = 0;
+ float scores[OUTPUT_LABELS_NUM];
+
+ memcpy(&scores, tensors[0].data, tensors[0].size);
+
+ for (int i = 0; i < OUTPUT_LABELS_NUM; i++) {
+ if (scores[i] > 0 && scores[i] > max_score) {
+ index = i;
+ max_score = scores[i];
+ }
+ }
+ } else {
+ printf("Unsupported type( type : %d )\n", tensors[0].type);
}
beyond_inference_unref_tensor(out_tensor_h);
- if ((index == -1) ||
- (loaded < index)) {
+ if (index == -1) {
printf("Failed to get label from output\n");
return false;
}
// for device
constexpr char DeviceModelFileOpt[] = "model_file";
+constexpr char DeviceModelDataTypeOpt[] = "model_dtype";
constexpr char DeviceImagePathOpt[] = "image_path";
constexpr char DeviceOutputLabelsOpt[] = "output_labels";
constexpr char DeviceReqIPOpt[] = "edge_ip";
constexpr char DeviceInputFPSOpt[] = "input_fps";
constexpr char DeviceRepeatOpt[] = "repeat";
-// mobilenet v1
+// Imagenet(ILSVRC-2012-CLS) classification with MobileNet V1
const int MOBILENETV1_HEIGHT = 224;
const int MOBILENETV1_WIDTH = 224;
const int OUTPUT_LABELS_NUM = 1001;
+const int UINT8_BYTES = 1;
+const int FLOAT32_BYTES = 4;
const int IMG_HEIGHT = 100;
const int IMG_WIDTH = 100;
ImageClassification()
: edge_ip_("127.0.0.1")
, peer_name_(BEYOND_PLUGIN_PEER_NN_NAME)
+ , model_dtype_("uint8")
, req_port_(3000)
, rep_port_(3001)
, service_port_(3000)
, repeat_(1)
, num_invoked_(0)
, discovered_(0)
+ , num_bytes_per_channel_(UINT8_BYTES)
, main_loop_(g_main_loop_new(nullptr, FALSE))
, target_(TargetMode::UNKNOWN)
, invoke_(InvokeMode::SYNC)
std::string edge_ip_;
std::string peer_name_;
std::string invocation_; /* invocation mode in sync or async */
+ std::string model_dtype_;
unsigned short req_port_;
unsigned short rep_port_;
unsigned short service_port_;
int repeat_;
int num_invoked_;
int discovered_;
+ int num_bytes_per_channel_;
GMainLoop *main_loop_;
TargetMode target_;
Option::CreateOption(UseConfigOpt, &use_config_,
"Peer configuration On:1, Off:0 (default: 0)\n"),
Option::CreateOption(DeviceModelFileOpt, &model_file_path_,
- "Path to tflite model file"),
+ "Path to tflite model file(Imagenet classification with MobileNet V1)"),
+ Option::CreateOption(DeviceModelDataTypeOpt, &model_dtype_,
+ "Model data type(`uint8` or `float32` default: uint8)"),
Option::CreateOption(DeviceImagePathOpt, &input_image_path_,
"Path to input image file that will be evaluated"),
Option::CreateOption(DeviceOutputLabelsOpt, &output_label_path_,
invoke_ = InvokeMode::SYNC;
}
+ if (model_dtype_.compare("float32") == 0) {
+ num_bytes_per_channel_ = FLOAT32_BYTES;
+ } else if (model_dtype_.compare("uint8") == 0) {
+ num_bytes_per_channel_ = UINT8_BYTES;
+ } else {
+ printf("Unsupported data type : %s\n", model_dtype_.c_str());
+ result = false;
+ }
+
if ((input_fps_ < 1) || (input_fps_ > 60)) {
printf("Out of range(1 ~ 60) of input fps : %d is set to default(10)\n", input_fps_);
input_fps_ = 10;
if (result == true) {
printf("------------------------------\n");
printf("Target : %s \n", run_as_.c_str());
- printf("Model File : %s \n", model_file_path_.c_str());
+ printf("Model : %s (data type %s)\n", model_file_path_.c_str(), model_dtype_.c_str());
printf("Input Image File : %s \n", input_image_path_.c_str());
printf("Output Label File : %s \n", output_label_path_.c_str());
printf("Edge IP Address : %s \n", edge_ip_.c_str());
}
if (use_config_ == 1) {
+ const char *trans_mode;
+ const char *trans_opt;
+ if (num_bytes_per_channel_ == 4) {
+ trans_mode = "arithmetic";
+ trans_opt = "typecast:float32,add:-127.5,div:127.5";
+ } else {
+ trans_mode = "typecast";
+ trans_opt = "uint8";
+ }
struct beyond_input_image_config image_config = {
.format = "BGR",
.width = IMG_WIDTH,
.convert_format = "RGB",
.convert_width = MOBILENETV1_WIDTH,
.convert_height = MOBILENETV1_HEIGHT,
- .transform_mode = "typecast",
- .transform_option = "uint8"
+ .transform_mode = trans_mode,
+ .transform_option = trans_opt
};
struct beyond_input_config input_config;
input_config.input_type = BEYOND_INPUT_TYPE_IMAGE;
while (std::getline(stream, line)) {
image_labels_.push_back(line);
}
+
+ int loaded = image_labels_.size();
+ if (OUTPUT_LABELS_NUM != loaded) {
+ printf("Failed to get label from output(loaded %d)\n", loaded);
+ return false;
+ }
+
return true;
}
return false;
}
- if (use_config_ == 1) {
- // NO implementation yet for service config
- struct beyond_config config = { 's', nullptr };
- ret = beyond_peer_configure(peer_h_, &config);
- if (ret < 0) {
- printf("Failed to config input : %d\n", ret);
- return false;
- }
- }
-
struct beyond_peer_info info = {
.name = const_cast<char *>("name"),
.host = const_cast<char *>("0.0.0.0"),
cv::resize(inputImage, resizedImage,
cv::Size(IMG_WIDTH, IMG_HEIGHT));
} else {
- cv::resize(inputImage, resizedImage,
- cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
- cv::cvtColor(resizedImage, resizedImage, cv::COLOR_BGR2RGB);
+ if (num_bytes_per_channel_ == FLOAT32_BYTES) {
+ cv::Mat temp;
+ cv::resize(inputImage, temp,
+ cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
+ cv::cvtColor(temp, temp, cv::COLOR_BGR2RGB);
+ temp.convertTo(resizedImage, CV_32FC3, 1/255.0);
+ }
+ else {
+ cv::resize(inputImage, resizedImage,
+ cv::Size(MOBILENETV1_WIDTH, MOBILENETV1_HEIGHT));
+ cv::cvtColor(resizedImage, resizedImage, cv::COLOR_BGR2RGB);
+ }
}
- int size_in_byte = resizedImage.size().width * resizedImage.size().height * resizedImage.channels() * sizeof(unsigned char);
-
- // configure tensor_info, tensor (by user for a tempoerary) ?
- // input tensor
const struct beyond_tensor_info *input_info;
int num_inputs;
if (beyond_inference_get_input_tensor_info(inference_h_, &input_info, &num_inputs)) {
beyond_tensor *beyond_tensors = BEYOND_TENSOR(in_tensor_h);
auto &in = beyond_tensors[0];
- in.type = BEYOND_TENSOR_TYPE_UINT8;
- in.size = size_in_byte;
- memcpy(in.data, resizedImage.data, size_in_byte);
+ if (DEBUG == true) {
+ printf("model input (type : 0x%.2X, size : %d )\n", in.type, in.size);
+ }
+ memcpy(in.data, resizedImage.data, in.size);
// invoke
num_invoked_++;
bool ImageClassification::PrintResult()
{
beyond_tensor_h out_tensor_h;
- int count; // dummy: Could not get count in this api beyond_inference_get_output
+ int count;
+ int index = -1;
+ int copy_bytes = OUTPUT_LABELS_NUM * num_bytes_per_channel_;
+
if (beyond_inference_get_output(inference_h_, &out_tensor_h, &count) < 0) {
printf("Failed beyond_inference_get_output\n");
return false;
}
+ if ((out_tensor_h == nullptr) || (count <= 0)) {
+ printf("Invalid out_tensor_h:%p, count: %d\n", out_tensor_h, count);
+ return false;
+ }
beyond_tensor *tensors = BEYOND_TENSOR(out_tensor_h);
- if ((tensors[0].type != BEYOND_TENSOR_TYPE_UINT8) ||
- (tensors[0].size != OUTPUT_LABELS_NUM)) {
- printf("incorrect output( type : %d, size : %d)\n", tensors[0].type, tensors[0].size);
- printf("expected result( type : %d, size : %d)\n", BEYOND_TENSOR_TYPE_UINT8, OUTPUT_LABELS_NUM);
+ if (DEBUG == true) {
+ printf("model output (type : 0x%.2X, size : %d )\n", tensors[0].type, tensors[0].size);
}
- uint8_t max_score = 0;
- uint8_t scores[OUTPUT_LABELS_NUM];
- int index = -1;
- int loaded = image_labels_.size();
+ if (tensors[0].size != copy_bytes) {
+ printf("incorrect size( %d, but expected : %d)\n", tensors[0].size, copy_bytes);
+ return false;
+ }
- memcpy(&scores, tensors[0].data, tensors[0].size);
+ if (num_bytes_per_channel_ == UINT8_BYTES) {
+ if (tensors[0].type != BEYOND_TENSOR_TYPE_UINT8) {
+ printf("incorrect type( 0x%.2X, but expected : %d )\n", tensors[0].type, BEYOND_TENSOR_TYPE_UINT8);
+ return false;
+ }
+ uint8_t max_score = 0;
+ uint8_t scores[OUTPUT_LABELS_NUM];
+
+ memcpy(&scores, tensors[0].data, copy_bytes);
+
+ for (int i = 0; i < OUTPUT_LABELS_NUM; i++) {
+ if (scores[i] > 0 && scores[i] > max_score) {
+ index = i;
+ max_score = scores[i];
+ }
+ }
+ } else if (num_bytes_per_channel_ == FLOAT32_BYTES) {
+ if (tensors[0].type != BEYOND_TENSOR_TYPE_FLOAT32) {
+ printf("incorrect type( %d, but expected : %d )\n", tensors[0].type, BEYOND_TENSOR_TYPE_FLOAT32);
+ return false;
+ }
+ float max_score = 0;
+ float scores[OUTPUT_LABELS_NUM];
+
+ memcpy(&scores, tensors[0].data, tensors[0].size);
- for (int i = 0; i < tensors[0].size; i++) {
- if (scores[i] > 0 && scores[i] > max_score) {
- index = i;
- max_score = scores[i];
+ for (int i = 0; i < OUTPUT_LABELS_NUM; i++) {
+ if (scores[i] > 0 && scores[i] > max_score) {
+ index = i;
+ max_score = scores[i];
+ }
}
+ } else {
+ printf("Unsupported type( type : %d )\n", tensors[0].type);
}
beyond_inference_unref_tensor(out_tensor_h);
- if ((index == -1) ||
- (loaded < index)) {
+ if (index == -1) {
printf("Failed to get label from output\n");
return false;
}