[C.C++] Windows10上使用VS2017编译MXNet源码操作步骤(C++)

671 0
Honkers 2026-1-29 18:29:03 来自手机 | 显示全部楼层 |阅读模式

MXNet是一种开源的深度学习框架,核心代码是由C++实现。MXNet官网推荐使用VS2015或VS2017编译,因为源码中使用了一些C++14的特性,VS2013是不支持的。这里通过VS2017编译,步骤如下:

1. 编译OpenCV,版本为3.4.2,可参考 https://blog.csdn.net/fengbingchun/article/details/78163217 ,注意加入opencv_contrib模块;

2. 编译OpenBLAS,版本为0.3.3,可参考: https://blog.csdn.net/fengbingchun/article/details/55509764  ;

3. 编译dmlc-core,版本为0.3:

4. 下载mshadow,注意不能是1.0或1.1版本,只能是master,因为它们的文件名不一致,里面仅有头文件;

5. 编译tvm,版本为0.4,在编译MXNet时,目前仅需要nnvm/src下的c_api, core, pass三个目录的文件参与:

6. 编译dlpack,版本为最新master,commit为bee4d1d,

7. 编译MXNet,版本为1.3.0:

8. 使用mxnet/cpp-package/scripts/OpWrapperGenerator.py生成mxnet/cpp-package/include/mxnet-cpp目录下的op.h文件操作步骤:

(1). 将lib/rel/x64目录下的libmxnet.dll和libopenblas.dll两个动态库拷贝到mxnet/cpp-package/scripts/目录下;

(2). 在mxnet/cpp-package/scripts/目录下打开命令行提示符,执行:

  1. python OpWrapperGenerator.py libmxnet.dll
复制代码

(3). 修改生成的op.h文件中的两处UpSampling函数:将参数scale,修改为int scale;将参数num_filter = 0,修改为int num_filter = 0; 注:直接通过以下命令生成op.h文件时不用作任何修改,后面查找下原因

  1. git clone --recursive https://github.com/apache/incubator-mxnet
复制代码

注意:

(1). 关于MXNet中的依赖库介绍和使用可参考:https://blog.csdn.net/fengbingchun/article/details/84981969

(2). 为了正常编译整个工程,部分源码作了微小的调整;

(3). 所有项目依赖的版本如下:

  1. 1. OpenBLAS:
  2. commit: fd8d186
  3. version: 0.3.3
  4. date: 2018.08.31
  5. url: https://github.com/xianyi/OpenBLAS/releases
  6. 2. dlpack:
  7. commit: bee4d1d
  8. version: master
  9. date: 2018.08.24
  10. url: https://github.com/dmlc/dlpack
  11. 3. mshadow:
  12. commit: 2e3a895
  13. version: master
  14. date: 2018.11.08
  15. url: https://github.com/dmlc/mshadow
  16. 4. dmlc-core:
  17. commit: 85c1180
  18. version: 0.3
  19. date: 2018.07.18
  20. url: https://github.com/dmlc/dmlc-core/releases
  21. 5. tvm:
  22. commit: 60769b7
  23. version: 0.4
  24. date: 2018.09.04
  25. url: https://github.com/dmlc/tvm/releases
  26. 6. HalideIR:
  27. commit: a08e26e
  28. version: master
  29. date: 2018.11.28
  30. url: https://github.com/dmlc/HalideIR
  31. 7. mxnet:
  32. commit: b3be92f
  33. version: 1.3.0
  34. date: 2018.09.12
  35. url: https://github.com/apache/incubator-mxnet/releases
复制代码

(4). 整个项目可以从https://github.com/fengbingchun/MXNet_Test clone到E:/GitCode目录下直接编译即可。

