前言
依據(jù)mxnet的官方文檔,將其整體移植到移動平臺上是非常困難的冠胯,只有預測部分可以整合成單文件的形式應用到移動平臺上火诸。但網(wǎng)上有關(guān)這部分的資料極其稀少,而且已經(jīng)是很多年以前的了荠察,按照官方文檔編譯的時候也出現(xiàn)了很多錯誤置蜀,故有此文,將自己這幾天踩過的坑記錄一下悉盆,同時也為想在iOS上使用mxnet的同學們提供一點幫助盯荤。
環(huán)境
Xcode 9.3
iOS >= 10.0, macOS 10.13.4
mxnet 1.2.1
安裝OpenBLAS
mxnet的本地編譯需要OpenBLAS作為基礎(chǔ),可以通過Homebrew安裝:
brew install openblas
一般情況下焕盟,openblas的安裝路徑是/usr/local/opt/openblas
下載mxnet及其第三方依賴庫
下載mxnet源碼秋秤,定位到3rdParty目錄,查看它所有第三方依賴庫的目錄下面是否有內(nèi)容,如果沒有灼卢,需要繼續(xù)下載那些第三方庫绍哎。
在這里推薦使用Github Desktop直接clone到本地,這樣會順便把那些第三方依賴庫也同時下好鞋真。
如果您把OpenBLAS安裝在了其他位置崇堰,請相應調(diào)整amalgamation/Makefile中的OPENBLAS_ROOT,將其指向OpenBLAS的真實安裝位置涩咖。
修改dmlc-minimum0.cc
打開amalgamation/dmlc-minimum0.cc海诲,找到
#include "../3rdparty/dmlc-core/src/io/local_filesys.cc"
在下方增加
#include "../3rdparty/dmlc-core/src/io/filesys.cc"
修改mxnet_predict0.cc
打開amalgamation/mxnet_predict0.cc,找到
#include "src/ndarray/ndarray_function.cc"
在其上方增加(注意抠藕!這個是上方6龇巍)
#include "src/common/utils.cc"
找到
#include "src/imperative/cached_op.cc"
在其下方增加
#include "src/imperative/imperative.cc"
找到
#include "src/engine/naive_engine.cc"
在其下方增加
#include "src/engine/openmp.cc"
找到
#include "src/profiler/profiler.cc"
在其下方增加
#include "src/profiler/aggregate_stats.cc"
找到
#include "src/executor/inplace_addto_detect_pass.cc"
在其下方增加
#include "src/executor/infer_graph_attr_pass.cc"
找到
#include "src/c_api/c_api_error.cc"
在其下方增加
#include "src/c_api/c_api_profile.cc"
編譯mxnet_predict-all.cc
定位到amalgamation目錄蒋困,在命令行里面輸入
make
并等待一段時間盾似,如果一切順利,最終會輸出:
ar rcs libmxnet_predict.a mxnet_predict-all.o
如果在這個過程中出現(xiàn)任何error信息(包括在ar命令執(zhí)行過程中出現(xiàn)任何erorr信息)雪标,需要檢查mxnet_predict0.cc和dmlc-minimum0.cc兩個文件是否修改正確零院。
在amalgamation目錄下會多出一些文件,我們需要mxnet_predict-all.cc村刨,這就是mxnet預測部分的單文件版本告抄。
修改mxnet_predict-all.cc
打開mxnet_predict-all.cc,找到
#include <cblas.h>
改為
#include <Accelerate/Accelerate.h>
增加
#include <execinfo.h>
#include <shared_mutex>
刪除以下兩個頭文件的引用
#include <emmintrin.h>
#include <x86intrin.h>
找到
#ifndef MSHADOW_USE_SSE
#define MSHADOW_USE_SSE 1
#endif
改為
#ifndef MSHADOW_USE_SSE
#define MSHADOW_USE_SSE 0
#endif
找到
#if defined(_MSC_VER) || defined(__CUDACC__)
#define MSHADOW_USE_F16C 0
#elif defined(__clang__) && \
((__clang_major__ < 8) || ((__clang_major__ == 8) && (__clang_minor__ < 1)))
#define MSHADOW_USE_F16C 0
#else
#define MSHADOW_USE_F16C 1
#endif
改為
#define MSHADOW_USE_F16C 0
注釋掉以下部分:
#if MSHADOW_USE_MKL == 0
//中間的代碼段全部注釋掉
#endif // MSHADOW_USE_MKL == 0
將mxnet_predict-all.cc以及../include/mxnet/c_predict_api.h拷出來備用嵌牺。
建立iOS工程
新建一個iOS工程打洼,不管是APP也好,靜態(tài)庫也好逆粹,還是動態(tài)庫也好募疮,都可以。
將剛才的mxnet_predict-all.cc以及c_predict_api.h加入工程僻弹。
在Build Phases的Link Binary with Libraries中阿浓,加入Accelerate.framework,然后編譯蹋绽。
一些資源
- 如果覺得上面的步驟太麻煩芭毙,可以直接用我修改好的版本,只用其中的dmlc-minimum0.cc和mxnet_predict0.cc
- 很久沒有更新的生成predict-all的官方文檔可以作為參考
mxnet_predict-all生成原理
從amalgamation/Makefile文件可以看出卸耘,mxnet_predict-all.cc主要依靠dmlc-minimum0.cc退敦、nnvm.cc和mxnet_predict0.cc等若干個模板文件,依據(jù)amalgamation.py這個腳本文件解析模板文件蚣抗,將其展開侈百、合并到一個大的文件中。
所以如果最后生成的文件中存在什么問題,直接到模板文件里面找原因就行了设哗。
常見問題
1 Undefined Symbol for archetecture xxx
檢查mxnet_predict-all.cc里面有沒有對應的實現(xiàn)唱捣,如果沒有,繼續(xù)檢查mxnet_predict0.cc以及dmlc-minimum0.cc兩個文件是否有正確修改网梢。
2 mxnet_predict-all.cc里面include文件未找到
仔細對比mxnet_predict-all.cc是否有按前述過程修改震缭,我遇到的很多種情況是因為某些其他平臺的宏未關(guān)閉(例如MSHADOW_USE_SSE未置0)引起的
3 其他問題請在評論區(qū)留言,我將及時更新這份文檔战虏。