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

8 years ago
8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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. if (layer.type() == "Convolution")
  269. {
  270. const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
  271. if (convolution_param.group() != 1)
  272. fprintf(pp, "%-16s", "ConvolutionDepthWise");
  273. else
  274. fprintf(pp, "%-16s", "Convolution");
  275. }
  276. else
  277. {
  278. fprintf(pp, "%-16s", layer.type().c_str());
  279. }
  280. fprintf(pp, " %-16s %d %d", layer.name().c_str(), layer.bottom_size(), layer.top_size());
  281. for (int j=0; j<layer.bottom_size(); j++)
  282. {
  283. std::string blob_name = layer.bottom(j);
  284. if (blob_name_decorated.find(layer.bottom(j)) != blob_name_decorated.end())
  285. {
  286. blob_name = blob_name_decorated[layer.bottom(j)];
  287. }
  288. if (bottom_reference.find(blob_name) != bottom_reference.end())
  289. {
  290. int refidx = bottom_reference[blob_name] - 1;
  291. bottom_reference[blob_name] = refidx;
  292. char splitsuffix[256];
  293. sprintf(splitsuffix, "_splitncnn_%d", refidx);
  294. blob_name = blob_name + splitsuffix;
  295. }
  296. fprintf(pp, " %s", blob_name.c_str());
  297. }
  298. // decorated
  299. if (layer.bottom_size() == 1 && layer.top_size() == 1 && layer.bottom(0) == layer.top(0))
  300. {
  301. std::string blob_name = layer.top(0) + "_" + layer.name();
  302. blob_name_decorated[layer.top(0)] = blob_name;
  303. fprintf(pp, " %s", blob_name.c_str());
  304. }
  305. else
  306. {
  307. for (int j=0; j<layer.top_size(); j++)
  308. {
  309. std::string blob_name = layer.top(j);
  310. fprintf(pp, " %s", blob_name.c_str());
  311. }
  312. }
  313. // find blob binary by layer name
  314. int netidx;
  315. for (netidx=0; netidx<net.layer_size(); netidx++)
  316. {
  317. if (net.layer(netidx).name() == layer.name())
  318. {
  319. break;
  320. }
  321. }
  322. // layer specific params
  323. if (layer.type() == "BatchNorm")
  324. {
  325. const caffe::LayerParameter& binlayer = net.layer(netidx);
  326. const caffe::BlobProto& mean_blob = binlayer.blobs(0);
  327. const caffe::BlobProto& var_blob = binlayer.blobs(1);
  328. fprintf(pp, " %d", (int)mean_blob.data_size());
  329. const caffe::BatchNormParameter& batch_norm_param = layer.batch_norm_param();
  330. float eps = batch_norm_param.eps();
  331. std::vector<float> ones(mean_blob.data_size(), 1.f);
  332. fwrite(ones.data(), sizeof(float), ones.size(), bp);// slope
  333. if (binlayer.blobs_size() < 3)
  334. {
  335. fwrite(mean_blob.data().data(), sizeof(float), mean_blob.data_size(), bp);
  336. float tmp;
  337. for (int j=0; j<var_blob.data_size(); j++)
  338. {
  339. tmp = var_blob.data().data()[j] + eps;
  340. fwrite(&tmp, sizeof(float), 1, bp);
  341. }
  342. }
  343. else
  344. {
  345. float scale_factor = 1 / binlayer.blobs(2).data().data()[0];
  346. // premultiply scale_factor to mean and variance
  347. float tmp;
  348. for (int j=0; j<mean_blob.data_size(); j++)
  349. {
  350. tmp = mean_blob.data().data()[j] * scale_factor;
  351. fwrite(&tmp, sizeof(float), 1, bp);
  352. }
  353. for (int j=0; j<var_blob.data_size(); j++)
  354. {
  355. tmp = var_blob.data().data()[j] * scale_factor + eps;
  356. fwrite(&tmp, sizeof(float), 1, bp);
  357. }
  358. }
  359. std::vector<float> zeros(mean_blob.data_size(), 0.f);
  360. fwrite(zeros.data(), sizeof(float), zeros.size(), bp);// bias
  361. }
  362. else if (layer.type() == "Convolution")
  363. {
  364. const caffe::LayerParameter& binlayer = net.layer(netidx);
  365. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  366. const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
  367. fprintf(pp, " %d %d %d %d %d %d %d", convolution_param.num_output(), convolution_param.kernel_size(0),
  368. convolution_param.dilation_size() != 0 ? convolution_param.dilation(0) : 1,
  369. convolution_param.stride_size() != 0 ? convolution_param.stride(0) : 1,
  370. convolution_param.pad_size() != 0 ? convolution_param.pad(0) : 0,
  371. convolution_param.bias_term(),
  372. weight_blob.data_size());
  373. if (convolution_param.group() != 1)
  374. {
  375. fprintf(pp, " %d", convolution_param.group());
  376. }
  377. for (int j = 0; j < binlayer.blobs_size(); j++)
  378. {
  379. int quantize_tag = 0;
  380. const caffe::BlobProto& blob = binlayer.blobs(j);
  381. std::vector<float> quantize_table;
  382. std::vector<unsigned char> quantize_index;
  383. std::vector<unsigned short> float16_weights;
  384. // we will not quantize the bias values
  385. if (j == 0 && quantize_level != 0)
  386. {
  387. if (quantize_level == 256)
  388. {
  389. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), quantize_level, quantize_table, quantize_index);
  390. }
  391. else if (quantize_level == 65536)
  392. {
  393. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), float16_weights);
  394. }
  395. }
  396. // write quantize tag first
  397. if (j == 0)
  398. fwrite(&quantize_tag, sizeof(int), 1, bp);
  399. if (quantize_tag)
  400. {
  401. int p0 = ftell(bp);
  402. if (quantize_level == 256)
  403. {
  404. // write quantize table and index
  405. fwrite(quantize_table.data(), sizeof(float), quantize_table.size(), bp);
  406. fwrite(quantize_index.data(), sizeof(unsigned char), quantize_index.size(), bp);
  407. }
  408. else if (quantize_level == 65536)
  409. {
  410. fwrite(float16_weights.data(), sizeof(unsigned short), float16_weights.size(), bp);
  411. }
  412. // padding to 32bit align
  413. int nwrite = ftell(bp) - p0;
  414. int nalign = alignSize(nwrite, 4);
  415. unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00};
  416. fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp);
  417. }
  418. else
  419. {
  420. // write original data
  421. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  422. }
  423. }
  424. }
  425. else if (layer.type() == "Crop")
  426. {
  427. const caffe::CropParameter& crop_param = layer.crop_param();
  428. int num_offset = crop_param.offset_size();
  429. int woffset = (num_offset == 2) ? crop_param.offset(0) : 0;
  430. int hoffset = (num_offset == 2) ? crop_param.offset(1) : 0;
  431. fprintf(pp, " %d %d", woffset, hoffset);
  432. }
  433. else if (layer.type() == "Deconvolution")
  434. {
  435. const caffe::LayerParameter& binlayer = net.layer(netidx);
  436. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  437. const caffe::ConvolutionParameter& convolution_param = layer.convolution_param();
  438. fprintf(pp, " %d %d %d %d %d %d %d", convolution_param.num_output(), convolution_param.kernel_size(0),
  439. convolution_param.dilation_size() != 0 ? convolution_param.dilation(0) : 1,
  440. convolution_param.stride_size() != 0 ? convolution_param.stride(0) : 1,
  441. convolution_param.pad_size() != 0 ? convolution_param.pad(0) : 0,
  442. convolution_param.bias_term(),
  443. weight_blob.data_size());
  444. int quantized_weight = 0;
  445. fwrite(&quantized_weight, sizeof(int), 1, bp);
  446. // reorder weight from inch-outch to outch-inch
  447. int ksize = convolution_param.kernel_size(0);
  448. int num_output = convolution_param.num_output();
  449. int num_input = weight_blob.data_size() / (ksize * ksize) / num_output;
  450. const float* weight_data_ptr = weight_blob.data().data();
  451. for (int k=0; k<num_output; k++)
  452. {
  453. for (int j=0; j<num_input; j++)
  454. {
  455. fwrite(weight_data_ptr + (j*num_output + k) * ksize * ksize, sizeof(float), ksize * ksize, bp);
  456. }
  457. }
  458. for (int j=1; j<binlayer.blobs_size(); j++)
  459. {
  460. const caffe::BlobProto& blob = binlayer.blobs(j);
  461. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  462. }
  463. }
  464. else if (layer.type() == "Eltwise")
  465. {
  466. const caffe::EltwiseParameter& eltwise_param = layer.eltwise_param();
  467. int coeff_size = eltwise_param.coeff_size();
  468. fprintf(pp, " %d %d", (int)eltwise_param.operation(), coeff_size);
  469. for (int j=0; j<coeff_size; j++)
  470. {
  471. fprintf(pp, " %f", eltwise_param.coeff(j));
  472. }
  473. }
  474. else if (layer.type() == "ELU")
  475. {
  476. const caffe::ELUParameter& elu_param = layer.elu_param();
  477. fprintf(pp, " %f", elu_param.alpha());
  478. }
  479. else if (layer.type() == "InnerProduct")
  480. {
  481. const caffe::LayerParameter& binlayer = net.layer(netidx);
  482. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  483. const caffe::InnerProductParameter& inner_product_param = layer.inner_product_param();
  484. fprintf(pp, " %d %d %d", inner_product_param.num_output(), inner_product_param.bias_term(),
  485. weight_blob.data_size());
  486. for (int j=0; j<binlayer.blobs_size(); j++)
  487. {
  488. int quantize_tag = 0;
  489. const caffe::BlobProto& blob = binlayer.blobs(j);
  490. std::vector<float> quantize_table;
  491. std::vector<unsigned char> quantize_index;
  492. std::vector<unsigned short> float16_weights;
  493. // we will not quantize the bias values
  494. if (j == 0 && quantize_level != 0)
  495. {
  496. if (quantize_level == 256)
  497. {
  498. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), quantize_level, quantize_table, quantize_index);
  499. }
  500. else if (quantize_level == 65536)
  501. {
  502. quantize_tag = quantize_weight((float *)blob.data().data(), blob.data_size(), float16_weights);
  503. }
  504. }
  505. // write quantize tag first
  506. if (j == 0)
  507. fwrite(&quantize_tag, sizeof(int), 1, bp);
  508. if (quantize_tag)
  509. {
  510. int p0 = ftell(bp);
  511. if (quantize_level == 256)
  512. {
  513. // write quantize table and index
  514. fwrite(quantize_table.data(), sizeof(float), quantize_table.size(), bp);
  515. fwrite(quantize_index.data(), sizeof(unsigned char), quantize_index.size(), bp);
  516. }
  517. else if (quantize_level == 65536)
  518. {
  519. fwrite(float16_weights.data(), sizeof(unsigned short), float16_weights.size(), bp);
  520. }
  521. // padding to 32bit align
  522. int nwrite = ftell(bp) - p0;
  523. int nalign = alignSize(nwrite, 4);
  524. unsigned char padding[4] = {0x00, 0x00, 0x00, 0x00};
  525. fwrite(padding, sizeof(unsigned char), nalign - nwrite, bp);
  526. }
  527. else
  528. {
  529. // write original data
  530. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  531. }
  532. }
  533. }
  534. else if (layer.type() == "Input")
  535. {
  536. const caffe::InputParameter& input_param = layer.input_param();
  537. const caffe::BlobShape& bs = input_param.shape(0);
  538. for (int j=1; j<std::min((int)bs.dim_size(), 4); j++)
  539. {
  540. fprintf(pp, " %lld", bs.dim(j));
  541. }
  542. for (int j=bs.dim_size(); j<4; j++)
  543. {
  544. fprintf(pp, " -233");
  545. }
  546. }
  547. else if (layer.type() == "LRN")
  548. {
  549. const caffe::LRNParameter& lrn_param = layer.lrn_param();
  550. fprintf(pp, " %d %d %.8f %.8f", lrn_param.norm_region(), lrn_param.local_size(), lrn_param.alpha(), lrn_param.beta());
  551. }
  552. else if (layer.type() == "MemoryData")
  553. {
  554. const caffe::MemoryDataParameter& memory_data_param = layer.memory_data_param();
  555. fprintf(pp, " %d %d %d", memory_data_param.channels(), memory_data_param.width(), memory_data_param.height());
  556. }
  557. else if (layer.type() == "Pooling")
  558. {
  559. const caffe::PoolingParameter& pooling_param = layer.pooling_param();
  560. fprintf(pp, " %d %d %d %d %d", pooling_param.pool(), pooling_param.kernel_size(), pooling_param.stride(), pooling_param.pad(),
  561. pooling_param.has_global_pooling() ? pooling_param.global_pooling() : 0);
  562. }
  563. else if (layer.type() == "Power")
  564. {
  565. const caffe::PowerParameter& power_param = layer.power_param();
  566. fprintf(pp, " %f %f %f", power_param.power(), power_param.scale(), power_param.shift());
  567. }
  568. else if (layer.type() == "PReLU")
  569. {
  570. const caffe::LayerParameter& binlayer = net.layer(netidx);
  571. const caffe::BlobProto& slope_blob = binlayer.blobs(0);
  572. fprintf(pp, " %d", slope_blob.data_size());
  573. fwrite(slope_blob.data().data(), sizeof(float), slope_blob.data_size(), bp);
  574. }
  575. else if (layer.type() == "Proposal")
  576. {
  577. const caffe::PythonParameter& python_param = layer.python_param();
  578. int feat_stride = 16;
  579. sscanf(python_param.param_str().c_str(), "'feat_stride': %d", &feat_stride);
  580. int base_size = 16;
  581. // float ratio;
  582. // float scale;
  583. int pre_nms_topN = 6000;
  584. int after_nms_topN = 5;
  585. float nms_thresh = 0.7;
  586. int min_size = 16;
  587. fprintf(pp, " %d %d %d %d %f %d", feat_stride, base_size, pre_nms_topN, after_nms_topN, nms_thresh, min_size);
  588. }
  589. else if (layer.type() == "ReLU")
  590. {
  591. const caffe::ReLUParameter& relu_param = layer.relu_param();
  592. fprintf(pp, " %f", relu_param.negative_slope());
  593. }
  594. else if (layer.type() == "Reshape")
  595. {
  596. const caffe::ReshapeParameter& reshape_param = layer.reshape_param();
  597. const caffe::BlobShape& bs = reshape_param.shape();
  598. for (int j=1; j<std::min((int)bs.dim_size(), 4); j++)
  599. {
  600. fprintf(pp, " %lld", bs.dim(j));
  601. }
  602. for (int j=bs.dim_size(); j<4; j++)
  603. {
  604. fprintf(pp, " -233");
  605. }
  606. fprintf(pp, " 0");
  607. }
  608. else if (layer.type() == "ROIPooling")
  609. {
  610. const caffe::ROIPoolingParameter& roi_pooling_param = layer.roi_pooling_param();
  611. fprintf(pp, " %d %d %.8f", roi_pooling_param.pooled_w(), roi_pooling_param.pooled_h(), roi_pooling_param.spatial_scale());
  612. }
  613. else if (layer.type() == "Scale")
  614. {
  615. const caffe::LayerParameter& binlayer = net.layer(netidx);
  616. const caffe::BlobProto& weight_blob = binlayer.blobs(0);
  617. const caffe::ScaleParameter& scale_param = layer.scale_param();
  618. fprintf(pp, " %d %d", (int)weight_blob.data_size(), scale_param.bias_term());
  619. for (int j=0; j<binlayer.blobs_size(); j++)
  620. {
  621. const caffe::BlobProto& blob = binlayer.blobs(j);
  622. fwrite(blob.data().data(), sizeof(float), blob.data_size(), bp);
  623. }
  624. }
  625. else if (layer.type() == "Slice")
  626. {
  627. const caffe::SliceParameter& slice_param = layer.slice_param();
  628. if (slice_param.has_slice_dim())
  629. {
  630. int num_slice = layer.top_size();
  631. fprintf(pp, " %d", num_slice);
  632. for (int j=0; j<num_slice; j++)
  633. {
  634. fprintf(pp, " -233");
  635. }
  636. }
  637. else
  638. {
  639. int num_slice = slice_param.slice_point_size() + 1;
  640. fprintf(pp, " %d", num_slice);
  641. int prev_offset = 0;
  642. for (int j=0; j<slice_param.slice_point_size(); j++)
  643. {
  644. int offset = slice_param.slice_point(j);
  645. fprintf(pp, " %d", offset - prev_offset);
  646. prev_offset = offset;
  647. }
  648. fprintf(pp, " -233");
  649. }
  650. }
  651. else if (layer.type() == "Threshold")
  652. {
  653. const caffe::ThresholdParameter& threshold_param = layer.threshold_param();
  654. fprintf(pp, " %f", threshold_param.threshold());
  655. }
  656. fprintf(pp, "\n");
  657. // add split layer if top reference larger than one
  658. if (layer.bottom_size() == 1 && layer.top_size() == 1 && layer.bottom(0) == layer.top(0))
  659. {
  660. std::string blob_name = blob_name_decorated[layer.top(0)];
  661. if (bottom_reference.find(blob_name) != bottom_reference.end())
  662. {
  663. int refcount = bottom_reference[blob_name];
  664. if (refcount > 1)
  665. {
  666. char splitname[256];
  667. sprintf(splitname, "splitncnn_%d", internal_split);
  668. fprintf(pp, "%-16s %-16s %d %d", "Split", splitname, 1, refcount);
  669. fprintf(pp, " %s", blob_name.c_str());
  670. for (int j=0; j<refcount; j++)
  671. {
  672. fprintf(pp, " %s_splitncnn_%d", blob_name.c_str(), j);
  673. }
  674. fprintf(pp, "\n");
  675. internal_split++;
  676. }
  677. }
  678. }
  679. else
  680. {
  681. for (int j=0; j<layer.top_size(); j++)
  682. {
  683. std::string blob_name = layer.top(j);
  684. if (bottom_reference.find(blob_name) != bottom_reference.end())
  685. {
  686. int refcount = bottom_reference[blob_name];
  687. if (refcount > 1)
  688. {
  689. char splitname[256];
  690. sprintf(splitname, "splitncnn_%d", internal_split);
  691. fprintf(pp, "%-16s %-16s %d %d", "Split", splitname, 1, refcount);
  692. fprintf(pp, " %s", blob_name.c_str());
  693. for (int j=0; j<refcount; j++)
  694. {
  695. fprintf(pp, " %s_splitncnn_%d", blob_name.c_str(), j);
  696. }
  697. fprintf(pp, "\n");
  698. internal_split++;
  699. }
  700. }
  701. }
  702. }
  703. }
  704. fclose(pp);
  705. fclose(bp);
  706. return 0;
  707. }