Skip to content

Commit 26a122f

Browse files
committed
up
1 parent 050da98 commit 26a122f

5 files changed

Lines changed: 233 additions & 106 deletions

File tree

docs/developer-guide/param-and-model-file-structure.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ the meaning of existing param key index can be looked up at [operation-param-wei
4646
* integer array value : [array size],int,int,...,int
4747
* float array value : [array size],float,float,...,float
4848

49-
Use a decimal point or exponent for floating-point scalar values, including integral values, for example `1=6.0`, `1=6e0`, or `1=0.0`. Integer spellings such as `1=6` denote integer parameters and must not be used for floating-point attributes.
49+
Use a decimal point or exponent when generating floating-point scalar values, including integral values, for example `1=6.0`, `1=6e0`, or `1=0.0`. When loading text parameters, the float getter also converts integer spellings such as `1=6` and `1=0` to `6.0f` and `0.0f`. The int getter does not convert floating-point parameters to integers.
50+
51+
Keep floating-point spellings when converting models with `ncnn2mem`: binary scalar parameters do not retain integer/float type tags, and the converter writes integer spellings as integer bit patterns without this numeric conversion.
5052

5153
Use a decimal point or exponent for every element of a floating-point array, including integral values, for example `-23303=2,1.0,2.0`. Mixed integer and float element spellings within an array are not defined by the format.
5254

src/paramdict.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ int ParamDict::get(int id, int def) const
117117
float ParamDict::get(int id, float def) const
118118
{
119119
const int t = type(id);
120+
if (t == 2)
121+
return (float)d->params[id].i;
120122
return t == 1 || t == 3 ? d->params[id].f : def;
121123
}
122124

@@ -178,6 +180,7 @@ void ParamDict::clear()
178180
}
179181
}
180182

183+
// keep array length checks in sync with tools/ncnn2mem.cpp
181184
static size_t max_array_length()
182185
{
183186
// leave room for Mat alignment, the reference count and fastMalloc overhead
@@ -403,7 +406,7 @@ int ParamDict::load_param(const DataReader& dr)
403406
}
404407
if (!long_line.empty())
405408
long_line.push_back('\0');
406-
const char* p = long_line.empty() ? line : long_line.data();
409+
const char* p = long_line.empty() ? line : &long_line[0];
407410

408411
while (1)
409412
{

src/paramdict.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class NCNN_EXPORT ParamDict
3636
// get int
3737
int get(int id, int def) const;
3838
// get float
39-
// integer 0 is a type mismatch; use set(id, 0.f) or text id=0.0 for floating-point zero
39+
// integer parameters are converted to float
4040
float get(int id, float def) const;
4141
// get array
4242
Mat get(int id, const Mat& def) const;

tests/test_paramdict.cpp

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -715,13 +715,13 @@ static int test_paramdict_access()
715715
return -1;
716716
}
717717
}
718-
if (pd.get(0, 0) != 10 || pd.get(31, 0) != 31)
718+
if (pd.get(0, 0) != 10 || pd.get(0, 7.f) != 10.f || pd.get(31, 0) != 31)
719719
{
720720
fprintf(stderr, "ParamDict valid id access failed\n");
721721
return -1;
722722
}
723723

