私の最初のカフェAndroidプログラム



My First Caffe Android Program



前の記事で ' 私の最初のcaffeC ++プログラム 'では、最も単純なcaffe C ++プログラムの作成方法を説明していますが、私の最終的な目標は、Androidアプリでcaffeフレームワークを使用することです。次に、モデルテストプログラムtestXORをAndroidに移植して、Androidアプリでもcaffeディープラーニングフレームワークを使用できるようにします。

caffeフレームワークはC ++言語で記述されており、移植性に優れていますが、公式コードはAndroidプラットフォームに移植されていません。幸いなことに、多くの民俗神もいます。インターネットを検索したところ、誰かがすでにAndroidプラットフォームのカフェを移植していることがわかりました。プロジェクトの住所は次のとおりです。 https://github.com/sh1r0/caffe-android-lib



caffe-android-libをコンパイルします

caffe-android-libのコンパイルでは、dockerを使用してビルドすることをお勧めします。ローカルのAndroidNDKでコンパイルしようとしましたが、NDKのバージョンが異なり、コンパイルに特定の問題があることがわかりました。 caffe-android-libプロジェクトのホームページにdockerbuildメソッドがあります。

git clone --recursive https://github.com/sh1r0/caffe-android-lib.git cd caffe-android-lib # build image docker build -t caffe-android-lib . # run a container for building your own caffe-android-lib, e.g., docker run --rm --name caffe-android-builder -e ANDROID_ABI=x86_64 -e N_JOBS=2 -v $(pwd)/android_lib/x86_64:/caffe-android-lib/android_lib caffe-android-lib ./build.sh

注:ガイドで指定されているANDROID_ABIはx86_64です。ほとんどの携帯電話では、armeabi-v7aに変更してください



コンパイル後、caffeおよび関連ライブラリのヘッダーファイルとライブラリファイルはandroid_libディレクトリにあります。次の手順では、これらのヘッダーファイルをサンプルプロジェクトにコピーする必要があります。

Androidプロジェクト

Android Studioで新しいAndroidプロジェクトを作成し、ウィザードをステップバイステップで実行します。次に、前の手順のandroid_libディレクトリにヘッダーファイルとライブラリファイルをコピーし、それらをcpp / third_partyディレクトリに配置します。 caffeライブラリはそのように構築されているので、jniLibsディレクトリに配置します。

完全なプロジェクトソースコードは、以下を参照できます。 https://gitee.com/mogoweb/dpexamples.git



XORusingCAFFE-androidディレクトリには、Androidバージョンのcaffeサンプルプログラムがあります。 C ++側のコードは次のとおりです。

extern 'C' JNIEXPORT jstring JNICALL Java_com_mogoweb_caffe_xorusingcaffe_MainActivity_startXORTest( JNIEnv *env, jobject /* this */, jstring modelProto, jstring caffeModel) { // caffe is using google logging (aka 'glog') as its logging module, and hence this module must be initialized once when running caffe. // Therefore the following line ::google::InitGoogleLogging('') // load the trained weights cached inside XOR_iter_5000000.caffemodel shared_ptrfloat> > testnet std::string modelproto = jstring2string(env, modelProto) std::string caffemodel = jstring2string(env, caffeModel) __android_log_print(ANDROID_LOG_INFO, 'XOR', 'modelproto:%s, caffemodel:%s', modelproto.c_str(), caffemodel.c_str()) testnet.reset(new Net<float>(modelproto, TEST)) testnet->CopyTrainedLayersFrom(caffemodel) // obtain the input MemoryData layer and pass the input to it for testing float testab[] = {0, 0, 0, 1, 1, 0, 1, 1} float testc[] = {0, 1, 1, 0} MemoryDataLayer<float> *dataLayer_testnet = (MemoryDataLayer<float> *)(testnet->layer_by_name('test_inputdata').get()) dataLayer_testnet->Reset(testab, testc, 4) // calculate the neural network output testnet->Forward() // access blobs to display results boost::shared_ptr float> > output_layer = testnet->blob_by_name('output') const float* begin = output_layer->cpu_data() const float* end = begin + 4 // We know the output size is 4, and we save the outputs into the result vector vector<float> result(begin, end) // display the result char buf[512] = {0} string s for (int i = 0 i sprintf(buf, 'input: %d xor %d, truth: %d, result by NN: %f ', (int)testab[i * 2 + 0], (int)testab[i * 2 + 1], (int)testc[i],result[i]) s += buf } __android_log_print(ANDROID_LOG_INFO, 'XOR', 'test result:%s', s.c_str()) return string2jstring(env, s) }

Linuxバージョンのコードと比較すると、いくつかの変更があります。

  1. モデルファイルのパスは、model.prototxtファイルとXOR_iter_5000000.caffemodelファイルのフルパスであるJavaレイヤーから渡されます。
  2. 出力結果は、JNIを介してJavaレイヤーに返されます。

Java側のコードは次のとおりです。

public class MainActivity extends AppCompatActivity { File sdcard = Environment.getExternalStorageDirectory() String modelDir = sdcard.getAbsolutePath() String modelProto = modelDir + '/model.prototxt' String modelBinary = modelDir + '/XOR_iter_5000000.caffemodel' // Used to load the 'native-lib' library on application startup. static { System.loadLibrary('native-lib') System.loadLibrary('caffe') } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) final TextView tv = findViewById(R.id.result) Button btn = findViewById(R.id.start_test) btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { tv.setText(MainActivity.this.startXORTest(modelProto, modelBinary)) } }) } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String startXORTest(String modelProto, String caffeModel) }

このコードは、モデルファイルがsdcardにあることを前提としているため、コードを実行する前に、model.prototxtファイルとXOR_iter_5000000.caffemodelファイルを/ sdcard /にプッシュする必要があります。

adb push app/src/main/model/model.prototxt /sdcard/ adb push app/src/main/model/XOR_iter_5000000.caffemodel /sdcard/

コードのコンパイルと実行

アンドロイドスタジオを使用してビルドします。重要なのはCMakeLists.txtの準備です。

# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp ) add_definitions(-DCPU_ONLY) add_compile_options(-std=c++11) include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/caffe/include ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/boost/include ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/gflags/include ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/glog/include ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/protobuf/include ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/openblas/include) add_library(boost_system STATIC IMPORTED) set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/cpp/third_party/boost/lib/libboost_system.a ) add_library(caffe SHARED IMPORTED) set_target_properties(caffe PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libcaffe.so) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log ) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. native-lib # Links the target library to the log library # included in the NDK. ${log-lib} caffe boost_system)

知っておく必要があるのは:
1. Androidアプリでは、GPUを一時的に使用できないため、-DCPU_ONLYの定義を追加する必要があります
2.caffeおよび関連ライブラリのヘッダーファイルパスを追加する必要があります
3.カフェと関連ライブラリをリンクする必要があります

最終的な操作の結果は、LinuxPC環境での結果と同じです。

画像

参照

  1. 私の最初のcaffeC ++プログラム
  2. caffe-android-lib