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.

caffe2ncnn.cpp 29 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2017 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 <stdio.h>
  15. #include <limits.h>
  16. #include <fstream>
  17. #include <set>
  18. #include <limits>
  19. #include <algorithm>
  20. #include <google/protobuf/io/coded_stream.h>
  21. #include <google/protobuf/io/zero_copy_stream_impl.h>
  22. #include <google/protobuf/text_format.h>
  23. #include <google/protobuf/message.h>
  24. #include "caffe.pb.h"
  25. static inline size_t alignSize(size_t sz, int n)
  26. {
  27. return (sz + n-1) & -n;
  28. }
  29. // convert float to half precision floating point
  30. static unsigned short float2half(float value)
  31. {
  32. // 1 : 8 : 23
  33. union
  34. {
  35. unsigned int u;
  36. float f;
  37. } tmp;
  38. tmp.f = value;
  39. // 1 : 8 : 23
  40. unsigned short sign = (tmp.u & 0x80000000) >> 31;
  41. unsigned short exponent = (tmp.u & 0x7F800000) >> 23;
  42. unsigned int significand = tmp.u & 0x7FFFFF;
  43. // fprintf(stderr, "%d %d %d\n", sign, exponent, significand);
  44. // 1 : 5 : 10
  45. unsigned short fp16;
  46. if (exponent == 0)
  47. {
  48. // zero or denormal, always underflow
  49. fp16 = (sign << 15) | (0x00 << 10) | 0x00;
  50. }
  51. else if (exponent == 0xFF)
  52. {
  53. // infinity or NaN
  54. fp16 = (sign << 15) | (0x1F << 10) | (significand ? 0x200 : 0x00);
  55. }
  56. else
  57. {
  58. // normalized
  59. short newexp = exponent + (- 127 + 15);
  60. if (newexp >= 31)
  61. {
  62. // overflow, return infinity
  63. fp16 = (sign << 15) | (0x1F << 10) | 0x00;
  64. }
  65. else if (newexp <= 0)
  66. {
  67. // underflow
  68. if (newexp >= -10)
  69. {
  70. // denormal half-precision
  71. unsigned short sig = (significand | 0x800000) >> (14 - newexp);
  72. fp16 = (sign << 15) | (0x00 << 10) | sig;
  73. }
  74. else
  75. {
  76. // underflow
  77. fp16 = (sign << 15) | (0x00 << 10) | 0x00;
  78. }
  79. }
  80. else
  81. {
  82. fp16 = (sign << 15) | (newexp << 10) | (significand >> 13);
  83. }
  84. }
  85. return fp16;
  86. }
  87. static int quantize_weight(float *data, size_t data_length, std::vector<unsigned short>& float16_weights)
  88. {
  89. float16_weights.resize(data_length);
  90. for (size_t i = 0; i < data_length; i++)
  91. {
  92. float f = data[i];
  93. unsigned short fp16 = float2half(f);
  94. float16_weights[i] = fp16;
  95. }
  96. // magic tag for half-precision floating point
  97. return 0x01306B47;
  98. }
  99. static bool quantize_weight(float *data, size_t data_length, int quantize_level, std::vector<float> &quantize_table, std::vector<unsigned char> &quantize_index) {
  100. assert(quantize_level != 0);
  101. assert(data != NULL);
  102. assert(data_length > 0);
  103. if (data_length < static_cast<size_t>(quantize_level)) {
  104. fprintf(stderr, "No need quantize,because: data_length < quantize_level");
  105. return false;
  106. }
  107. quantize_table.reserve(quantize_level);
  108. quantize_index.reserve(data_length);
  109. // 1. Find min and max value
  110. float max_value = std::numeric_limits<float>::min();
  111. float min_value = std::numeric_limits<float>::max();
  112. for (size_t i = 0; i < data_length; ++i)
  113. {
  114. if (max_value < data[i]) max_value = data[i];
  115. if (min_value > data[i]) min_value = data[i];
  116. }
  117. float strides = (max_value - min_value) / quantize_level;
  118. // 2. Generate quantize table
  119. for (int i = 0; i < quantize_level; ++i)
  120. {
  121. quantize_table.push_back(min_value + i * strides);
  122. }
  123. // 3. Align data to the quantized value
  124. for (size_t i = 0; i < data_length; ++i)
  125. {
  126. size_t table_index = int((data[i] - min_value) / strides);
  127. table_index = std::min<float>(table_index, quantize_level - 1);
  128. float low_value = quantize_table[table_index];
  129. float high_value = low_value + strides;
  130. // find a nearest value between low and high value.
  131. float targetValue = data[i] - low_value < high_value - data[i] ? low_value : high_value;
  132. table_index = int((targetValue - min_value) / strides);
  133. table_index = std::min<float>(table_index, quantize_level - 1);
  134. quantize_index.push_back(table_index);
  135. }
  136. return true;
  137. }
  138. static bool read_proto_from_text(const char* filepath, google::protobuf::Message* message)
  139. {
  140. std::ifstream fs(filepath, std::ifstream::in);
  141. if (!fs.is_open())
  142. {
  143. fprintf(stderr, "open failed %s\n", filepath);
  144. return false;
  145. }
  146. google::protobuf::io::IstreamInputStream input(&fs);
  147. bool success = google::protobuf::TextFormat::Parse(&input, message);
  148. fs.close();
  149. return success;
  150. }
  151. static bool read_proto_from_binary(const char* filepath, google::protobuf::Message* message)
  152. {
  153. std::ifstream fs(filepath, std::ifstream::in | std::ifstream::binary);
  154. if (!fs.is_open())
  155. {
  156. fprintf(stderr, "open failed %s\n", filepath);
  157. return false;
  158. }
  159. google::protobuf::io::IstreamInputStream input(&fs);
  160. google::protobuf::io::CodedInputStream codedstr(&input);
  161. codedstr.SetTotalBytesLimit(INT_MAX, INT_MAX / 2);
  162. bool success = message->ParseFromCodedStream(&codedstr);
  163. fs.close();
  164. return success;
  165. }
  166. int main(int argc, char** argv)
  167. {
  168. if (!(argc == 3 || argc == 5 || argc == 6))
  169. {
  170. fprintf(stderr, "Usage: %s [caffeproto] [caffemodel] [ncnnproto] [ncnnbin] [quantizelevel]\n", argv[0]);
  171. return -1;
  172. }
  173. const char* caffeproto = argv[1];
  174. const char* caffemodel = argv[2];
  175. const char* ncnn_prototxt = argc >= 5 ? argv[3] : "ncnn.proto";
  176. const char* ncnn_modelbin = argc >= 5 ? argv[4] : "ncnn.bin";
  177. const char* quantize_param = argc == 6 ? argv[5] : "0";
  178. int quantize_level = atoi(quantize_param);
  179. if (quantize_level != 0 && quantize_level != 256 && quantize_level != 65536) {
  180. fprintf(stderr, "%s: only support quantize level = 0, 256, or 65536", argv[0]);
  181. return -1;
  182. }
  183. caffe::NetParameter proto;
  184. caffe::NetParameter net;
  185. // load
  186. bool s0 = read_proto_from_text(caffeproto, &proto);
  187. if (!s0)
  188. {
  189. fprintf(stderr, "read_proto_from_text failed\n");
  190. return -1;
  191. }
  192. bool s1 = read_proto_from_binary(caffemodel, &net);
  193. if (!s1)
  194. {
  195. fprintf(stderr, "read_proto_from_binary failed\n");
  196. return -1;
  197. }
  198. FILE* pp = fopen(ncnn_prototxt, "wb");
  199. FILE* bp = fopen(ncnn_modelbin, "wb");
  200. // rename mapping for identical bottom top style
  201. std::map<std::string, std::string> blob_name_decorated;
  202. // bottom blob reference
  203. std::map<std::string, int> bottom_reference;
  204. // global definition line
  205. // [layer count] [blob count]
  206. int layer_count = proto.layer_size();
  207. std::set<std::string> blob_names;
  208. for (int i=0; i<layer_count; i++)
  209. {
  210. const caffe::LayerParameter& layer = proto.layer(i);
  211. for (int j=0; j<layer.bottom_size(); j++)
  212. {
  213. std::string blob_name = layer.bottom(j);
  214. if (blob_name_decorated.find(blob_name) != blob_name_decorated.end())
  215. {
  216. blob_name = blob_name_decorated[blob_name];
  217. }
  218. blob_names.insert(blob_name);
  219. if (bottom_reference.find(blob_name) == bottom_reference.end())
  220. {
  221. bottom_reference[blob_name] = 1;
  222. }
  223. else
  224. {
  225. bottom_reference[blob_name] = bottom_reference[blob_name] + 1;
  226. }
  227. }
  228. if (layer.bottom_size() == 1 && layer.top_size() == 1 && layer.bottom(0) == layer.top(0))
  229. {
  230. std::string blob_name = layer.top(0) + "_" + layer.name();
  231. blob_name_decorated[layer.top(0)] = blob_name;
  232. blob_names.insert(blob_name);
  233. }
  234. else
  235. {
  236. for (int j=0; j<layer.top_size(); j++)
  237. {
  238. std::string blob_name = layer.top(j);
  239. blob_names.insert(blob_name);
  240. }
  241. }
  242. }
  243. // remove bottom_reference entry with reference equals to one
  244. int splitncnn_blob_count = 0;
  245. std::map<std::string, int>::iterator it = bottom_reference.begin();
  246. while (it != bottom_reference.end())
  247. {
  248. if (it->second == 1)
  249. {
  250. bottom_reference.erase(it++);
  251. }
  252. else
  253. {
  254. splitncnn_blob_count += it->second;
  255. // fprintf(stderr, "%s %d\n", it->first.c_str(), it->second);
  256. ++it;
  257. }
  258. }
  259. fprintf(pp, "%lu %lu\n", layer_count + bottom_reference.size(), blob_names.size() + splitncnn_blob_count);
  260. // populate
  261. blob_name_decorated.clear();
  262. int internal_split = 0;
  263. for (int i=0; i<layer_count; i++)
  264. {
  265. const caffe::LayerParameter& layer = proto.layer(i);
  266. // layer definition line, repeated
  267. // [type] [name] [bottom blob count] [top blob count] [bottom blobs] [top blobs] [layer specific params]
  268. fprintf(pp, "%-16s %-16s %d %d", layer.type().c_str(), layer.name().c_str(), layer.bottom_size(), layer.top_size());
  269. for (int j=0; j<layer.bottom_size(); j++)
  270. {
  271. std::string blob_name = layer.bottom(j);
  272. if (blob_name_decorated.find(layer.bottom(j)) != blob_name_decorated.end())
  273. {
  274. blob_name = blob_name_decorated[layer.bottom(j)];
  275. }
  276. if (bottom_reference.find(blob_name) != bottom_reference.end())
  277. {
  278. int refidx = bottom_reference[blob_name] - 1;
  279. bottom_reference[blob_name] = refidx;
  280. char splitsuffix[256];
  281. sprintf(splitsuffix, "_splitncnn_%d", refidx);
  282. blob_name = blob_name + splitsuffix;
  283. }
  284. fprintf(pp, " %s", blob_name.c_str());
  285. }
  286. // decorated
  287. if (layer.bottom_size() == 1 && layer.top_size() == 1 && layer.bottom(0) == layer.top(0))
  288. {
  289. std::string blob_name = layer.top(0) + "_" + layer.name();
  290. blob_name_decorated[layer.top(0)] = blob_name;
  291. fprintf(pp, " %s", blob_name.c_str());
  292. }
  293. else
  294. {
  295. for (int j=0; j<layer.top_size(); j++)
  296. {
  297. std::string blob_name = layer.top(j);
  298. fprintf(pp, " %s", blob_name.c_str());
  299. }
  300. }
  301. // find blob binary by layer name
  302. int netidx;
  303. for (netidx=0; netidx<net.layer_size(); netidx++)
  304. {
  305. if (net.layer(netidx).name() == layer.name())
  306. {
  307. break;
  308. }
  309. }
  310. // layer specific params
  311. if (layer.type() == "BatchNorm")
  312. {
  313. const caffe::LayerParameter& binlayer = net.layer(netidx);
  314. const caffe::BlobProto& mean_blob = binlayer.blobs(0);
  315. const caffe::BlobProto& var_blob = binlayer.blobs(1);
  316. fprintf(pp, " %d", (int)mean_blob.data_size());
  317. const caffe::BatchNormParameter& batch_norm_param = layer.batch_norm_param();
  318. float eps = batch_norm_param.eps();
  319. std::vector<float> ones(mean_blob.data_size(), 1.f);
  320. fwrite(ones.data(), sizeof(float), ones.size(), bp);// slope
  321. if (binlayer.blobs_size() < 3)
  322. {
  323. fwrite(mean_blob.data().data(), sizeof(float), mean_blob.data_size(), bp);
  324. float tmp;
  325. for (int j=0; j<var_blob.data_size(); j++)
  326. {
  327. tmp = var_blob.data().data()[j] + eps;
  328. fwrite(&tmp, sizeof(float), 1, bp);
  329. }
  330. }
  331. else
  332. {
  333. float scale_factor = 1 / binlayer.blobs(2).data().data()[0];
  334. // premultiply scale_factor to mean and variance
  335. float tmp;
  336. for (int j=0; j<mean_blob.data_size(); j++)
  337. {
  338. tmp = mean_blob.data().data()[j] * scale_factor;
  339. fwrite(&tmp, sizeof(float), 1, bp);
  340. }
  341. for (int j=0; j<var_blob.data_size(); j++)
  342. {
  343. tmp = var_blob.data().data()[j] * scale_factor + eps;
  344. fwrite(&tmp, sizeof(float), 1, bp);
  345. }
  346. }
  347. std::vector<float> zeros(mean_blob.data_size(), 0.f);
  348. fwrite(zeros.data(), sizeof(float), zeros.size(), bp);// bias
  349. }
  350. else if (layer.type() == "Convolution")
  351. {
  352. const caffe::LayerParameter& binlayer = net.layer(netidx);
  353. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  354. const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
  355. fprintf(pp, " %d %d %d %d %d %d %d", convolution_param.num_output(), convolution_param.kernel_size(0),
  356. convolution_param.dilation_size() != 0 ? convolution_param.dilation(0) : 1,
  357. convolution_param.stride_size() != 0 ? convolution_param.stride(0) : 1,
  358. convolution_param.pad_size() != 0 ? convolution_param.pad(0) : 0,
  359. convolution_param.bias_term(),
  360. weight_blob.data_size());
  361. for (int j = 0; j < binlayer.blobs_size(); j++)
  362. {
  363. int quantize_tag = 0;
  364. const caffe::BlobProto& blob = binlayer.blobs(j);
  365. std::vector<float> quantize_table;
  366. std::vector<unsigned char> quantize_index;
  367. std::vector<unsigned short> float16_weights;
  368. // we will not quantize the bias values
  369. if (j == 0 && quantize_level != 0)
  370. {
  371. if (quantize_level == 256)
  372. {
  373. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), quantize_level, quantize_table, quantize_index);
  374. }
  375. else if (quantize_level == 65536)
  376. {
  377. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), float16_weights);
  378. }
  379. }
  380. // write quantize tag first
  381. if (j == 0)
  382. fwrite(&quantize_tag, sizeof(int), 1, bp);
  383. if (quantize_tag)
  384. {
  385. int p0 = ftell(bp);
  386. if (quantize_level == 256)
  387. {
  388. // write quantize table and index
  389. fwrite(quantize_table.data(), sizeof(float), quantize_table.size(), bp);
  390. fwrite(quantize_index.data(), sizeof(unsigned char), quantize_index.size(), bp);
  391. }
  392. else if (quantize_level == 65536)
  393. {
  394. fwrite(float16_weights.data(), sizeof(unsigned short), float16_weights.size(), bp);
  395. }
  396. // padding to 32bit align
  397. int nwrite = ftell(bp) - p0;
  398. int nalign = alignSize(nwrite, 4);
  399. unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00};
  400. fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp);
  401. }
  402. else
  403. {
  404. // write original data
  405. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  406. }
  407. }
  408. }
  409. else if (layer.type() == "Crop")
  410. {
  411. const caffe::CropParameter& crop_param = layer.crop_param();
  412. int num_offset = crop_param.offset_size();
  413. int woffset = (num_offset == 2) ? crop_param.offset(0) : 0;
  414. int hoffset = (num_offset == 2) ? crop_param.offset(1) : 0;
  415. fprintf(pp, " %d %d", woffset, hoffset);
  416. }
  417. else if (layer.type() == "Deconvolution")
  418. {
  419. const caffe::LayerParameter& binlayer = net.layer(netidx);
  420. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  421. const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
  422. fprintf(pp, " %d %d %d %d %d %d %d", convolution_param.num_output(), convolution_param.kernel_size(0),
  423. convolution_param.dilation_size() != 0 ? convolution_param.dilation(0) : 1,
  424. convolution_param.stride_size() != 0 ? convolution_param.stride(0) : 1,
  425. convolution_param.pad_size() != 0 ? convolution_param.pad(0) : 0,
  426. convolution_param.bias_term(),
  427. weight_blob.data_size());
  428. int quantized_weight = 0;
  429. fwrite(&quantized_weight, sizeof(int), 1, bp);
  430. // reorder weight from inch-outch to outch-inch
  431. int ksize = convolution_param.kernel_size(0);
  432. int num_output = convolution_param.num_output();
  433. int num_input = weight_blob.data_size() / (ksize * ksize) / num_output;
  434. const float* weight_data_ptr = weight_blob.data().data();
  435. for (int k=0; k<num_output; k++)
  436. {
  437. for (int j=0; j<num_input; j++)
  438. {
  439. fwrite(weight_data_ptr + (j*num_output + k) * ksize * ksize, sizeof(float), ksize * ksize, bp);
  440. }
  441. }
  442. for (int j=1; j<binlayer.blobs_size(); j++)
  443. {
  444. const caffe::BlobProto& blob = binlayer.blobs(j);
  445. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  446. }
  447. }
  448. else if (layer.type() == "Eltwise")
  449. {
  450. const caffe::EltwiseParameter& eltwise_param = layer.eltwise_param();
  451. int coeff_size = eltwise_param.coeff_size();
  452. fprintf(pp, " %d %d", (int)eltwise_param.operation(), coeff_size);
  453. for (int j=0; j<coeff_size; j++)
  454. {
  455. fprintf(pp, " %f", eltwise_param.coeff(j));
  456. }
  457. }
  458. else if (layer.type() == "InnerProduct")
  459. {
  460. const caffe::LayerParameter& binlayer = net.layer(netidx);
  461. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  462. const caffe::InnerProductParameter& inner_product_param = layer.inner_product_param();
  463. fprintf(pp, " %d %d %d", inner_product_param.num_output(), inner_product_param.bias_term(),
  464. weight_blob.data_size());
  465. for (int j=0; j<binlayer.blobs_size(); j++)
  466. {
  467. int quantize_tag = 0;
  468. const caffe::BlobProto& blob = binlayer.blobs(j);
  469. std::vector<float> quantize_table;
  470. std::vector<unsigned char> quantize_index;
  471. std::vector<unsigned short> float16_weights;
  472. // we will not quantize the bias values
  473. if (j == 0 && quantize_level != 0)
  474. {
  475. if (quantize_level == 256)
  476. {
  477. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), quantize_level, quantize_table, quantize_index);
  478. }
  479. else if (quantize_level == 65536)
  480. {
  481. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), float16_weights);
  482. }
  483. }
  484. // write quantize tag first
  485. if (j == 0)
  486. fwrite(&quantize_tag, sizeof(int), 1, bp);
  487. if (quantize_tag)
  488. {
  489. int p0 = ftell(bp);
  490. if (quantize_level == 256)
  491. {
  492. // write quantize table and index
  493. fwrite(quantize_table.data(), sizeof(float), quantize_table.size(), bp);
  494. fwrite(quantize_index.data(), sizeof(unsigned char), quantize_index.size(), bp);
  495. }
  496. else if (quantize_level == 65536)
  497. {
  498. fwrite(float16_weights.data(), sizeof(unsigned short), float16_weights.size(), bp);
  499. }
  500. // padding to 32bit align
  501. int nwrite = ftell(bp) - p0;
  502. int nalign = alignSize(nwrite, 4);
  503. unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00};
  504. fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp);
  505. }
  506. else
  507. {
  508. // write original data
  509. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  510. }
  511. }
  512. }
  513. else if (layer.type() == "Input")
  514. {
  515. const caffe::InputParameter& input_param = layer.input_param();
  516. const caffe::BlobShape& bs = input_param.shape(0);
  517. for (int j=1; j<std::min((int)bs.dim_size(), 4); j++)
  518. {
  519. fprintf(pp, " %lld", bs.dim(j));
  520. }
  521. for (int j=bs.dim_size(); j<4; j++)
  522. {
  523. fprintf(pp, " -233");
  524. }
  525. }
  526. else if (layer.type() == "LRN")
  527. {
  528. const caffe::LRNParameter& lrn_param = layer.lrn_param();
  529. fprintf(pp, " %d %d %.8f %.8f", lrn_param.norm_region(), lrn_param.local_size(), lrn_param.alpha(), lrn_param.beta());
  530. }
  531. else if (layer.type() == "MemoryData")
  532. {
  533. const caffe::MemoryDataParameter& memory_data_param = layer.memory_data_param();
  534. fprintf(pp, " %d %d %d", memory_data_param.channels(), memory_data_param.width(), memory_data_param.height());
  535. }
  536. else if (layer.type() == "Pooling")
  537. {
  538. const caffe::PoolingParameter& pooling_param = layer.pooling_param();
  539. fprintf(pp, " %d %d %d %d %d", pooling_param.pool(), pooling_param.kernel_size(), pooling_param.stride(), pooling_param.pad(),
  540. pooling_param.has_global_pooling() ? pooling_param.global_pooling() : 0);
  541. }
  542. else if (layer.type() == "Power")
  543. {
  544. const caffe::PowerParameter& power_param = layer.power_param();
  545. fprintf(pp, " %f %f %f", power_param.power(), power_param.scale(), power_param.shift());
  546. }
  547. else if (layer.type() == "PReLU")
  548. {
  549. const caffe::LayerParameter& binlayer = net.layer(netidx);
  550. const caffe::BlobProto& slope_blob = binlayer.blobs(0);
  551. fprintf(pp, " %d", slope_blob.data_size());
  552. fwrite(slope_blob.data().data(), sizeof(float), slope_blob.data_size(), bp);
  553. }
  554. else if (layer.type() == "Proposal")
  555. {
  556. const caffe::PythonParameter& python_param = layer.python_param();
  557. int feat_stride = 16;
  558. sscanf(python_param.param_str().c_str(), "'feat_stride': %d", &feat_stride);
  559. int base_size = 16;
  560. // float ratio;
  561. // float scale;
  562. int pre_nms_topN = 6000;
  563. int after_nms_topN = 5;
  564. float nms_thresh = 0.7;
  565. int min_size = 16;
  566. fprintf(pp, " %d %d %d %d %f %d", feat_stride, base_size, pre_nms_topN, after_nms_topN, nms_thresh, min_size);
  567. }
  568. else if (layer.type() == "ReLU")
  569. {
  570. const caffe::ReLUParameter& relu_param = layer.relu_param();
  571. fprintf(pp, " %f", relu_param.negative_slope());
  572. }
  573. else if (layer.type() == "Reshape")
  574. {
  575. const caffe::ReshapeParameter& reshape_param = layer.reshape_param();
  576. const caffe::BlobShape& bs = reshape_param.shape();
  577. for (int j=1; j<std::min((int)bs.dim_size(), 4); j++)
  578. {
  579. fprintf(pp, " %lld", bs.dim(j));
  580. }
  581. for (int j=bs.dim_size(); j<4; j++)
  582. {
  583. fprintf(pp, " -233");
  584. }
  585. fprintf(pp, " 0");
  586. }
  587. else if (layer.type() == "ROIPooling")
  588. {
  589. const caffe::ROIPoolingParameter& roi_pooling_param = layer.roi_pooling_param();
  590. fprintf(pp, " %d %d %.8f", roi_pooling_param.pooled_w(), roi_pooling_param.pooled_h(), roi_pooling_param.spatial_scale());
  591. }
  592. else if (layer.type() == "Scale")
  593. {
  594. const caffe::LayerParameter& binlayer = net.layer(netidx);
  595. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  596. const caffe::ScaleParameter& scale_param = layer.scale_param();
  597. fprintf(pp, " %d %d", (int)weight_blob.data_size(), scale_param.bias_term());
  598. for (int j=0; j<binlayer.blobs_size(); j++)
  599. {
  600. const caffe::BlobProto& blob = binlayer.blobs(j);
  601. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  602. }
  603. }
  604. else if (layer.type() == "Slice")
  605. {
  606. const caffe::SliceParameter& slice_param = layer.slice_param();
  607. if (slice_param.has_slice_dim())
  608. {
  609. int num_slice = layer.top_size();
  610. fprintf(pp, " %d", num_slice);
  611. for (int j=0; j<num_slice; j++)
  612. {
  613. fprintf(pp, " -233");
  614. }
  615. }
  616. else
  617. {
  618. int num_slice = slice_param.slice_point_size() + 1;
  619. fprintf(pp, " %d", num_slice);
  620. int prev_offset = 0;
  621. for (int j=0; j<slice_param.slice_point_size(); j++)
  622. {
  623. int offset = slice_param.slice_point(j);
  624. fprintf(pp, " %d", offset - prev_offset);
  625. prev_offset = offset;
  626. }
  627. fprintf(pp, " -233");
  628. }
  629. }
  630. else if (layer.type() == "Threshold")
  631. {
  632. const caffe::ThresholdParameter& threshold_param = layer.threshold_param();
  633. fprintf(pp, " %f", threshold_param.threshold());
  634. }
  635. fprintf(pp, "\n");
  636. // add split layer if top reference larger than one
  637. if (layer.bottom_size() == 1 && layer.top_size() == 1 && layer.bottom(0) == layer.top(0))
  638. {
  639. std::string blob_name = blob_name_decorated[layer.top(0)];
  640. if (bottom_reference.find(blob_name) != bottom_reference.end())
  641. {
  642. int refcount = bottom_reference[blob_name];
  643. if (refcount > 1)
  644. {
  645. char splitname[256];
  646. sprintf(splitname, "splitncnn_%d", internal_split);
  647. fprintf(pp, "%-16s %-16s %d %d", "Split", splitname, 1, refcount);
  648. fprintf(pp, " %s", blob_name.c_str());
  649. for (int j=0; j<refcount; j++)
  650. {
  651. fprintf(pp, " %s_splitncnn_%d", blob_name.c_str(), j);
  652. }
  653. fprintf(pp, "\n");
  654. internal_split++;
  655. }
  656. }
  657. }
  658. else
  659. {
  660. for (int j=0; j<layer.top_size(); j++)
  661. {
  662. std::string blob_name = layer.top(j);
  663. if (bottom_reference.find(blob_name) != bottom_reference.end())
  664. {
  665. int refcount = bottom_reference[blob_name];
  666. if (refcount > 1)
  667. {
  668. char splitname[256];
  669. sprintf(splitname, "splitncnn_%d", internal_split);
  670. fprintf(pp, "%-16s %-16s %d %d", "Split", splitname, 1, refcount);
  671. fprintf(pp, " %s", blob_name.c_str());
  672. for (int j=0; j<refcount; j++)
  673. {
  674. fprintf(pp, " %s_splitncnn_%d", blob_name.c_str(), j);
  675. }
  676. fprintf(pp, "\n");
  677. internal_split++;
  678. }
  679. }
  680. }
  681. }
  682. }
  683. fclose(pp);
  684. fclose(bp);
  685. return 0;
  686. }