724-
if (pd.get(0, 7.f) != 7.f || pd.get(1, 7) != 7
724+
if (pd.get(1, 7) != 7
725725
|| pd.get(2, 7) != 7 || pd.get(2, 7.f) != 7.f
726726
|| pd.get(3, 7) != 7 || pd.get(3, 7.f) != 7.f
727727
|| pd.get(0, array).data != array.data || pd.get(0, text) != text
@@ -741,8 +741,11 @@ static int test_paramdict_access()
741741
assigned = pd;
742742
const ncnn::ParamDict& alias = assigned;
743743
assigned = alias;
744-
if (!copied.get(2, ncnn::Mat()).empty() || copied.get(3, std::string()) != ""
745-
|| !assigned.get(2, ncnn::Mat()).empty() || assigned.get(3, std::string()) != ""
744+
ncnn::Mat fallback_array(1);
745+
((int*)fallback_array)[0] = 99;
746+
const std::string fallback_text = "fallback";
747+
if (copied.get(2, fallback_array).data != fallback_array.data || copied.get(3, fallback_text) != fallback_text
748+
|| assigned.get(2, fallback_array).data != fallback_array.data || assigned.get(3, fallback_text) != fallback_text
746749
|| copied.get(2, 0) != 22 || assigned.get(3, 0) != 33)
747750
{
748751
fprintf(stderr, "ParamDict retagged copy access failed\n");
@@ -759,29 +762,34 @@ static int test_paramdict_access()
759762
return 0;
760763
}
761764

762-
static int test_paramdict_zero_type()
765+
static int test_paramdict_numeric_conversion()
763766
{
764-
const char* text = "0=0 1=0.0";
765-
for (int mode = 0; mode < 2; mode++)
766-
{
767-
ParamDictTest pd;
768-
if (mode == 0)
767+
const int integers[] = {0, 6, -6, 16777217, INT_MIN, INT_MAX};
768+
const float expected[] = {0.f, 6.f, -6.f, 16777216.f, -2147483648.f, 2147483648.f};
769+
for (size_t j = 0; j < sizeof(integers) / sizeof(integers[0]); j++)
770+
for (int mode = 0; mode < 2; mode++)
769771
{
770-
pd.set(0, 0);
771-
pd.set(1, 0.f);
772-
}
773-
else
774-
{
775-
if (pd.load_param(text))
772+
ParamDictTest pd;
773+
if (mode == 0)
774+
{
775+
pd.set(0, integers[j]);
776+
pd.set(1, 0.f);
777+
}
778+
else
779+
{
780+
char text[64];
781+
snprintf(text, sizeof(text), "0=%d 1=0.0", integers[j]);
782+
if (pd.load_param(text))
783+
return -1;
784+
}
785+
if (pd.get(0, 7.f) != expected[j] || pd.type(0) != 2 || pd.get(0, 7) != integers[j]
786+
|| pd.type(1) != 3 || pd.get(1, 7.f) != 0.f || pd.get(1, 7) != 7
787+
|| pd.get(2, 7.f) != 7.f)
788+
{
789+
fprintf(stderr, "ParamDict numeric conversion failed value=%d mode=%d\n", integers[j], mode);
776790
return -1;
791+
}
777792
}
778-
if (pd.type(0) != 2 || pd.get(0, 7) != 0 || pd.get(0, 7.f) != 7.f
779-
|| pd.type(1) != 3 || pd.get(1, 7.f) != 0.f || pd.get(1, 7) != 7)
780-
{
781-
fprintf(stderr, "ParamDict zero type access failed mode=%d\n", mode);
782-
return -1;
783-
}
784-
}
785793
return 0;
786794
}
787795

@@ -884,6 +892,22 @@ static int test_paramdict_text_boundaries()
884892
}
885893
}
886894

895+
// accept signs, leading zeroes and trailing commas without changing element types
896+
if (pd.load_param("0=+7 1=0007 -23302=1,+2 3=1,2, 4=+1.5 5=1.0,2.0,"))
897+
return -1;
898+
a = pd.get(2, ncnn::Mat());
899+
b = pd.get(3, ncnn::Mat());
900+
c = pd.get(5, ncnn::Mat());
901+
if (pd.type(0) != 2 || pd.get(0, 0) != 7 || pd.type(1) != 2 || pd.get(1, 0) != 7
902+
|| pd.type(2) != 5 || a.w != 1 || ((const int*)a)[0] != 2
903+
|| pd.type(3) != 5 || b.w != 2 || ((const int*)b)[0] != 1 || ((const int*)b)[1] != 2
904+
|| pd.type(4) != 3 || pd.get(4, 0.f) != 1.5f
905+
|| pd.type(5) != 6 || c.w != 2 || c[0] != 1.f || c[1] != 2.f)
906+
{
907+
fprintf(stderr, "ParamDict numeric spelling failed\n");
908+
return -1;
909+
}
910+
887911
// lines may end at a read-buffer boundary or split a quoted/numeric token across it
888912
const int line_lengths[] = {1022, 1023, 1024, 1035, 1048, 2046, 2047};
889913
for (size_t j = 0; j < sizeof(line_lengths) / sizeof(line_lengths[0]); j++)
@@ -981,14 +1005,20 @@ static int check_float_boundary(const char* text, float expected, int count, boo
9811005

9821006
static int test_paramdict_float_boundaries()
9831007
{
984-
// old array elements retain the full numeric token limit
1008+
// old and modern array elements retain the full numeric token limit
9851009
for (int len = 127; len <= 128; len++)
9861010
{
9871011
std::string text = "-23300=1,0.";
9881012
text += make_param_string(len - 2, '0');
9891013
text += " 1=42\nReLU next 1 1 in out\n";
9901014
if (check_float_boundary(text.c_str(), 0.f, 1, len == 127))
9911015
return -1;
1016+
1017+
text = "0=0.0,1.";
1018+
text += make_param_string(len - 2, '0');
1019+
text += " 1=42\nReLU next 1 1 in out\n";
1020+
if (check_float_boundary(text.c_str(), 0.f, 2, len == 127))
1021+
return -1;
9921022
}
9931023

9941024
const char* numbers[] = {
@@ -999,13 +1029,13 @@ static int test_paramdict_float_boundaries()
9991029
"340282356779733661637539395458142568447.0", "340282356779733661637539395458142568448.0",
10001030
"340282356779733661637539395458142568449.0",
10011031
"0.000340282356779733661637539395458142568447e42",
1002-
"000340282356779733661637539395458142568448e0"
1032+
"000340282356779733661637539395458142568448e0", "1e-46"
10031033
};
10041034
const float expected[] = {
10051035
32768.015625f, 32768.015625f, 32768.01953125f, 32768.01953125f, 32768.0234375f, 32768.0234375f,
1006-
FLT_MAX, FLT_MAX, FLT_MAX, 3.402823e38f, 0.f, 0.f, FLT_MAX, 0.f, FLT_MAX, 0.f, 0.f, FLT_MAX, 0.f
1036+
FLT_MAX, FLT_MAX, FLT_MAX, 3.402823e38f, 0.f, 0.f, FLT_MAX, 0.f, FLT_MAX, 0.f, 0.f, FLT_MAX, 0.f, 0.f
10071037
};
1008-
const bool valid[] = {true, true, true, true, true, true, true, true, true, true, false, false, true, false, true, false, false, true, false};
1038+
const bool valid[] = {true, true, true, true, true, true, true, true, true, true, false, false, true, false, true, false, false, true, false, true};
10091039
for (size_t i = 0; i < sizeof(numbers) / sizeof(numbers[0]); i++)
10101040
for (int negative = 0; negative < 2; negative++)
10111041
{
@@ -1178,7 +1208,7 @@ static int test_paramdict_reload()
11781208
{
11791209
const bool binary = mode == 2;
11801210
const char* input = mode == 0 ? text : old_array_text;
1181-
const unsigned char* ptr = binary ? data.data() : (const unsigned char*)input;
1211+
const unsigned char* ptr = binary ? &data[0] : (const unsigned char*)input;
11821212
ncnn::DataReaderFromMemory dr(ptr);
11831213
const int ret = check_paramdict_reload(dr, binary);
11841214
if (ret != 0)
@@ -1201,7 +1231,7 @@ static int test_paramdict_binary_bounds()
12011231
append_param_word(data, ids[i]);
12021232
append_param_word(data, lengths[j]);
12031233
append_param_word(data, -233);
1204-
BoundedParamReader reader(data.data(), data.size());
1234+
BoundedParamReader reader(&data[0], data.size());
12051235
ParamDictTest pd;
12061236
if (pd.load_param_bin(reader) == 0)
12071237
{
@@ -1216,7 +1246,7 @@ static int test_paramdict_binary_bounds()
12161246
std::vector<unsigned char> data;
12171247
append_param_word(data, invalid_ids[i]);
12181248
append_param_word(data, -233);
1219-
BoundedParamReader reader(data.data(), data.size());
1249+
BoundedParamReader reader(&data[0], data.size());
12201250
ParamDictTest pd;
12211251
if (pd.load_param_bin(reader) == 0)
12221252
{
@@ -1231,7 +1261,7 @@ static int test_paramdict_binary_bounds()
12311261
std::vector<unsigned char> data;
12321262
append_param_word(data, -23400);
12331263
append_param_word(data, invalid_string_lengths[i]);
1234-
BoundedParamReader reader(data.data(), data.size());
1264+
BoundedParamReader reader(&data[0], data.size());
12351265
ParamDictTest pd;
12361266
if (pd.load_param_bin(reader) == 0)
12371267
{
@@ -1245,7 +1275,7 @@ static int test_paramdict_binary_bounds()
12451275
std::vector<unsigned char> data;
12461276
append_param_word(data, -23300);
12471277
append_param_word(data, 0x40000000); // byte count wraps on 32-bit targets
1248-
BoundedParamReader reader(data.data(), data.size());
1278+
BoundedParamReader reader(&data[0], data.size());
12491279
ParamDictTest pd;
12501280
if (pd.load_param_bin(reader) == 0 || check_text_result("-23300=1073741824", false))
12511281
{
@@ -1285,7 +1315,7 @@ static int test_paramdict_binary_bounds()
12851315
append_param_word(data, 99);
12861316
append_param_word(data, -233);
12871317
ParamDictTest pd;
1288-
BoundedParamReader reader(data.data(), data.size());
1318+
BoundedParamReader reader(&data[0], data.size());
12891319
if (pd.load_param_bin(reader) || pd.get(0, 0) != 0x3f800000 || pd.get(0, 0.f) != 1.f
12901320
|| pd.get(1, ncnn::Mat()).w != 1 || pd.get(1, ncnn::Mat())[0] != 1.f
12911321
|| pd.type(2) != 4 || !pd.get(2, ncnn::Mat()).empty()
@@ -1308,7 +1338,7 @@ static int test_paramdict_binary_bounds()
13081338
// every truncation, including missing EOP and short scalar/array/string data, fails
13091339
for (size_t size = 0; size < data.size(); size++)
13101340
{
1311-
BoundedParamReader truncated(data.data(), size);
1341+
BoundedParamReader truncated(&data[0], size);
13121342
ParamDictTest partial;
13131343
if (partial.load_param_bin(truncated) == 0)
13141344
{
@@ -1330,7 +1360,7 @@ int main()
13301360
|| test_paramdict_5()
13311361
|| test_paramdict_6()
13321362
|| test_paramdict_access()
1333-
|| test_paramdict_zero_type()
1363+
|| test_paramdict_numeric_conversion()
13341364
|| test_paramdict_invalid_text()
13351365
|| test_paramdict_text_boundaries()
13361366
|| test_paramdict_float_boundaries()

0 commit comments

Comments
 (0)