下面测试代码是用生成的MXNet.dll动态库训练MNIST:

  1. #include "funset.hpp"
  2. #include <chrono>
  3. #include <string>
  4. #include <fstream>
  5. #include <vector>
  6. #include "mxnet-cpp/MxNetCpp.h"
  7. namespace {
  8. bool isFileExists(const std::string &filename)
  9. {
  10. std::ifstream fhandle(filename.c_str());
  11. return fhandle.good();
  12. }
  13. bool check_datafiles(const std::vector<std::string> &data_files)
  14. {
  15. for (size_t index = 0; index < data_files.size(); index++) {
  16. if (!(isFileExists(data_files[index]))) {
  17. LG << "Error: File does not exist: " << data_files[index];
  18. return false;
  19. }
  20. }
  21. return true;
  22. }
  23. bool setDataIter(mxnet::cpp::MXDataIter *iter, std::string useType, const std::vector<std::string> &data_files, int batch_size)
  24. {
  25. if (!check_datafiles(data_files))
  26. return false;
  27. iter->SetParam("batch_size", batch_size);
  28. iter->SetParam("shuffle", 1);
  29. iter->SetParam("flat", 1);
  30. if (useType == "Train") {
  31. iter->SetParam("image", data_files[0]);
  32. iter->SetParam("label", data_files[1]);
  33. } else if (useType == "Label") {
  34. iter->SetParam("image", data_files[2]);
  35. iter->SetParam("label", data_files[3]);
  36. }
  37. iter->CreateDataIter();
  38. return true;
  39. }
  40. } // namespace
  41. ////////////////////////////// mnist ////////////////////////
  42. /* reference:
  43. https://mxnet.incubator.apache.org/tutorials/c%2B%2B/basics.html
  44. mxnet_source/cpp-package/example/mlp_cpu.cpp
  45. */
  46. namespace {
  47. mxnet::cpp::Symbol mlp(const std::vector<int> &layers)
  48. {
  49. auto x = mxnet::cpp::Symbol::Variable("X");
  50. auto label = mxnet::cpp::Symbol::Variable("label");
  51. std::vector<mxnet::cpp::Symbol> weights(layers.size());
  52. std::vector<mxnet::cpp::Symbol> biases(layers.size());
  53. std::vector<mxnet::cpp::Symbol> outputs(layers.size());
  54. for (size_t i = 0; i < layers.size(); ++i) {
  55. weights[i] = mxnet::cpp::Symbol::Variable("w" + std::to_string(i));
  56. biases[i] = mxnet::cpp::Symbol::Variable("b" + std::to_string(i));
  57. mxnet::cpp::Symbol fc = mxnet::cpp::FullyConnected(i == 0 ? x : outputs[i - 1], weights[i], biases[i], layers[i]);
  58. outputs[i] = i == layers.size() - 1 ? fc : mxnet::cpp::Activation(fc, mxnet::cpp::ActivationActType::kRelu);
  59. }
  60. return mxnet::cpp::SoftmaxOutput(outputs.back(), label);
  61. }
  62. } // namespace
  63. int test_mnist_train()
  64. {
  65. const int image_size = 28;
  66. const std::vector<int> layers{ 128, 64, 10 };
  67. const int batch_size = 100;
  68. const int max_epoch = 20;
  69. const float learning_rate = 0.1;
  70. const float weight_decay = 1e-2;
  71. std::vector<std::string> data_files = { "E:/GitCode/MXNet_Test/data/mnist/train-images.idx3-ubyte",
  72. "E:/GitCode/MXNet_Test/data/mnist/train-labels.idx1-ubyte",
  73. "E:/GitCode/MXNet_Test/data/mnist/t10k-images.idx3-ubyte",
  74. "E:/GitCode/MXNet_Test/data/mnist/t10k-labels.idx1-ubyte"};
  75. auto train_iter = mxnet::cpp::MXDataIter("MNISTIter");
  76. setDataIter(&train_iter, "Train", data_files, batch_size);
  77. auto val_iter = mxnet::cpp::MXDataIter("MNISTIter");
  78. setDataIter(&val_iter, "Label", data_files, batch_size);
  79. auto net = mlp(layers);
  80. mxnet::cpp::Context ctx = mxnet::cpp::Context::cpu(); // Use CPU for training
  81. std::map<std::string, mxnet::cpp::NDArray> args;
  82. args["X"] = mxnet::cpp::NDArray(mxnet::cpp::Shape(batch_size, image_size*image_size), ctx);
  83. args["label"] = mxnet::cpp::NDArray(mxnet::cpp::Shape(batch_size), ctx);
  84. // Let MXNet infer shapes other parameters such as weights
  85. net.InferArgsMap(ctx, &args, args);
  86. // Initialize all parameters with uniform distribution U(-0.01, 0.01)
  87. auto initializer = mxnet::cpp::Uniform(0.01);
  88. for (auto& arg : args) {
  89. // arg.first is parameter name, and arg.second is the value
  90. initializer(arg.first, &arg.second);
  91. }
  92. // Create sgd optimizer
  93. mxnet::cpp::Optimizer* opt = mxnet::cpp::OptimizerRegistry::Find("sgd");
  94. opt->SetParam("rescale_grad", 1.0 / batch_size)->SetParam("lr", learning_rate)->SetParam("wd", weight_decay);
  95. // Create executor by binding parameters to the model
  96. auto *exec = net.SimpleBind(ctx, args);
  97. auto arg_names = net.ListArguments();
  98. // Start training
  99. for (int iter = 0; iter < max_epoch; ++iter) {
  100. int samples = 0;
  101. train_iter.Reset();
  102. auto tic = std::chrono::system_clock::now();
  103. while (train_iter.Next()) {
  104. samples += batch_size;
  105. auto data_batch = train_iter.GetDataBatch();
  106. // Set data and label
  107. data_batch.data.CopyTo(&args["X"]);
  108. data_batch.label.CopyTo(&args["label"]);
  109. // Compute gradients
  110. exec->Forward(true);
  111. exec->Backward();
  112. // Update parameters
  113. for (size_t i = 0; i < arg_names.size(); ++i) {
  114. if (arg_names[i] == "X" || arg_names[i] == "label") continue;
  115. opt->Update(i, exec->arg_arrays[i], exec->grad_arrays[i]);
  116. }
  117. }
  118. auto toc = std::chrono::system_clock::now();
  119. mxnet::cpp::Accuracy acc;
  120. val_iter.Reset();
  121. while (val_iter.Next()) {
  122. auto data_batch = val_iter.GetDataBatch();
  123. data_batch.data.CopyTo(&args["X"]);
  124. data_batch.label.CopyTo(&args["label"]);
  125. // Forward pass is enough as no gradient is needed when evaluating
  126. exec->Forward(false);
  127. acc.Update(data_batch.label, exec->outputs[0]);
  128. }
  129. float duration = std::chrono::duration_cast<std::chrono::milliseconds>
  130. (toc - tic).count() / 1000.0;
  131. LG << "Epoch: " << iter << " " << samples / duration << " samples/sec Accuracy: " << acc.Get();
  132. }
  133. std::string json_file{ "E:/GitCode/MXNet_Test/data/mnist.json" };
  134. std::string param_file{"E:/GitCode/MXNet_Test/data/mnist.params"};
  135. net.Save(json_file);
  136. mxnet::cpp::NDArray::Save(param_file, exec->arg_arrays);
  137. delete exec;
  138. MXNotifyShutdown();
  139. return 0;
  140. }
复制代码

执行结果如下:

在Windows上编译MXNet_Test工程时注意事项:

(1). clone MXNet_Test到E:/GitCode目录下;

(2). MXNet_Test使用VS2017既可在windows7 x64上编译,也可在Windows10 x64上编译;

(3). 由于每个人的机子上VS2017安装的Windows SDK版本不同,可能会导致出现"error MSB8036: 找不到 Windows SDK 版本10.0.17134.0"类似的错误,解决方法是:选中指定的项目,打开属性页,在配置属性->常规->Windows SDK版本中重新选择你已安装的Windows SDK版本即可。

GitHub: https://github.com/fengbingchun/MXNet_Test 

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行