tensorflow整合到Android以及so庫和pb檔案的動態載入實踐

水牛發表於2017-12-15

主要參考

官方整合指南

官方demo

深度學習利器:TensorFlow在智慧終端中的應用

機器學習:在Android中整合TensorFlow

動態載入so庫的實現方法與問題處理

整合簡述

整合的程式碼是在AndroidTensorFlowMachineLearningExample基礎上修改.

Android上整合tensorflow最簡單是步驟是:

1 complile引入

compile 'org.tensorflow:tensorflow-android:1.4.0'
複製程式碼

2 拿到AI演算法開發人員訓練好並壓縮好的pb檔案

3 根據其java的api開始寫程式碼

一般so庫通過compile引入後自動會打入,pb放在asserts資料夾,但這樣會增大apk包體積. so庫一般一個abi就10-15M,pb檔案20-100M不等. 所以需要動態載入: 放在伺服器,下載到本地,需要時直接從本地讀取.

pb檔案的載入

AndroidTensorFlowMachineLearningExample中api並無從流中載入pb檔案的api,而1.4.0中java api提供了以下構造方法,可以從檔案中載入. 只要預先下載好就行了.

new TensorFlowInferenceInterface(inputStream);
複製程式碼

so庫的動態載入

略顯麻煩, 一需要識別所支援的abi,然後下載對應的so檔案 二 需要註釋掉java程式碼中的靜態程式碼塊載入so庫的程式碼

依賴引入方式不再是上方的一行程式碼compile,而是將gradle快取中的tensorflow-android:1.4.0的jar包和jni包拷貝出來. jni包中的so檔案上傳到伺服器.

註釋靜態方法中的載入so庫的程式碼:

jar包需要註釋掉裡面靜態程式碼塊載入so庫的程式碼: jar包中多處呼叫TensorFlow.init()初始化,所以只要註釋init內部內容就好.

TensorFlow類中的: 
static void init() {
    //NativeLibrary.load();//註釋掉此行,由我們自己動態載入
  }

  static {
    init();
  }
複製程式碼

操作方法:

新建一個包名相同的TensorFlow類,將jar包中程式碼拷貝至此,註釋掉那一行程式碼,用java7(不能用java8)編譯後, 將jar包用winrar開啟,將編譯後的class檔案拖進jar包替換即可. 然後將jar包新增到工程libs目錄,新增為依賴.

so庫動態載入

獲取手機系統首選abi,然後去獲取對應url,下載到app內目錄,載入即可.

獲取首選abi:

private static String getFirstSupportedAbi() {
        String abi1 = "";
        if (Build.VERSION.SDK_INT >= 21) {
            String[] abis = Build.SUPPORTED_ABIS;
            if (abis != null) {
                String abistr  = "";
                //第一個是原生支援的,後面的是相容模式.雖然是相容,但手動載入時很多並不相容.
                abi1 = abis[0];
                for (String abi : abis) {
                    abistr = abistr + abi+",";
                }
                if(showLog)
                Log.e(TAG, "[copySo] supported api:" + abistr);
            }
        } else {
            if(showLog)
            Log.e(TAG, "[copySo] supported api:" + Build.CPU_ABI + "--- " + Build.CPU_ABI2);
            if (!TextUtils.isEmpty(Build.CPU_ABI)) {
                abi1 = Build.CPU_ABI;
            } else if (!TextUtils.isEmpty(Build.CPU_ABI2)) {
                abi1 = Build.CPU_ABI2;
            }
        }
        return abi1;
    }

複製程式碼

下載後的so檔案要放到app內目錄,不要放到sd卡:

String abi = getFirstSupportedAbi();
File dir = context.getDir("jnilibs", Context.MODE_PRIVATE);
File subDir = new File(dir, abi);
複製程式碼

載入so:

            try {
                    System.load(filePath);
                }catch (Throwable e){
                    e.printStackTrace();
                }

複製程式碼

檔案下載

都是大檔案,選一個比較靠譜,能夠斷點續傳的庫:FileDownloader

同時還需要注意:

  • 檔案很大,只在wifi時下載,以免耗流量
  • 下載完校驗md5.

程式碼

TensorFlowAndroidDynamic

相關文章