mirror of
https://github.com/Tencent/ncnn.git
synced 2026-10-19 23:03:17 +08:00
5ea98309e3
* harden layer parameter validation Original patches and author identities: https://github.com/Tencent/ncnn/pull/6912 (beilzx) https://github.com/Tencent/ncnn/pull/6919 (FluxMind-O) https://github.com/Tencent/ncnn/pull/6928 (lxcxjxhx) https://github.com/Tencent/ncnn/pull/6948 (ktz03) https://github.com/Tencent/ncnn/pull/6950 (ktz03) https://github.com/Tencent/ncnn/pull/6971 (LI) https://github.com/Tencent/ncnn/pull/6974 (LI) https://github.com/Tencent/ncnn/pull/6977 (LI) Co-authored-by: beilzx <2069360659@qq.com> Co-authored-by: FluxMind-O <3283918317@qq.com> Co-authored-by: lxcxjxhx <lxcxjxhx@users.noreply.github.com> Co-authored-by: ktz03 <2484593937@qq.com> Co-authored-by: LI <2484593937@qq.com>
460 lines
16 KiB
C++
460 lines
16 KiB
C++
// Copyright 2020 Tencent
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#include "testutil.h"
|
|
|
|
#include "layer_type.h"
|
|
|
|
#include <limits.h>
|
|
|
|
static int test_yolov3detectionoutput(const std::vector<ncnn::Mat>& a, int num_class,
|
|
int num_box, float confidence_threshold, float nms_threshold,
|
|
ncnn::Mat& biases, ncnn::Mat& mask, ncnn::Mat& anchors_scale)
|
|
{
|
|
ncnn::ParamDict pd;
|
|
pd.set(0, num_class);
|
|
pd.set(1, num_box);
|
|
pd.set(2, confidence_threshold);
|
|
pd.set(3, nms_threshold);
|
|
pd.set(4, biases);
|
|
pd.set(5, mask);
|
|
pd.set(6, anchors_scale);
|
|
|
|
std::vector<ncnn::Mat> weights(0);
|
|
|
|
int ret = test_layer("Yolov3DetectionOutput", pd, weights, a);
|
|
if (ret != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput failed a.dims=%d a=(%d %d %d) ", a[0].dims, a[0].w, a[0].h, a[0].c);
|
|
fprintf(stderr, " num_class=%d num_box=%d", num_class, num_box);
|
|
fprintf(stderr, " confidence_threshold=%f nms_threshold=%f\n", confidence_threshold, nms_threshold);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ncnn::Mat create_mat_from(const float* src, int length)
|
|
{
|
|
ncnn::Mat ret(length);
|
|
memcpy(ret.data, src, length * sizeof(float));
|
|
return ret;
|
|
}
|
|
|
|
static ncnn::Mat MyRandomMat(int w, int h, int c)
|
|
{
|
|
ncnn::Mat m(w, h, c);
|
|
Randomize(m, -15.f, 1.5f);
|
|
return m;
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_v4()
|
|
{
|
|
const float b[] = {12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401};
|
|
const float m[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
|
|
const float s[] = {9.6, 17.6, 33.6};
|
|
|
|
ncnn::Mat biases = create_mat_from(b, sizeof(b) / sizeof(b[0]));
|
|
ncnn::Mat mask = create_mat_from(m, sizeof(m) / sizeof(m[0]));
|
|
ncnn::Mat anchors_scale = create_mat_from(s, sizeof(s) / sizeof(s[0]));
|
|
|
|
std::vector<ncnn::Mat> a(3);
|
|
a[0] = MyRandomMat(76, 76, 255);
|
|
a[1] = MyRandomMat(38, 38, 255);
|
|
a[2] = MyRandomMat(19, 19, 255);
|
|
|
|
return 0
|
|
|| test_yolov3detectionoutput(a, 80, 3, 0.55f, 0.45f, biases, mask, anchors_scale);
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_v4tiny()
|
|
{
|
|
const float b[] = {10, 14, 23, 27, 37, 58, 81, 82, 135, 169, 344, 319};
|
|
const float m[] = {3, 4, 5, 1, 2, 3};
|
|
const float s[] = {33.6, 16.8};
|
|
|
|
ncnn::Mat biases = create_mat_from(b, sizeof(b) / sizeof(b[0]));
|
|
ncnn::Mat mask = create_mat_from(m, sizeof(m) / sizeof(m[0]));
|
|
ncnn::Mat anchors_scale = create_mat_from(s, sizeof(s) / sizeof(s[0]));
|
|
|
|
std::vector<ncnn::Mat> a(2);
|
|
a[0] = MyRandomMat(13, 13, 255);
|
|
a[1] = MyRandomMat(26, 26, 255);
|
|
|
|
return 0
|
|
|| test_yolov3detectionoutput(a, 80, 3, 0.4f, 0.45f, biases, mask, anchors_scale);
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_v3()
|
|
{
|
|
const float b[] = {10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326};
|
|
const float m[] = {6, 7, 8, 3, 4, 5, 0, 1, 2};
|
|
const float s[] = {32, 16, 8};
|
|
|
|
ncnn::Mat biases = create_mat_from(b, sizeof(b) / sizeof(b[0]));
|
|
ncnn::Mat mask = create_mat_from(m, sizeof(m) / sizeof(m[0]));
|
|
ncnn::Mat anchors_scale = create_mat_from(s, sizeof(s) / sizeof(s[0]));
|
|
|
|
std::vector<ncnn::Mat> a(3);
|
|
a[0] = MyRandomMat(19, 19, 255);
|
|
a[1] = MyRandomMat(38, 38, 255);
|
|
a[2] = MyRandomMat(76, 76, 255);
|
|
|
|
return 0
|
|
|| test_yolov3detectionoutput(a, 80, 3, 0.6f, 0.45f, biases, mask, anchors_scale);
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_v3tiny()
|
|
{
|
|
const float b[] = {10, 14, 23, 27, 37, 58, 81, 82, 135, 169, 344, 319};
|
|
const float m[] = {3, 4, 5, 1, 2, 3};
|
|
const float s[] = {32, 16};
|
|
|
|
ncnn::Mat biases = create_mat_from(b, sizeof(b) / sizeof(b[0]));
|
|
ncnn::Mat mask = create_mat_from(m, sizeof(m) / sizeof(m[0]));
|
|
ncnn::Mat anchors_scale = create_mat_from(s, sizeof(s) / sizeof(s[0]));
|
|
|
|
std::vector<ncnn::Mat> a(2);
|
|
a[0] = MyRandomMat(13, 13, 255);
|
|
a[1] = MyRandomMat(26, 26, 255);
|
|
|
|
return 0
|
|
|| test_yolov3detectionoutput(a, 80, 3, 0.3f, 0.45f, biases, mask, anchors_scale);
|
|
}
|
|
|
|
#if NCNN_VALIDATION
|
|
static int test_yolov3detectionoutput_load_param()
|
|
{
|
|
ncnn::ParamDict pd;
|
|
pd.set(0, 20);
|
|
pd.set(1, 1);
|
|
ncnn::Mat biases(2);
|
|
biases.fill(1.f);
|
|
pd.set(4, biases);
|
|
ncnn::Mat mask(1);
|
|
mask[0] = 0.f;
|
|
pd.set(5, mask);
|
|
ncnn::Mat scales(1);
|
|
scales[0] = 32.f;
|
|
pd.set(6, scales);
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, 0) != 0)
|
|
return -1;
|
|
|
|
const ncnn::ParamDict base = pd;
|
|
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 4, ncnn::Mat(0), -1)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 5, ncnn::Mat(0), -1)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 6, ncnn::Mat(0), -1))
|
|
return -1;
|
|
|
|
ncnn::Mat missing_data(0);
|
|
missing_data.w = 1;
|
|
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 4, missing_data, -1)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 5, missing_data, -1)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 6, missing_data, -1))
|
|
return -1;
|
|
|
|
const float invalid[] = {-1.f, 0.5f, 1.f, (float)INT_MAX};
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
mask[0] = invalid[i];
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, -1) != 0)
|
|
return -1;
|
|
}
|
|
mask[0] = 0.f;
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 6, ncnn::Mat(), -1) != 0)
|
|
return -1;
|
|
|
|
{
|
|
ncnn::ParamDict pd = base;
|
|
pd.set(6, ncnn::Mat());
|
|
pd.set(4, biases.range(0, 1));
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, -1) != 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_load_param_values()
|
|
{
|
|
ncnn::ParamDict pd;
|
|
pd.set(0, 1);
|
|
pd.set(1, 1);
|
|
ncnn::Mat biases(2);
|
|
biases.fill(1.f);
|
|
pd.set(4, biases);
|
|
ncnn::Mat mask(2);
|
|
mask.fill(0.f);
|
|
pd.set(5, mask);
|
|
ncnn::Mat scales(2);
|
|
scales.fill(32.f);
|
|
pd.set(6, scales);
|
|
|
|
const float valid[] = {0.5f, 1.f, 33.6f, 2147483520.f};
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
biases.fill(valid[i]);
|
|
scales.fill(valid[i]);
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, 0) != 0)
|
|
return -1;
|
|
}
|
|
biases.fill(1.f);
|
|
scales.fill(32.f);
|
|
|
|
// zero, negative zero, negative values, infinities and nan
|
|
const unsigned int invalid[] = {0x00000000u, 0x80000000u, 0xbf800000u, 0x7f800000u, 0xff800000u, 0x7fc00000u, 0x7f800001u};
|
|
for (int i = 0; i < 7; i++)
|
|
{
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
memcpy((float*)biases + j, &invalid[i], sizeof(float));
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, -1) != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_values failed biases[%d]=0x%08x\n", j, invalid[i]);
|
|
return -1;
|
|
}
|
|
biases[j] = 1.f;
|
|
|
|
memcpy((float*)scales + j, &invalid[i], sizeof(float));
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, -1) != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_values failed anchors_scale[%d]=0x%08x\n", j, invalid[i]);
|
|
return -1;
|
|
}
|
|
scales[j] = 32.f;
|
|
}
|
|
}
|
|
|
|
const unsigned int boundaries[] = {0x4effffffu, 0x4f000000u, 0x4f000001u};
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
memcpy((float*)scales + j, &boundaries[i], sizeof(float));
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, i == 0 ? 0 : -1) != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_values failed anchors_scale[%d]=0x%08x\n", j, boundaries[i]);
|
|
return -1;
|
|
}
|
|
scales[j] = 32.f;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_load_param_unused()
|
|
{
|
|
ncnn::ParamDict base;
|
|
base.set(0, 1);
|
|
base.set(1, 1);
|
|
ncnn::Mat biases(6);
|
|
biases.fill(1.f);
|
|
base.set(4, biases);
|
|
ncnn::Mat mask(2);
|
|
mask[0] = 2.f;
|
|
mask[1] = 0.f;
|
|
base.set(5, mask);
|
|
ncnn::Mat scales(3);
|
|
scales.fill(32.f);
|
|
base.set(6, scales);
|
|
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 0)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 6, scales.range(0, 1), -1))
|
|
return -1;
|
|
|
|
// unused anchors and scales may contain values that would otherwise be rejected
|
|
const unsigned int invalid[] = {0x00000000u, 0x80000000u, 0xbf800000u, 0x7f800000u, 0xff800000u, 0x7fc00000u, 0x7f800001u};
|
|
for (int i = 0; i < 7; i++)
|
|
{
|
|
memcpy((float*)scales + 2, &invalid[i], sizeof(float));
|
|
for (int anchor = 0; anchor < 3; anchor++)
|
|
{
|
|
mask[0] = (float)((anchor + 1) % 3);
|
|
mask[1] = (float)((anchor + 2) % 3);
|
|
ncnn::Mat used_mask = mask.clone();
|
|
used_mask[1] = (float)anchor;
|
|
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
memcpy((float*)biases + anchor * 2 + j, &invalid[i], sizeof(float));
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 0)
|
|
|| test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, 5, used_mask, -1))
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_unused failed anchor=%d component=%d value=0x%08x\n", anchor, j, invalid[i]);
|
|
return -1;
|
|
}
|
|
biases[anchor * 2 + j] = 1.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if NCNN_STRING
|
|
static int test_yolov3detectionoutput_load_param_text(const char* mask, int expected_ret)
|
|
{
|
|
TestParamDict pd;
|
|
if (pd.load_param(mask) != 0)
|
|
return -1;
|
|
|
|
const float b[] = {10, 14, 23, 27, 37, 58, 81, 82, 135, 169, 344, 319};
|
|
const float s[] = {33.6, 16.8};
|
|
ncnn::Mat biases = create_mat_from(b, sizeof(b) / sizeof(b[0]));
|
|
ncnn::Mat anchors_scale = create_mat_from(s, sizeof(s) / sizeof(s[0]));
|
|
|
|
pd.set(0, 80);
|
|
pd.set(1, 3);
|
|
pd.set(4, biases);
|
|
pd.set(6, anchors_scale);
|
|
int ret = test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, expected_ret);
|
|
if (ret != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_text failed mask=%s\n", mask);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_load_param_values_text(const char* params, int expected_ret)
|
|
{
|
|
TestParamDict pd;
|
|
if (pd.load_param(params) != 0)
|
|
return -1;
|
|
|
|
pd.set(0, 1);
|
|
pd.set(1, 1);
|
|
ncnn::Mat mask(1);
|
|
mask.fill(0.f);
|
|
pd.set(5, mask);
|
|
|
|
int ret = test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, expected_ret);
|
|
if (ret != 0)
|
|
{
|
|
fprintf(stderr, "test_yolov3detectionoutput_load_param_values_text failed params=%s\n", params);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
static int test_yolov3detectionoutput_load_param_text()
|
|
{
|
|
#if NCNN_STRING
|
|
return 0
|
|
// integer bit patterns written by ModelWriter for yolov4-tiny
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,1077936128,1082130432,1084227584,1065353216,1073741824,1077936128", 0)
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,3.0,4.0,5.0,1.0,2.0,3.0", 0)
|
|
// negative, fractional, out-of-range, infinite and nan indices
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,-1082130432,1082130432,1084227584,1065353216,1073741824,1077936128", -1)
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,1056964608,1082130432,1084227584,1065353216,1073741824,1077936128", -1)
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,1086324736,1082130432,1084227584,1065353216,1073741824,1077936128", -1)
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,2139095040,1082130432,1084227584,1065353216,1073741824,1077936128", -1)
|
|
|| test_yolov3detectionoutput_load_param_text("-23305=6,2143289344,1082130432,1084227584,1065353216,1073741824,1077936128", -1);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_load_param_values_text()
|
|
{
|
|
#if NCNN_STRING
|
|
return 0
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,32", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,0.5,1.5 -23306=1,0.5", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=4,10,14,0,-1 -23306=2,32,2147483647", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=4,10.0,14.0,0.0,-1.0 -23306=2,32.0,2147483648.0", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,0,14 -23306=1,32", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,-1 -23306=1,32", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,0", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,-1", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483520", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483583", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483584", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483520.0", 0)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483647.0", -1)
|
|
|| test_yolov3detectionoutput_load_param_values_text("-23304=2,10,14 -23306=1,2147483647", -1);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int test_yolov3detectionoutput_load_param_thresholds()
|
|
{
|
|
ncnn::ParamDict base;
|
|
base.set(0, 1);
|
|
base.set(1, 1);
|
|
ncnn::Mat biases(2);
|
|
biases.fill(1.f);
|
|
base.set(4, biases);
|
|
ncnn::Mat mask(1);
|
|
mask.fill(0.f);
|
|
base.set(5, mask);
|
|
ncnn::Mat scales(1);
|
|
scales.fill(32.f);
|
|
base.set(6, scales);
|
|
|
|
const float valid[] = {-1.f, 0.f, 0.5f, 1.f, 2.f};
|
|
const unsigned int special[] = {0x7f800000u, 0xff800000u, 0x7fc00000u, 0xffc00000u, 0x7f800001u, 0xff800001u};
|
|
for (int id = 2; id <= 3; id++)
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, id, valid[i], 0) != 0)
|
|
return -1;
|
|
}
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
float value;
|
|
memcpy(&value, &special[i], sizeof(value));
|
|
const int expected_ret = i < 2 ? 0 : -1;
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, base, id, value, expected_ret) != 0)
|
|
return -1;
|
|
|
|
// binary scalar parameters have no integer or float type tag
|
|
unsigned char binary[] = {0, 0, 0, 0, 0, 0, 0, 0, 0x17, 0xff, 0xff, 0xff};
|
|
binary[0] = (unsigned char)id;
|
|
for (int j = 0; j < 4; j++)
|
|
binary[4 + j] = (unsigned char)(special[i] >> (j * 8));
|
|
|
|
TestParamDict pd;
|
|
if (pd.load_param_bin(binary) != 0)
|
|
return -1;
|
|
pd.set(0, 1);
|
|
pd.set(1, 1);
|
|
pd.set(4, biases);
|
|
pd.set(5, mask);
|
|
pd.set(6, scales);
|
|
if (test_layer_param(ncnn::LayerType::Yolov3DetectionOutput, pd, expected_ret) != 0)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif // NCNN_VALIDATION
|
|
|
|
int main()
|
|
{
|
|
SRAND(7767517);
|
|
|
|
return 0
|
|
|| test_yolov3detectionoutput_v3tiny()
|
|
|| test_yolov3detectionoutput_v3()
|
|
|| test_yolov3detectionoutput_v4tiny()
|
|
|| test_yolov3detectionoutput_v4()
|
|
#if NCNN_VALIDATION
|
|
|| test_yolov3detectionoutput_load_param()
|
|
|| test_yolov3detectionoutput_load_param_text()
|
|
|| test_yolov3detectionoutput_load_param_values()
|
|
|| test_yolov3detectionoutput_load_param_unused()
|
|
|| test_yolov3detectionoutput_load_param_values_text()
|
|
|| test_yolov3detectionoutput_load_param_thresholds()
|
|
#endif // NCNN_VALIDATION
|
|
;
|
|
}
|