You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

paramdict.cpp 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // Copyright 2017 Tencent
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. #include "paramdict.h"
  4. #include "datareader.h"
  5. #include "mat.h"
  6. #include "platform.h"
  7. #include <ctype.h>
  8. #if NCNN_STDIO
  9. #include <stdio.h>
  10. #endif
  11. namespace ncnn {
  12. class ParamDictPrivate
  13. {
  14. public:
  15. struct
  16. {
  17. // 0 = null
  18. // 1 = int/float
  19. // 2 = int
  20. // 3 = float
  21. // 4 = array of int/float
  22. // 5 = array of int
  23. // 6 = array of float
  24. // 7 = string
  25. int type;
  26. union
  27. {
  28. int i;
  29. float f;
  30. };
  31. Mat v;
  32. std::string s;
  33. } params[NCNN_MAX_PARAM_COUNT];
  34. };
  35. ParamDict::ParamDict()
  36. : d(new ParamDictPrivate)
  37. {
  38. clear();
  39. }
  40. ParamDict::~ParamDict()
  41. {
  42. delete d;
  43. }
  44. ParamDict::ParamDict(const ParamDict& rhs)
  45. : d(new ParamDictPrivate)
  46. {
  47. for (int i = 0; i < NCNN_MAX_PARAM_COUNT; i++)
  48. {
  49. int type = rhs.d->params[i].type;
  50. d->params[i].type = type;
  51. if (type == 1 || type == 2 || type == 3)
  52. {
  53. d->params[i].i = rhs.d->params[i].i;
  54. }
  55. else if (type == 7)
  56. {
  57. d->params[i].s = rhs.d->params[i].s;
  58. }
  59. else // if (type == 4 || type == 5 || type == 6)
  60. {
  61. d->params[i].v = rhs.d->params[i].v;
  62. }
  63. }
  64. }
  65. ParamDict& ParamDict::operator=(const ParamDict& rhs)
  66. {
  67. if (this == &rhs)
  68. return *this;
  69. for (int i = 0; i < NCNN_MAX_PARAM_COUNT; i++)
  70. {
  71. int type = rhs.d->params[i].type;
  72. d->params[i].type = type;
  73. if (type == 1 || type == 2 || type == 3)
  74. {
  75. d->params[i].i = rhs.d->params[i].i;
  76. }
  77. else if (type == 7)
  78. {
  79. d->params[i].s = rhs.d->params[i].s;
  80. }
  81. else // if (type == 4 || type == 5 || type == 6)
  82. {
  83. d->params[i].v = rhs.d->params[i].v;
  84. }
  85. }
  86. return *this;
  87. }
  88. int ParamDict::type(int id) const
  89. {
  90. return d->params[id].type;
  91. }
  92. // TODO strict type check
  93. int ParamDict::get(int id, int def) const
  94. {
  95. return d->params[id].type ? d->params[id].i : def;
  96. }
  97. float ParamDict::get(int id, float def) const
  98. {
  99. return d->params[id].type ? d->params[id].f : def;
  100. }
  101. Mat ParamDict::get(int id, const Mat& def) const
  102. {
  103. return d->params[id].type ? d->params[id].v : def;
  104. }
  105. std::string ParamDict::get(int id, const std::string& def) const
  106. {
  107. return d->params[id].type ? d->params[id].s : def;
  108. }
  109. void ParamDict::set(int id, int i)
  110. {
  111. d->params[id].type = 2;
  112. d->params[id].i = i;
  113. }
  114. void ParamDict::set(int id, float f)
  115. {
  116. d->params[id].type = 3;
  117. d->params[id].f = f;
  118. }
  119. void ParamDict::set(int id, const Mat& v)
  120. {
  121. d->params[id].type = 4;
  122. d->params[id].v = v;
  123. }
  124. void ParamDict::set(int id, const std::string& s)
  125. {
  126. d->params[id].type = 7;
  127. d->params[id].s = s;
  128. }
  129. void ParamDict::clear()
  130. {
  131. for (int i = 0; i < NCNN_MAX_PARAM_COUNT; i++)
  132. {
  133. d->params[i].type = 0;
  134. d->params[i].i = 0;
  135. d->params[i].v = Mat();
  136. d->params[i].s.clear();
  137. }
  138. }
  139. #if NCNN_STRING
  140. static bool vstr_is_float(const char vstr[16])
  141. {
  142. // look ahead for determine isfloat
  143. for (int j = 0; j < 16; j++)
  144. {
  145. if (vstr[j] == '\0')
  146. break;
  147. if (vstr[j] == '.' || tolower(vstr[j]) == 'e')
  148. return true;
  149. }
  150. return false;
  151. }
  152. static bool vstr_is_string(const char vstr[16])
  153. {
  154. return isalpha(vstr[0]) || vstr[0] == '\"';
  155. }
  156. static float vstr_to_float(const char vstr[16])
  157. {
  158. double v = 0.0;
  159. const char* p = vstr;
  160. // sign
  161. bool sign = *p != '-';
  162. if (*p == '+' || *p == '-')
  163. {
  164. p++;
  165. }
  166. // digits before decimal point or exponent
  167. unsigned int v1 = 0;
  168. while (isdigit(*p))
  169. {
  170. v1 = v1 * 10 + (*p - '0');
  171. p++;
  172. }
  173. v = (double)v1;
  174. // digits after decimal point
  175. if (*p == '.')
  176. {
  177. p++;
  178. unsigned int pow10 = 1;
  179. unsigned int v2 = 0;
  180. while (isdigit(*p))
  181. {
  182. v2 = v2 * 10 + (*p - '0');
  183. pow10 *= 10;
  184. p++;
  185. }
  186. v += v2 / (double)pow10;
  187. }
  188. // exponent
  189. if (*p == 'e' || *p == 'E')
  190. {
  191. p++;
  192. // sign of exponent
  193. bool fact = *p != '-';
  194. if (*p == '+' || *p == '-')
  195. {
  196. p++;
  197. }
  198. // digits of exponent
  199. unsigned int expon = 0;
  200. while (isdigit(*p))
  201. {
  202. expon = expon * 10 + (*p - '0');
  203. p++;
  204. }
  205. double scale = 1.0;
  206. while (expon >= 8)
  207. {
  208. scale *= 1e8;
  209. expon -= 8;
  210. }
  211. while (expon > 0)
  212. {
  213. scale *= 10.0;
  214. expon -= 1;
  215. }
  216. v = fact ? v * scale : v / scale;
  217. }
  218. // fprintf(stderr, "v = %f\n", v);
  219. return sign ? (float)v : (float)-v;
  220. }
  221. int ParamDict::load_param(const DataReader& dr)
  222. {
  223. clear();
  224. // 0=100 1=1.250000 -23303=5,0.1,0.2,0.4,0.8,1.0
  225. // 3=0.1,0.2,0.4,0.8,1.0
  226. // parse each key=value pair
  227. int id = 0;
  228. while (dr.scan("%d=", &id) == 1)
  229. {
  230. bool is_array = id <= -23300;
  231. if (is_array)
  232. {
  233. id = -id - 23300;
  234. }
  235. if (id >= NCNN_MAX_PARAM_COUNT)
  236. {
  237. NCNN_LOGE("id < NCNN_MAX_PARAM_COUNT failed (id=%d, NCNN_MAX_PARAM_COUNT=%d)", id, NCNN_MAX_PARAM_COUNT);
  238. return -1;
  239. }
  240. if (is_array)
  241. {
  242. // old style array
  243. int len = 0;
  244. int nscan = dr.scan("%d", &len);
  245. if (nscan != 1)
  246. {
  247. NCNN_LOGE("ParamDict read array length failed");
  248. return -1;
  249. }
  250. d->params[id].v.create(len);
  251. for (int j = 0; j < len; j++)
  252. {
  253. char vstr[16];
  254. nscan = dr.scan(",%15[^,\n ]", vstr);
  255. if (nscan != 1)
  256. {
  257. NCNN_LOGE("ParamDict read array element failed");
  258. return -1;
  259. }
  260. bool is_float = vstr_is_float(vstr);
  261. if (is_float)
  262. {
  263. float* ptr = d->params[id].v;
  264. ptr[j] = vstr_to_float(vstr);
  265. }
  266. else
  267. {
  268. int* ptr = d->params[id].v;
  269. nscan = sscanf(vstr, "%d", &ptr[j]);
  270. if (nscan != 1)
  271. {
  272. NCNN_LOGE("ParamDict parse array element failed");
  273. return -1;
  274. }
  275. }
  276. d->params[id].type = is_float ? 6 : 5;
  277. }
  278. continue;
  279. }
  280. char vstr[16];
  281. char comma[4];
  282. int nscan = dr.scan("%15[^,\n ]", vstr);
  283. if (nscan != 1)
  284. {
  285. NCNN_LOGE("ParamDict read value failed");
  286. return -1;
  287. }
  288. bool is_string = vstr_is_string(vstr);
  289. if (is_string)
  290. {
  291. // scan the remaining string
  292. char vstr2[256];
  293. vstr2[241] = '\0'; // max 255 = 15 + 240
  294. if (vstr[0] == '\"')
  295. {
  296. nscan = dr.scan("%255[^\"\n]\"", vstr2);
  297. }
  298. else
  299. {
  300. nscan = dr.scan("%255[^\n ]", vstr2);
  301. }
  302. if (nscan == 1)
  303. {
  304. if (vstr2[241] != '\0')
  305. {
  306. NCNN_LOGE("string too long (id=%d)", id);
  307. return -1;
  308. }
  309. if (vstr[0] == '\"')
  310. d->params[id].s = std::string(&vstr[1]) + vstr2;
  311. else
  312. d->params[id].s = std::string(vstr) + vstr2;
  313. }
  314. else
  315. {
  316. if (vstr[0] == '\"')
  317. d->params[id].s = std::string(&vstr[1]);
  318. else
  319. d->params[id].s = std::string(vstr);
  320. }
  321. if (d->params[id].s[d->params[id].s.size() - 1] == '\"')
  322. d->params[id].s.resize(d->params[id].s.size() - 1);
  323. d->params[id].type = 7;
  324. continue;
  325. }
  326. bool is_float = vstr_is_float(vstr);
  327. nscan = dr.scan("%1[,]", comma);
  328. is_array = nscan == 1;
  329. if (is_array)
  330. {
  331. std::vector<float> af;
  332. std::vector<int> ai;
  333. if (is_float)
  334. {
  335. af.push_back(vstr_to_float(vstr));
  336. }
  337. else
  338. {
  339. int v = 0;
  340. nscan = sscanf(vstr, "%d", &v);
  341. if (nscan != 1)
  342. {
  343. NCNN_LOGE("ParamDict parse value failed");
  344. return -1;
  345. }
  346. ai.push_back(v);
  347. }
  348. while (1)
  349. {
  350. nscan = dr.scan("%15[^,\n ]", vstr);
  351. if (nscan != 1)
  352. {
  353. break;
  354. }
  355. if (is_float)
  356. {
  357. af.push_back(vstr_to_float(vstr));
  358. }
  359. else
  360. {
  361. int v = 0;
  362. nscan = sscanf(vstr, "%d", &v);
  363. if (nscan != 1)
  364. {
  365. NCNN_LOGE("ParamDict parse value failed");
  366. return -1;
  367. }
  368. ai.push_back(v);
  369. }
  370. nscan = dr.scan("%1[,]", comma);
  371. if (nscan != 1)
  372. {
  373. break;
  374. }
  375. }
  376. if (is_float)
  377. {
  378. d->params[id].v.create((int)af.size());
  379. memcpy(d->params[id].v.data, af.data(), af.size() * 4);
  380. }
  381. else
  382. {
  383. d->params[id].v.create((int)ai.size());
  384. memcpy(d->params[id].v.data, ai.data(), ai.size() * 4);
  385. }
  386. d->params[id].type = is_float ? 6 : 5;
  387. }
  388. else
  389. {
  390. if (is_float)
  391. {
  392. d->params[id].f = vstr_to_float(vstr);
  393. }
  394. else
  395. {
  396. nscan = sscanf(vstr, "%d", &d->params[id].i);
  397. if (nscan != 1)
  398. {
  399. NCNN_LOGE("ParamDict parse value failed");
  400. return -1;
  401. }
  402. }
  403. d->params[id].type = is_float ? 3 : 2;
  404. }
  405. }
  406. return 0;
  407. }
  408. #endif // NCNN_STRING
  409. int ParamDict::load_param_bin(const DataReader& dr)
  410. {
  411. clear();
  412. // binary 0
  413. // binary 100
  414. // binary 1
  415. // binary 1.250000
  416. // binary 3 | array_bit
  417. // binary 5
  418. // binary 0.1
  419. // binary 0.2
  420. // binary 0.4
  421. // binary 0.8
  422. // binary 1.0
  423. // binary -233(EOP)
  424. int id = 0;
  425. size_t nread;
  426. nread = dr.read(&id, sizeof(int));
  427. if (nread != sizeof(int))
  428. {
  429. NCNN_LOGE("ParamDict read id failed %zd", nread);
  430. return -1;
  431. }
  432. #if __BIG_ENDIAN__
  433. swap_endianness_32(&id);
  434. #endif
  435. while (id != -233)
  436. {
  437. bool is_array = id <= -23300;
  438. bool is_string = id <= -23400;
  439. if (is_string)
  440. {
  441. id = -id - 23400;
  442. }
  443. else if (is_array)
  444. {
  445. id = -id - 23300;
  446. }
  447. if (id >= NCNN_MAX_PARAM_COUNT)
  448. {
  449. NCNN_LOGE("id < NCNN_MAX_PARAM_COUNT failed (id=%d, NCNN_MAX_PARAM_COUNT=%d)", id, NCNN_MAX_PARAM_COUNT);
  450. return -1;
  451. }
  452. if (is_string)
  453. {
  454. int len = 0;
  455. nread = dr.read(&len, sizeof(int));
  456. if (nread != sizeof(int))
  457. {
  458. NCNN_LOGE("ParamDict read array length failed %zd", nread);
  459. return -1;
  460. }
  461. #if __BIG_ENDIAN__
  462. swap_endianness_32(&len);
  463. #endif
  464. if (len > 255)
  465. {
  466. NCNN_LOGE("string too long (id=%d)", id);
  467. return -1;
  468. }
  469. size_t len_padded = (len + 3) / 4 * 4;
  470. std::vector<char> tmpstr(len_padded + 1);
  471. char* ptr = (char*)tmpstr.data();
  472. nread = dr.read(ptr, len_padded);
  473. if (nread != len_padded)
  474. {
  475. NCNN_LOGE("ParamDict read string failed %zd", nread);
  476. return -1;
  477. }
  478. tmpstr[len_padded] = '\0';
  479. d->params[id].s = tmpstr.data();
  480. d->params[id].type = 7;
  481. }
  482. else if (is_array)
  483. {
  484. int len = 0;
  485. nread = dr.read(&len, sizeof(int));
  486. if (nread != sizeof(int))
  487. {
  488. NCNN_LOGE("ParamDict read array length failed %zd", nread);
  489. return -1;
  490. }
  491. #if __BIG_ENDIAN__
  492. swap_endianness_32(&len);
  493. #endif
  494. d->params[id].v.create(len);
  495. float* ptr = d->params[id].v;
  496. nread = dr.read(ptr, sizeof(float) * len);
  497. if (nread != sizeof(float) * len)
  498. {
  499. NCNN_LOGE("ParamDict read array element failed %zd", nread);
  500. return -1;
  501. }
  502. #if __BIG_ENDIAN__
  503. for (int i = 0; i < len; i++)
  504. {
  505. swap_endianness_32(ptr + i);
  506. }
  507. #endif
  508. d->params[id].type = 4;
  509. }
  510. else
  511. {
  512. nread = dr.read(&d->params[id].f, sizeof(float));
  513. if (nread != sizeof(float))
  514. {
  515. NCNN_LOGE("ParamDict read value failed %zd", nread);
  516. return -1;
  517. }
  518. #if __BIG_ENDIAN__
  519. swap_endianness_32(&d->params[id].f);
  520. #endif
  521. d->params[id].type = 1;
  522. }
  523. nread = dr.read(&id, sizeof(int));
  524. if (nread != sizeof(int))
  525. {
  526. NCNN_LOGE("ParamDict read EOP failed %zd", nread);
  527. return -1;
  528. }
  529. #if __BIG_ENDIAN__
  530. swap_endianness_32(&id);
  531. #endif
  532. }
  533. return 0;
  534. }
  535. } // namespace ncnn