diff --git a/docs/how-to-use-and-FAQ/quantized-int8-inference.md b/docs/how-to-use-and-FAQ/quantized-int8-inference.md index cf8e05c20952..a8846fc96ebf 100644 --- a/docs/how-to-use-and-FAQ/quantized-int8-inference.md +++ b/docs/how-to-use-and-FAQ/quantized-int8-inference.md @@ -20,7 +20,7 @@ Some imagenet sample images here https://github.com/nihui/imagenet-sample-images ```shell find images/ -type f > imagelist.txt -./ncnn2table mobilenet-opt.param mobilenet-opt.bin imagelist.txt mobilenet.table mean=[104,117,123] norm=[0.017,0.017,0.017] shape=[224,224,3] pixel=BGR thread=8 method=kl +./ncnn2table mobilenet-opt.param mobilenet-opt.bin imagelist.txt mobilenet.table mean=[104,117,123] norm=[0.017,0.017,0.017] shape=[224,224,3] pixel=BGR thread=8 method=kl format=txt ``` * mean and norm are the values you passed to ```Mat::substract_mean_normalize()``` @@ -35,6 +35,7 @@ find images/ -type f > imagelist.txt * pixel is the pixel format of your model, image pixels will be converted to this type before ```Extractor::input()``` * thread is the CPU thread count that could be used for parallel inference * method is the post training quantization algorithm, kl and aciq are currently supported +* format is the output file type of quantization parameters, choose `ini` for `txt`. Using `txt` by default If your model has multiple input nodes, you can use multiple list files and other parameters @@ -60,7 +61,7 @@ mobilenet.load_model("mobilenet-int8.bin"); ## mixed precision inference -Before quantize your model, comment the layer weight scale line in table file, then the layer will do the float32 inference +Before quantize your model, comment layer weight scale line in the table file with `txt` format, then the layer will do the float32 inference ``` conv1_param_0 156.639840536 @@ -69,3 +70,26 @@ conv1_param_0 156.639840536 ``` #conv1_param_0 156.639840536 ``` + +If you are using `ini` format, just remove whole quantization parameters of the layer, for example: + +``` +[conv0] +type = "Conv" +weight = [ 156.639840536 ] +input_scale = 1.23 + +[fire] +type = "Gemm" +weight = [ 156.639840536 ] +input_scale = 1.23 +``` + +to + +``` +[fire] +type = "Gemm" +weight = [ 156.639840536 ] +input_scale = 1.23 +``` diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 7bcd0590457a..6acf2d197627 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -26,7 +26,7 @@ if(NCNN_VULKAN) target_link_libraries(ncnn2mem PRIVATE ${Vulkan_LIBRARY}) endif() -add_executable(ncnnoptimize ncnnoptimize.cpp) +add_executable(ncnnoptimize ncnnoptimize.cpp modelwriter.cpp) target_link_libraries(ncnnoptimize PRIVATE ncnn) if(NCNN_VULKAN) target_link_libraries(ncnnoptimize PRIVATE ${Vulkan_LIBRARY}) diff --git a/tools/modelwriter.cpp b/tools/modelwriter.cpp new file mode 100644 index 000000000000..6b8d31975199 --- /dev/null +++ b/tools/modelwriter.cpp @@ -0,0 +1,2052 @@ +#include "modelwriter.h" + +MemoryFootprintAllocator::MemoryFootprintAllocator() +{ + current_memory_usage = 0; + memory_footprint = 0; +} + +void* MemoryFootprintAllocator::fastMalloc(size_t size) +{ + ncnn::MutexLockGuard g(lock); + void* ptr = ncnn::fastMalloc(size); + bookkeeper[ptr] = size; + current_memory_usage += size; + memory_footprint = std::max(memory_footprint, current_memory_usage); + return ptr; +} + +void MemoryFootprintAllocator::fastFree(void* ptr) +{ + ncnn::MutexLockGuard g(lock); + size_t size = bookkeeper[ptr]; + current_memory_usage -= size; + bookkeeper.erase(bookkeeper.find(ptr)); + ncnn::fastFree(ptr); +} + +int CustomLayer::load_param(const ncnn::ParamDict& pd) +{ + mpd = pd; + return 0; +} + +void CustomLayer::write_param(FILE* pp) +{ + for (int i = 0; i < NCNN_MAX_PARAM_COUNT; i++) + { + int type = mpd.type(i); + if (type == 0) + continue; + + if (type == 2) + { + fprintf(pp, " %d=%d", i, mpd.get(i, 0)); + } + if (type == 3) + { + fprintf(pp, " %d=%e", i, mpd.get(i, 0.f)); + } + if (type == 5) + { + ncnn::Mat v = mpd.get(i, ncnn::Mat()); + int len = v.w; + fprintf(pp, " %d=%d", -i - 23300, len); + const int* p = v; + for (int j = 0; j < len; j++) + { + fprintf(pp, ",%d", p[j]); + } + } + if (type == 6) + { + ncnn::Mat v = mpd.get(i, ncnn::Mat()); + int len = v.w; + fprintf(pp, " %d=%d", -i - 23300, len); + const float* p = v; + for (int j = 0; j < len; j++) + { + fprintf(pp, ",%e", p[j]); + } + } + } +} + +DEFINE_LAYER_CREATOR(CustomLayer) + +ModelWriter::ModelWriter() + : blobs(mutable_blobs()), layers(mutable_layers()) +{ + opt.lightmode = false; + has_custom_layer = false; + gen_random_weight = false; + cutstart = -1; + cutend = -1; + + SRAND(7767517); +} + +ncnn::Layer* ModelWriter::create_custom_layer(const char* type) +{ + ncnn::Layer* layer = Net::create_custom_layer(type); + if (layer) + return layer; + + fprintf(stderr, "create_custom_layer %s\n", type); + + register_custom_layer(type, CustomLayer_layer_creator); + + has_custom_layer = true; + + return Net::create_custom_layer(type); +} + +int ModelWriter::set_cutparam(const char* cutstartname, const char* cutendname) +{ + if (cutstartname != nullptr) + { + int layindex = find_layer_index_by_name(cutstartname); + if (layindex >= 0) + { + cutstart = layindex; + fprintf(stderr, "cutstart layer %d:%s\n", layindex, cutstartname); + } + else + { + fprintf(stderr, "not find target cutstart layer %s\n", cutstartname); + return -1; + } + } + + if (cutendname != nullptr) + { + int layindex = find_layer_index_by_name(cutendname); + if (layindex >= 0) + { + cutend = layindex; + fprintf(stderr, "cutend layer %d:%s\n", layindex, cutendname); + } + else + { + fprintf(stderr, "not find target cutend layer %s\n", cutendname); + return -1; + } + } + + return 0; +} + +int ModelWriter::shape_inference() +{ + if (has_custom_layer) + { + fprintf(stderr, "model has custom layer, shape_inference skipped\n"); + return -1; + } + + const size_t layer_count = layers.size(); + const size_t blob_count = blobs.size(); + + // recreate layer pipeline for param and weight changes + for (size_t i = 0; i < layer_count; i++) + { + ncnn::Layer* layer = layers[i]; + + layer->destroy_pipeline(opt); + + int cret = layer->create_pipeline(opt); + if (cret != 0) + { + NCNN_LOGE("layer create_pipeline %d %s failed", (int)i, layer->name.c_str()); + return -1; + } + } + + ncnn::Extractor ex = create_extractor(); + ex.set_light_mode(true); + + // prepare Input blobs + for (size_t i = 0; i < layer_count; i++) + { + const ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + if (layer->type != "Input") + continue; + + ncnn::Input* input = (ncnn::Input*)layer; + + int w = input->w; + int h = input->h; + int c = input->c; + + int dims = 0; + if (w == 0 && h == 0 && c == 0) dims = 0; + if (w != 0 && h == 0 && c == 0) dims = 1; + if (w != 0 && h != 0 && c == 0) dims = 2; + if (w != 0 && h != 0 && c != 0) dims = 3; + + if (dims == 0) + { + fprintf(stderr, "Input layer %s without shape info, shape_inference skipped\n", layer->name.c_str()); + return -1; + } + + ncnn::Mat m; + if (dims == 1) m.create(w); + if (dims == 2) m.create(w, h); + if (dims == 3) m.create(w, h, c); + + ex.input(layer->tops[0], m); + } + + // prepare blobs with predefined shape + for (size_t i = 0; i < blob_count; i++) + { + const ncnn::Blob& blob = blobs[i]; + + int dims = blob.shape.dims; + int w = blob.shape.w; + int h = blob.shape.h; + int c = blob.shape.c; + + if (dims == 0) + continue; + + ncnn::Mat m; + if (dims == 1) m.create(w); + if (dims == 2) m.create(w, h); + if (dims == 3) m.create(w, h, c); + + m.fill(0.f); + + ex.input(int(i), m); + } + + fprintf(stderr, "shape_inference\n"); + + // resolve all layer output blob shape + for (size_t i = 0; i < layer_count; i++) + { + const ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + for (size_t j = 0; j < layer->tops.size(); j++) + { + int top_blob_index = layer->tops[j]; + + ncnn::Mat m; + ex.extract(top_blob_index, m); + + blobs[top_blob_index].shape = m; + } + } + + // assign all layer blob shape + for (size_t i = 0; i < layer_count; i++) + { + ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + layer->bottom_shapes.resize(layer->bottoms.size()); + for (size_t j = 0; j < layer->bottoms.size(); j++) + { + int bottom_blob_index = layer->bottoms[j]; + + layer->bottom_shapes[j] = blobs[bottom_blob_index].shape; + } + + layer->top_shapes.resize(layer->tops.size()); + for (size_t j = 0; j < layer->tops.size(); j++) + { + int top_blob_index = layer->tops[j]; + + layer->top_shapes[j] = blobs[top_blob_index].shape; + + // fprintf(stderr, "%d %4d %4d %4d | %2d %s\n", blobs[top_blob_index].shape.dims, blobs[top_blob_index].shape.w, blobs[top_blob_index].shape.h, blobs[top_blob_index].shape.c, top_blob_index, blobs[top_blob_index].name.c_str()); + } + } + + return 0; +} + +int ModelWriter::estimate_memory_footprint() +{ + if (has_custom_layer) + { + fprintf(stderr, "model has custom layer, estimate_memory_footprint skipped\n"); + return -1; + } + + const size_t layer_count = layers.size(); + const size_t blob_count = blobs.size(); + + MemoryFootprintAllocator allocator; + + ncnn::Extractor ex = create_extractor(); + ex.set_light_mode(true); + + ex.set_blob_allocator(&allocator); + ex.set_workspace_allocator(&allocator); + + // prepare Input blobs + for (size_t i = 0; i < layer_count; i++) + { + const ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + if (layer->type != "Input") + continue; + + ncnn::Input* input = (ncnn::Input*)layer; + + int w = input->w; + int h = input->h; + int c = input->c; + + int dims = 0; + if (w == 0 && h == 0 && c == 0) dims = 0; + if (w != 0 && h == 0 && c == 0) dims = 1; + if (w != 0 && h != 0 && c == 0) dims = 2; + if (w != 0 && h != 0 && c != 0) dims = 3; + + if (dims == 0) + { + fprintf(stderr, "Input layer %s without shape info, estimate_memory_footprint skipped\n", layer->name.c_str()); + return -1; + } + + ncnn::Mat m; + if (dims == 1) m.create(w, 4u, &allocator); + if (dims == 2) m.create(w, h, 4u, &allocator); + if (dims == 3) m.create(w, h, c, 4u, &allocator); + + ex.input(layer->tops[0], m); + + fprintf(stderr, "input = %s\n", blobs[layer->tops[0]].name.c_str()); + } + + // find output blobs and do inference + std::vector outputs; + for (size_t i = 0; i < blob_count; i++) + { + const ncnn::Blob& blob = blobs[i]; + + if (blob.producer == -1 || blob.consumer != -1) + continue; + + if (layers[blob.producer]->type == "ncnnfused") + continue; + + // treat blob without any consumers as output + ncnn::Mat m; + ex.extract(int(i), m); + outputs.push_back(m); + + fprintf(stderr, "extract = %s\n", blob.name.c_str()); + } + + fprintf(stderr, "estimated memory footprint = %.2f KB = %.2f MB\n", allocator.memory_footprint / 1024.f, allocator.memory_footprint / 1024.f / 1024.f); + + return 0; +} + +int ModelWriter::fprintf_param_int_array(int id, const ncnn::Mat& m, FILE* pp) +{ + const int count = m.w; + const int* ptr = m; + + fprintf(pp, " -%d=%d", 23300 + id, count); + for (int i = 0; i < count; i++) + { + fprintf(pp, ",%d", ptr[i]); + } + + return 0; +} + +int ModelWriter::fprintf_param_float_array(int id, const ncnn::Mat& m, FILE* pp) +{ + const int count = m.w; + const float* ptr = m; + + fprintf(pp, " -%d=%d", 23300 + id, count); + for (int i = 0; i < count; i++) + { + fprintf(pp, ",%e", ptr[i]); + } + + return 0; +} + +static inline size_t alignSize(size_t sz, int n) +{ + return (sz + n - 1) & -n; +} + +static void replace_denormals_with_zero(float* data, size_t data_length) +{ + const int total = static_cast(data_length); + for (size_t i = 0; i < data_length; ++i) + { + float value = data[i]; + + if (fabsf(value) < 1e-30 && fabsf(value) != 0.f) + { + data[i] = 0.f; + } + } +} + +static float RandomFloat(float a = -1.2f, float b = 1.2f) +{ + float random = ((float)RAND()) / (float)uint64_t(-1); //RAND_MAX; + float diff = b - a; + float r = random * diff; + return a + r; +} + +static void Randomize(ncnn::Mat& m, float a = -1.2f, float b = 1.2f) +{ + if (m.elemsize == 4) + { + for (size_t i = 0; i < m.total(); i++) + { + m[i] = RandomFloat(a, b); + } + } + else if (m.elemsize == 2) + { + unsigned short* p = m; + for (size_t i = 0; i < m.total(); i++) + { + p[i] = ncnn::float32_to_float16(RandomFloat(a, b)); + } + } + else if (m.elemsize == 1) + { + signed char* p = m; + for (size_t i = 0; i < m.total(); i++) + { + p[i] = (signed char)RandomFloat(-127, 127); + } + } +} + +int ModelWriter::fwrite_weight_tag_data(const ncnn::Mat& data, FILE* bp, float a, float b) +{ + int p0 = ftell(bp); + + ncnn::Mat data_flattened = data.reshape(data.w * data.h * data.c); + if (gen_random_weight) + Randomize(data_flattened, a, b); + + if (data_flattened.elemsize == 4) + { + if (storage_type == 1) + { + const int tag = 0x01306B47; // fp16 magic + fwrite(&tag, sizeof(int), 1, bp); + ncnn::Mat data_flattened_fp16; + ncnn::cast_float32_to_float16(data_flattened, data_flattened_fp16); + fwrite(data_flattened_fp16.data, data_flattened_fp16.elemsize, data_flattened_fp16.w, bp); + } + else + { + const int tag = 0; // fp32 magic + fwrite(&tag, sizeof(int), 1, bp); + replace_denormals_with_zero(data_flattened, data_flattened.w); + fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); + } + } + else if (data_flattened.elemsize == 2) + { + const int tag = 0x01306B47; // fp16 magic + fwrite(&tag, sizeof(int), 1, bp); + fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); + } + else if (data_flattened.elemsize == 1) + { + const int tag = 0x000D4B38; // int8 magic + fwrite(&tag, sizeof(int), 1, bp); + fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); + } + else + { + fprintf(stderr, "unknown weight data type %d\n", (int)data_flattened.elemsize); + } + + // padding to 32bit align + int nwrite = ftell(bp) - p0; + size_t nalign = alignSize(nwrite, 4); + unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00}; + fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp); + + return 0; +} + +int ModelWriter::fwrite_weight_data(const ncnn::Mat& data, FILE* bp, float a, float b) +{ + int p0 = ftell(bp); + + ncnn::Mat data_flattened = data.reshape(data.w * data.h * data.c); + if (gen_random_weight) + Randomize(data_flattened, a, b); + + if (data_flattened.elemsize == 4) // fp32 + { + replace_denormals_with_zero(data_flattened, data_flattened.w); + } + + fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); + + // padding to 32bit align + int nwrite = ftell(bp) - p0; + size_t nalign = alignSize(nwrite, 4); + unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00}; + fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp); + + return 0; +} + +int ModelWriter::save(const char* parampath, const char* binpath) +{ + uint64_t mac = 0; + + FILE* pp = fopen(parampath, "wb"); + FILE* bp = fopen(binpath, "wb"); + + fprintf(pp, "7767517\n"); + + const size_t layer_count = layers.size(); + + int layer_count_fused = 0; + std::set blob_names; + for (size_t i = 0; i < layer_count; i++) + { + const ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + layer_count_fused++; + + size_t bottom_count = layer->bottoms.size(); + for (size_t j = 0; j < bottom_count; j++) + { + int bottom_blob_index = layer->bottoms[j]; + blob_names.insert(blobs[bottom_blob_index].name); + } + + size_t top_count = layer->tops.size(); + for (size_t j = 0; j < top_count; j++) + { + int top_blob_index = layer->tops[j]; + blob_names.insert(blobs[top_blob_index].name); + } + } + + size_t blob_count_fused = blob_names.size(); + + fprintf(pp, "%d %zd\n", layer_count_fused, blob_count_fused); + + for (size_t i = 0; i < layer_count; i++) + { + const ncnn::Layer* layer = layers[i]; + if (layer->type == "ncnnfused") + continue; + + if (cutstart > 0 && i < cutstart) + continue; + + if (cutend > 0 && i > cutend) + continue; + + size_t bottom_count = layer->bottoms.size(); + size_t top_count = layer->tops.size(); + + fprintf(pp, "%-24s %-24s %zd %zd", layer->type.c_str(), layer->name.c_str(), bottom_count, top_count); + + for (size_t j = 0; j < bottom_count; j++) + { + int bottom_blob_index = layer->bottoms[j]; + fprintf(pp, " %s", blobs[bottom_blob_index].name.c_str()); + } + for (size_t j = 0; j < top_count; j++) + { + int top_blob_index = layer->tops[j]; + fprintf(pp, " %s", blobs[top_blob_index].name.c_str()); + } + + // write shape hints + bool shape_ready = true; + for (size_t j = 0; j < top_count; j++) + { + int top_blob_index = layer->tops[j]; + + int dims = blobs[top_blob_index].shape.dims; + if (dims == 0) + { + shape_ready = false; + break; + } + } + if (shape_ready) + { + fprintf(pp, " -23330=%zd", top_count * 4); + for (size_t j = 0; j < top_count; j++) + { + int top_blob_index = layer->tops[j]; + + int dims = blobs[top_blob_index].shape.dims; + int w = blobs[top_blob_index].shape.w; + int h = blobs[top_blob_index].shape.h; + int c = blobs[top_blob_index].shape.c; + + fprintf(pp, ",%d,%d,%d,%d", dims, w, h, c); + } + } + + // custom op + if (layer->typeindex & ncnn::LayerType::CustomBit) + { + ((CustomLayer*)layer)->write_param(pp); + + fprintf(pp, "\n"); + + continue; + } + + ncnn::Layer* layer_default = ncnn::create_layer(layer->typeindex); + + ncnn::ParamDict pd; + layer_default->load_param(pd); + +#define fprintf_param_value(format, phase) \ + { \ + if (op->phase != op_default->phase) fprintf(pp, format, op->phase); \ + } + + if (layer->type == "BatchNorm") + { + ncnn::BatchNorm* op = (ncnn::BatchNorm*)layer; + ncnn::BatchNorm* op_default = (ncnn::BatchNorm*)layer_default; + + fprintf_param_value(" 0=%d", channels) + fprintf_param_value(" 1=%e", eps) + + fwrite_weight_data(op->slope_data, bp); + fwrite_weight_data(op->mean_data, bp); + fwrite_weight_data(op->var_data, bp); + fwrite_weight_data(op->bias_data, bp); + } + else if (layer->type == "Bias") + { + ncnn::Bias* op = (ncnn::Bias*)layer; + ncnn::Bias* op_default = (ncnn::Bias*)layer_default; + + fprintf_param_value(" 0=%d", bias_data_size) + + fwrite_weight_data(op->bias_data, bp); + } + else if (layer->type == "BinaryOp") + { + ncnn::BinaryOp* op = (ncnn::BinaryOp*)layer; + ncnn::BinaryOp* op_default = (ncnn::BinaryOp*)layer_default; + + fprintf_param_value(" 0=%d", op_type) + fprintf_param_value(" 1=%d", with_scalar) + fprintf_param_value(" 2=%e", b) + } + else if (layer->type == "Clip") + { + ncnn::Clip* op = (ncnn::Clip*)layer; + ncnn::Clip* op_default = (ncnn::Clip*)layer_default; + + fprintf_param_value(" 0=%e", min) + fprintf_param_value(" 1=%e", max) + } + else if (layer->type == "Concat") + { + ncnn::Concat* op = (ncnn::Concat*)layer; + ncnn::Concat* op_default = (ncnn::Concat*)layer_default; + + fprintf_param_value(" 0=%d", axis) + } + else if (layer->type == "Convolution") + { + ncnn::Convolution* op = (ncnn::Convolution*)layer; + ncnn::Convolution* op_default = (ncnn::Convolution*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 8=%d", int8_scale_term) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + +#if NCNN_INT8 + // write int8_scale data + if (op->int8_scale_term) + { + fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); + fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); + fwrite_weight_data(op->top_blob_int8_scales, bp, 0.001, 1); + } +#endif // NCNN_INT8 + + if (shape_ready) + { + int inc = blobs[layer->bottoms[0]].shape.c; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_h * op->kernel_w * outw * outh * outc * inc; + } + } + else if (layer->type == "Convolution1D") + { + ncnn::Convolution1D* op = (ncnn::Convolution1D*)layer; + ncnn::Convolution1D* op_default = (ncnn::Convolution1D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + fprintf_param_value(" 2=%d", dilation_w) + fprintf_param_value(" 3=%d", stride_w) + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inh = blobs[layer->bottoms[0]].shape.h; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + + mac += (uint64_t)op->kernel_w * outw * outh * inh; + } + } + else if (layer->type == "Convolution3D") + { + ncnn::Convolution3D* op = (ncnn::Convolution3D*)layer; + ncnn::Convolution3D* op_default = (ncnn::Convolution3D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + { + if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inc = blobs[layer->bottoms[0]].shape.c; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + int outd = blobs[layer->tops[0]].shape.d; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * outw * outh * outd * outc * inc; + } + } + else if (layer->type == "ConvolutionDepthWise") + { + ncnn::ConvolutionDepthWise* op = (ncnn::ConvolutionDepthWise*)layer; + ncnn::ConvolutionDepthWise* op_default = (ncnn::ConvolutionDepthWise*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 8=%d", int8_scale_term) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + +#if NCNN_INT8 + // write int8_scale data + if (op->int8_scale_term == 1 || op->int8_scale_term == 101) + { + op->bottom_blob_int8_scales.w = 1; + } + if (op->int8_scale_term == 2 || op->int8_scale_term == 102) + { + op->weight_data_int8_scales.w = 1; + op->bottom_blob_int8_scales.w = 1; + } + if (op->int8_scale_term > 100) + { + op->top_blob_int8_scales.w = 1; + } + + if (op->int8_scale_term) + { + fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); + fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); + fwrite_weight_data(op->top_blob_int8_scales, bp, 0.001, 1); + } +#endif // NCNN_INT8 + + if (shape_ready) + { + int inc = blobs[layer->bottoms[0]].shape.c; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_h * op->kernel_w * outw * outh * (outc / op->group) * (inc / op->group) * op->group; + } + } + else if (layer->type == "ConvolutionDepthWise1D") + { + ncnn::ConvolutionDepthWise1D* op = (ncnn::ConvolutionDepthWise1D*)layer; + ncnn::ConvolutionDepthWise1D* op_default = (ncnn::ConvolutionDepthWise1D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + fprintf_param_value(" 2=%d", dilation_w) + fprintf_param_value(" 3=%d", stride_w) + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inh = blobs[layer->bottoms[0]].shape.h; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + + mac += (uint64_t)op->kernel_w * outw * (outh / op->group) * (inh / op->group) * op->group; + } + } + else if (layer->type == "ConvolutionDepthWise3D") + { + ncnn::ConvolutionDepthWise3D* op = (ncnn::ConvolutionDepthWise3D*)layer; + ncnn::ConvolutionDepthWise3D* op_default = (ncnn::ConvolutionDepthWise3D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + { + if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); + } + fprintf_param_value(" 18=%e", pad_value) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inc = blobs[layer->bottoms[0]].shape.c; + int outw = blobs[layer->tops[0]].shape.w; + int outh = blobs[layer->tops[0]].shape.h; + int outd = blobs[layer->tops[0]].shape.d; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * outw * outh * outd * (outc / op->group) * (inc / op->group) * op->group; + } + } + else if (layer->type == "Crop") + { + ncnn::Crop* op = (ncnn::Crop*)layer; + ncnn::Crop* op_default = (ncnn::Crop*)layer_default; + + fprintf_param_value(" 0=%d", woffset) + fprintf_param_value(" 1=%d", hoffset) + fprintf_param_value(" 2=%d", coffset) + fprintf_param_value(" 3=%d", outw) + fprintf_param_value(" 4=%d", outh) + fprintf_param_value(" 5=%d", outc) + fprintf_param_value(" 6=%d", woffset2) + fprintf_param_value(" 7=%d", hoffset2) + fprintf_param_value(" 8=%d", coffset2) + { + if (!op->starts.empty()) fprintf_param_int_array(9, op->starts, pp); + } + { + if (!op->ends.empty()) fprintf_param_int_array(10, op->ends, pp); + } + { + if (!op->axes.empty()) fprintf_param_int_array(11, op->axes, pp); + } + } + else if (layer->type == "Deconvolution") + { + ncnn::Deconvolution* op = (ncnn::Deconvolution*)layer; + ncnn::Deconvolution* op_default = (ncnn::Deconvolution*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + fprintf_param_value(" 18=%d", output_pad_right) + { + if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); + } + fprintf_param_value(" 20=%d", output_w) + { + if (op->output_h != op->output_w) fprintf(pp, " 21=%d", op->output_h); + } + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int inc = blobs[layer->bottoms[0]].shape.c; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_h * op->kernel_w * inw * inh * outc * inc; + } + } + else if (layer->type == "Deconvolution1D") + { + ncnn::Deconvolution1D* op = (ncnn::Deconvolution1D*)layer; + ncnn::Deconvolution1D* op_default = (ncnn::Deconvolution1D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + fprintf_param_value(" 2=%d", dilation_w) + fprintf_param_value(" 3=%d", stride_w) + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + fprintf_param_value(" 18=%d", output_pad_right) + fprintf_param_value(" 20=%d", output_w) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int outh = blobs[layer->tops[0]].shape.h; + + mac += (uint64_t)op->kernel_w * inw * outh * inh; + } + } + else if (layer->type == "Deconvolution3D") + { + ncnn::Deconvolution3D* op = (ncnn::Deconvolution3D*)layer; + ncnn::Deconvolution3D* op_default = (ncnn::Deconvolution3D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + { + if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); + } + fprintf_param_value(" 18=%d", output_pad_right) + { + if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); + if (op->output_pad_behind != op->output_pad_right) fprintf(pp, " 20=%d", op->output_pad_behind); + } + fprintf_param_value(" 25=%d", output_w) + { + if (op->output_h != op->output_w) fprintf(pp, " 26=%d", op->output_h); + if (op->output_d != op->output_w) fprintf(pp, " 27=%d", op->output_d); + } + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int ind = blobs[layer->bottoms[0]].shape.d; + int inc = blobs[layer->bottoms[0]].shape.c; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * inw * inh * ind * outc * inc; + } + } + else if (layer->type == "DeconvolutionDepthWise") + { + ncnn::DeconvolutionDepthWise* op = (ncnn::DeconvolutionDepthWise*)layer; + ncnn::DeconvolutionDepthWise* op_default = (ncnn::DeconvolutionDepthWise*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + fprintf_param_value(" 18=%d", output_pad_right) + { + if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); + } + fprintf_param_value(" 20=%d", output_w) + { + if (op->output_h != op->output_w) fprintf(pp, " 21=%d", op->output_h); + } + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int inc = blobs[layer->bottoms[0]].shape.c; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_h * op->kernel_w * inw * inh * (outc / op->group) * (inc / op->group) * op->group; + } + } + else if (layer->type == "DeconvolutionDepthWise1D") + { + ncnn::DeconvolutionDepthWise1D* op = (ncnn::DeconvolutionDepthWise1D*)layer; + ncnn::DeconvolutionDepthWise1D* op_default = (ncnn::DeconvolutionDepthWise1D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + fprintf_param_value(" 2=%d", dilation_w) + fprintf_param_value(" 3=%d", stride_w) + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + fprintf_param_value(" 18=%d", output_pad_right) + fprintf_param_value(" 20=%d", output_w) + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int outh = blobs[layer->tops[0]].shape.h; + + mac += (uint64_t)op->kernel_w * inw * (outh / op->group) * (inh / op->group) * op->group; + } + } + else if (layer->type == "DeconvolutionDepthWise3D") + { + ncnn::DeconvolutionDepthWise3D* op = (ncnn::DeconvolutionDepthWise3D*)layer; + ncnn::DeconvolutionDepthWise3D* op_default = (ncnn::DeconvolutionDepthWise3D*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); + } + fprintf_param_value(" 2=%d", dilation_w) + { + if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); + if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); + } + fprintf_param_value(" 3=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); + if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); + } + fprintf_param_value(" 4=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); + if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); + } + { + if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); + } + fprintf_param_value(" 18=%d", output_pad_right) + { + if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); + if (op->output_pad_behind != op->output_pad_right) fprintf(pp, " 20=%d", op->output_pad_behind); + } + fprintf_param_value(" 25=%d", output_w) + { + if (op->output_h != op->output_w) fprintf(pp, " 26=%d", op->output_h); + if (op->output_d != op->output_w) fprintf(pp, " 27=%d", op->output_d); + } + fprintf_param_value(" 5=%d", bias_term) + fprintf_param_value(" 6=%d", weight_data_size) + fprintf_param_value(" 7=%d", group) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int ind = blobs[layer->bottoms[0]].shape.d; + int inc = blobs[layer->bottoms[0]].shape.c; + int outc = blobs[layer->tops[0]].shape.c; + + mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * inw * inh * ind * (outc / op->group) * (inc / op->group) * op->group; + } + } + else if (layer->type == "DetectionOutput") + { + ncnn::DetectionOutput* op = (ncnn::DetectionOutput*)layer; + ncnn::DetectionOutput* op_default = (ncnn::DetectionOutput*)layer_default; + + fprintf_param_value(" 0=%d", num_class) + fprintf_param_value(" 1=%e", nms_threshold) + fprintf_param_value(" 2=%d", nms_top_k) + fprintf_param_value(" 3=%d", keep_top_k) + fprintf_param_value(" 4=%e", confidence_threshold) + fprintf_param_value(" 5=%e", variances[0]) + fprintf_param_value(" 6=%e", variances[1]) + fprintf_param_value(" 7=%e", variances[2]) + fprintf_param_value(" 8=%e", variances[3]) + } + else if (layer->type == "Dropout") + { + ncnn::Dropout* op = (ncnn::Dropout*)layer; + ncnn::Dropout* op_default = (ncnn::Dropout*)layer_default; + + fprintf_param_value(" 0=%e", scale) + } + else if (layer->type == "Eltwise") + { + ncnn::Eltwise* op = (ncnn::Eltwise*)layer; + ncnn::Eltwise* op_default = (ncnn::Eltwise*)layer_default; + + fprintf_param_value(" 0=%d", op_type) + { + if (!op->coeffs.empty()) fprintf_param_float_array(1, op->coeffs, pp); + } + } + else if (layer->type == "ELU") + { + ncnn::ELU* op = (ncnn::ELU*)layer; + ncnn::ELU* op_default = (ncnn::ELU*)layer_default; + + fprintf_param_value(" 0=%e", alpha) + } + else if (layer->type == "Embed") + { + ncnn::Embed* op = (ncnn::Embed*)layer; + ncnn::Embed* op_default = (ncnn::Embed*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", input_dim) + fprintf_param_value(" 2=%d", bias_term) + fprintf_param_value(" 3=%d", weight_data_size) + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + } + else if (layer->type == "Exp") + { + ncnn::Exp* op = (ncnn::Exp*)layer; + ncnn::Exp* op_default = (ncnn::Exp*)layer_default; + + fprintf_param_value(" 0=%e", base) + fprintf_param_value(" 1=%e", scale) + fprintf_param_value(" 2=%e", shift) + } + else if (layer->type == "ExpandDims") + { + ncnn::ExpandDims* op = (ncnn::ExpandDims*)layer; + ncnn::ExpandDims* op_default = (ncnn::ExpandDims*)layer_default; + + fprintf_param_value(" 0=%d", expand_w) + fprintf_param_value(" 1=%d", expand_h) + fprintf_param_value(" 2=%d", expand_c) + { + if (!op->axes.empty()) fprintf_param_int_array(0, op->axes, pp); + } + } + else if (layer->type == "GELU") + { + ncnn::GELU* op = (ncnn::GELU*)layer; + ncnn::GELU* op_default = (ncnn::GELU*)layer_default; + + fprintf_param_value(" 0=%d", fast_gelu) + } + else if (layer->type == "Gemm") + { + ncnn::Gemm* op = (ncnn::Gemm*)layer; + ncnn::Gemm* op_default = (ncnn::Gemm*)layer_default; + + fprintf_param_value(" 0=%e", alpha) + fprintf_param_value(" 1=%e", beta) + fprintf_param_value(" 2=%d", transA) + fprintf_param_value(" 3=%d", transB) + } + else if (layer->type == "GroupNorm") + { + ncnn::GroupNorm* op = (ncnn::GroupNorm*)layer; + ncnn::GroupNorm* op_default = (ncnn::GroupNorm*)layer_default; + + fprintf_param_value(" 0=%d", group) + fprintf_param_value(" 1=%d", channels) + fprintf_param_value(" 2=%e", eps) + fprintf_param_value(" 3=%d", affine) + + fwrite_weight_data(op->gamma_data, bp); + fwrite_weight_data(op->beta_data, bp); + } + else if (layer->type == "GRU") + { + ncnn::GRU* op = (ncnn::GRU*)layer; + ncnn::GRU* op_default = (ncnn::GRU*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", weight_data_size) + fprintf_param_value(" 2=%d", direction) + + fwrite_weight_tag_data(op->weight_xc_data, bp); + fwrite_weight_tag_data(op->bias_c_data, bp); + fwrite_weight_tag_data(op->weight_hc_data, bp); + } + else if (layer->type == "HardSigmoid") + { + ncnn::HardSigmoid* op = (ncnn::HardSigmoid*)layer; + ncnn::HardSigmoid* op_default = (ncnn::HardSigmoid*)layer_default; + + fprintf_param_value(" 0=%e", alpha) + fprintf_param_value(" 1=%e", beta) + } + else if (layer->type == "HardSwish") + { + ncnn::HardSwish* op = (ncnn::HardSwish*)layer; + ncnn::HardSwish* op_default = (ncnn::HardSwish*)layer_default; + + fprintf_param_value(" 0=%e", alpha) + fprintf_param_value(" 1=%e", beta) + } + else if (layer->type == "InnerProduct") + { + ncnn::InnerProduct* op = (ncnn::InnerProduct*)layer; + ncnn::InnerProduct* op_default = (ncnn::InnerProduct*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", bias_term) + fprintf_param_value(" 2=%d", weight_data_size) + fprintf_param_value(" 8=%d", int8_scale_term) + fprintf_param_value(" 9=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); + } + + fwrite_weight_tag_data(op->weight_data, bp); + fwrite_weight_data(op->bias_data, bp); + +#if NCNN_INT8 + // write int8_scale data + if (op->int8_scale_term) + { + fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); + fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); + } +#endif // NCNN_INT8 + + if (shape_ready) + { + int inw = blobs[layer->bottoms[0]].shape.w; + int inh = blobs[layer->bottoms[0]].shape.h; + int inc = blobs[layer->bottoms[0]].shape.c; + int outw = blobs[layer->tops[0]].shape.w; + + mac += (uint64_t)inw * inh * inc * outw; + } + } + else if (layer->type == "Input") + { + ncnn::Input* op = (ncnn::Input*)layer; + ncnn::Input* op_default = (ncnn::Input*)layer_default; + + fprintf_param_value(" 0=%d", w) + fprintf_param_value(" 1=%d", h) + fprintf_param_value(" 2=%d", c) + } + else if (layer->type == "InstanceNorm") + { + ncnn::InstanceNorm* op = (ncnn::InstanceNorm*)layer; + ncnn::InstanceNorm* op_default = (ncnn::InstanceNorm*)layer_default; + + fprintf_param_value(" 0=%d", channels) + fprintf_param_value(" 1=%e", eps) + fprintf_param_value(" 2=%d", affine) + + fwrite_weight_data(op->gamma_data, bp); + fwrite_weight_data(op->beta_data, bp); + } + else if (layer->type == "Interp") + { + ncnn::Interp* op = (ncnn::Interp*)layer; + ncnn::Interp* op_default = (ncnn::Interp*)layer_default; + + fprintf_param_value(" 0=%d", resize_type) + fprintf_param_value(" 1=%e", height_scale) + fprintf_param_value(" 2=%e", width_scale) + fprintf_param_value(" 3=%d", output_height) + fprintf_param_value(" 4=%d", output_width) + fprintf_param_value(" 5=%d", dynamic_target_size) + fprintf_param_value(" 6=%d", align_corner) + } + else if (layer->type == "LayerNorm") + { + ncnn::LayerNorm* op = (ncnn::LayerNorm*)layer; + ncnn::LayerNorm* op_default = (ncnn::LayerNorm*)layer_default; + + fprintf_param_value(" 0=%d", affine_size) + fprintf_param_value(" 1=%e", eps) + fprintf_param_value(" 2=%d", affine) + + fwrite_weight_data(op->gamma_data, bp); + fwrite_weight_data(op->beta_data, bp); + } + else if (layer->type == "Log") + { + ncnn::Log* op = (ncnn::Log*)layer; + ncnn::Log* op_default = (ncnn::Log*)layer_default; + + fprintf_param_value(" 0=%e", base) + fprintf_param_value(" 1=%e", scale) + fprintf_param_value(" 2=%e", shift) + } + else if (layer->type == "LRN") + { + ncnn::LRN* op = (ncnn::LRN*)layer; + ncnn::LRN* op_default = (ncnn::LRN*)layer_default; + + fprintf_param_value(" 0=%d", region_type) + fprintf_param_value(" 1=%d", local_size) + fprintf_param_value(" 2=%e", alpha) + fprintf_param_value(" 3=%e", beta) + fprintf_param_value(" 4=%e", bias) + } + else if (layer->type == "LSTM") + { + ncnn::LSTM* op = (ncnn::LSTM*)layer; + ncnn::LSTM* op_default = (ncnn::LSTM*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", weight_data_size) + fprintf_param_value(" 2=%d", direction) + + fwrite_weight_tag_data(op->weight_xc_data, bp); + fwrite_weight_tag_data(op->bias_c_data, bp); + fwrite_weight_tag_data(op->weight_hc_data, bp); + } + else if (layer->type == "MatMul") + { + ncnn::MatMul* op = (ncnn::MatMul*)layer; + ncnn::MatMul* op_default = (ncnn::MatMul*)layer_default; + + fprintf_param_value(" 0=%d", transB) + } + else if (layer->type == "MemoryData") + { + ncnn::MemoryData* op = (ncnn::MemoryData*)layer; + ncnn::MemoryData* op_default = (ncnn::MemoryData*)layer_default; + + fprintf_param_value(" 0=%d", w) + fprintf_param_value(" 1=%d", h) + fprintf_param_value(" 2=%d", c) + fwrite_weight_data(op->data, bp); + } + else if (layer->type == "MultiHeadAttention") + { + ncnn::MultiHeadAttention* op = (ncnn::MultiHeadAttention*)layer; + ncnn::MultiHeadAttention* op_default = (ncnn::MultiHeadAttention*)layer_default; + + fprintf_param_value(" 0=%d", embed_dim) + fprintf_param_value(" 1=%d", num_head) + fprintf_param_value(" 2=%d", weight_data_size) + + fwrite_weight_tag_data(op->q_weight_data, bp); + fwrite_weight_data(op->q_bias_data, bp); + fwrite_weight_tag_data(op->k_weight_data, bp); + fwrite_weight_data(op->k_bias_data, bp); + fwrite_weight_tag_data(op->v_weight_data, bp); + fwrite_weight_data(op->v_bias_data, bp); + fwrite_weight_tag_data(op->out_weight_data, bp); + fwrite_weight_data(op->out_bias_data, bp); + } + else if (layer->type == "MVN") + { + ncnn::MVN* op = (ncnn::MVN*)layer; + ncnn::MVN* op_default = (ncnn::MVN*)layer_default; + + fprintf_param_value(" 0=%d", normalize_variance) + fprintf_param_value(" 1=%d", across_channels) + fprintf_param_value(" 2=%e", eps) + } + else if (layer->type == "Normalize") + { + ncnn::Normalize* op = (ncnn::Normalize*)layer; + ncnn::Normalize* op_default = (ncnn::Normalize*)layer_default; + + fprintf_param_value(" 0=%d", across_spatial) + fprintf_param_value(" 1=%d", channel_shared) + fprintf_param_value(" 2=%e", eps) + fprintf_param_value(" 3=%d", scale_data_size) + fprintf_param_value(" 4=%d", across_channel) + fprintf_param_value(" 9=%d", eps_mode) + + fwrite_weight_data(op->scale_data, bp); + } + else if (layer->type == "Padding") + { + ncnn::Padding* op = (ncnn::Padding*)layer; + ncnn::Padding* op_default = (ncnn::Padding*)layer_default; + + fprintf_param_value(" 0=%d", top) + fprintf_param_value(" 1=%d", bottom) + fprintf_param_value(" 2=%d", left) + fprintf_param_value(" 3=%d", right) + fprintf_param_value(" 4=%d", type) + fprintf_param_value(" 5=%e", value) + fprintf_param_value(" 6=%d", per_channel_pad_data_size) + fprintf_param_value(" 7=%d", front) + fprintf_param_value(" 8=%d", behind) + + fwrite_weight_data(op->per_channel_pad_data, bp); + } + else if (layer->type == "Permute") + { + ncnn::Permute* op = (ncnn::Permute*)layer; + ncnn::Permute* op_default = (ncnn::Permute*)layer_default; + + fprintf_param_value(" 0=%d", order_type) + } + else if (layer->type == "PixelShuffle") + { + ncnn::PixelShuffle* op = (ncnn::PixelShuffle*)layer; + ncnn::PixelShuffle* op_default = (ncnn::PixelShuffle*)layer_default; + + fprintf_param_value(" 0=%d", upscale_factor) + fprintf_param_value(" 1=%d", mode) + } + else if (layer->type == "Pooling") + { + ncnn::Pooling* op = (ncnn::Pooling*)layer; + ncnn::Pooling* op_default = (ncnn::Pooling*)layer_default; + + fprintf_param_value(" 0=%d", pooling_type) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + } + fprintf_param_value(" 2=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 12=%d", op->stride_h); + } + fprintf_param_value(" 3=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 13=%d", op->pad_top); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 15=%d", op->pad_bottom); + } + fprintf_param_value(" 4=%d", global_pooling) + fprintf_param_value(" 5=%d", pad_mode) + fprintf_param_value(" 6=%d", avgpool_count_include_pad) + fprintf_param_value(" 7=%d", adaptive_pooling) + fprintf_param_value(" 8=%d", out_w) + { + if (op->out_h != op->out_w) fprintf(pp, " 18=%d", op->out_h); + } + } + else if (layer->type == "Pooling1D") + { + ncnn::Pooling1D* op = (ncnn::Pooling1D*)layer; + ncnn::Pooling1D* op_default = (ncnn::Pooling1D*)layer_default; + + fprintf_param_value(" 0=%d", pooling_type) + fprintf_param_value(" 1=%d", kernel_w) + fprintf_param_value(" 2=%d", stride_w) + fprintf_param_value(" 3=%d", pad_left) + { + if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); + } + fprintf_param_value(" 4=%d", global_pooling) + fprintf_param_value(" 5=%d", pad_mode) + fprintf_param_value(" 6=%d", avgpool_count_include_pad) + fprintf_param_value(" 7=%d", adaptive_pooling) + fprintf_param_value(" 8=%d", out_w) + } + else if (layer->type == "Pooling3D") + { + ncnn::Pooling3D* op = (ncnn::Pooling3D*)layer; + ncnn::Pooling3D* op_default = (ncnn::Pooling3D*)layer_default; + + fprintf_param_value(" 0=%d", pooling_type) + fprintf_param_value(" 1=%d", kernel_w) + { + if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); + if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); + } + fprintf_param_value(" 2=%d", stride_w) + { + if (op->stride_h != op->stride_w) fprintf(pp, " 12=%d", op->stride_h); + if (op->stride_d != op->stride_w) fprintf(pp, " 22=%d", op->stride_d); + } + fprintf_param_value(" 3=%d", pad_left) + { + if (op->pad_top != op->pad_left) fprintf(pp, " 13=%d", op->pad_top); + if (op->pad_front != op->pad_left) fprintf(pp, " 23=%d", op->pad_front); + } + { + if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); + } + { + if (op->pad_bottom != op->pad_top) fprintf(pp, " 15=%d", op->pad_bottom); + } + { + if (op->pad_behind != op->pad_front) fprintf(pp, " 16=%d", op->pad_behind); + } + fprintf_param_value(" 4=%d", global_pooling) + fprintf_param_value(" 5=%d", pad_mode) + fprintf_param_value(" 6=%d", avgpool_count_include_pad) + fprintf_param_value(" 7=%d", adaptive_pooling) + fprintf_param_value(" 8=%d", out_w) + { + if (op->out_h != op->out_w) fprintf(pp, " 18=%d", op->out_h); + if (op->out_d != op->out_w) fprintf(pp, " 28=%d", op->out_d); + } + } + else if (layer->type == "Power") + { + ncnn::Power* op = (ncnn::Power*)layer; + ncnn::Power* op_default = (ncnn::Power*)layer_default; + + fprintf_param_value(" 0=%e", power) + fprintf_param_value(" 1=%e", scale) + fprintf_param_value(" 2=%e", shift) + } + else if (layer->type == "PReLU") + { + ncnn::PReLU* op = (ncnn::PReLU*)layer; + ncnn::PReLU* op_default = (ncnn::PReLU*)layer_default; + + fprintf_param_value(" 0=%d", num_slope) + + fwrite_weight_data(op->slope_data, bp); + } + else if (layer->type == "PriorBox") + { + ncnn::PriorBox* op = (ncnn::PriorBox*)layer; + ncnn::PriorBox* op_default = (ncnn::PriorBox*)layer_default; + + { + if (!op->min_sizes.empty()) fprintf_param_float_array(0, op->min_sizes, pp); + } + { + if (!op->max_sizes.empty()) fprintf_param_float_array(1, op->max_sizes, pp); + } + { + if (!op->aspect_ratios.empty()) fprintf_param_float_array(2, op->aspect_ratios, pp); + } + fprintf_param_value(" 3=%e", variances[0]) + fprintf_param_value(" 4=%e", variances[1]) + fprintf_param_value(" 5=%e", variances[2]) + fprintf_param_value(" 6=%e", variances[3]) + fprintf_param_value(" 7=%d", flip) + fprintf_param_value(" 8=%d", clip) + fprintf_param_value(" 9=%d", image_width) + fprintf_param_value(" 10=%d", image_height) + fprintf_param_value(" 11=%e", step_width) + fprintf_param_value(" 12=%e", step_height) + fprintf_param_value(" 13=%e", offset) + } + else if (layer->type == "Proposal") + { + ncnn::Proposal* op = (ncnn::Proposal*)layer; + ncnn::Proposal* op_default = (ncnn::Proposal*)layer_default; + + fprintf_param_value(" 0=%d", feat_stride) + fprintf_param_value(" 1=%d", base_size) + fprintf_param_value(" 2=%d", pre_nms_topN) + fprintf_param_value(" 3=%d", after_nms_topN) + fprintf_param_value(" 4=%e", nms_thresh) + fprintf_param_value(" 5=%d", min_size) + } + else if (layer->type == "PSROIPooling") + { + ncnn::PSROIPooling* op = (ncnn::PSROIPooling*)layer; + ncnn::PSROIPooling* op_default = (ncnn::PSROIPooling*)layer_default; + + fprintf_param_value(" 0=%d", pooled_width) + fprintf_param_value(" 1=%d", pooled_height) + fprintf_param_value(" 2=%e", spatial_scale) + fprintf_param_value(" 3=%d", output_dim) + } + else if (layer->type == "Quantize") + { + ncnn::Quantize* op = (ncnn::Quantize*)layer; + ncnn::Quantize* op_default = (ncnn::Quantize*)layer_default; + + fprintf_param_value(" 0=%d", scale_data_size) + + fwrite_weight_data(op->scale_data, bp); + } + else if (layer->type == "Reduction") + { + ncnn::Reduction* op = (ncnn::Reduction*)layer; + ncnn::Reduction* op_default = (ncnn::Reduction*)layer_default; + + fprintf_param_value(" 0=%d", operation) + fprintf_param_value(" 1=%d", reduce_all) + fprintf_param_value(" 2=%e", coeff) + { + if (!op->axes.empty()) fprintf_param_int_array(3, op->axes, pp); + } + fprintf_param_value(" 4=%d", keepdims) + + // HACK + if (!op->axes.empty()) + { + int fixbug0 = 1; + fprintf(pp, " 5=%d", fixbug0); + } + } + else if (layer->type == "ReLU") + { + ncnn::ReLU* op = (ncnn::ReLU*)layer; + ncnn::ReLU* op_default = (ncnn::ReLU*)layer_default; + + fprintf_param_value(" 0=%e", slope) + } + else if (layer->type == "Reorg") + { + ncnn::Reorg* op = (ncnn::Reorg*)layer; + ncnn::Reorg* op_default = (ncnn::Reorg*)layer_default; + + fprintf_param_value(" 0=%d", stride) + fprintf_param_value(" 1=%d", mode) + } + else if (layer->type == "Requantize") + { + ncnn::Requantize* op = (ncnn::Requantize*)layer; + ncnn::Requantize* op_default = (ncnn::Requantize*)layer_default; + + fprintf_param_value(" 0=%d", scale_in_data_size) + fprintf_param_value(" 1=%d", scale_out_data_size) + fprintf_param_value(" 2=%d", bias_data_size) + fprintf_param_value(" 3=%d", activation_type) + { + if (!op->activation_params.empty()) fprintf_param_float_array(4, op->activation_params, pp); + } + + fwrite_weight_data(op->scale_in_data, bp); + fwrite_weight_data(op->scale_out_data, bp); + fwrite_weight_data(op->bias_data, bp); + } + else if (layer->type == "Reshape") + { + ncnn::Reshape* op = (ncnn::Reshape*)layer; + ncnn::Reshape* op_default = (ncnn::Reshape*)layer_default; + + fprintf_param_value(" 0=%d", w) + fprintf_param_value(" 1=%d", h) + fprintf_param_value(" 2=%d", c) + fprintf_param_value(" 3=%d", permute) + } + else if (layer->type == "RNN") + { + ncnn::RNN* op = (ncnn::RNN*)layer; + ncnn::RNN* op_default = (ncnn::RNN*)layer_default; + + fprintf_param_value(" 0=%d", num_output) + fprintf_param_value(" 1=%d", weight_data_size) + fprintf_param_value(" 2=%d", direction) + + fwrite_weight_tag_data(op->weight_xc_data, bp); + fwrite_weight_tag_data(op->bias_c_data, bp); + fwrite_weight_tag_data(op->weight_hc_data, bp); + } + else if (layer->type == "ROIAlign") + { + ncnn::ROIAlign* op = (ncnn::ROIAlign*)layer; + ncnn::ROIAlign* op_default = (ncnn::ROIAlign*)layer_default; + + fprintf_param_value(" 0=%d", pooled_width) + fprintf_param_value(" 1=%d", pooled_height) + fprintf_param_value(" 2=%e", spatial_scale) + fprintf_param_value(" 3=%d", sampling_ratio) + fprintf_param_value(" 4=%d", aligned) + fprintf_param_value(" 5=%d", version) + } + else if (layer->type == "ROIPooling") + { + ncnn::ROIPooling* op = (ncnn::ROIPooling*)layer; + ncnn::ROIPooling* op_default = (ncnn::ROIPooling*)layer_default; + + fprintf_param_value(" 0=%d", pooled_width) + fprintf_param_value(" 1=%d", pooled_height) + fprintf_param_value(" 2=%e", spatial_scale) + } + else if (layer->type == "Scale") + { + ncnn::Scale* op = (ncnn::Scale*)layer; + ncnn::Scale* op_default = (ncnn::Scale*)layer_default; + + fprintf_param_value(" 0=%d", scale_data_size) + fprintf_param_value(" 1=%d", bias_term) + + fwrite_weight_data(op->scale_data, bp); + fwrite_weight_data(op->bias_data, bp); + } + else if (layer->type == "ShuffleChannel") + { + ncnn::ShuffleChannel* op = (ncnn::ShuffleChannel*)layer; + ncnn::ShuffleChannel* op_default = (ncnn::ShuffleChannel*)layer_default; + + fprintf_param_value(" 0=%d", group) + fprintf_param_value(" 1=%d", reverse) + } + else if (layer->type == "Slice") + { + ncnn::Slice* op = (ncnn::Slice*)layer; + ncnn::Slice* op_default = (ncnn::Slice*)layer_default; + + { + if (!op->slices.empty()) fprintf_param_int_array(0, op->slices, pp); + } + fprintf_param_value(" 1=%d", axis) + } + else if (layer->type == "Softmax") + { + ncnn::Softmax* op = (ncnn::Softmax*)layer; + ncnn::Softmax* op_default = (ncnn::Softmax*)layer_default; + + fprintf_param_value(" 0=%d", axis) + + // HACK + if (op->axis != 0) + { + int fixbug0 = 1; + fprintf(pp, " 1=%d", fixbug0); + } + } + else if (layer->type == "Squeeze") + { + ncnn::Squeeze* op = (ncnn::Squeeze*)layer; + ncnn::Squeeze* op_default = (ncnn::Squeeze*)layer_default; + + fprintf_param_value(" 0=%d", squeeze_w) + fprintf_param_value(" 1=%d", squeeze_h) + fprintf_param_value(" 2=%d", squeeze_c) + { + if (!op->axes.empty()) fprintf_param_int_array(0, op->axes, pp); + } + } + else if (layer->type == "Threshold") + { + ncnn::Threshold* op = (ncnn::Threshold*)layer; + ncnn::Threshold* op_default = (ncnn::Threshold*)layer_default; + + fprintf_param_value(" 0=%e", threshold) + } + else if (layer->type == "UnaryOp") + { + ncnn::UnaryOp* op = (ncnn::UnaryOp*)layer; + ncnn::UnaryOp* op_default = (ncnn::UnaryOp*)layer_default; + + fprintf_param_value(" 0=%d", op_type) + } + else if (layer->type == "YoloDetectionOutput") + { + ncnn::YoloDetectionOutput* op = (ncnn::YoloDetectionOutput*)layer; + ncnn::YoloDetectionOutput* op_default = (ncnn::YoloDetectionOutput*)layer_default; + + fprintf_param_value(" 0=%d", num_class) + fprintf_param_value(" 1=%d", num_box) + fprintf_param_value(" 2=%e", confidence_threshold) + fprintf_param_value(" 3=%e", nms_threshold) + { + if (!op->biases.empty()) fprintf_param_float_array(4, op->biases, pp); + } + } + else if (layer->type == "Yolov3DetectionOutput") + { + ncnn::Yolov3DetectionOutput* op = (ncnn::Yolov3DetectionOutput*)layer; + ncnn::Yolov3DetectionOutput* op_default = (ncnn::Yolov3DetectionOutput*)layer_default; + + fprintf_param_value(" 0=%d", num_class) + fprintf_param_value(" 1=%d", num_box) + fprintf_param_value(" 2=%e", confidence_threshold) + fprintf_param_value(" 3=%e", nms_threshold) + { + if (!op->biases.empty()) fprintf_param_float_array(4, op->biases, pp); + } + { + if (!op->mask.empty()) fprintf_param_int_array(5, op->mask, pp); + } + { + if (!op->anchors_scale.empty()) fprintf_param_float_array(6, op->anchors_scale, pp); + } + } + +#undef fprintf_param_value + + fprintf(pp, "\n"); + + delete layer_default; + } + + fclose(pp); + fclose(bp); + + if (mac) + { + fprintf(stderr, "mac = %llu = %.2f M\n", static_cast(mac), mac / 1000000.0); + } + + return 0; +} diff --git a/tools/modelwriter.h b/tools/modelwriter.h index 4b51620bdc60..844c6d4f6efa 100644 --- a/tools/modelwriter.h +++ b/tools/modelwriter.h @@ -11,7 +11,7 @@ // 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. - +#pragma once #ifdef _MSC_VER #define _CRT_SECURE_NO_DEPRECATE #endif @@ -115,30 +115,11 @@ static struct prng_rand_t g_prng_rand_state; class MemoryFootprintAllocator : public ncnn::Allocator { public: - MemoryFootprintAllocator() - { - current_memory_usage = 0; - memory_footprint = 0; - } + MemoryFootprintAllocator(); - virtual void* fastMalloc(size_t size) - { - ncnn::MutexLockGuard g(lock); - void* ptr = ncnn::fastMalloc(size); - bookkeeper[ptr] = size; - current_memory_usage += size; - memory_footprint = std::max(memory_footprint, current_memory_usage); - return ptr; - } + virtual void* fastMalloc(size_t size); - virtual void fastFree(void* ptr) - { - ncnn::MutexLockGuard g(lock); - size_t size = bookkeeper[ptr]; - current_memory_usage -= size; - bookkeeper.erase(bookkeeper.find(ptr)); - ncnn::fastFree(ptr); - } + virtual void fastFree(void* ptr); public: int current_memory_usage; @@ -150,59 +131,14 @@ class MemoryFootprintAllocator : public ncnn::Allocator class CustomLayer : public ncnn::Layer { public: - virtual int load_param(const ncnn::ParamDict& pd) - { - mpd = pd; - return 0; - } - - void write_param(FILE* pp) - { - for (int i = 0; i < NCNN_MAX_PARAM_COUNT; i++) - { - int type = mpd.type(i); - if (type == 0) - continue; + virtual int load_param(const ncnn::ParamDict& pd); - if (type == 2) - { - fprintf(pp, " %d=%d", i, mpd.get(i, 0)); - } - if (type == 3) - { - fprintf(pp, " %d=%e", i, mpd.get(i, 0.f)); - } - if (type == 5) - { - ncnn::Mat v = mpd.get(i, ncnn::Mat()); - int len = v.w; - fprintf(pp, " %d=%d", -i - 23300, len); - const int* p = v; - for (int j = 0; j < len; j++) - { - fprintf(pp, ",%d", p[j]); - } - } - if (type == 6) - { - ncnn::Mat v = mpd.get(i, ncnn::Mat()); - int len = v.w; - fprintf(pp, " %d=%d", -i - 23300, len); - const float* p = v; - for (int j = 0; j < len; j++) - { - fprintf(pp, ",%e", p[j]); - } - } - } - } + void write_param(FILE* pp); public: ncnn::ParamDict mpd; }; -DEFINE_LAYER_CREATOR(CustomLayer) - class ModelWriter : public ncnn::Net { public: @@ -240,1980 +176,3 @@ class ModelWriter : public ncnn::Net int save(const char* parampath, const char* binpath); }; - -ModelWriter::ModelWriter() - : blobs(mutable_blobs()), layers(mutable_layers()) -{ - opt.lightmode = false; - has_custom_layer = false; - gen_random_weight = false; - cutstart = -1; - cutend = -1; - - SRAND(7767517); -} - -ncnn::Layer* ModelWriter::create_custom_layer(const char* type) -{ - ncnn::Layer* layer = Net::create_custom_layer(type); - if (layer) - return layer; - - fprintf(stderr, "create_custom_layer %s\n", type); - - register_custom_layer(type, CustomLayer_layer_creator); - - has_custom_layer = true; - - return Net::create_custom_layer(type); -} - -int ModelWriter::set_cutparam(const char* cutstartname, const char* cutendname) -{ - if (cutstartname != nullptr) - { - int layindex = find_layer_index_by_name(cutstartname); - if (layindex >= 0) - { - cutstart = layindex; - fprintf(stderr, "cutstart layer %d:%s\n", layindex, cutstartname); - } - else - { - fprintf(stderr, "not find target cutstart layer %s\n", cutstartname); - return -1; - } - } - - if (cutendname != nullptr) - { - int layindex = find_layer_index_by_name(cutendname); - if (layindex >= 0) - { - cutend = layindex; - fprintf(stderr, "cutend layer %d:%s\n", layindex, cutendname); - } - else - { - fprintf(stderr, "not find target cutend layer %s\n", cutendname); - return -1; - } - } - - return 0; -} - -int ModelWriter::shape_inference() -{ - if (has_custom_layer) - { - fprintf(stderr, "model has custom layer, shape_inference skipped\n"); - return -1; - } - - const size_t layer_count = layers.size(); - const size_t blob_count = blobs.size(); - - // recreate layer pipeline for param and weight changes - for (size_t i = 0; i < layer_count; i++) - { - ncnn::Layer* layer = layers[i]; - - layer->destroy_pipeline(opt); - - int cret = layer->create_pipeline(opt); - if (cret != 0) - { - NCNN_LOGE("layer create_pipeline %d %s failed", (int)i, layer->name.c_str()); - return -1; - } - } - - ncnn::Extractor ex = create_extractor(); - ex.set_light_mode(true); - - // prepare Input blobs - for (size_t i = 0; i < layer_count; i++) - { - const ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - if (layer->type != "Input") - continue; - - ncnn::Input* input = (ncnn::Input*)layer; - - int w = input->w; - int h = input->h; - int c = input->c; - - int dims = 0; - if (w == 0 && h == 0 && c == 0) dims = 0; - if (w != 0 && h == 0 && c == 0) dims = 1; - if (w != 0 && h != 0 && c == 0) dims = 2; - if (w != 0 && h != 0 && c != 0) dims = 3; - - if (dims == 0) - { - fprintf(stderr, "Input layer %s without shape info, shape_inference skipped\n", layer->name.c_str()); - return -1; - } - - ncnn::Mat m; - if (dims == 1) m.create(w); - if (dims == 2) m.create(w, h); - if (dims == 3) m.create(w, h, c); - - ex.input(layer->tops[0], m); - } - - // prepare blobs with predefined shape - for (size_t i = 0; i < blob_count; i++) - { - const ncnn::Blob& blob = blobs[i]; - - int dims = blob.shape.dims; - int w = blob.shape.w; - int h = blob.shape.h; - int c = blob.shape.c; - - if (dims == 0) - continue; - - ncnn::Mat m; - if (dims == 1) m.create(w); - if (dims == 2) m.create(w, h); - if (dims == 3) m.create(w, h, c); - - m.fill(0.f); - - ex.input(int(i), m); - } - - fprintf(stderr, "shape_inference\n"); - - // resolve all layer output blob shape - for (size_t i = 0; i < layer_count; i++) - { - const ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - for (size_t j = 0; j < layer->tops.size(); j++) - { - int top_blob_index = layer->tops[j]; - - ncnn::Mat m; - ex.extract(top_blob_index, m); - - blobs[top_blob_index].shape = m; - } - } - - // assign all layer blob shape - for (size_t i = 0; i < layer_count; i++) - { - ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - layer->bottom_shapes.resize(layer->bottoms.size()); - for (size_t j = 0; j < layer->bottoms.size(); j++) - { - int bottom_blob_index = layer->bottoms[j]; - - layer->bottom_shapes[j] = blobs[bottom_blob_index].shape; - } - - layer->top_shapes.resize(layer->tops.size()); - for (size_t j = 0; j < layer->tops.size(); j++) - { - int top_blob_index = layer->tops[j]; - - layer->top_shapes[j] = blobs[top_blob_index].shape; - - // fprintf(stderr, "%d %4d %4d %4d | %2d %s\n", blobs[top_blob_index].shape.dims, blobs[top_blob_index].shape.w, blobs[top_blob_index].shape.h, blobs[top_blob_index].shape.c, top_blob_index, blobs[top_blob_index].name.c_str()); - } - } - - return 0; -} - -int ModelWriter::estimate_memory_footprint() -{ - if (has_custom_layer) - { - fprintf(stderr, "model has custom layer, estimate_memory_footprint skipped\n"); - return -1; - } - - const size_t layer_count = layers.size(); - const size_t blob_count = blobs.size(); - - MemoryFootprintAllocator allocator; - - ncnn::Extractor ex = create_extractor(); - ex.set_light_mode(true); - - ex.set_blob_allocator(&allocator); - ex.set_workspace_allocator(&allocator); - - // prepare Input blobs - for (size_t i = 0; i < layer_count; i++) - { - const ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - if (layer->type != "Input") - continue; - - ncnn::Input* input = (ncnn::Input*)layer; - - int w = input->w; - int h = input->h; - int c = input->c; - - int dims = 0; - if (w == 0 && h == 0 && c == 0) dims = 0; - if (w != 0 && h == 0 && c == 0) dims = 1; - if (w != 0 && h != 0 && c == 0) dims = 2; - if (w != 0 && h != 0 && c != 0) dims = 3; - - if (dims == 0) - { - fprintf(stderr, "Input layer %s without shape info, estimate_memory_footprint skipped\n", layer->name.c_str()); - return -1; - } - - ncnn::Mat m; - if (dims == 1) m.create(w, 4u, &allocator); - if (dims == 2) m.create(w, h, 4u, &allocator); - if (dims == 3) m.create(w, h, c, 4u, &allocator); - - ex.input(layer->tops[0], m); - - fprintf(stderr, "input = %s\n", blobs[layer->tops[0]].name.c_str()); - } - - // find output blobs and do inference - std::vector outputs; - for (size_t i = 0; i < blob_count; i++) - { - const ncnn::Blob& blob = blobs[i]; - - if (blob.producer == -1 || blob.consumer != -1) - continue; - - if (layers[blob.producer]->type == "ncnnfused") - continue; - - // treat blob without any consumers as output - ncnn::Mat m; - ex.extract(int(i), m); - outputs.push_back(m); - - fprintf(stderr, "extract = %s\n", blob.name.c_str()); - } - - fprintf(stderr, "estimated memory footprint = %.2f KB = %.2f MB\n", allocator.memory_footprint / 1024.f, allocator.memory_footprint / 1024.f / 1024.f); - - return 0; -} - -int ModelWriter::fprintf_param_int_array(int id, const ncnn::Mat& m, FILE* pp) -{ - const int count = m.w; - const int* ptr = m; - - fprintf(pp, " -%d=%d", 23300 + id, count); - for (int i = 0; i < count; i++) - { - fprintf(pp, ",%d", ptr[i]); - } - - return 0; -} - -int ModelWriter::fprintf_param_float_array(int id, const ncnn::Mat& m, FILE* pp) -{ - const int count = m.w; - const float* ptr = m; - - fprintf(pp, " -%d=%d", 23300 + id, count); - for (int i = 0; i < count; i++) - { - fprintf(pp, ",%e", ptr[i]); - } - - return 0; -} - -static inline size_t alignSize(size_t sz, int n) -{ - return (sz + n - 1) & -n; -} - -static void replace_denormals_with_zero(float* data, size_t data_length) -{ - const int total = static_cast(data_length); - for (size_t i = 0; i < data_length; ++i) - { - float value = data[i]; - - if (fabsf(value) < 1e-30 && fabsf(value) != 0.f) - { - data[i] = 0.f; - } - } -} - -static float RandomFloat(float a = -1.2f, float b = 1.2f) -{ - float random = ((float)RAND()) / (float)uint64_t(-1); //RAND_MAX; - float diff = b - a; - float r = random * diff; - return a + r; -} - -static void Randomize(ncnn::Mat& m, float a = -1.2f, float b = 1.2f) -{ - if (m.elemsize == 4) - { - for (size_t i = 0; i < m.total(); i++) - { - m[i] = RandomFloat(a, b); - } - } - else if (m.elemsize == 2) - { - unsigned short* p = m; - for (size_t i = 0; i < m.total(); i++) - { - p[i] = ncnn::float32_to_float16(RandomFloat(a, b)); - } - } - else if (m.elemsize == 1) - { - signed char* p = m; - for (size_t i = 0; i < m.total(); i++) - { - p[i] = (signed char)RandomFloat(-127, 127); - } - } -} - -int ModelWriter::fwrite_weight_tag_data(const ncnn::Mat& data, FILE* bp, float a, float b) -{ - int p0 = ftell(bp); - - ncnn::Mat data_flattened = data.reshape(data.w * data.h * data.c); - if (gen_random_weight) - Randomize(data_flattened, a, b); - - if (data_flattened.elemsize == 4) - { - if (storage_type == 1) - { - const int tag = 0x01306B47; // fp16 magic - fwrite(&tag, sizeof(int), 1, bp); - ncnn::Mat data_flattened_fp16; - ncnn::cast_float32_to_float16(data_flattened, data_flattened_fp16); - fwrite(data_flattened_fp16.data, data_flattened_fp16.elemsize, data_flattened_fp16.w, bp); - } - else - { - const int tag = 0; // fp32 magic - fwrite(&tag, sizeof(int), 1, bp); - replace_denormals_with_zero(data_flattened, data_flattened.w); - fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); - } - } - else if (data_flattened.elemsize == 2) - { - const int tag = 0x01306B47; // fp16 magic - fwrite(&tag, sizeof(int), 1, bp); - fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); - } - else if (data_flattened.elemsize == 1) - { - const int tag = 0x000D4B38; // int8 magic - fwrite(&tag, sizeof(int), 1, bp); - fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); - } - else - { - fprintf(stderr, "unknown weight data type %d\n", (int)data_flattened.elemsize); - } - - // padding to 32bit align - int nwrite = ftell(bp) - p0; - size_t nalign = alignSize(nwrite, 4); - unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00}; - fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp); - - return 0; -} - -int ModelWriter::fwrite_weight_data(const ncnn::Mat& data, FILE* bp, float a, float b) -{ - int p0 = ftell(bp); - - ncnn::Mat data_flattened = data.reshape(data.w * data.h * data.c); - if (gen_random_weight) - Randomize(data_flattened, a, b); - - if (data_flattened.elemsize == 4) // fp32 - { - replace_denormals_with_zero(data_flattened, data_flattened.w); - } - - fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp); - - // padding to 32bit align - int nwrite = ftell(bp) - p0; - size_t nalign = alignSize(nwrite, 4); - unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00}; - fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp); - - return 0; -} - -int ModelWriter::save(const char* parampath, const char* binpath) -{ - uint64_t mac = 0; - - FILE* pp = fopen(parampath, "wb"); - FILE* bp = fopen(binpath, "wb"); - - fprintf(pp, "7767517\n"); - - const size_t layer_count = layers.size(); - - int layer_count_fused = 0; - std::set blob_names; - for (size_t i = 0; i < layer_count; i++) - { - const ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - layer_count_fused++; - - size_t bottom_count = layer->bottoms.size(); - for (size_t j = 0; j < bottom_count; j++) - { - int bottom_blob_index = layer->bottoms[j]; - blob_names.insert(blobs[bottom_blob_index].name); - } - - size_t top_count = layer->tops.size(); - for (size_t j = 0; j < top_count; j++) - { - int top_blob_index = layer->tops[j]; - blob_names.insert(blobs[top_blob_index].name); - } - } - - size_t blob_count_fused = blob_names.size(); - - fprintf(pp, "%d %zd\n", layer_count_fused, blob_count_fused); - - for (size_t i = 0; i < layer_count; i++) - { - const ncnn::Layer* layer = layers[i]; - if (layer->type == "ncnnfused") - continue; - - if (cutstart > 0 && i < cutstart) - continue; - - if (cutend > 0 && i > cutend) - continue; - - size_t bottom_count = layer->bottoms.size(); - size_t top_count = layer->tops.size(); - - fprintf(pp, "%-24s %-24s %zd %zd", layer->type.c_str(), layer->name.c_str(), bottom_count, top_count); - - for (size_t j = 0; j < bottom_count; j++) - { - int bottom_blob_index = layer->bottoms[j]; - fprintf(pp, " %s", blobs[bottom_blob_index].name.c_str()); - } - for (size_t j = 0; j < top_count; j++) - { - int top_blob_index = layer->tops[j]; - fprintf(pp, " %s", blobs[top_blob_index].name.c_str()); - } - - // write shape hints - bool shape_ready = true; - for (size_t j = 0; j < top_count; j++) - { - int top_blob_index = layer->tops[j]; - - int dims = blobs[top_blob_index].shape.dims; - if (dims == 0) - { - shape_ready = false; - break; - } - } - if (shape_ready) - { - fprintf(pp, " -23330=%zd", top_count * 4); - for (size_t j = 0; j < top_count; j++) - { - int top_blob_index = layer->tops[j]; - - int dims = blobs[top_blob_index].shape.dims; - int w = blobs[top_blob_index].shape.w; - int h = blobs[top_blob_index].shape.h; - int c = blobs[top_blob_index].shape.c; - - fprintf(pp, ",%d,%d,%d,%d", dims, w, h, c); - } - } - - // custom op - if (layer->typeindex & ncnn::LayerType::CustomBit) - { - ((CustomLayer*)layer)->write_param(pp); - - fprintf(pp, "\n"); - - continue; - } - - ncnn::Layer* layer_default = ncnn::create_layer(layer->typeindex); - - ncnn::ParamDict pd; - layer_default->load_param(pd); - -#define fprintf_param_value(format, phase) \ - { \ - if (op->phase != op_default->phase) fprintf(pp, format, op->phase); \ - } - - if (layer->type == "BatchNorm") - { - ncnn::BatchNorm* op = (ncnn::BatchNorm*)layer; - ncnn::BatchNorm* op_default = (ncnn::BatchNorm*)layer_default; - - fprintf_param_value(" 0=%d", channels) - fprintf_param_value(" 1=%e", eps) - - fwrite_weight_data(op->slope_data, bp); - fwrite_weight_data(op->mean_data, bp); - fwrite_weight_data(op->var_data, bp); - fwrite_weight_data(op->bias_data, bp); - } - else if (layer->type == "Bias") - { - ncnn::Bias* op = (ncnn::Bias*)layer; - ncnn::Bias* op_default = (ncnn::Bias*)layer_default; - - fprintf_param_value(" 0=%d", bias_data_size) - - fwrite_weight_data(op->bias_data, bp); - } - else if (layer->type == "BinaryOp") - { - ncnn::BinaryOp* op = (ncnn::BinaryOp*)layer; - ncnn::BinaryOp* op_default = (ncnn::BinaryOp*)layer_default; - - fprintf_param_value(" 0=%d", op_type) - fprintf_param_value(" 1=%d", with_scalar) - fprintf_param_value(" 2=%e", b) - } - else if (layer->type == "Clip") - { - ncnn::Clip* op = (ncnn::Clip*)layer; - ncnn::Clip* op_default = (ncnn::Clip*)layer_default; - - fprintf_param_value(" 0=%e", min) - fprintf_param_value(" 1=%e", max) - } - else if (layer->type == "Concat") - { - ncnn::Concat* op = (ncnn::Concat*)layer; - ncnn::Concat* op_default = (ncnn::Concat*)layer_default; - - fprintf_param_value(" 0=%d", axis) - } - else if (layer->type == "Convolution") - { - ncnn::Convolution* op = (ncnn::Convolution*)layer; - ncnn::Convolution* op_default = (ncnn::Convolution*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 8=%d", int8_scale_term) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - -#if NCNN_INT8 - // write int8_scale data - if (op->int8_scale_term) - { - fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); - fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); - fwrite_weight_data(op->top_blob_int8_scales, bp, 0.001, 1); - } -#endif // NCNN_INT8 - - if (shape_ready) - { - int inc = blobs[layer->bottoms[0]].shape.c; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_h * op->kernel_w * outw * outh * outc * inc; - } - } - else if (layer->type == "Convolution1D") - { - ncnn::Convolution1D* op = (ncnn::Convolution1D*)layer; - ncnn::Convolution1D* op_default = (ncnn::Convolution1D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - fprintf_param_value(" 2=%d", dilation_w) - fprintf_param_value(" 3=%d", stride_w) - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inh = blobs[layer->bottoms[0]].shape.h; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - - mac += (uint64_t)op->kernel_w * outw * outh * inh; - } - } - else if (layer->type == "Convolution3D") - { - ncnn::Convolution3D* op = (ncnn::Convolution3D*)layer; - ncnn::Convolution3D* op_default = (ncnn::Convolution3D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - { - if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inc = blobs[layer->bottoms[0]].shape.c; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - int outd = blobs[layer->tops[0]].shape.d; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * outw * outh * outd * outc * inc; - } - } - else if (layer->type == "ConvolutionDepthWise") - { - ncnn::ConvolutionDepthWise* op = (ncnn::ConvolutionDepthWise*)layer; - ncnn::ConvolutionDepthWise* op_default = (ncnn::ConvolutionDepthWise*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 8=%d", int8_scale_term) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - -#if NCNN_INT8 - // write int8_scale data - if (op->int8_scale_term == 1 || op->int8_scale_term == 101) - { - op->bottom_blob_int8_scales.w = 1; - } - if (op->int8_scale_term == 2 || op->int8_scale_term == 102) - { - op->weight_data_int8_scales.w = 1; - op->bottom_blob_int8_scales.w = 1; - } - if (op->int8_scale_term > 100) - { - op->top_blob_int8_scales.w = 1; - } - - if (op->int8_scale_term) - { - fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); - fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); - fwrite_weight_data(op->top_blob_int8_scales, bp, 0.001, 1); - } -#endif // NCNN_INT8 - - if (shape_ready) - { - int inc = blobs[layer->bottoms[0]].shape.c; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_h * op->kernel_w * outw * outh * (outc / op->group) * (inc / op->group) * op->group; - } - } - else if (layer->type == "ConvolutionDepthWise1D") - { - ncnn::ConvolutionDepthWise1D* op = (ncnn::ConvolutionDepthWise1D*)layer; - ncnn::ConvolutionDepthWise1D* op_default = (ncnn::ConvolutionDepthWise1D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - fprintf_param_value(" 2=%d", dilation_w) - fprintf_param_value(" 3=%d", stride_w) - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inh = blobs[layer->bottoms[0]].shape.h; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - - mac += (uint64_t)op->kernel_w * outw * (outh / op->group) * (inh / op->group) * op->group; - } - } - else if (layer->type == "ConvolutionDepthWise3D") - { - ncnn::ConvolutionDepthWise3D* op = (ncnn::ConvolutionDepthWise3D*)layer; - ncnn::ConvolutionDepthWise3D* op_default = (ncnn::ConvolutionDepthWise3D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - { - if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); - } - fprintf_param_value(" 18=%e", pad_value) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inc = blobs[layer->bottoms[0]].shape.c; - int outw = blobs[layer->tops[0]].shape.w; - int outh = blobs[layer->tops[0]].shape.h; - int outd = blobs[layer->tops[0]].shape.d; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * outw * outh * outd * (outc / op->group) * (inc / op->group) * op->group; - } - } - else if (layer->type == "Crop") - { - ncnn::Crop* op = (ncnn::Crop*)layer; - ncnn::Crop* op_default = (ncnn::Crop*)layer_default; - - fprintf_param_value(" 0=%d", woffset) - fprintf_param_value(" 1=%d", hoffset) - fprintf_param_value(" 2=%d", coffset) - fprintf_param_value(" 3=%d", outw) - fprintf_param_value(" 4=%d", outh) - fprintf_param_value(" 5=%d", outc) - fprintf_param_value(" 6=%d", woffset2) - fprintf_param_value(" 7=%d", hoffset2) - fprintf_param_value(" 8=%d", coffset2) - { - if (!op->starts.empty()) fprintf_param_int_array(9, op->starts, pp); - } - { - if (!op->ends.empty()) fprintf_param_int_array(10, op->ends, pp); - } - { - if (!op->axes.empty()) fprintf_param_int_array(11, op->axes, pp); - } - } - else if (layer->type == "Deconvolution") - { - ncnn::Deconvolution* op = (ncnn::Deconvolution*)layer; - ncnn::Deconvolution* op_default = (ncnn::Deconvolution*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - fprintf_param_value(" 18=%d", output_pad_right) - { - if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); - } - fprintf_param_value(" 20=%d", output_w) - { - if (op->output_h != op->output_w) fprintf(pp, " 21=%d", op->output_h); - } - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int inc = blobs[layer->bottoms[0]].shape.c; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_h * op->kernel_w * inw * inh * outc * inc; - } - } - else if (layer->type == "Deconvolution1D") - { - ncnn::Deconvolution1D* op = (ncnn::Deconvolution1D*)layer; - ncnn::Deconvolution1D* op_default = (ncnn::Deconvolution1D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - fprintf_param_value(" 2=%d", dilation_w) - fprintf_param_value(" 3=%d", stride_w) - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - fprintf_param_value(" 18=%d", output_pad_right) - fprintf_param_value(" 20=%d", output_w) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int outh = blobs[layer->tops[0]].shape.h; - - mac += (uint64_t)op->kernel_w * inw * outh * inh; - } - } - else if (layer->type == "Deconvolution3D") - { - ncnn::Deconvolution3D* op = (ncnn::Deconvolution3D*)layer; - ncnn::Deconvolution3D* op_default = (ncnn::Deconvolution3D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - { - if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); - } - fprintf_param_value(" 18=%d", output_pad_right) - { - if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); - if (op->output_pad_behind != op->output_pad_right) fprintf(pp, " 20=%d", op->output_pad_behind); - } - fprintf_param_value(" 25=%d", output_w) - { - if (op->output_h != op->output_w) fprintf(pp, " 26=%d", op->output_h); - if (op->output_d != op->output_w) fprintf(pp, " 27=%d", op->output_d); - } - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int ind = blobs[layer->bottoms[0]].shape.d; - int inc = blobs[layer->bottoms[0]].shape.c; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * inw * inh * ind * outc * inc; - } - } - else if (layer->type == "DeconvolutionDepthWise") - { - ncnn::DeconvolutionDepthWise* op = (ncnn::DeconvolutionDepthWise*)layer; - ncnn::DeconvolutionDepthWise* op_default = (ncnn::DeconvolutionDepthWise*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - fprintf_param_value(" 18=%d", output_pad_right) - { - if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); - } - fprintf_param_value(" 20=%d", output_w) - { - if (op->output_h != op->output_w) fprintf(pp, " 21=%d", op->output_h); - } - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int inc = blobs[layer->bottoms[0]].shape.c; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_h * op->kernel_w * inw * inh * (outc / op->group) * (inc / op->group) * op->group; - } - } - else if (layer->type == "DeconvolutionDepthWise1D") - { - ncnn::DeconvolutionDepthWise1D* op = (ncnn::DeconvolutionDepthWise1D*)layer; - ncnn::DeconvolutionDepthWise1D* op_default = (ncnn::DeconvolutionDepthWise1D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - fprintf_param_value(" 2=%d", dilation_w) - fprintf_param_value(" 3=%d", stride_w) - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - fprintf_param_value(" 18=%d", output_pad_right) - fprintf_param_value(" 20=%d", output_w) - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int outh = blobs[layer->tops[0]].shape.h; - - mac += (uint64_t)op->kernel_w * inw * (outh / op->group) * (inh / op->group) * op->group; - } - } - else if (layer->type == "DeconvolutionDepthWise3D") - { - ncnn::DeconvolutionDepthWise3D* op = (ncnn::DeconvolutionDepthWise3D*)layer; - ncnn::DeconvolutionDepthWise3D* op_default = (ncnn::DeconvolutionDepthWise3D*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); - } - fprintf_param_value(" 2=%d", dilation_w) - { - if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); - if (op->dilation_d != op->dilation_w) fprintf(pp, " 22=%d", op->dilation_d); - } - fprintf_param_value(" 3=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); - if (op->stride_d != op->stride_w) fprintf(pp, " 23=%d", op->stride_d); - } - fprintf_param_value(" 4=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 14=%d", op->pad_top); - if (op->pad_front != op->pad_left) fprintf(pp, " 24=%d", op->pad_front); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 15=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 16=%d", op->pad_bottom); - } - { - if (op->pad_behind != op->pad_front) fprintf(pp, " 17=%d", op->pad_behind); - } - fprintf_param_value(" 18=%d", output_pad_right) - { - if (op->output_pad_bottom != op->output_pad_right) fprintf(pp, " 19=%d", op->output_pad_bottom); - if (op->output_pad_behind != op->output_pad_right) fprintf(pp, " 20=%d", op->output_pad_behind); - } - fprintf_param_value(" 25=%d", output_w) - { - if (op->output_h != op->output_w) fprintf(pp, " 26=%d", op->output_h); - if (op->output_d != op->output_w) fprintf(pp, " 27=%d", op->output_d); - } - fprintf_param_value(" 5=%d", bias_term) - fprintf_param_value(" 6=%d", weight_data_size) - fprintf_param_value(" 7=%d", group) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int ind = blobs[layer->bottoms[0]].shape.d; - int inc = blobs[layer->bottoms[0]].shape.c; - int outc = blobs[layer->tops[0]].shape.c; - - mac += (uint64_t)op->kernel_d * op->kernel_h * op->kernel_w * inw * inh * ind * (outc / op->group) * (inc / op->group) * op->group; - } - } - else if (layer->type == "DetectionOutput") - { - ncnn::DetectionOutput* op = (ncnn::DetectionOutput*)layer; - ncnn::DetectionOutput* op_default = (ncnn::DetectionOutput*)layer_default; - - fprintf_param_value(" 0=%d", num_class) - fprintf_param_value(" 1=%e", nms_threshold) - fprintf_param_value(" 2=%d", nms_top_k) - fprintf_param_value(" 3=%d", keep_top_k) - fprintf_param_value(" 4=%e", confidence_threshold) - fprintf_param_value(" 5=%e", variances[0]) - fprintf_param_value(" 6=%e", variances[1]) - fprintf_param_value(" 7=%e", variances[2]) - fprintf_param_value(" 8=%e", variances[3]) - } - else if (layer->type == "Dropout") - { - ncnn::Dropout* op = (ncnn::Dropout*)layer; - ncnn::Dropout* op_default = (ncnn::Dropout*)layer_default; - - fprintf_param_value(" 0=%e", scale) - } - else if (layer->type == "Eltwise") - { - ncnn::Eltwise* op = (ncnn::Eltwise*)layer; - ncnn::Eltwise* op_default = (ncnn::Eltwise*)layer_default; - - fprintf_param_value(" 0=%d", op_type) - { - if (!op->coeffs.empty()) fprintf_param_float_array(1, op->coeffs, pp); - } - } - else if (layer->type == "ELU") - { - ncnn::ELU* op = (ncnn::ELU*)layer; - ncnn::ELU* op_default = (ncnn::ELU*)layer_default; - - fprintf_param_value(" 0=%e", alpha) - } - else if (layer->type == "Embed") - { - ncnn::Embed* op = (ncnn::Embed*)layer; - ncnn::Embed* op_default = (ncnn::Embed*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", input_dim) - fprintf_param_value(" 2=%d", bias_term) - fprintf_param_value(" 3=%d", weight_data_size) - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - } - else if (layer->type == "Exp") - { - ncnn::Exp* op = (ncnn::Exp*)layer; - ncnn::Exp* op_default = (ncnn::Exp*)layer_default; - - fprintf_param_value(" 0=%e", base) - fprintf_param_value(" 1=%e", scale) - fprintf_param_value(" 2=%e", shift) - } - else if (layer->type == "ExpandDims") - { - ncnn::ExpandDims* op = (ncnn::ExpandDims*)layer; - ncnn::ExpandDims* op_default = (ncnn::ExpandDims*)layer_default; - - fprintf_param_value(" 0=%d", expand_w) - fprintf_param_value(" 1=%d", expand_h) - fprintf_param_value(" 2=%d", expand_c) - { - if (!op->axes.empty()) fprintf_param_int_array(0, op->axes, pp); - } - } - else if (layer->type == "GELU") - { - ncnn::GELU* op = (ncnn::GELU*)layer; - ncnn::GELU* op_default = (ncnn::GELU*)layer_default; - - fprintf_param_value(" 0=%d", fast_gelu) - } - else if (layer->type == "Gemm") - { - ncnn::Gemm* op = (ncnn::Gemm*)layer; - ncnn::Gemm* op_default = (ncnn::Gemm*)layer_default; - - fprintf_param_value(" 0=%e", alpha) - fprintf_param_value(" 1=%e", beta) - fprintf_param_value(" 2=%d", transA) - fprintf_param_value(" 3=%d", transB) - } - else if (layer->type == "GroupNorm") - { - ncnn::GroupNorm* op = (ncnn::GroupNorm*)layer; - ncnn::GroupNorm* op_default = (ncnn::GroupNorm*)layer_default; - - fprintf_param_value(" 0=%d", group) - fprintf_param_value(" 1=%d", channels) - fprintf_param_value(" 2=%e", eps) - fprintf_param_value(" 3=%d", affine) - - fwrite_weight_data(op->gamma_data, bp); - fwrite_weight_data(op->beta_data, bp); - } - else if (layer->type == "GRU") - { - ncnn::GRU* op = (ncnn::GRU*)layer; - ncnn::GRU* op_default = (ncnn::GRU*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", weight_data_size) - fprintf_param_value(" 2=%d", direction) - - fwrite_weight_tag_data(op->weight_xc_data, bp); - fwrite_weight_tag_data(op->bias_c_data, bp); - fwrite_weight_tag_data(op->weight_hc_data, bp); - } - else if (layer->type == "HardSigmoid") - { - ncnn::HardSigmoid* op = (ncnn::HardSigmoid*)layer; - ncnn::HardSigmoid* op_default = (ncnn::HardSigmoid*)layer_default; - - fprintf_param_value(" 0=%e", alpha) - fprintf_param_value(" 1=%e", beta) - } - else if (layer->type == "HardSwish") - { - ncnn::HardSwish* op = (ncnn::HardSwish*)layer; - ncnn::HardSwish* op_default = (ncnn::HardSwish*)layer_default; - - fprintf_param_value(" 0=%e", alpha) - fprintf_param_value(" 1=%e", beta) - } - else if (layer->type == "InnerProduct") - { - ncnn::InnerProduct* op = (ncnn::InnerProduct*)layer; - ncnn::InnerProduct* op_default = (ncnn::InnerProduct*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", bias_term) - fprintf_param_value(" 2=%d", weight_data_size) - fprintf_param_value(" 8=%d", int8_scale_term) - fprintf_param_value(" 9=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(10, op->activation_params, pp); - } - - fwrite_weight_tag_data(op->weight_data, bp); - fwrite_weight_data(op->bias_data, bp); - -#if NCNN_INT8 - // write int8_scale data - if (op->int8_scale_term) - { - fwrite_weight_data(op->weight_data_int8_scales, bp, 90, 100); - fwrite_weight_data(op->bottom_blob_int8_scales, bp, 0.001, 1); - } -#endif // NCNN_INT8 - - if (shape_ready) - { - int inw = blobs[layer->bottoms[0]].shape.w; - int inh = blobs[layer->bottoms[0]].shape.h; - int inc = blobs[layer->bottoms[0]].shape.c; - int outw = blobs[layer->tops[0]].shape.w; - - mac += (uint64_t)inw * inh * inc * outw; - } - } - else if (layer->type == "Input") - { - ncnn::Input* op = (ncnn::Input*)layer; - ncnn::Input* op_default = (ncnn::Input*)layer_default; - - fprintf_param_value(" 0=%d", w) - fprintf_param_value(" 1=%d", h) - fprintf_param_value(" 2=%d", c) - } - else if (layer->type == "InstanceNorm") - { - ncnn::InstanceNorm* op = (ncnn::InstanceNorm*)layer; - ncnn::InstanceNorm* op_default = (ncnn::InstanceNorm*)layer_default; - - fprintf_param_value(" 0=%d", channels) - fprintf_param_value(" 1=%e", eps) - fprintf_param_value(" 2=%d", affine) - - fwrite_weight_data(op->gamma_data, bp); - fwrite_weight_data(op->beta_data, bp); - } - else if (layer->type == "Interp") - { - ncnn::Interp* op = (ncnn::Interp*)layer; - ncnn::Interp* op_default = (ncnn::Interp*)layer_default; - - fprintf_param_value(" 0=%d", resize_type) - fprintf_param_value(" 1=%e", height_scale) - fprintf_param_value(" 2=%e", width_scale) - fprintf_param_value(" 3=%d", output_height) - fprintf_param_value(" 4=%d", output_width) - fprintf_param_value(" 5=%d", dynamic_target_size) - fprintf_param_value(" 6=%d", align_corner) - } - else if (layer->type == "LayerNorm") - { - ncnn::LayerNorm* op = (ncnn::LayerNorm*)layer; - ncnn::LayerNorm* op_default = (ncnn::LayerNorm*)layer_default; - - fprintf_param_value(" 0=%d", affine_size) - fprintf_param_value(" 1=%e", eps) - fprintf_param_value(" 2=%d", affine) - - fwrite_weight_data(op->gamma_data, bp); - fwrite_weight_data(op->beta_data, bp); - } - else if (layer->type == "Log") - { - ncnn::Log* op = (ncnn::Log*)layer; - ncnn::Log* op_default = (ncnn::Log*)layer_default; - - fprintf_param_value(" 0=%e", base) - fprintf_param_value(" 1=%e", scale) - fprintf_param_value(" 2=%e", shift) - } - else if (layer->type == "LRN") - { - ncnn::LRN* op = (ncnn::LRN*)layer; - ncnn::LRN* op_default = (ncnn::LRN*)layer_default; - - fprintf_param_value(" 0=%d", region_type) - fprintf_param_value(" 1=%d", local_size) - fprintf_param_value(" 2=%e", alpha) - fprintf_param_value(" 3=%e", beta) - fprintf_param_value(" 4=%e", bias) - } - else if (layer->type == "LSTM") - { - ncnn::LSTM* op = (ncnn::LSTM*)layer; - ncnn::LSTM* op_default = (ncnn::LSTM*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", weight_data_size) - fprintf_param_value(" 2=%d", direction) - - fwrite_weight_tag_data(op->weight_xc_data, bp); - fwrite_weight_tag_data(op->bias_c_data, bp); - fwrite_weight_tag_data(op->weight_hc_data, bp); - } - else if (layer->type == "MatMul") - { - ncnn::MatMul* op = (ncnn::MatMul*)layer; - ncnn::MatMul* op_default = (ncnn::MatMul*)layer_default; - - fprintf_param_value(" 0=%d", transB) - } - else if (layer->type == "MemoryData") - { - ncnn::MemoryData* op = (ncnn::MemoryData*)layer; - ncnn::MemoryData* op_default = (ncnn::MemoryData*)layer_default; - - fprintf_param_value(" 0=%d", w) - fprintf_param_value(" 1=%d", h) - fprintf_param_value(" 2=%d", c) - fwrite_weight_data(op->data, bp); - } - else if (layer->type == "MultiHeadAttention") - { - ncnn::MultiHeadAttention* op = (ncnn::MultiHeadAttention*)layer; - ncnn::MultiHeadAttention* op_default = (ncnn::MultiHeadAttention*)layer_default; - - fprintf_param_value(" 0=%d", embed_dim) - fprintf_param_value(" 1=%d", num_head) - fprintf_param_value(" 2=%d", weight_data_size) - - fwrite_weight_tag_data(op->q_weight_data, bp); - fwrite_weight_data(op->q_bias_data, bp); - fwrite_weight_tag_data(op->k_weight_data, bp); - fwrite_weight_data(op->k_bias_data, bp); - fwrite_weight_tag_data(op->v_weight_data, bp); - fwrite_weight_data(op->v_bias_data, bp); - fwrite_weight_tag_data(op->out_weight_data, bp); - fwrite_weight_data(op->out_bias_data, bp); - } - else if (layer->type == "MVN") - { - ncnn::MVN* op = (ncnn::MVN*)layer; - ncnn::MVN* op_default = (ncnn::MVN*)layer_default; - - fprintf_param_value(" 0=%d", normalize_variance) - fprintf_param_value(" 1=%d", across_channels) - fprintf_param_value(" 2=%e", eps) - } - else if (layer->type == "Normalize") - { - ncnn::Normalize* op = (ncnn::Normalize*)layer; - ncnn::Normalize* op_default = (ncnn::Normalize*)layer_default; - - fprintf_param_value(" 0=%d", across_spatial) - fprintf_param_value(" 1=%d", channel_shared) - fprintf_param_value(" 2=%e", eps) - fprintf_param_value(" 3=%d", scale_data_size) - fprintf_param_value(" 4=%d", across_channel) - fprintf_param_value(" 9=%d", eps_mode) - - fwrite_weight_data(op->scale_data, bp); - } - else if (layer->type == "Padding") - { - ncnn::Padding* op = (ncnn::Padding*)layer; - ncnn::Padding* op_default = (ncnn::Padding*)layer_default; - - fprintf_param_value(" 0=%d", top) - fprintf_param_value(" 1=%d", bottom) - fprintf_param_value(" 2=%d", left) - fprintf_param_value(" 3=%d", right) - fprintf_param_value(" 4=%d", type) - fprintf_param_value(" 5=%e", value) - fprintf_param_value(" 6=%d", per_channel_pad_data_size) - fprintf_param_value(" 7=%d", front) - fprintf_param_value(" 8=%d", behind) - - fwrite_weight_data(op->per_channel_pad_data, bp); - } - else if (layer->type == "Permute") - { - ncnn::Permute* op = (ncnn::Permute*)layer; - ncnn::Permute* op_default = (ncnn::Permute*)layer_default; - - fprintf_param_value(" 0=%d", order_type) - } - else if (layer->type == "PixelShuffle") - { - ncnn::PixelShuffle* op = (ncnn::PixelShuffle*)layer; - ncnn::PixelShuffle* op_default = (ncnn::PixelShuffle*)layer_default; - - fprintf_param_value(" 0=%d", upscale_factor) - fprintf_param_value(" 1=%d", mode) - } - else if (layer->type == "Pooling") - { - ncnn::Pooling* op = (ncnn::Pooling*)layer; - ncnn::Pooling* op_default = (ncnn::Pooling*)layer_default; - - fprintf_param_value(" 0=%d", pooling_type) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - } - fprintf_param_value(" 2=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 12=%d", op->stride_h); - } - fprintf_param_value(" 3=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 13=%d", op->pad_top); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 15=%d", op->pad_bottom); - } - fprintf_param_value(" 4=%d", global_pooling) - fprintf_param_value(" 5=%d", pad_mode) - fprintf_param_value(" 6=%d", avgpool_count_include_pad) - fprintf_param_value(" 7=%d", adaptive_pooling) - fprintf_param_value(" 8=%d", out_w) - { - if (op->out_h != op->out_w) fprintf(pp, " 18=%d", op->out_h); - } - } - else if (layer->type == "Pooling1D") - { - ncnn::Pooling1D* op = (ncnn::Pooling1D*)layer; - ncnn::Pooling1D* op_default = (ncnn::Pooling1D*)layer_default; - - fprintf_param_value(" 0=%d", pooling_type) - fprintf_param_value(" 1=%d", kernel_w) - fprintf_param_value(" 2=%d", stride_w) - fprintf_param_value(" 3=%d", pad_left) - { - if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); - } - fprintf_param_value(" 4=%d", global_pooling) - fprintf_param_value(" 5=%d", pad_mode) - fprintf_param_value(" 6=%d", avgpool_count_include_pad) - fprintf_param_value(" 7=%d", adaptive_pooling) - fprintf_param_value(" 8=%d", out_w) - } - else if (layer->type == "Pooling3D") - { - ncnn::Pooling3D* op = (ncnn::Pooling3D*)layer; - ncnn::Pooling3D* op_default = (ncnn::Pooling3D*)layer_default; - - fprintf_param_value(" 0=%d", pooling_type) - fprintf_param_value(" 1=%d", kernel_w) - { - if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); - if (op->kernel_d != op->kernel_w) fprintf(pp, " 21=%d", op->kernel_d); - } - fprintf_param_value(" 2=%d", stride_w) - { - if (op->stride_h != op->stride_w) fprintf(pp, " 12=%d", op->stride_h); - if (op->stride_d != op->stride_w) fprintf(pp, " 22=%d", op->stride_d); - } - fprintf_param_value(" 3=%d", pad_left) - { - if (op->pad_top != op->pad_left) fprintf(pp, " 13=%d", op->pad_top); - if (op->pad_front != op->pad_left) fprintf(pp, " 23=%d", op->pad_front); - } - { - if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); - } - { - if (op->pad_bottom != op->pad_top) fprintf(pp, " 15=%d", op->pad_bottom); - } - { - if (op->pad_behind != op->pad_front) fprintf(pp, " 16=%d", op->pad_behind); - } - fprintf_param_value(" 4=%d", global_pooling) - fprintf_param_value(" 5=%d", pad_mode) - fprintf_param_value(" 6=%d", avgpool_count_include_pad) - fprintf_param_value(" 7=%d", adaptive_pooling) - fprintf_param_value(" 8=%d", out_w) - { - if (op->out_h != op->out_w) fprintf(pp, " 18=%d", op->out_h); - if (op->out_d != op->out_w) fprintf(pp, " 28=%d", op->out_d); - } - } - else if (layer->type == "Power") - { - ncnn::Power* op = (ncnn::Power*)layer; - ncnn::Power* op_default = (ncnn::Power*)layer_default; - - fprintf_param_value(" 0=%e", power) - fprintf_param_value(" 1=%e", scale) - fprintf_param_value(" 2=%e", shift) - } - else if (layer->type == "PReLU") - { - ncnn::PReLU* op = (ncnn::PReLU*)layer; - ncnn::PReLU* op_default = (ncnn::PReLU*)layer_default; - - fprintf_param_value(" 0=%d", num_slope) - - fwrite_weight_data(op->slope_data, bp); - } - else if (layer->type == "PriorBox") - { - ncnn::PriorBox* op = (ncnn::PriorBox*)layer; - ncnn::PriorBox* op_default = (ncnn::PriorBox*)layer_default; - - { - if (!op->min_sizes.empty()) fprintf_param_float_array(0, op->min_sizes, pp); - } - { - if (!op->max_sizes.empty()) fprintf_param_float_array(1, op->max_sizes, pp); - } - { - if (!op->aspect_ratios.empty()) fprintf_param_float_array(2, op->aspect_ratios, pp); - } - fprintf_param_value(" 3=%e", variances[0]) - fprintf_param_value(" 4=%e", variances[1]) - fprintf_param_value(" 5=%e", variances[2]) - fprintf_param_value(" 6=%e", variances[3]) - fprintf_param_value(" 7=%d", flip) - fprintf_param_value(" 8=%d", clip) - fprintf_param_value(" 9=%d", image_width) - fprintf_param_value(" 10=%d", image_height) - fprintf_param_value(" 11=%e", step_width) - fprintf_param_value(" 12=%e", step_height) - fprintf_param_value(" 13=%e", offset) - } - else if (layer->type == "Proposal") - { - ncnn::Proposal* op = (ncnn::Proposal*)layer; - ncnn::Proposal* op_default = (ncnn::Proposal*)layer_default; - - fprintf_param_value(" 0=%d", feat_stride) - fprintf_param_value(" 1=%d", base_size) - fprintf_param_value(" 2=%d", pre_nms_topN) - fprintf_param_value(" 3=%d", after_nms_topN) - fprintf_param_value(" 4=%e", nms_thresh) - fprintf_param_value(" 5=%d", min_size) - } - else if (layer->type == "PSROIPooling") - { - ncnn::PSROIPooling* op = (ncnn::PSROIPooling*)layer; - ncnn::PSROIPooling* op_default = (ncnn::PSROIPooling*)layer_default; - - fprintf_param_value(" 0=%d", pooled_width) - fprintf_param_value(" 1=%d", pooled_height) - fprintf_param_value(" 2=%e", spatial_scale) - fprintf_param_value(" 3=%d", output_dim) - } - else if (layer->type == "Quantize") - { - ncnn::Quantize* op = (ncnn::Quantize*)layer; - ncnn::Quantize* op_default = (ncnn::Quantize*)layer_default; - - fprintf_param_value(" 0=%d", scale_data_size) - - fwrite_weight_data(op->scale_data, bp); - } - else if (layer->type == "Reduction") - { - ncnn::Reduction* op = (ncnn::Reduction*)layer; - ncnn::Reduction* op_default = (ncnn::Reduction*)layer_default; - - fprintf_param_value(" 0=%d", operation) - fprintf_param_value(" 1=%d", reduce_all) - fprintf_param_value(" 2=%e", coeff) - { - if (!op->axes.empty()) fprintf_param_int_array(3, op->axes, pp); - } - fprintf_param_value(" 4=%d", keepdims) - - // HACK - if (!op->axes.empty()) - { - int fixbug0 = 1; - fprintf(pp, " 5=%d", fixbug0); - } - } - else if (layer->type == "ReLU") - { - ncnn::ReLU* op = (ncnn::ReLU*)layer; - ncnn::ReLU* op_default = (ncnn::ReLU*)layer_default; - - fprintf_param_value(" 0=%e", slope) - } - else if (layer->type == "Reorg") - { - ncnn::Reorg* op = (ncnn::Reorg*)layer; - ncnn::Reorg* op_default = (ncnn::Reorg*)layer_default; - - fprintf_param_value(" 0=%d", stride) - fprintf_param_value(" 1=%d", mode) - } - else if (layer->type == "Requantize") - { - ncnn::Requantize* op = (ncnn::Requantize*)layer; - ncnn::Requantize* op_default = (ncnn::Requantize*)layer_default; - - fprintf_param_value(" 0=%d", scale_in_data_size) - fprintf_param_value(" 1=%d", scale_out_data_size) - fprintf_param_value(" 2=%d", bias_data_size) - fprintf_param_value(" 3=%d", activation_type) - { - if (!op->activation_params.empty()) fprintf_param_float_array(4, op->activation_params, pp); - } - - fwrite_weight_data(op->scale_in_data, bp); - fwrite_weight_data(op->scale_out_data, bp); - fwrite_weight_data(op->bias_data, bp); - } - else if (layer->type == "Reshape") - { - ncnn::Reshape* op = (ncnn::Reshape*)layer; - ncnn::Reshape* op_default = (ncnn::Reshape*)layer_default; - - fprintf_param_value(" 0=%d", w) - fprintf_param_value(" 1=%d", h) - fprintf_param_value(" 2=%d", c) - fprintf_param_value(" 3=%d", permute) - } - else if (layer->type == "RNN") - { - ncnn::RNN* op = (ncnn::RNN*)layer; - ncnn::RNN* op_default = (ncnn::RNN*)layer_default; - - fprintf_param_value(" 0=%d", num_output) - fprintf_param_value(" 1=%d", weight_data_size) - fprintf_param_value(" 2=%d", direction) - - fwrite_weight_tag_data(op->weight_xc_data, bp); - fwrite_weight_tag_data(op->bias_c_data, bp); - fwrite_weight_tag_data(op->weight_hc_data, bp); - } - else if (layer->type == "ROIAlign") - { - ncnn::ROIAlign* op = (ncnn::ROIAlign*)layer; - ncnn::ROIAlign* op_default = (ncnn::ROIAlign*)layer_default; - - fprintf_param_value(" 0=%d", pooled_width) - fprintf_param_value(" 1=%d", pooled_height) - fprintf_param_value(" 2=%e", spatial_scale) - fprintf_param_value(" 3=%d", sampling_ratio) - fprintf_param_value(" 4=%d", aligned) - fprintf_param_value(" 5=%d", version) - } - else if (layer->type == "ROIPooling") - { - ncnn::ROIPooling* op = (ncnn::ROIPooling*)layer; - ncnn::ROIPooling* op_default = (ncnn::ROIPooling*)layer_default; - - fprintf_param_value(" 0=%d", pooled_width) - fprintf_param_value(" 1=%d", pooled_height) - fprintf_param_value(" 2=%e", spatial_scale) - } - else if (layer->type == "Scale") - { - ncnn::Scale* op = (ncnn::Scale*)layer; - ncnn::Scale* op_default = (ncnn::Scale*)layer_default; - - fprintf_param_value(" 0=%d", scale_data_size) - fprintf_param_value(" 1=%d", bias_term) - - fwrite_weight_data(op->scale_data, bp); - fwrite_weight_data(op->bias_data, bp); - } - else if (layer->type == "ShuffleChannel") - { - ncnn::ShuffleChannel* op = (ncnn::ShuffleChannel*)layer; - ncnn::ShuffleChannel* op_default = (ncnn::ShuffleChannel*)layer_default; - - fprintf_param_value(" 0=%d", group) - fprintf_param_value(" 1=%d", reverse) - } - else if (layer->type == "Slice") - { - ncnn::Slice* op = (ncnn::Slice*)layer; - ncnn::Slice* op_default = (ncnn::Slice*)layer_default; - - { - if (!op->slices.empty()) fprintf_param_int_array(0, op->slices, pp); - } - fprintf_param_value(" 1=%d", axis) - } - else if (layer->type == "Softmax") - { - ncnn::Softmax* op = (ncnn::Softmax*)layer; - ncnn::Softmax* op_default = (ncnn::Softmax*)layer_default; - - fprintf_param_value(" 0=%d", axis) - - // HACK - if (op->axis != 0) - { - int fixbug0 = 1; - fprintf(pp, " 1=%d", fixbug0); - } - } - else if (layer->type == "Squeeze") - { - ncnn::Squeeze* op = (ncnn::Squeeze*)layer; - ncnn::Squeeze* op_default = (ncnn::Squeeze*)layer_default; - - fprintf_param_value(" 0=%d", squeeze_w) - fprintf_param_value(" 1=%d", squeeze_h) - fprintf_param_value(" 2=%d", squeeze_c) - { - if (!op->axes.empty()) fprintf_param_int_array(0, op->axes, pp); - } - } - else if (layer->type == "Threshold") - { - ncnn::Threshold* op = (ncnn::Threshold*)layer; - ncnn::Threshold* op_default = (ncnn::Threshold*)layer_default; - - fprintf_param_value(" 0=%e", threshold) - } - else if (layer->type == "UnaryOp") - { - ncnn::UnaryOp* op = (ncnn::UnaryOp*)layer; - ncnn::UnaryOp* op_default = (ncnn::UnaryOp*)layer_default; - - fprintf_param_value(" 0=%d", op_type) - } - else if (layer->type == "YoloDetectionOutput") - { - ncnn::YoloDetectionOutput* op = (ncnn::YoloDetectionOutput*)layer; - ncnn::YoloDetectionOutput* op_default = (ncnn::YoloDetectionOutput*)layer_default; - - fprintf_param_value(" 0=%d", num_class) - fprintf_param_value(" 1=%d", num_box) - fprintf_param_value(" 2=%e", confidence_threshold) - fprintf_param_value(" 3=%e", nms_threshold) - { - if (!op->biases.empty()) fprintf_param_float_array(4, op->biases, pp); - } - } - else if (layer->type == "Yolov3DetectionOutput") - { - ncnn::Yolov3DetectionOutput* op = (ncnn::Yolov3DetectionOutput*)layer; - ncnn::Yolov3DetectionOutput* op_default = (ncnn::Yolov3DetectionOutput*)layer_default; - - fprintf_param_value(" 0=%d", num_class) - fprintf_param_value(" 1=%d", num_box) - fprintf_param_value(" 2=%e", confidence_threshold) - fprintf_param_value(" 3=%e", nms_threshold) - { - if (!op->biases.empty()) fprintf_param_float_array(4, op->biases, pp); - } - { - if (!op->mask.empty()) fprintf_param_int_array(5, op->mask, pp); - } - { - if (!op->anchors_scale.empty()) fprintf_param_float_array(6, op->anchors_scale, pp); - } - } - -#undef fprintf_param_value - - fprintf(pp, "\n"); - - delete layer_default; - } - - fclose(pp); - fclose(bp); - - if (mac) - { - fprintf(stderr, "mac = %llu = %.2f M\n", static_cast(mac), mac / 1000000.0); - } - - return 0; -} diff --git a/tools/quantize/CMakeLists.txt b/tools/quantize/CMakeLists.txt index 72c76d135015..6258896122ec 100644 --- a/tools/quantize/CMakeLists.txt +++ b/tools/quantize/CMakeLists.txt @@ -1,3 +1,4 @@ +set(CMAKE_CXX_STANDARD 11) if(NCNN_PIXEL) if(NOT NCNN_SIMPLEOCV) @@ -34,7 +35,7 @@ if(NCNN_PIXEL) set_property(TARGET ncnn2table PROPERTY FOLDER "tools/optimization") endif() -add_executable(ncnn2int8 ncnn2int8.cpp) +add_executable(ncnn2int8 ncnn2int8.cpp net_quantize.cpp ../modelwriter.cpp) target_link_libraries(ncnn2int8 PRIVATE ncnn) # add ncnn2int8 tool to a virtual project group diff --git a/tools/quantize/ini_config.h b/tools/quantize/ini_config.h new file mode 100644 index 000000000000..5ced78555ffc --- /dev/null +++ b/tools/quantize/ini_config.h @@ -0,0 +1,319 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ini format table reader and writer +// file example: +// +// [Conv_0] +// type = "Conv" +// input_scale = 127.0 +// weight = [ 1117.265625, 8819.232421875 ] +// +// [LayerNorm_66] +// type = "LayerNorm" +// zero_point = -24 + +namespace ini { + +template +std::string value_set(T data) +{ + return std::to_string(data); +} + +template<> +std::string value_set(std::string data) +{ + return "\"" + data + "\""; +} + +template<> +std::string value_set(const char* data) +{ + return "\"" + std::string(data) + "\""; +} + +template +std::string value_set(const std::vector& data) +{ + std::string text = "[ "; + size_t len = data.size(); + if (len > 0) + { + size_t i = 0; + for (; i < len - 1; ++i) + { + text += std::to_string(data[i]); + text += ", "; + } + text += std::to_string(data[i]); + text += " "; + } + text += "]"; + return text; +} + +template +T value_get(std::string text) +{ + T result; + std::stringstream ss; + ss << text; + ss >> result; + return result; +} + +template<> +std::string value_get(std::string text) +{ + auto start = text.find('\"'); + auto end = text.find_last_of('\"'); + + return text.substr(start + 1, end - start - 1); +} + +/** + * @brief parse `[1, 2.2]` format to value list + * + * @tparam T + * @param text + * @return std::vector + */ +template +std::vector value_get_list(std::string text) +{ + std::vector result; + std::string no_brace; + { + // remove brace + auto start = text.find('['); + auto end = text.find(']'); + no_brace = text.substr(start + 1, end - start - 1); + } + + { + // split with the separator ',' + std::stringstream ss; + size_t end = 0, start = 0; + while (true) + { + end = no_brace.find(',', start); + if (end == std::string::npos) + { + break; + } + + std::string val_str = no_brace.substr(start, end - start); + start = end + 1; + + T val; + ss << val_str; + ss >> val; + ss.clear(); + result.emplace_back(val); + } + + // parse the last one + std::string val_str = no_brace.substr(start); + T val; + ss << val_str; + ss >> val; + result.emplace_back(val); + } + return result; +} + +/** + * @brief contains multiple `key=value` lines + * + */ +class Table +{ +public: + Table() + { + } + + void feed(std::string line) + { + auto pos = line.find('='); + assert(pos != std::string::npos); + + std::string key = line.substr(0, pos - 1); + std::string value_str = line.substr(pos + 2); + + values[key] = value_str; + } + + void feed(const std::vector& lines) + { + for (auto& line : lines) + { + feed(line); + } + } + + std::string operator[](std::string key) + { + return values[key]; + } + + template + T get(std::string key) + { + std::string text = values.at(key); + return value_get(text); + } + + template + std::vector get_list(std::string key) + { + std::string text = values[key]; + return value_get_list(text); + } + + template + void append(std::string key, T data) + { + values[key] = value_set(data); + } + + template + void append(std::string key, const std::vector& data) + { + values[key] = value_set(data); + } + + std::string stringify() + { + std::string result; + for (auto itra = values.begin(); itra != values.end(); ++itra) + { + result += itra->first; + result += " = "; + result += itra->second; + result += '\n'; + } + return result; + } + +private: + std::map values; +}; + +/** + * @brief `Config` consist of multiple key-table + * + */ +class Config +{ +public: + Config() + { + } + + void read(std::string path) + { + std::ifstream fin; + fin.open(path, std::ios::in); + + if (!fin.is_open()) + { + fprintf(stderr, "open %s failed\n", path.c_str()); + return; + } + + std::shared_ptr pTable = nullptr; + constexpr int BUF_LEN = 1024 * 1024; + char buf[BUF_LEN] = {0}; + std::string line; + while (!fin.eof()) + { + fin.getline(buf, BUF_LEN); + line = std::string(buf); + + if (line.length() <= 2) + { + pTable = nullptr; + continue; + } + + if (nullptr == pTable) + { + auto start = line.find('['); + auto end = line.find(']'); + assert(start != std::string::npos); + assert(end != std::string::npos); + + std::string key = line.substr(start + 1, end - start - 1); + + pTable = std::make_shared
(); + append(key, pTable); + continue; + } + + pTable->feed(line); + } + + fin.close(); + } + + std::vector keys() + { + std::vector result; + for (auto& pair : tables) + { + result.push_back(std::get<0>(pair)); + } + return result; + } + + size_t size() + { + return tables.size(); + } + + std::tuple > operator[](size_t i) + { + return tables[i]; + } + + void append(const std::string& key, std::shared_ptr
table) + { + tables.emplace_back(std::make_pair(key, table)); + } + + void write(const std::string& path) + { + std::ofstream fout; + fout.open(path, std::ios::out); + if (!fout.is_open()) + { + fprintf(stderr, "open %s failed\n", path.c_str()); + } + + for (auto& pair : tables) + { + std::string name = std::get<0>(pair); + std::shared_ptr
ptable = std::get<1>(pair); + fout << "[" << name << "]\n"; + fout << ptable->stringify(); + fout << "\n"; + } + fout.flush(); + fout.close(); + } + +private: + std::vector > > tables; +}; + +} // namespace ini diff --git a/tools/quantize/ncnn2int8.cpp b/tools/quantize/ncnn2int8.cpp index f712306b0228..68141009a23e 100644 --- a/tools/quantize/ncnn2int8.cpp +++ b/tools/quantize/ncnn2int8.cpp @@ -24,12 +24,9 @@ // ncnn public header #include "datareader.h" -#include "layer.h" -#include "layer_type.h" -#include "net.h" // ncnn private header -#include "../modelwriter.h" +#include "net_quantize.h" class DataReaderFromEmpty : public ncnn::DataReader { @@ -45,476 +42,6 @@ class DataReaderFromEmpty : public ncnn::DataReader } }; -static bool read_int8scale_table(const char* filepath, std::map& blob_int8scale_table, std::map& weight_int8scale_table) -{ - blob_int8scale_table.clear(); - weight_int8scale_table.clear(); - - FILE* fp = fopen(filepath, "rb"); - if (!fp) - { - fprintf(stderr, "Open %s failed.\n", filepath); - return false; - } - - std::string key_str; - std::vector scales; - - std::vector line(10240000); - char* pch = NULL; - size_t len = 0; - - while (!feof(fp)) - { - char* s = fgets(line.data(), (int)line.size(), fp); - if (!s) - break; - - float scale = 1.f; - char key[256]; - line[strcspn(line.data(), "\r\n")] = 0; - - pch = strtok(line.data(), " "); - - if (pch == NULL) break; - - bool is_key = true; - while (pch != NULL) - { - if (is_key) - { - sscanf(pch, "%255s", key); - - key_str = key; - is_key = false; - } - else - { - sscanf(pch, "%f", &scale); - - scales.push_back(scale); - } - - pch = strtok(NULL, " "); - } - - // XYZ_param_N pattern - if (strstr(key_str.c_str(), "_param_")) - { - weight_int8scale_table[key_str] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); - } - else - { - blob_int8scale_table[key_str] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); - } - key_str.clear(); - scales.clear(); - } - - fclose(fp); - - return true; -} - -class NetQuantize : public ModelWriter -{ -public: - NetQuantize(); - - std::map blob_int8scale_table; - std::map weight_int8scale_table; - -public: - int quantize_convolution(); - int quantize_convolutiondepthwise(); - int quantize_innerproduct(); - - int fuse_requantize(); -}; - -NetQuantize::NetQuantize() - : ModelWriter() -{ -} - -int NetQuantize::quantize_convolution() -{ - const int layer_count = static_cast(layers.size()); - for (int i = 0; i < layer_count; i++) - { - // find convolution layer - if (layers[i]->type != "Convolution") - continue; - - // find convolution layer - std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); - if (iter_data == blob_int8scale_table.end()) - continue; - - char key[256]; - sprintf(key, "%s_param_0", layers[i]->name.c_str()); - - std::map::iterator iter = weight_int8scale_table.find(key); - if (iter == weight_int8scale_table.end()) - { - fprintf(stderr, "this layer need to be quantized, but no scale param!\n"); - return -1; - } - - // Convolution - quantize weight from fp32 to int8 - ncnn::Convolution* convolution = (ncnn::Convolution*)layers[i]; - - ncnn::Mat bottom_blob_int8_scales = iter_data->second; - ncnn::Mat weight_data_int8_scales = iter->second; - - fprintf(stderr, "quantize_convolution %s\n", convolution->name.c_str()); - - { - const int maxk = convolution->kernel_w * convolution->kernel_h; - const int num_input = convolution->weight_data_size / convolution->num_output / maxk; - - ncnn::Mat weight_data_r2 = convolution->weight_data.reshape(maxk, num_input, convolution->num_output); - - ncnn::Mat weight_data_int8; - - ncnn::Option opt_q = opt; - opt_q.blob_allocator = convolution->weight_data.allocator; - opt_q.use_packing_layout = false; - ncnn::quantize_to_int8(weight_data_r2, weight_data_int8, weight_data_int8_scales, opt_q); - if (weight_data_int8.empty()) - return -100; - - convolution->weight_data = weight_data_int8.reshape(convolution->weight_data_size); - } - - convolution->int8_scale_term = 2; - convolution->weight_data_int8_scales = weight_data_int8_scales; - convolution->bottom_blob_int8_scales = bottom_blob_int8_scales; - } - - return 0; -} - -int NetQuantize::quantize_convolutiondepthwise() -{ - const int layer_count = static_cast(layers.size()); - for (int i = 0; i < layer_count; i++) - { - // find convolution layer - if (layers[i]->type != "ConvolutionDepthWise") - continue; - - // find convolutiondepthwise layer - std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); - if (iter_data == blob_int8scale_table.end()) - continue; - - char key[256]; - sprintf(key, "%s_param_0", layers[i]->name.c_str()); - - std::map::iterator iter = weight_int8scale_table.find(key); - if (iter == weight_int8scale_table.end()) - { - fprintf(stderr, "this layer need to be quantized, but no scale param!\n"); - return -1; - } - - // Convolution - quantize weight from fp32 to int8 - ncnn::ConvolutionDepthWise* convdw = (ncnn::ConvolutionDepthWise*)layers[i]; - - ncnn::Mat bottom_blob_int8_scales = iter_data->second; - ncnn::Mat weight_data_int8_scales = iter->second; - - fprintf(stderr, "quantize_convolutiondepthwise %s\n", convdw->name.c_str()); - - { - ncnn::Mat int8_weight_data(convdw->weight_data_size, (size_t)1u); - if (int8_weight_data.empty()) - return -100; - - const int weight_data_size_g = convdw->weight_data_size / convdw->group; - - for (int g = 0; g < convdw->group; g++) - { - ncnn::Option opt_q = opt; - opt_q.blob_allocator = int8_weight_data.allocator; - opt_q.use_packing_layout = false; - - const ncnn::Mat weight_data_g = convdw->weight_data.range(weight_data_size_g * g, weight_data_size_g); - ncnn::Mat int8_weight_data_g = int8_weight_data.range(weight_data_size_g * g, weight_data_size_g); - const ncnn::Mat weight_data_int8_scales_g = weight_data_int8_scales.range(g, 1); - ncnn::quantize_to_int8(weight_data_g, int8_weight_data_g, weight_data_int8_scales_g, opt_q); - } - - convdw->weight_data = int8_weight_data; - } - - convdw->int8_scale_term = 1; - convdw->weight_data_int8_scales = weight_data_int8_scales; - convdw->bottom_blob_int8_scales = bottom_blob_int8_scales; - } - - return 0; -} - -int NetQuantize::quantize_innerproduct() -{ - const int layer_count = static_cast(layers.size()); - for (int i = 0; i < layer_count; i++) - { - // find convolution layer - if (layers[i]->type != "InnerProduct") - continue; - - // find InnerProduct layer - std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); - if (iter_data == blob_int8scale_table.end()) - continue; - - char key[256]; - sprintf(key, "%s_param_0", layers[i]->name.c_str()); - - std::map::iterator iter = weight_int8scale_table.find(key); - if (iter == weight_int8scale_table.end()) - { - fprintf(stderr, "this layer need to be quantized, but no scale param!\n"); - return -1; - } - - // InnerProduct - quantize weight from fp32 to int8 - ncnn::InnerProduct* fc = (ncnn::InnerProduct*)layers[i]; - - ncnn::Mat bottom_blob_int8_scales = iter_data->second; - ncnn::Mat weight_data_int8_scales = iter->second; - - fprintf(stderr, "quantize_innerproduct %s\n", fc->name.c_str()); - - { - const int num_input = fc->weight_data_size / fc->num_output; - - ncnn::Mat weight_data_r2 = fc->weight_data.reshape(num_input, fc->num_output); - - ncnn::Mat weight_data_int8; - ncnn::Option opt_q = opt; - opt_q.use_packing_layout = false; - ncnn::quantize_to_int8(weight_data_r2, weight_data_int8, weight_data_int8_scales, opt_q); - if (weight_data_int8.empty()) - return -100; - - fc->weight_data = weight_data_int8.reshape(fc->weight_data_size); - } - - fc->int8_scale_term = 2; - fc->weight_data_int8_scales = weight_data_int8_scales; - fc->bottom_blob_int8_scales = bottom_blob_int8_scales; - } - - return 0; -} - -int NetQuantize::fuse_requantize() -{ - const size_t layer_count = layers.size(); - for (size_t i = 0; i < layer_count; i++) - { - if (layers[i]->type != "Convolution" && layers[i]->type != "ConvolutionDepthWise") - continue; - - // Convolution/ConvolutionDepthWise - Convolution/ConvolutionDepthWise - int top_blob_index = layers[i]->tops[0]; - - size_t j = i + 1; - for (; j < layer_count; j++) - { - if (layers[j]->type != "Convolution" && layers[j]->type != "ConvolutionDepthWise") - continue; - - if (layers[j]->bottoms.size() != 1) - continue; - - if (layers[j]->bottoms[0] == top_blob_index) - break; - } - - if (j == layer_count) - continue; - - // fuse requantize - fprintf(stderr, "fuse_requantize %s %s\n", layers[i]->name.c_str(), layers[j]->name.c_str()); - - if (layers[i]->type == "Convolution" && layers[j]->type == "Convolution") - { - ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; - ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "Convolution" && layers[j]->type == "ConvolutionDepthWise") - { - ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; - ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "Convolution") - { - ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; - ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "ConvolutionDepthWise") - { - ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; - ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - } - - for (size_t i = 0; i < layer_count; i++) - { - if (layers[i]->type != "Convolution" && layers[i]->type != "ConvolutionDepthWise") - continue; - - // Convolution/ConvolutionDepthWise - Split - Convolution/ConvolutionDepthWise - int top_blob_index = layers[i]->tops[0]; - - size_t j = i + 1; - for (; j < layer_count; j++) - { - if (layers[j]->type != "Split") - continue; - - if (layers[j]->bottoms.size() != 1) - continue; - - if (layers[j]->bottoms[0] == top_blob_index) - break; - } - - if (j == layer_count) - continue; - - ncnn::Split* split = (ncnn::Split*)layers[j]; - - bool all_conv = true; - for (size_t p = 0; p < split->tops.size(); p++) - { - int split_top_blob_index = split->tops[p]; - - size_t k = j + 1; - for (; k < layer_count; k++) - { - if (layers[k]->type != "Convolution" && layers[k]->type != "ConvolutionDepthWise") - continue; - - if (layers[k]->bottoms.size() != 1) - continue; - - if (layers[k]->bottoms[0] == split_top_blob_index) - break; - } - - if (k == layer_count) - { - all_conv = false; - break; - } - - if (layers[k]->type == "Convolution") - { - ncnn::Convolution* convolution = (ncnn::Convolution*)layers[k]; - if (convolution->weight_data.elemsize != 1u) - { - all_conv = false; - break; - } - } - if (layers[k]->type == "ConvolutionDepthWise") - { - ncnn::ConvolutionDepthWise* convolution = (ncnn::ConvolutionDepthWise*)layers[k]; - if (convolution->weight_data.elemsize != 1u) - { - all_conv = false; - break; - } - } - } - - if (!all_conv) - continue; - - j = blobs[split->tops[0]].consumer; - - // fuse requantize - fprintf(stderr, "fuse_requantize %s %s\n", layers[i]->name.c_str(), split->name.c_str()); - - if (layers[i]->type == "Convolution" && layers[j]->type == "Convolution") - { - ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; - ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "Convolution" && layers[j]->type == "ConvolutionDepthWise") - { - ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; - ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "Convolution") - { - ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; - ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "ConvolutionDepthWise") - { - ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; - ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; - - if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) - continue; - - convolution1->int8_scale_term += 100; - convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; - } - } - - return 0; -} - int main(int argc, char** argv) { if (argc != 6) @@ -532,14 +59,21 @@ int main(int argc, char** argv) NetQuantize quantizer; // parse the calibration scale table - if (int8scale_table_path) + bool success = false; + if (std::string(int8scale_table_path).find(".ini") == std::string::npos) + { + quantizer.set_weight_suffix("_param_0"); + success = quantizer.read_txt_format(int8scale_table_path); + } + else { - bool s2 = read_int8scale_table(int8scale_table_path, quantizer.blob_int8scale_table, quantizer.weight_int8scale_table); - if (!s2) - { - fprintf(stderr, "read_int8scale_table failed\n"); - return -1; - } + success = quantizer.read_ini_format(int8scale_table_path); + } + + if (!success) + { + fprintf(stderr, "read_int8scale_table failed\n"); + return -1; } quantizer.load_param(inparam); diff --git a/tools/quantize/ncnn2table.cpp b/tools/quantize/ncnn2table.cpp index 9fbafa2d1813..5f83706a0b9b 100644 --- a/tools/quantize/ncnn2table.cpp +++ b/tools/quantize/ncnn2table.cpp @@ -38,6 +38,7 @@ #endif #include #include +#include "ini_config.h" // ncnn public header #include "benchmark.h" @@ -91,6 +92,7 @@ class QuantNet : public ncnn::Net int init(); void print_quant_info() const; int save_table(const char* tablepath); + int save_ini(const char* filepath); int quantize_KL(); int quantize_ACIQ(); int quantize_EQ(); @@ -98,6 +100,7 @@ class QuantNet : public ncnn::Net public: std::vector input_blobs; std::vector conv_layers; + std::vector type_list; std::vector conv_bottom_blobs; std::vector conv_top_blobs; @@ -132,6 +135,7 @@ int QuantNet::init() if (layer->type == "Convolution" || layer->type == "ConvolutionDepthWise" || layer->type == "InnerProduct") { conv_layers.push_back(i); + type_list.push_back(layer->type); conv_bottom_blobs.push_back(layer->bottoms[0]); conv_top_blobs.push_back(layer->tops[0]); } @@ -190,6 +194,62 @@ int QuantNet::save_table(const char* tablepath) return 0; } +int QuantNet::save_ini(const char* filepath) +{ + auto root = ini::Config(); + + const int conv_layer_count = static_cast(conv_layers.size()); + const int conv_bottom_blob_count = static_cast(conv_bottom_blobs.size()); + + for (int i = 0; i < conv_layer_count; i++) + { + auto tbl = std::make_shared(); + + // write opr type + auto type = type_list[i]; + if (type == "Convolution" || type == "ConvolutionDepthWise") + { + tbl->append("type", std::string("Conv")); + } + else if (type == "InnerProduct") + { + tbl->append("type", std::string("Gemm")); + } + else + { + fprintf(stderr, "unknown type %s\n", type.c_str()); + } + + // write weight scales + { + const ncnn::Mat& weight_scale = weight_scales[i]; + + std::vector scales = {}; + for (int j = 0; j < weight_scale.w; j++) + { + scales.push_back(static_cast(weight_scale[j])); + } + tbl->append("weight", scales); + } + + // write input scale + { + const ncnn::Mat& bottom_blob_scale = bottom_blob_scales[i]; + if (bottom_blob_scale.w != 1) + { + fprintf(stderr, "not support conv input scale length=%d\n", bottom_blob_scale.w); + return -1; + } + tbl->append("input_scale", static_cast(bottom_blob_scale[0])); + } + + const std::string name = layers[conv_layers[i]]->name; + root.append(name, tbl); + } + root.write(std::string(filepath)); + return 0; +} + void QuantNet::print_quant_info() const { for (int i = 0; i < (int)conv_bottom_blobs.size(); i++) @@ -1586,7 +1646,8 @@ static void show_usage() fprintf(stderr, " pixel=RAW/RGB/BGR/GRAY/RGBA/BGRA,...\n"); fprintf(stderr, " thread=8\n"); fprintf(stderr, " method=kl/aciq/eq\n"); - fprintf(stderr, "Sample usage: ncnn2table squeezenet.param squeezenet.bin imagelist.txt squeezenet.table mean=[104.0,117.0,123.0] norm=[1.0,1.0,1.0] shape=[227,227,3] pixel=BGR method=kl\n"); + fprintf(stderr, " format=txt/ini\n"); + fprintf(stderr, "Sample usage: ncnn2table squeezenet.param squeezenet.bin imagelist.txt squeezenet.table mean=[104.0,117.0,123.0] norm=[1.0,1.0,1.0] shape=[227,227,3] pixel=BGR method=kl format=txt\n"); } int main(int argc, char** argv) @@ -1629,6 +1690,7 @@ int main(int argc, char** argv) net.listspaths = parse_comma_path_list(lists); std::string method = "kl"; + std::string format = "txt"; for (int i = 5; i < argc; i++) { @@ -1649,17 +1711,37 @@ int main(int argc, char** argv) // load mean norm shape if (memcmp(key, "mean", 4) == 0) + { net.means = parse_comma_float_array_list(value); - if (memcmp(key, "norm", 4) == 0) + } + else if (memcmp(key, "norm", 4) == 0) + { net.norms = parse_comma_float_array_list(value); - if (memcmp(key, "shape", 5) == 0) + } + else if (memcmp(key, "shape", 5) == 0) + { net.shapes = parse_comma_int_array_list(value); - if (memcmp(key, "pixel", 5) == 0) + } + else if (memcmp(key, "pixel", 5) == 0) + { net.type_to_pixels = parse_comma_pixel_type_list(value); - if (memcmp(key, "thread", 6) == 0) + } + else if (memcmp(key, "thread", 6) == 0) + { net.quantize_num_threads = atoi(value); - if (memcmp(key, "method", 6) == 0) + } + else if (memcmp(key, "method", 6) == 0) + { method = std::string(value); + } + else if (memcmp(key, "format", 6) == 0) + { + format = std::string(value); + } + else + { + fprintf(stderr, "unknown key=%s\n", key); + } } // sanity check @@ -1735,7 +1817,14 @@ int main(int argc, char** argv) net.print_quant_info(); - net.save_table(outtable); + if (format == "ini") + { + net.save_ini(outtable); + } + else + { + net.save_table(outtable); + } return 0; } diff --git a/tools/quantize/net_quantize.cpp b/tools/quantize/net_quantize.cpp new file mode 100644 index 000000000000..0ef6ec30c284 --- /dev/null +++ b/tools/quantize/net_quantize.cpp @@ -0,0 +1,498 @@ + +#include "layer.h" +#include "layer_type.h" +#include "net.h" +#include "net_quantize.h" +#include +#include +#include +#include "ini_config.h" + +void NetQuantize::set_weight_suffix(std::string str) +{ + suffix = str; +} + +bool NetQuantize::read_txt_format(const char* filepath) +{ + blob_int8scale_table.clear(); + weight_int8scale_table.clear(); + + FILE* fp = fopen(filepath, "rb"); + if (!fp) + { + fprintf(stderr, "Open %s failed.\n", filepath); + return false; + } + + std::string key_str; + std::vector scales; + + std::vector line(10240000); + char* pch = NULL; + size_t len = 0; + + while (!feof(fp)) + { + char* s = fgets(line.data(), (int)line.size(), fp); + if (!s) + break; + + float scale = 1.f; + char key[256]; + line[strcspn(line.data(), "\r\n")] = 0; + + pch = strtok(line.data(), " "); + + if (pch == NULL) break; + + bool is_key = true; + while (pch != NULL) + { + if (is_key) + { + sscanf(pch, "%255s", key); + + key_str = key; + is_key = false; + } + else + { + sscanf(pch, "%f", &scale); + + scales.push_back(scale); + } + + pch = strtok(NULL, " "); + } + + // XYZ_param_N pattern + if (strstr(key_str.c_str(), "_param_")) + { + weight_int8scale_table[key_str] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); + } + else + { + blob_int8scale_table[key_str] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); + } + key_str.clear(); + scales.clear(); + } + + fclose(fp); + + return true; +} + +bool NetQuantize::read_ini_format(const char* path) +{ + blob_int8scale_table.clear(); + weight_int8scale_table.clear(); + + ini::Config root; + root.read(std::string(path)); + + size_t len = root.size(); + std::string name, type; + std::shared_ptr ptable; + for (size_t i = 0; i < len; ++i) + { + std::tie(name, ptable) = root[i]; + type = ptable->get("type"); + + if (type == "Conv" || type == "Gemm") + { + // load weight scales + { + std::vector scales = ptable->get_list("weight"); + weight_int8scale_table[name] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); + } + + // load input scale + { + std::vector scales = {ptable->get("input_scale")}; + blob_int8scale_table[name] = ncnn::Mat((int)scales.size(), (void*)scales.data()).clone(); + } + } + } + + return true; +} + +int NetQuantize::quantize_convolution() +{ + const int layer_count = static_cast(layers.size()); + for (int i = 0; i < layer_count; i++) + { + // find convolution layer + if (layers[i]->type != "Convolution") + continue; + + // find convolution layer + std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); + if (iter_data == blob_int8scale_table.end()) + continue; + + char key[256]; + sprintf(key, "%s%s", layers[i]->name.c_str(), suffix.c_str()); + + std::map::iterator iter = weight_int8scale_table.find(key); + if (iter == weight_int8scale_table.end()) + { + fprintf(stderr, "%s need to be quantized, but no scale param!\n", key); + return -1; + } + + // Convolution - quantize weight from fp32 to int8 + ncnn::Convolution* convolution = (ncnn::Convolution*)layers[i]; + + ncnn::Mat bottom_blob_int8_scales = iter_data->second; + ncnn::Mat weight_data_int8_scales = iter->second; + + fprintf(stderr, "quantize_convolution %s\n", convolution->name.c_str()); + + { + const int maxk = convolution->kernel_w * convolution->kernel_h; + const int num_input = convolution->weight_data_size / convolution->num_output / maxk; + + ncnn::Mat weight_data_r2 = convolution->weight_data.reshape(maxk, num_input, convolution->num_output); + + ncnn::Mat weight_data_int8; + + ncnn::Option opt_q = opt; + opt_q.blob_allocator = convolution->weight_data.allocator; + opt_q.use_packing_layout = false; + ncnn::quantize_to_int8(weight_data_r2, weight_data_int8, weight_data_int8_scales, opt_q); + if (weight_data_int8.empty()) + return -100; + + convolution->weight_data = weight_data_int8.reshape(convolution->weight_data_size); + } + + convolution->int8_scale_term = 2; + convolution->weight_data_int8_scales = weight_data_int8_scales; + convolution->bottom_blob_int8_scales = bottom_blob_int8_scales; + } + + return 0; +} + +int NetQuantize::quantize_convolutiondepthwise() +{ + const int layer_count = static_cast(layers.size()); + for (int i = 0; i < layer_count; i++) + { + // find convolution layer + if (layers[i]->type != "ConvolutionDepthWise") + continue; + + // find convolutiondepthwise layer + std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); + if (iter_data == blob_int8scale_table.end()) + continue; + + char key[256]; + sprintf(key, "%s%s", layers[i]->name.c_str(), suffix.c_str()); + + std::map::iterator iter = weight_int8scale_table.find(key); + if (iter == weight_int8scale_table.end()) + { + fprintf(stderr, "this layer need to be quantized, but no scale param!\n"); + return -1; + } + + // Convolution - quantize weight from fp32 to int8 + ncnn::ConvolutionDepthWise* convdw = (ncnn::ConvolutionDepthWise*)layers[i]; + + ncnn::Mat bottom_blob_int8_scales = iter_data->second; + ncnn::Mat weight_data_int8_scales = iter->second; + + fprintf(stderr, "quantize_convolutiondepthwise %s\n", convdw->name.c_str()); + + { + ncnn::Mat int8_weight_data(convdw->weight_data_size, (size_t)1u); + if (int8_weight_data.empty()) + return -100; + + const int weight_data_size_g = convdw->weight_data_size / convdw->group; + + for (int g = 0; g < convdw->group; g++) + { + ncnn::Option opt_q = opt; + opt_q.blob_allocator = int8_weight_data.allocator; + opt_q.use_packing_layout = false; + + const ncnn::Mat weight_data_g = convdw->weight_data.range(weight_data_size_g * g, weight_data_size_g); + ncnn::Mat int8_weight_data_g = int8_weight_data.range(weight_data_size_g * g, weight_data_size_g); + const ncnn::Mat weight_data_int8_scales_g = weight_data_int8_scales.range(g, 1); + ncnn::quantize_to_int8(weight_data_g, int8_weight_data_g, weight_data_int8_scales_g, opt_q); + } + + convdw->weight_data = int8_weight_data; + } + + convdw->int8_scale_term = 1; + convdw->weight_data_int8_scales = weight_data_int8_scales; + convdw->bottom_blob_int8_scales = bottom_blob_int8_scales; + } + + return 0; +} + +int NetQuantize::quantize_innerproduct() +{ + const int layer_count = static_cast(layers.size()); + for (int i = 0; i < layer_count; i++) + { + // find convolution layer + if (layers[i]->type != "InnerProduct") + continue; + + // find InnerProduct layer + std::map::iterator iter_data = blob_int8scale_table.find(layers[i]->name); + if (iter_data == blob_int8scale_table.end()) + continue; + + char key[256]; + sprintf(key, "%s%s", layers[i]->name.c_str(), suffix.c_str()); + + std::map::iterator iter = weight_int8scale_table.find(key); + if (iter == weight_int8scale_table.end()) + { + fprintf(stderr, "this layer need to be quantized, but no scale param!\n"); + return -1; + } + + // InnerProduct - quantize weight from fp32 to int8 + ncnn::InnerProduct* fc = (ncnn::InnerProduct*)layers[i]; + + ncnn::Mat bottom_blob_int8_scales = iter_data->second; + ncnn::Mat weight_data_int8_scales = iter->second; + + fprintf(stderr, "quantize_innerproduct %s\n", fc->name.c_str()); + + { + const int num_input = fc->weight_data_size / fc->num_output; + + ncnn::Mat weight_data_r2 = fc->weight_data.reshape(num_input, fc->num_output); + + ncnn::Mat weight_data_int8; + ncnn::Option opt_q = opt; + opt_q.use_packing_layout = false; + ncnn::quantize_to_int8(weight_data_r2, weight_data_int8, weight_data_int8_scales, opt_q); + if (weight_data_int8.empty()) + return -100; + + fc->weight_data = weight_data_int8.reshape(fc->weight_data_size); + } + + fc->int8_scale_term = 2; + fc->weight_data_int8_scales = weight_data_int8_scales; + fc->bottom_blob_int8_scales = bottom_blob_int8_scales; + } + + return 0; +} + +int NetQuantize::fuse_requantize() +{ + const size_t layer_count = layers.size(); + for (size_t i = 0; i < layer_count; i++) + { + if (layers[i]->type != "Convolution" && layers[i]->type != "ConvolutionDepthWise") + continue; + + // Convolution/ConvolutionDepthWise - Convolution/ConvolutionDepthWise + int top_blob_index = layers[i]->tops[0]; + + size_t j = i + 1; + for (; j < layer_count; j++) + { + if (layers[j]->type != "Convolution" && layers[j]->type != "ConvolutionDepthWise") + continue; + + if (layers[j]->bottoms.size() != 1) + continue; + + if (layers[j]->bottoms[0] == top_blob_index) + break; + } + + if (j == layer_count) + continue; + + // fuse requantize + fprintf(stderr, "fuse_requantize %s %s\n", layers[i]->name.c_str(), layers[j]->name.c_str()); + + if (layers[i]->type == "Convolution" && layers[j]->type == "Convolution") + { + ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; + ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "Convolution" && layers[j]->type == "ConvolutionDepthWise") + { + ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; + ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "Convolution") + { + ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; + ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "ConvolutionDepthWise") + { + ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; + ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + } + + for (size_t i = 0; i < layer_count; i++) + { + if (layers[i]->type != "Convolution" && layers[i]->type != "ConvolutionDepthWise") + continue; + + // Convolution/ConvolutionDepthWise - Split - Convolution/ConvolutionDepthWise + int top_blob_index = layers[i]->tops[0]; + + size_t j = i + 1; + for (; j < layer_count; j++) + { + if (layers[j]->type != "Split") + continue; + + if (layers[j]->bottoms.size() != 1) + continue; + + if (layers[j]->bottoms[0] == top_blob_index) + break; + } + + if (j == layer_count) + continue; + + ncnn::Split* split = (ncnn::Split*)layers[j]; + + bool all_conv = true; + for (size_t p = 0; p < split->tops.size(); p++) + { + int split_top_blob_index = split->tops[p]; + + size_t k = j + 1; + for (; k < layer_count; k++) + { + if (layers[k]->type != "Convolution" && layers[k]->type != "ConvolutionDepthWise") + continue; + + if (layers[k]->bottoms.size() != 1) + continue; + + if (layers[k]->bottoms[0] == split_top_blob_index) + break; + } + + if (k == layer_count) + { + all_conv = false; + break; + } + + if (layers[k]->type == "Convolution") + { + ncnn::Convolution* convolution = (ncnn::Convolution*)layers[k]; + if (convolution->weight_data.elemsize != 1u) + { + all_conv = false; + break; + } + } + if (layers[k]->type == "ConvolutionDepthWise") + { + ncnn::ConvolutionDepthWise* convolution = (ncnn::ConvolutionDepthWise*)layers[k]; + if (convolution->weight_data.elemsize != 1u) + { + all_conv = false; + break; + } + } + } + + if (!all_conv) + continue; + + j = blobs[split->tops[0]].consumer; + + // fuse requantize + fprintf(stderr, "fuse_requantize %s %s\n", layers[i]->name.c_str(), split->name.c_str()); + + if (layers[i]->type == "Convolution" && layers[j]->type == "Convolution") + { + ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; + ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "Convolution" && layers[j]->type == "ConvolutionDepthWise") + { + ncnn::Convolution* convolution1 = (ncnn::Convolution*)layers[i]; + ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "Convolution") + { + ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; + ncnn::Convolution* convolution2 = (ncnn::Convolution*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + if (layers[i]->type == "ConvolutionDepthWise" && layers[j]->type == "ConvolutionDepthWise") + { + ncnn::ConvolutionDepthWise* convolution1 = (ncnn::ConvolutionDepthWise*)layers[i]; + ncnn::ConvolutionDepthWise* convolution2 = (ncnn::ConvolutionDepthWise*)layers[j]; + + if (convolution1->weight_data.elemsize != 1u || convolution2->weight_data.elemsize != 1u) + continue; + + convolution1->int8_scale_term += 100; + convolution1->top_blob_int8_scales = convolution2->bottom_blob_int8_scales; + } + } + + return 0; +} diff --git a/tools/quantize/net_quantize.h b/tools/quantize/net_quantize.h new file mode 100644 index 000000000000..a69be3896840 --- /dev/null +++ b/tools/quantize/net_quantize.h @@ -0,0 +1,26 @@ +#pragma once +// ncnn private header +#include "../modelwriter.h" + +class NetQuantize : public ModelWriter +{ +public: + NetQuantize() + { + } + std::map blob_int8scale_table; + std::map weight_int8scale_table; + +public: + bool read_txt_format(const char* path); + bool read_ini_format(const char* path); + int quantize_convolution(); + int quantize_convolutiondepthwise(); + int quantize_innerproduct(); + int fuse_requantize(); + + void set_weight_suffix(std::string s); + +private: + std::string suffix; +};