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.

ncnnoptimize.cpp 42 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include <set>
  15. #include <vector>
  16. // ncnn public header
  17. #include "net.h"
  18. #include "layer.h"
  19. // ncnn private header
  20. #include "layer/batchnorm.h"
  21. #include "layer/bias.h"
  22. #include "layer/binaryop.h"
  23. #include "layer/clip.h"
  24. #include "layer/concat.h"
  25. #include "layer/convolution.h"
  26. #include "layer/convolutiondepthwise.h"
  27. #include "layer/crop.h"
  28. #include "layer/deconvolution.h"
  29. #include "layer/deconvolutiondepthwise.h"
  30. #include "layer/detectionoutput.h"
  31. #include "layer/dropout.h"
  32. #include "layer/eltwise.h"
  33. #include "layer/elu.h"
  34. #include "layer/exp.h"
  35. #include "layer/innerproduct.h"
  36. #include "layer/input.h"
  37. #include "layer/instancenorm.h"
  38. #include "layer/interp.h"
  39. #include "layer/log.h"
  40. #include "layer/lrn.h"
  41. #include "layer/mvn.h"
  42. #include "layer/normalize.h"
  43. #include "layer/padding.h"
  44. #include "layer/permute.h"
  45. #include "layer/pooling.h"
  46. #include "layer/power.h"
  47. #include "layer/prelu.h"
  48. #include "layer/priorbox.h"
  49. #include "layer/proposal.h"
  50. #include "layer/psroipooling.h"
  51. #include "layer/quantize.h"
  52. #include "layer/reduction.h"
  53. #include "layer/relu.h"
  54. #include "layer/reorg.h"
  55. #include "layer/requantize.h"
  56. #include "layer/reshape.h"
  57. #include "layer/roialign.h"
  58. #include "layer/roipooling.h"
  59. #include "layer/scale.h"
  60. #include "layer/slice.h"
  61. #include "layer/shufflechannel.h"
  62. #include "layer/softmax.h"
  63. #include "layer/threshold.h"
  64. #include "layer/unaryop.h"
  65. #include "layer/yolodetectionoutput.h"
  66. #include "layer/yolov3detectionoutput.h"
  67. class NetOptimize : public ncnn::Net
  68. {
  69. public:
  70. int fuse_batchnorm_scale();
  71. int fuse_convolution_batchnorm();
  72. int fuse_convolutiondepthwise_batchnorm();
  73. int fuse_innerproduct_batchnorm();
  74. int fuse_convolution_relu();
  75. int fuse_convolutiondepthwise_relu();
  76. int fuse_innerproduct_relu();
  77. int eliminate_dropout();
  78. public:
  79. int fprintf_param_int_array(int id, const ncnn::Mat& m, FILE* pp);
  80. int fprintf_param_float_array(int id, const ncnn::Mat& m, FILE* pp);
  81. int fwrite_weight_tag(int tag, FILE* bp);
  82. int fwrite_weight_data(const ncnn::Mat& data, FILE* bp);
  83. int save(const char* parampath, const char* binpath);
  84. };
  85. int NetOptimize::fuse_batchnorm_scale()
  86. {
  87. const int layer_count = layers.size();
  88. for (int i=0; i<layer_count; i++)
  89. {
  90. if (layers[i]->type != "BatchNorm")
  91. continue;
  92. // BatchNorm - Scale
  93. int top_blob_index = layers[i]->tops[0];
  94. int j = i + 1;
  95. for (; j<layer_count; j++)
  96. {
  97. if (layers[j]->type != "Scale")
  98. continue;
  99. if (layers[j]->bottoms.size() != 1)
  100. continue;
  101. if (layers[j]->bottoms[0] == top_blob_index)
  102. break;
  103. }
  104. if (j == layer_count)
  105. continue;
  106. // fuse BatchNorm - Scale to BatchNorm
  107. ncnn::BatchNorm* batchnorm = (ncnn::BatchNorm*)layers[i];
  108. ncnn::Scale* scale = (ncnn::Scale*)layers[j];
  109. fprintf(stderr, "fuse_batchnorm_scale %s %s\n", batchnorm->name.c_str(), scale->name.c_str());
  110. {
  111. // v = ((v - mean) / sqrt(var + eps) * slope + bias) * s + b
  112. // = (v - mean) / sqrt(var + eps) * (slope * s) + (bias * s + b)
  113. int channels = batchnorm->channels;
  114. float* slope = batchnorm->slope_data;
  115. float* bias = batchnorm->bias_data;
  116. for (int q=0; q<channels; q++)
  117. {
  118. slope[q] = slope[q] * scale->scale_data[q];
  119. if (scale->bias_term)
  120. bias[q] = bias[q] * scale->scale_data[q] + scale->bias_data[q];
  121. else
  122. bias[q] = bias[q] * scale->scale_data[q];
  123. }
  124. }
  125. int top_blob_index_final = scale->tops[0];
  126. batchnorm->tops[0] = top_blob_index_final;
  127. blobs[top_blob_index_final].producer = i;
  128. scale->type = "ncnnfused";
  129. }
  130. return 0;
  131. }
  132. int NetOptimize::fuse_convolution_batchnorm()
  133. {
  134. const int layer_count = layers.size();
  135. for (int i=0; i<layer_count; i++)
  136. {
  137. if (layers[i]->type != "Convolution")
  138. continue;
  139. // Convolution - BatchNorm
  140. int top_blob_index = layers[i]->tops[0];
  141. int j = i + 1;
  142. for (; j<layer_count; j++)
  143. {
  144. if (layers[j]->type != "BatchNorm")
  145. continue;
  146. if (layers[j]->bottoms.size() != 1)
  147. continue;
  148. if (layers[j]->bottoms[0] == top_blob_index)
  149. break;
  150. }
  151. if (j == layer_count)
  152. continue;
  153. // fuse Convolution - BatchNorm to Convolution
  154. ncnn::Convolution* convolution = (ncnn::Convolution*)layers[i];
  155. ncnn::BatchNorm* batchnorm = (ncnn::BatchNorm*)layers[j];
  156. fprintf(stderr, "fuse_convolution_batchnorm %s %s\n", convolution->name.c_str(), batchnorm->name.c_str());
  157. {
  158. int channels = batchnorm->channels;
  159. float eps = batchnorm->eps;
  160. // a = bias - slope * mean / sqrt(var + eps)
  161. // b = slope / sqrt(var + eps)
  162. // value = value * b + a
  163. std::vector<float> a(channels);
  164. std::vector<float> b(channels);
  165. for (int i=0; i<channels; i++)
  166. {
  167. float sqrt_var = sqrt(batchnorm->var_data[i] + eps);
  168. a[i] = batchnorm->bias_data[i] - batchnorm->slope_data[i] * batchnorm->mean_data[i] / sqrt_var;
  169. b[i] = batchnorm->slope_data[i] / sqrt_var;
  170. }
  171. if (convolution->bias_term == 0)
  172. {
  173. // init bias as zero
  174. convolution->bias_term = 1;
  175. convolution->bias_data = ncnn::Mat(channels);
  176. convolution->bias_data.fill(0.f);
  177. }
  178. const int weight_per_outch = convolution->weight_data_size / channels;
  179. float* weight = convolution->weight_data;
  180. float* bias = convolution->bias_data;
  181. for (int i=0; i<channels; i++)
  182. {
  183. float* conv_weight_outch = weight + weight_per_outch * i;
  184. for (int j=0; j<weight_per_outch; j++)
  185. {
  186. conv_weight_outch[j] *= b[i];
  187. }
  188. bias[i] += a[i];
  189. }
  190. }
  191. int top_blob_index_final = batchnorm->tops[0];
  192. convolution->tops[0] = top_blob_index_final;
  193. blobs[top_blob_index_final].producer = i;
  194. batchnorm->type = "ncnnfused";
  195. }
  196. return 0;
  197. }
  198. int NetOptimize::fuse_convolutiondepthwise_batchnorm()
  199. {
  200. const int layer_count = layers.size();
  201. for (int i=0; i<layer_count; i++)
  202. {
  203. if (layers[i]->type != "ConvolutionDepthWise")
  204. continue;
  205. // ConvolutionDepthWise - BatchNorm
  206. int top_blob_index = layers[i]->tops[0];
  207. int j = i + 1;
  208. for (; j<layer_count; j++)
  209. {
  210. if (layers[j]->type != "BatchNorm")
  211. continue;
  212. if (layers[j]->bottoms.size() != 1)
  213. continue;
  214. if (layers[j]->bottoms[0] == top_blob_index)
  215. break;
  216. }
  217. if (j == layer_count)
  218. continue;
  219. // fuse ConvolutionDepthWise - BatchNorm to ConvolutionDepthWise
  220. ncnn::ConvolutionDepthWise* convolutiondepthwise = (ncnn::ConvolutionDepthWise*)layers[i];
  221. ncnn::BatchNorm* batchnorm = (ncnn::BatchNorm*)layers[j];
  222. fprintf(stderr, "fuse_convolutiondepthwise_batchnorm %s %s\n", convolutiondepthwise->name.c_str(), batchnorm->name.c_str());
  223. {
  224. int channels = batchnorm->channels;
  225. float eps = batchnorm->eps;
  226. // a = bias - slope * mean / sqrt(var + eps)
  227. // b = slope / sqrt(var + eps)
  228. // value = value * b + a
  229. std::vector<float> a(channels);
  230. std::vector<float> b(channels);
  231. for (int i=0; i<channels; i++)
  232. {
  233. float sqrt_var = sqrt(batchnorm->var_data[i] + eps);
  234. a[i] = batchnorm->bias_data[i] - batchnorm->slope_data[i] * batchnorm->mean_data[i] / sqrt_var;
  235. b[i] = batchnorm->slope_data[i] / sqrt_var;
  236. }
  237. if (convolutiondepthwise->bias_term == 0)
  238. {
  239. // init bias as zero
  240. convolutiondepthwise->bias_term = 1;
  241. convolutiondepthwise->bias_data = ncnn::Mat(channels);
  242. convolutiondepthwise->bias_data.fill(0.f);
  243. }
  244. const int weight_per_outch = convolutiondepthwise->weight_data_size / channels;
  245. float* weight = convolutiondepthwise->weight_data;
  246. float* bias = convolutiondepthwise->bias_data;
  247. for (int i=0; i<channels; i++)
  248. {
  249. float* conv_weight_outch = weight + weight_per_outch * i;
  250. for (int j=0; j<weight_per_outch; j++)
  251. {
  252. conv_weight_outch[j] *= b[i];
  253. }
  254. bias[i] += a[i];
  255. }
  256. }
  257. int top_blob_index_final = batchnorm->tops[0];
  258. convolutiondepthwise->tops[0] = top_blob_index_final;
  259. blobs[top_blob_index_final].producer = i;
  260. batchnorm->type = "ncnnfused";
  261. }
  262. return 0;
  263. }
  264. int NetOptimize::fuse_innerproduct_batchnorm()
  265. {
  266. const int layer_count = layers.size();
  267. for (int i=0; i<layer_count; i++)
  268. {
  269. if (layers[i]->type != "InnerProduct")
  270. continue;
  271. // InnerProduct - BatchNorm
  272. int top_blob_index = layers[i]->tops[0];
  273. int j = i + 1;
  274. for (; j<layer_count; j++)
  275. {
  276. if (layers[j]->type != "BatchNorm")
  277. continue;
  278. if (layers[j]->bottoms.size() != 1)
  279. continue;
  280. if (layers[j]->bottoms[0] == top_blob_index)
  281. break;
  282. }
  283. if (j == layer_count)
  284. continue;
  285. // fuse InnerProduct - BatchNorm to InnerProduct
  286. ncnn::InnerProduct* innerproduct = (ncnn::InnerProduct*)layers[i];
  287. ncnn::BatchNorm* batchnorm = (ncnn::BatchNorm*)layers[j];
  288. fprintf(stderr, "fuse_innerproduct_batchnorm %s %s\n", innerproduct->name.c_str(), batchnorm->name.c_str());
  289. {
  290. int channels = batchnorm->channels;
  291. float eps = batchnorm->eps;
  292. // a = bias - slope * mean / sqrt(var + eps)
  293. // b = slope / sqrt(var + eps)
  294. // value = value * b + a
  295. std::vector<float> a(channels);
  296. std::vector<float> b(channels);
  297. for (int i=0; i<channels; i++)
  298. {
  299. float sqrt_var = sqrt(batchnorm->var_data[i] + eps);
  300. a[i] = batchnorm->bias_data[i] - batchnorm->slope_data[i] * batchnorm->mean_data[i] / sqrt_var;
  301. b[i] = batchnorm->slope_data[i] / sqrt_var;
  302. }
  303. if (innerproduct->bias_term == 0)
  304. {
  305. // init bias as zero
  306. innerproduct->bias_term = 1;
  307. innerproduct->bias_data = ncnn::Mat(channels);
  308. innerproduct->bias_data.fill(0.f);
  309. }
  310. const int weight_per_outch = innerproduct->weight_data_size / channels;
  311. float* weight = innerproduct->weight_data;
  312. float* bias = innerproduct->bias_data;
  313. for (int i=0; i<channels; i++)
  314. {
  315. float* conv_weight_outch = weight + weight_per_outch * i;
  316. for (int j=0; j<weight_per_outch; j++)
  317. {
  318. conv_weight_outch[j] *= b[i];
  319. }
  320. bias[i] += a[i];
  321. }
  322. }
  323. int top_blob_index_final = batchnorm->tops[0];
  324. innerproduct->tops[0] = top_blob_index_final;
  325. blobs[top_blob_index_final].producer = i;
  326. batchnorm->type = "ncnnfused";
  327. }
  328. return 0;
  329. }
  330. int NetOptimize::fuse_convolution_relu()
  331. {
  332. const int layer_count = layers.size();
  333. for (int i=0; i<layer_count; i++)
  334. {
  335. if (layers[i]->type != "Convolution")
  336. continue;
  337. // Convolution - ReLU
  338. int top_blob_index = layers[i]->tops[0];
  339. int j = i + 1;
  340. for (; j<layer_count; j++)
  341. {
  342. if (layers[j]->type != "ReLU")
  343. continue;
  344. if (layers[j]->bottoms.size() != 1)
  345. continue;
  346. if (layers[j]->bottoms[0] == top_blob_index)
  347. break;
  348. }
  349. if (j == layer_count)
  350. continue;
  351. // fuse Convolution - ReLU to Convolution
  352. ncnn::Convolution* convolution = (ncnn::Convolution*)layers[i];
  353. ncnn::ReLU* relu = (ncnn::ReLU*)layers[j];
  354. fprintf(stderr, "fuse_convolution_relu %s %s\n", convolution->name.c_str(), relu->name.c_str());
  355. {
  356. //TODO
  357. }
  358. int top_blob_index_final = relu->tops[0];
  359. convolution->tops[0] = top_blob_index_final;
  360. blobs[top_blob_index_final].producer = i;
  361. relu->type = "ncnnfused";
  362. }
  363. return 0;
  364. }
  365. int NetOptimize::fuse_convolutiondepthwise_relu()
  366. {
  367. const int layer_count = layers.size();
  368. for (int i=0; i<layer_count; i++)
  369. {
  370. if (layers[i]->type != "ConvolutionDepthWise")
  371. continue;
  372. // ConvolutionDepthWise - ReLU
  373. int top_blob_index = layers[i]->tops[0];
  374. int j = i + 1;
  375. for (; j<layer_count; j++)
  376. {
  377. if (layers[j]->type != "ReLU")
  378. continue;
  379. if (layers[j]->bottoms.size() != 1)
  380. continue;
  381. if (layers[j]->bottoms[0] == top_blob_index)
  382. break;
  383. }
  384. if (j == layer_count)
  385. continue;
  386. // fuse ConvolutionDepthWise - ReLU to ConvolutionDepthWise
  387. ncnn::ConvolutionDepthWise* convolutiondepthwise = (ncnn::ConvolutionDepthWise*)layers[i];
  388. ncnn::ReLU* relu = (ncnn::ReLU*)layers[j];
  389. fprintf(stderr, "fuse_convolutiondepthwise_relu %s %s\n", convolutiondepthwise->name.c_str(), relu->name.c_str());
  390. {
  391. //TODO
  392. }
  393. int top_blob_index_final = relu->tops[0];
  394. convolutiondepthwise->tops[0] = top_blob_index_final;
  395. blobs[top_blob_index_final].producer = i;
  396. relu->type = "ncnnfused";
  397. }
  398. return 0;
  399. }
  400. int NetOptimize::fuse_innerproduct_relu()
  401. {
  402. const int layer_count = layers.size();
  403. for (int i=0; i<layer_count; i++)
  404. {
  405. if (layers[i]->type != "InnerProduct")
  406. continue;
  407. // InnerProduct - ReLU
  408. int top_blob_index = layers[i]->tops[0];
  409. int j = i + 1;
  410. for (; j<layer_count; j++)
  411. {
  412. if (layers[j]->type != "ReLU")
  413. continue;
  414. if (layers[j]->bottoms.size() != 1)
  415. continue;
  416. if (layers[j]->bottoms[0] == top_blob_index)
  417. break;
  418. }
  419. if (j == layer_count)
  420. continue;
  421. // fuse InnerProduct - ReLU to InnerProduct
  422. ncnn::InnerProduct* innerproduct = (ncnn::InnerProduct*)layers[i];
  423. ncnn::ReLU* relu = (ncnn::ReLU*)layers[j];
  424. fprintf(stderr, "fuse_innerproduct_relu %s %s\n", innerproduct->name.c_str(), relu->name.c_str());
  425. {
  426. //TODO
  427. }
  428. int top_blob_index_final = relu->tops[0];
  429. innerproduct->tops[0] = top_blob_index_final;
  430. blobs[top_blob_index_final].producer = i;
  431. relu->type = "ncnnfused";
  432. }
  433. return 0;
  434. }
  435. int NetOptimize::eliminate_dropout()
  436. {
  437. const int layer_count = layers.size();
  438. for (int i=0; i<layer_count; i++)
  439. {
  440. if (layers[i]->type != "Dropout")
  441. continue;
  442. // TODO
  443. }
  444. return 0;
  445. }
  446. int NetOptimize::fprintf_param_int_array(int id, const ncnn::Mat& m, FILE* pp)
  447. {
  448. const int count = m.w;
  449. const int* ptr = m;
  450. fprintf(pp, " -%d=%d", 23300 + id, count);
  451. for (int i=0; i<count; i++)
  452. {
  453. fprintf(pp, ",%d", ptr[i]);
  454. }
  455. return 0;
  456. }
  457. int NetOptimize::fprintf_param_float_array(int id, const ncnn::Mat& m, FILE* pp)
  458. {
  459. const int count = m.w;
  460. const float* ptr = m;
  461. fprintf(pp, " -%d=%d", 23300 + id, count);
  462. for (int i=0; i<count; i++)
  463. {
  464. fprintf(pp, ",%f", ptr[i]);
  465. }
  466. return 0;
  467. }
  468. int NetOptimize::fwrite_weight_tag(int tag, FILE* bp)
  469. {
  470. fwrite(&tag, sizeof(int), 1, bp);
  471. return 0;
  472. }
  473. int NetOptimize::fwrite_weight_data(const ncnn::Mat& data, FILE* bp)
  474. {
  475. ncnn::Mat data_flattened = data.reshape(data.w * data.h * data.c);
  476. fwrite(data_flattened.data, data_flattened.elemsize, data_flattened.w, bp);
  477. return 0;
  478. }
  479. int NetOptimize::save(const char* parampath, const char* binpath)
  480. {
  481. FILE* pp = fopen(parampath, "wb");
  482. FILE* bp = fopen(binpath, "wb");
  483. fprintf(pp, "7767517\n");
  484. const int layer_count = layers.size();
  485. int layer_count_fused = 0;
  486. std::set<std::string> blob_names;
  487. for (int i=0; i<layer_count; i++)
  488. {
  489. const ncnn::Layer* layer = layers[i];
  490. if (layer->type == "ncnnfused")
  491. continue;
  492. layer_count_fused++;
  493. int bottom_count = layer->bottoms.size();
  494. for (int j=0; j<bottom_count; j++)
  495. {
  496. int bottom_blob_index = layer->bottoms[j];
  497. blob_names.insert(blobs[bottom_blob_index].name);
  498. }
  499. int top_count = layer->tops.size();
  500. for (int j=0; j<top_count; j++)
  501. {
  502. int top_blob_index = layer->tops[j];
  503. blob_names.insert(blobs[top_blob_index].name);
  504. }
  505. }
  506. int blob_count_fused = blob_names.size();
  507. fprintf(pp, "%d %d\n", layer_count_fused, blob_count_fused);
  508. for (int i=0; i<layer_count; i++)
  509. {
  510. const ncnn::Layer* layer = layers[i];
  511. if (layer->type == "ncnnfused")
  512. continue;
  513. int bottom_count = layer->bottoms.size();
  514. int top_count = layer->tops.size();
  515. fprintf(pp, "%-24s %-24s %d %d", layer->type.c_str(), layer->name.c_str(), bottom_count, top_count);
  516. for (int j=0; j<bottom_count; j++)
  517. {
  518. int bottom_blob_index = layer->bottoms[j];
  519. fprintf(pp, " %s", blobs[bottom_blob_index].name.c_str());
  520. }
  521. for (int j=0; j<top_count; j++)
  522. {
  523. int top_blob_index = layer->tops[j];
  524. fprintf(pp, " %s", blobs[top_blob_index].name.c_str());
  525. }
  526. ncnn::Layer* layer_default = ncnn::create_layer(layer->typeindex);
  527. ncnn::ParamDict pd;
  528. layer_default->load_param(pd);
  529. #define fprintf_param_value(format, phase) \
  530. { if (op->phase != op_default->phase) fprintf(pp, format, op->phase); }
  531. if (layer->type == "BatchNorm")
  532. {
  533. ncnn::BatchNorm* op = (ncnn::BatchNorm*)layer;
  534. ncnn::BatchNorm* op_default = (ncnn::BatchNorm*)layer_default;
  535. fprintf_param_value(" 0=%d", channels)
  536. fprintf_param_value(" 1=%f", eps)
  537. fwrite_weight_data(op->slope_data, bp);
  538. fwrite_weight_data(op->mean_data, bp);
  539. fwrite_weight_data(op->var_data, bp);
  540. fwrite_weight_data(op->bias_data, bp);
  541. }
  542. else if (layer->type == "Bias")
  543. {
  544. ncnn::Bias* op = (ncnn::Bias*)layer;
  545. ncnn::Bias* op_default = (ncnn::Bias*)layer_default;
  546. fprintf_param_value(" 0=%d", bias_data_size)
  547. fwrite_weight_data(op->bias_data, bp);
  548. }
  549. else if (layer->type == "BinaryOp")
  550. {
  551. ncnn::BinaryOp* op = (ncnn::BinaryOp*)layer;
  552. ncnn::BinaryOp* op_default = (ncnn::BinaryOp*)layer_default;
  553. fprintf_param_value(" 0=%d", op_type)
  554. fprintf_param_value(" 1=%d", with_scalar)
  555. fprintf_param_value(" 2=%f", b)
  556. }
  557. else if (layer->type == "Clip")
  558. {
  559. ncnn::Clip* op = (ncnn::Clip*)layer;
  560. ncnn::Clip* op_default = (ncnn::Clip*)layer_default;
  561. fprintf_param_value(" 0=%f", min)
  562. fprintf_param_value(" 1=%f", max)
  563. }
  564. else if (layer->type == "Concat")
  565. {
  566. ncnn::Concat* op = (ncnn::Concat*)layer;
  567. ncnn::Concat* op_default = (ncnn::Concat*)layer_default;
  568. fprintf_param_value(" 0=%d", axis)
  569. }
  570. else if (layer->type == "Convolution")
  571. {
  572. ncnn::Convolution* op = (ncnn::Convolution*)layer;
  573. ncnn::Convolution* op_default = (ncnn::Convolution*)layer_default;
  574. fprintf_param_value(" 0=%d", num_output)
  575. fprintf_param_value(" 1=%d", kernel_w)
  576. { if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); }
  577. fprintf_param_value(" 2=%d", dilation_w)
  578. { if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); }
  579. fprintf_param_value(" 3=%d", stride_w)
  580. { if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); }
  581. fprintf_param_value(" 4=%d", pad_w)
  582. { if (op->pad_h != op->pad_w) fprintf(pp, " 14=%d", op->pad_h); }
  583. fprintf_param_value(" 5=%d", bias_term)
  584. fprintf_param_value(" 6=%d", weight_data_size)
  585. fprintf_param_value(" 8=%d", int8_scale_term)
  586. fwrite_weight_tag(0, bp);
  587. fwrite_weight_data(op->weight_data, bp);
  588. fwrite_weight_data(op->bias_data, bp);
  589. }
  590. else if (layer->type == "ConvolutionDepthWise")
  591. {
  592. ncnn::ConvolutionDepthWise* op = (ncnn::ConvolutionDepthWise*)layer;
  593. ncnn::ConvolutionDepthWise* op_default = (ncnn::ConvolutionDepthWise*)layer_default;
  594. fprintf_param_value(" 0=%d", num_output)
  595. fprintf_param_value(" 1=%d", kernel_w)
  596. { if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); }
  597. fprintf_param_value(" 2=%d", dilation_w)
  598. { if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); }
  599. fprintf_param_value(" 3=%d", stride_w)
  600. { if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); }
  601. fprintf_param_value(" 4=%d", pad_w)
  602. { if (op->pad_h != op->pad_w) fprintf(pp, " 14=%d", op->pad_h); }
  603. fprintf_param_value(" 5=%d", bias_term)
  604. fprintf_param_value(" 6=%d", weight_data_size)
  605. fprintf_param_value(" 7=%d", group)
  606. fprintf_param_value(" 8=%d", int8_scale_term)
  607. fwrite_weight_tag(0, bp);
  608. fwrite_weight_data(op->weight_data, bp);
  609. fwrite_weight_data(op->bias_data, bp);
  610. }
  611. else if (layer->type == "Crop")
  612. {
  613. ncnn::Crop* op = (ncnn::Crop*)layer;
  614. ncnn::Crop* op_default = (ncnn::Crop*)layer_default;
  615. fprintf_param_value(" 0=%d", woffset)
  616. fprintf_param_value(" 1=%d", hoffset)
  617. fprintf_param_value(" 2=%d", coffset)
  618. fprintf_param_value(" 3=%d", outw)
  619. fprintf_param_value(" 4=%d", outh)
  620. fprintf_param_value(" 5=%d", outc)
  621. }
  622. else if (layer->type == "Deconvolution")
  623. {
  624. ncnn::Deconvolution* op = (ncnn::Deconvolution*)layer;
  625. ncnn::Deconvolution* op_default = (ncnn::Deconvolution*)layer_default;
  626. fprintf_param_value(" 0=%d", num_output)
  627. fprintf_param_value(" 1=%d", kernel_w)
  628. { if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); }
  629. fprintf_param_value(" 2=%d", dilation_w)
  630. { if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); }
  631. fprintf_param_value(" 3=%d", stride_w)
  632. { if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); }
  633. fprintf_param_value(" 4=%d", pad_w)
  634. { if (op->pad_h != op->pad_w) fprintf(pp, " 14=%d", op->pad_h); }
  635. fprintf_param_value(" 5=%d", bias_term)
  636. fprintf_param_value(" 6=%d", weight_data_size)
  637. fwrite_weight_tag(0, bp);
  638. fwrite_weight_data(op->weight_data, bp);
  639. fwrite_weight_data(op->bias_data, bp);
  640. }
  641. else if (layer->type == "DeconvolutionDepthWise")
  642. {
  643. ncnn::DeconvolutionDepthWise* op = (ncnn::DeconvolutionDepthWise*)layer;
  644. ncnn::DeconvolutionDepthWise* op_default = (ncnn::DeconvolutionDepthWise*)layer_default;
  645. fprintf_param_value(" 0=%d", num_output)
  646. fprintf_param_value(" 1=%d", kernel_w)
  647. { if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); }
  648. fprintf_param_value(" 2=%d", dilation_w)
  649. { if (op->dilation_h != op->dilation_w) fprintf(pp, " 12=%d", op->dilation_h); }
  650. fprintf_param_value(" 3=%d", stride_w)
  651. { if (op->stride_h != op->stride_w) fprintf(pp, " 13=%d", op->stride_h); }
  652. fprintf_param_value(" 4=%d", pad_w)
  653. { if (op->pad_h != op->pad_w) fprintf(pp, " 14=%d", op->pad_h); }
  654. fprintf_param_value(" 5=%d", bias_term)
  655. fprintf_param_value(" 6=%d", weight_data_size)
  656. fprintf_param_value(" 7=%d", group)
  657. fwrite_weight_tag(0, bp);
  658. fwrite_weight_data(op->weight_data, bp);
  659. fwrite_weight_data(op->bias_data, bp);
  660. }
  661. else if (layer->type == "DetectionOutput")
  662. {
  663. ncnn::DetectionOutput* op = (ncnn::DetectionOutput*)layer;
  664. ncnn::DetectionOutput* op_default = (ncnn::DetectionOutput*)layer_default;
  665. fprintf_param_value(" 0=%d", num_class)
  666. fprintf_param_value(" 1=%f", nms_threshold)
  667. fprintf_param_value(" 2=%d", nms_top_k)
  668. fprintf_param_value(" 3=%d", keep_top_k)
  669. fprintf_param_value(" 4=%f", confidence_threshold)
  670. fprintf_param_value(" 5=%f", variances[0])
  671. fprintf_param_value(" 6=%f", variances[1])
  672. fprintf_param_value(" 7=%f", variances[2])
  673. fprintf_param_value(" 8=%f", variances[3])
  674. }
  675. else if (layer->type == "Dropout")
  676. {
  677. ncnn::Dropout* op = (ncnn::Dropout*)layer;
  678. ncnn::Dropout* op_default = (ncnn::Dropout*)layer_default;
  679. fprintf_param_value(" 0=%f", scale)
  680. }
  681. else if (layer->type == "Eltwise")
  682. {
  683. ncnn::Eltwise* op = (ncnn::Eltwise*)layer;
  684. ncnn::Eltwise* op_default = (ncnn::Eltwise*)layer_default;
  685. fprintf_param_value(" 0=%d", op_type)
  686. { if (!op->coeffs.empty()) fprintf_param_int_array(1, op->coeffs, pp); }
  687. }
  688. else if (layer->type == "ELU")
  689. {
  690. ncnn::ELU* op = (ncnn::ELU*)layer;
  691. ncnn::ELU* op_default = (ncnn::ELU*)layer_default;
  692. fprintf_param_value(" 0=%f", alpha)
  693. }
  694. else if (layer->type == "Exp")
  695. {
  696. ncnn::Exp* op = (ncnn::Exp*)layer;
  697. ncnn::Exp* op_default = (ncnn::Exp*)layer_default;
  698. fprintf_param_value(" 0=%f", base)
  699. fprintf_param_value(" 1=%f", scale)
  700. fprintf_param_value(" 2=%f", shift)
  701. }
  702. else if (layer->type == "InnerProduct")
  703. {
  704. ncnn::InnerProduct* op = (ncnn::InnerProduct*)layer;
  705. ncnn::InnerProduct* op_default = (ncnn::InnerProduct*)layer_default;
  706. fprintf_param_value(" 0=%d", num_output)
  707. fprintf_param_value(" 1=%d", bias_term)
  708. fprintf_param_value(" 2=%d", weight_data_size)
  709. fprintf_param_value(" 8=%d", int8_scale_term)
  710. fwrite_weight_tag(0, bp);
  711. fwrite_weight_data(op->weight_data, bp);
  712. fwrite_weight_data(op->bias_data, bp);
  713. }
  714. else if (layer->type == "Input")
  715. {
  716. ncnn::Input* op = (ncnn::Input*)layer;
  717. ncnn::Input* op_default = (ncnn::Input*)layer_default;
  718. fprintf_param_value(" 0=%d", w)
  719. fprintf_param_value(" 1=%d", h)
  720. fprintf_param_value(" 2=%d", c)
  721. }
  722. else if (layer->type == "InstanceNorm")
  723. {
  724. ncnn::InstanceNorm* op = (ncnn::InstanceNorm*)layer;
  725. ncnn::InstanceNorm* op_default = (ncnn::InstanceNorm*)layer_default;
  726. fprintf_param_value(" 0=%d", channels)
  727. fprintf_param_value(" 1=%f", eps)
  728. }
  729. else if (layer->type == "Interp")
  730. {
  731. ncnn::Interp* op = (ncnn::Interp*)layer;
  732. ncnn::Interp* op_default = (ncnn::Interp*)layer_default;
  733. fprintf_param_value(" 0=%d", resize_type)
  734. fprintf_param_value(" 1=%f", height_scale)
  735. fprintf_param_value(" 2=%f", width_scale)
  736. fprintf_param_value(" 3=%d", output_height)
  737. fprintf_param_value(" 4=%d", output_width)
  738. }
  739. else if (layer->type == "Log")
  740. {
  741. ncnn::Log* op = (ncnn::Log*)layer;
  742. ncnn::Log* op_default = (ncnn::Log*)layer_default;
  743. fprintf_param_value(" 0=%f", base)
  744. fprintf_param_value(" 1=%f", scale)
  745. fprintf_param_value(" 2=%f", shift)
  746. }
  747. else if (layer->type == "LRN")
  748. {
  749. ncnn::LRN* op = (ncnn::LRN*)layer;
  750. ncnn::LRN* op_default = (ncnn::LRN*)layer_default;
  751. fprintf_param_value(" 0=%d", region_type)
  752. fprintf_param_value(" 1=%d", local_size)
  753. fprintf_param_value(" 2=%f", alpha)
  754. fprintf_param_value(" 3=%f", beta)
  755. fprintf_param_value(" 4=%f", bias)
  756. }
  757. else if (layer->type == "MVN")
  758. {
  759. ncnn::MVN* op = (ncnn::MVN*)layer;
  760. ncnn::MVN* op_default = (ncnn::MVN*)layer_default;
  761. fprintf_param_value(" 0=%d", normalize_variance)
  762. fprintf_param_value(" 1=%d", across_channels)
  763. fprintf_param_value(" 2=%f", eps)
  764. }
  765. else if (layer->type == "Normalize")
  766. {
  767. ncnn::Normalize* op = (ncnn::Normalize*)layer;
  768. ncnn::Normalize* op_default = (ncnn::Normalize*)layer_default;
  769. fprintf_param_value(" 0=%d", across_spatial)
  770. fprintf_param_value(" 1=%d", channel_shared)
  771. fprintf_param_value(" 2=%f", eps)
  772. fprintf_param_value(" 3=%d", scale_data_size)
  773. fprintf_param_value(" 4=%d", across_channel)
  774. fwrite_weight_data(op->scale_data, bp);
  775. }
  776. else if (layer->type == "Padding")
  777. {
  778. ncnn::Padding* op = (ncnn::Padding*)layer;
  779. ncnn::Padding* op_default = (ncnn::Padding*)layer_default;
  780. fprintf_param_value(" 0=%d", top)
  781. fprintf_param_value(" 1=%d", bottom)
  782. fprintf_param_value(" 2=%d", left)
  783. fprintf_param_value(" 3=%d", right)
  784. fprintf_param_value(" 4=%d", type)
  785. fprintf_param_value(" 5=%f", value)
  786. }
  787. else if (layer->type == "Permute")
  788. {
  789. ncnn::Permute* op = (ncnn::Permute*)layer;
  790. ncnn::Permute* op_default = (ncnn::Permute*)layer_default;
  791. fprintf_param_value(" 0=%d", order_type)
  792. }
  793. else if (layer->type == "Pooling")
  794. {
  795. ncnn::Pooling* op = (ncnn::Pooling*)layer;
  796. ncnn::Pooling* op_default = (ncnn::Pooling*)layer_default;
  797. fprintf_param_value(" 0=%d", pooling_type)
  798. fprintf_param_value(" 1=%d", kernel_w)
  799. { if (op->kernel_h != op->kernel_w) fprintf(pp, " 11=%d", op->kernel_h); }
  800. fprintf_param_value(" 2=%d", stride_w)
  801. { if (op->stride_h != op->stride_w) fprintf(pp, " 12=%d", op->stride_h); }
  802. fprintf_param_value(" 3=%d", pad_left)
  803. { if (op->pad_top != op->pad_left) fprintf(pp, " 13=%d", op->pad_top); }
  804. { if (op->pad_right != op->pad_left) fprintf(pp, " 14=%d", op->pad_right); }
  805. { if (op->pad_bottom != op->pad_top) fprintf(pp, " 15=%d", op->pad_bottom); }
  806. fprintf_param_value(" 4=%d", global_pooling)
  807. fprintf_param_value(" 5=%d", pad_mode)
  808. }
  809. else if (layer->type == "Power")
  810. {
  811. ncnn::Power* op = (ncnn::Power*)layer;
  812. ncnn::Power* op_default = (ncnn::Power*)layer_default;
  813. fprintf_param_value(" 0=%f", power)
  814. fprintf_param_value(" 1=%f", scale)
  815. fprintf_param_value(" 2=%f", shift)
  816. }
  817. else if (layer->type == "PReLU")
  818. {
  819. ncnn::PReLU* op = (ncnn::PReLU*)layer;
  820. ncnn::PReLU* op_default = (ncnn::PReLU*)layer_default;
  821. fprintf_param_value(" 0=%d", num_slope)
  822. fwrite_weight_data(op->slope_data, bp);
  823. }
  824. else if (layer->type == "PriorBox")
  825. {
  826. ncnn::PriorBox* op = (ncnn::PriorBox*)layer;
  827. ncnn::PriorBox* op_default = (ncnn::PriorBox*)layer_default;
  828. { if (!op->min_sizes.empty()) fprintf_param_int_array(0, op->min_sizes, pp); }
  829. { if (!op->max_sizes.empty()) fprintf_param_int_array(1, op->max_sizes, pp); }
  830. { if (!op->aspect_ratios.empty()) fprintf_param_int_array(2, op->aspect_ratios, pp); }
  831. fprintf_param_value(" 3=%f", variances[0])
  832. fprintf_param_value(" 4=%f", variances[1])
  833. fprintf_param_value(" 5=%f", variances[2])
  834. fprintf_param_value(" 6=%f", variances[3])
  835. fprintf_param_value(" 7=%d", flip)
  836. fprintf_param_value(" 8=%d", clip)
  837. fprintf_param_value(" 9=%d", image_width)
  838. fprintf_param_value(" 10=%d", image_height)
  839. fprintf_param_value(" 11=%f", step_width)
  840. fprintf_param_value(" 12=%f", step_height)
  841. fprintf_param_value(" 13=%f", offset)
  842. }
  843. else if (layer->type == "Proposal")
  844. {
  845. ncnn::Proposal* op = (ncnn::Proposal*)layer;
  846. ncnn::Proposal* op_default = (ncnn::Proposal*)layer_default;
  847. fprintf_param_value(" 0=%d", feat_stride)
  848. fprintf_param_value(" 1=%d", base_size)
  849. fprintf_param_value(" 2=%d", pre_nms_topN)
  850. fprintf_param_value(" 3=%d", after_nms_topN)
  851. fprintf_param_value(" 4=%f", nms_thresh)
  852. fprintf_param_value(" 5=%d", min_size)
  853. }
  854. else if (layer->type == "PSROIPooling")
  855. {
  856. ncnn::PSROIPooling* op = (ncnn::PSROIPooling*)layer;
  857. ncnn::PSROIPooling* op_default = (ncnn::PSROIPooling*)layer_default;
  858. fprintf_param_value(" 0=%d", pooled_width)
  859. fprintf_param_value(" 1=%d", pooled_height)
  860. fprintf_param_value(" 2=%f", spatial_scale)
  861. fprintf_param_value(" 3=%d", output_dim)
  862. }
  863. else if (layer->type == "Quantize")
  864. {
  865. ncnn::Quantize* op = (ncnn::Quantize*)layer;
  866. ncnn::Quantize* op_default = (ncnn::Quantize*)layer_default;
  867. fprintf_param_value(" 0=%f", scale)
  868. }
  869. else if (layer->type == "Reduction")
  870. {
  871. ncnn::Reduction* op = (ncnn::Reduction*)layer;
  872. ncnn::Reduction* op_default = (ncnn::Reduction*)layer_default;
  873. fprintf_param_value(" 0=%d", operation)
  874. fprintf_param_value(" 1=%d", dim)
  875. fprintf_param_value(" 2=%f", coeff)
  876. }
  877. else if (layer->type == "ReLU")
  878. {
  879. ncnn::ReLU* op = (ncnn::ReLU*)layer;
  880. ncnn::ReLU* op_default = (ncnn::ReLU*)layer_default;
  881. fprintf_param_value(" 0=%f", slope)
  882. }
  883. else if (layer->type == "Reorg")
  884. {
  885. ncnn::Reorg* op = (ncnn::Reorg*)layer;
  886. ncnn::Reorg* op_default = (ncnn::Reorg*)layer_default;
  887. fprintf_param_value(" 0=%d", stride)
  888. }
  889. else if (layer->type == "Requantize")
  890. {
  891. ncnn::Requantize* op = (ncnn::Requantize*)layer;
  892. ncnn::Requantize* op_default = (ncnn::Requantize*)layer_default;
  893. fprintf_param_value(" 0=%f", scale_in)
  894. fprintf_param_value(" 1=%f", scale_out)
  895. fprintf_param_value(" 2=%d", bias_term)
  896. fprintf_param_value(" 3=%d", bias_data_size)
  897. fprintf_param_value(" 4=%d", fusion_relu)
  898. }
  899. else if (layer->type == "Reshape")
  900. {
  901. ncnn::Reshape* op = (ncnn::Reshape*)layer;
  902. ncnn::Reshape* op_default = (ncnn::Reshape*)layer_default;
  903. fprintf_param_value(" 0=%d", w)
  904. fprintf_param_value(" 1=%d", h)
  905. fprintf_param_value(" 2=%d", c)
  906. fprintf_param_value(" 3=%d", permute)
  907. }
  908. else if (layer->type == "ROIAlign")
  909. {
  910. ncnn::ROIAlign* op = (ncnn::ROIAlign*)layer;
  911. ncnn::ROIAlign* op_default = (ncnn::ROIAlign*)layer_default;
  912. fprintf_param_value(" 0=%d", pooled_width)
  913. fprintf_param_value(" 1=%d", pooled_height)
  914. fprintf_param_value(" 2=%f", spatial_scale)
  915. }
  916. else if (layer->type == "ROIPooling")
  917. {
  918. ncnn::ROIPooling* op = (ncnn::ROIPooling*)layer;
  919. ncnn::ROIPooling* op_default = (ncnn::ROIPooling*)layer_default;
  920. fprintf_param_value(" 0=%d", pooled_width)
  921. fprintf_param_value(" 1=%d", pooled_height)
  922. fprintf_param_value(" 2=%f", spatial_scale)
  923. }
  924. else if (layer->type == "Scale")
  925. {
  926. ncnn::Scale* op = (ncnn::Scale*)layer;
  927. ncnn::Scale* op_default = (ncnn::Scale*)layer_default;
  928. fprintf_param_value(" 0=%d", scale_data_size)
  929. fprintf_param_value(" 1=%d", bias_term)
  930. fwrite_weight_data(op->scale_data, bp);
  931. fwrite_weight_data(op->bias_data, bp);
  932. }
  933. else if (layer->type == "ShuffleChannel")
  934. {
  935. ncnn::ShuffleChannel* op = (ncnn::ShuffleChannel*)layer;
  936. ncnn::ShuffleChannel* op_default = (ncnn::ShuffleChannel*)layer_default;
  937. fprintf_param_value(" 0=%d", group)
  938. }
  939. else if (layer->type == "Slice")
  940. {
  941. ncnn::Slice* op = (ncnn::Slice*)layer;
  942. ncnn::Slice* op_default = (ncnn::Slice*)layer_default;
  943. { if (!op->slices.empty()) fprintf_param_int_array(0, op->slices, pp); }
  944. fprintf_param_value(" 1=%d", axis)
  945. }
  946. else if (layer->type == "Softmax")
  947. {
  948. ncnn::Softmax* op = (ncnn::Softmax*)layer;
  949. ncnn::Softmax* op_default = (ncnn::Softmax*)layer_default;
  950. fprintf_param_value(" 0=%d", axis)
  951. // HACK
  952. if (op->axis != 0)
  953. {
  954. int fixbug0 = 1;
  955. fprintf(pp, " 1=%d", fixbug0);
  956. }
  957. }
  958. else if (layer->type == "Threshold")
  959. {
  960. ncnn::Threshold* op = (ncnn::Threshold*)layer;
  961. ncnn::Threshold* op_default = (ncnn::Threshold*)layer_default;
  962. fprintf_param_value(" 0=%f", threshold)
  963. }
  964. else if (layer->type == "UnaryOp")
  965. {
  966. ncnn::UnaryOp* op = (ncnn::UnaryOp*)layer;
  967. ncnn::UnaryOp* op_default = (ncnn::UnaryOp*)layer_default;
  968. fprintf_param_value(" 0=%d", op_type)
  969. }
  970. else if (layer->type == "YoloDetectionOutput")
  971. {
  972. ncnn::YoloDetectionOutput* op = (ncnn::YoloDetectionOutput*)layer;
  973. ncnn::YoloDetectionOutput* op_default = (ncnn::YoloDetectionOutput*)layer_default;
  974. fprintf_param_value(" 0=%d", num_class)
  975. fprintf_param_value(" 1=%d", num_box)
  976. fprintf_param_value(" 2=%f", confidence_threshold)
  977. fprintf_param_value(" 3=%f", nms_threshold)
  978. { if (!op->biases.empty()) fprintf_param_int_array(4, op->biases, pp); }
  979. }
  980. else if (layer->type == "Yolov3DetectionOutput")
  981. {
  982. ncnn::Yolov3DetectionOutput* op = (ncnn::Yolov3DetectionOutput*)layer;
  983. ncnn::Yolov3DetectionOutput* op_default = (ncnn::Yolov3DetectionOutput*)layer_default;
  984. fprintf_param_value(" 0=%d", num_class)
  985. fprintf_param_value(" 1=%d", num_box)
  986. fprintf_param_value(" 2=%f", confidence_threshold)
  987. fprintf_param_value(" 3=%f", nms_threshold)
  988. { if (!op->biases.empty()) fprintf_param_int_array(4, op->biases, pp); }
  989. { if (!op->mask.empty()) fprintf_param_int_array(5, op->mask, pp); }
  990. { if (!op->anchors_scale.empty()) fprintf_param_int_array(6, op->anchors_scale, pp); }
  991. }
  992. #undef fprintf_param_value
  993. fprintf(pp, "\n");
  994. delete layer_default;
  995. }
  996. fclose(pp);
  997. fclose(bp);
  998. return 0;
  999. }
  1000. int main(int argc, char** argv)
  1001. {
  1002. // in in out out 65535
  1003. const char* inparam = argv[1];
  1004. const char* inbin = argv[2];
  1005. const char* outparam = argv[3];
  1006. const char* outbin = argv[4];
  1007. int flag = atoi(argv[5]);
  1008. NetOptimize optimizer;
  1009. optimizer.load_param(inparam);
  1010. optimizer.load_model(inbin);
  1011. optimizer.fuse_batchnorm_scale();
  1012. optimizer.fuse_convolution_batchnorm();
  1013. optimizer.fuse_convolutiondepthwise_batchnorm();
  1014. optimizer.fuse_innerproduct_batchnorm();
  1015. // optimizer.fuse_convolution_relu();
  1016. // optimizer.fuse_convolutiondepthwise_relu();
  1017. // optimizer.fuse_innerproduct_relu();
  1018. optimizer.save(outparam, outbin);
  1019. return 0;
  1020. }