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.

README.en.md 15 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # MindSpore Lite Style Transfer Demo (Android)
  2. This sample application demonstrates how to use the MindSpore Lite API and MindSpore Lite style transfer model to perform inference on the device, replace the art style of the target image based on the built-in standard image in the demo, and display the image on the image preview screen of the app.
  3. ## Running Dependencies
  4. - Android Studio 3.2 or later (Android 4.0 or later is recommended.)
  5. ## Building and Running
  6. 1. Load the sample source code to Android Studio.
  7. ![start_home](images/home.png)
  8. Start Android Studio, click `File > Settings > System Settings > Android SDK`, and select the corresponding `SDK Tools`. As shown in the following figure, select an SDK and click `OK`. Android Studio automatically installs the SDK.
  9. ![start_sdk](images/sdk_management.jpg)
  10. > Android SDK Tools is the default installation. You can see this by unchecking the `Hide Obsolete Packages`box.
  11. >
  12. > If you have any Android Studio configuration problem when trying this demo, please refer to item 4 to resolve it.
  13. 2. Connect to an Android device and runs this application.
  14. Connect to the Android device through a USB cable for debugging. Click `Run 'app'` to run the sample project on your device.
  15. ![run_app](images/run_app.PNG)
  16. > Android Studio will automatically download MindSpore Lite, model files and other dependencies during the compilation process. Please be patient during this process.
  17. >
  18. > For details about how to connect the Android Studio to a device for debugging, see <https://developer.android.com/studio/run/device?hl=zh-cn>.
  19. >
  20. > The mobile phone needs to be turn on "USB debugging mode" before Android Studio can recognize the mobile phone. Huawei mobile phones generally turn on "USB debugging model" in Settings -> system and update -> developer Options -> USB debugging.
  21. 3. Continue the installation on the Android device. After the installation is complete, you can view the content captured by a camera and the inference result.
  22. ![result](images/app_result.jpg)
  23. 4. The solutions of configuration problems:
  24. 4.1 Problems of NDK, CMake, JDK Tools:
  25. If the tools installed in Android Studio are not recognized, you can re-download and install them from the corresponding official website, and configure the path.
  26. - NDK >= 21.3 [NDK](https://developer.android.google.cn/ndk/downloads?hl=zh-cn)
  27. - CMake >= 3.10.2 [CMake](https://cmake.org/download)
  28. - Android SDK >= 26 [SDK](https://developer.microsoft.com/zh-cn/windows/downloads/windows-10-sdk/)
  29. - JDK >= 1.8 [JDK](https://www.oracle.com/cn/java/technologies/javase/javase-jdk8-downloads.html)
  30. ![project_structure](images/project_structure.png)
  31. 4.2 NDK version does not match:
  32. Open `Android SDK`, click `Show Package Details`, and select the appropriate NDK version according to the error message.
  33. ![NDK_version](images/NDK_version.jpg)
  34. 4.3 Problem of Android Studio version:
  35. Update the Android Studio version in `Toolbar - Help - Checkout for Updates`.
  36. 4.4 Gradle dependencies installed too slowly:
  37. As shown in the picture, open the Demo root directory `build. Gradle` file, then add huawei mirror source address: `maven {url 'https://developer.huawei.com/repo/'}`, modify the classpath to 4.0.0 and click ` sync ` . Once the download is complete, restore the classpath version and synchronize it again.
  38. ![maven](images/maven.jpg)
  39. ## Detailed Description of the Sample Application
  40. The style transfer sample application on the Android device uses the Android Camera 2 API to enable a camera to obtain image frames and process images, as well as using [runtime](https://www.mindspore.cn/tutorial/lite/en/master/use/runtime.html) to complete model inference.
  41. ### Sample Application Structure
  42. ```text
  43. ├── app
  44. │   ├── build.gradle # Other Android configuration file.
  45. │   ├── download.gradle # During app building, the .gradle file automatically downloads the dependent library files and model files from the Huawei server.
  46. │   ├── proguard-rules.pro
  47. │   └── src
  48. │   ├── main
  49. │   │   ├── AndroidManifest.xml # Android configuration file.
  50. │   │   ├── java # Application code at the Java layer.
  51. │   │   │   └── com
  52. │   │   │   └── mindspore
  53. │   │   │   └── posenetdemo # Image processing and inference process implementation
  54. │   │   │   ├── CameraDataDealListener.java
  55. │   │   │   ├── ImageUtils.java
  56. │   │   │   ├── MainActivity.java
  57. │   │   │   ├── PoseNetFragment.java
  58. │   │   │   ├── Posenet.java #
  59. │   │   │   └── TestActivity.java
  60. │   │   └── res # Resource files related to Android.
  61. │   └── test
  62. └── ...
  63. ```
  64. ### Downloading and Deploying the Model File
  65. Download the model file from MindSpore Model Hub. The objective detection model file used in this sample application is `style_predict_quant.ms` and `style_transfer_quant.ms`, which is automatically downloaded during app building using the `download.gradle` script and stored in the `app/src/main/assets` project directory.
  66. > If the download fails, manually download the model files [style_predict_quant.ms](https://download.mindspore.cn/model_zoo/official/lite/style_lite/style_predict_quant.ms) and [style_transfer_quant.ms](https://download.mindspore.cn/model_zoo/official/lite/style_lite/style_transfer_quant.ms).
  67. ### Writing On-Device Inference Code
  68. In the style transfer demo, the Java API is used to implement on-device inference. Compared with the C++ API, the Java API can be directly called in the Java Class and does not need to implement the related code at the JNI layer. Therefore, the Java API is more convenient.
  69. The inference code process of style transfer demo is as follows. For details about the complete code, see `src/main/java/com/mindspore/styletransferdemo/StyleTransferModelExecutor.java`.
  70. 1. Load the MindSpore Lite model file and build the context, session, and computational graph for inference.
  71. - Loading a model: Read a MindSpore Lite model from the file system and parse it.
  72. ```java
  73. // Load the .ms model.
  74. style_predict_model = new Model();
  75. if (!style_predict_model.loadModel(mContext, "style_predict_quant.ms")) {
  76. Log.e("MS_LITE", "Load style_predict_model failed");
  77. }
  78. style_transform_model = new Model();
  79. if (!style_transform_model.loadModel(mContext, "style_transfer_quant.ms")) {
  80. Log.e("MS_LITE", "Load style_transform_model failed");
  81. }
  82. ```
  83. - Creating a configuration context: Create the configuration context `MSConfig` and save some basic configuration parameters required by the session for guiding graph building and execution.
  84. ```java
  85. msConfig = new MSConfig();
  86. if (!msConfig.init(DeviceType.DT_CPU, NUM_THREADS, CpuBindMode.MID_CPU)) {
  87. Log.e("MS_LITE", "Init context failed");
  88. }
  89. ```
  90. - Creating a session: Create `LiteSession` and call the `init` method to configure the `MSConfig` obtained in the previous step to the session.
  91. ```java
  92. // Create the MindSpore lite session.
  93. Predict_session = new LiteSession();
  94. if (!Predict_session.init(msConfig)) {
  95. Log.e("MS_LITE", "Create Predict_session failed");
  96. msConfig.free();
  97. }
  98. Transform_session = new LiteSession();
  99. if (!Transform_session.init(msConfig)) {
  100. Log.e("MS_LITE", "Create Predict_session failed");
  101. msConfig.free();
  102. }
  103. msConfig.free();
  104. ```
  105. - Load the model file and build a computational graph for inference.
  106. ```java
  107. // Compile graph.
  108. if (!Predict_session.compileGraph(style_predict_model)) {
  109. Log.e("MS_LITE", "Compile style_predict graph failed");
  110. style_predict_model.freeBuffer();
  111. }
  112. if (!Transform_session.compileGraph(style_transform_model)) {
  113. Log.e("MS_LITE", "Compile style_transform graph failed");
  114. style_transform_model.freeBuffer();
  115. }
  116. // Note: when use model.freeBuffer(), the model can not be compile graph again.
  117. style_predict_model.freeBuffer();
  118. style_transform_model.freeBuffer();
  119. ```
  120. 2. Input data. Currently, Java supports two types of data: `byte[]` and `ByteBuffer`. Set the data of the input tensor.
  121. - Convert a float array to a byte array before data is input.
  122. ```java
  123. public static byte[] floatArrayToByteArray(float[] floats) {
  124. ByteBuffer buffer = ByteBuffer.allocate(4 * floats.length);
  125. buffer.order(ByteOrder.nativeOrder());
  126. FloatBuffer floatBuffer = buffer.asFloatBuffer();
  127. floatBuffer.put(floats);
  128. return buffer.array();
  129. }
  130. ```
  131. - Input data through `ByteBuffer`. `contentImage` is the image provided by users, and `styleBitmap` is the built-in style image.
  132. ```java
  133. public ModelExecutionResult execute(Bitmap contentImage, Bitmap styleBitmap) {
  134. Log.i(TAG, "running models");
  135. fullExecutionTime = SystemClock.uptimeMillis();
  136. preProcessTime = SystemClock.uptimeMillis();
  137. ByteBuffer contentArray =
  138. ImageUtils.bitmapToByteBuffer(contentImage, CONTENT_IMAGE_SIZE, CONTENT_IMAGE_SIZE, 0, 255);
  139. ByteBuffer input = ImageUtils.bitmapToByteBuffer(styleBitmap, STYLE_IMAGE_SIZE, STYLE_IMAGE_SIZE, 0, 255);
  140. ```
  141. 3. Perform inference on the input tensor based on the model, obtain the output tensor, and perform post-processing.
  142. - Use `runGraph` to perform model inference on the built-in image and obtain the result `Predict_results`.
  143. ```java
  144. List<MSTensor> Predict_inputs = Predict_session.getInputs();
  145. if (Predict_inputs.size() != 1) {
  146. return null;
  147. }
  148. MSTensor Predict_inTensor = Predict_inputs.get(0);
  149. Predict_inTensor.setData(input);
  150. preProcessTime = SystemClock.uptimeMillis() - preProcessTime;
  151. stylePredictTime = SystemClock.uptimeMillis();
  152. ```
  153. ```java
  154. if (!Predict_session.runGraph()) {
  155. Log.e("MS_LITE", "Run Predict_graph failed");
  156. return null;
  157. }
  158. stylePredictTime = SystemClock.uptimeMillis() - stylePredictTime;
  159. Log.d(TAG, "Style Predict Time to run: " + stylePredictTime);
  160. // Get output tensor values.
  161. List<String> tensorNames = Predict_session.getOutputTensorNames();
  162. Map<String, MSTensor> outputs = Predict_session.getOutputMapByTensor();
  163. Set<Map.Entry<String, MSTensor>> entry = outputs.entrySet();
  164. float[] Predict_results = null;
  165. for (String tensorName : tensorNames) {
  166. MSTensor output = outputs.get(tensorName);
  167. if (output == null) {
  168. Log.e("MS_LITE", "Can not find Predict_session output " + tensorName);
  169. return null;
  170. }
  171. int type = output.getDataType();
  172. Predict_results = output.getFloatData();
  173. }
  174. ```
  175. - Perform model inference on the user image again based on the previous result to obtain the style transfer result `transform_results`.
  176. ```java
  177. List<MSTensor> Transform_inputs = Transform_session.getInputs();
  178. // transform model have 2 input tensor, tensor0: 1*1*1*100, tensor1; 1*384*384*3
  179. MSTensor Transform_inputs_inTensor0 = Transform_inputs.get(0);
  180. Transform_inputs_inTensor0.setData(floatArrayToByteArray(Predict_results));
  181. MSTensor Transform_inputs_inTensor1 = Transform_inputs.get(1);
  182. Transform_inputs_inTensor1.setData(contentArray);
  183. ```
  184. ```java
  185. styleTransferTime = SystemClock.uptimeMillis();
  186. if (!Transform_session.runGraph()) {
  187. Log.e("MS_LITE", "Run Transform_graph failed");
  188. return null;
  189. }
  190. styleTransferTime = SystemClock.uptimeMillis() - styleTransferTime;
  191. Log.d(TAG, "Style apply Time to run: " + styleTransferTime);
  192. postProcessTime = SystemClock.uptimeMillis();
  193. // Get output tensor values.
  194. List<String> Transform_tensorNames = Transform_session.getOutputTensorNames();
  195. Map<String, MSTensor> Transform_outputs = Transform_session.getOutputMapByTensor();
  196. float[] transform_results = null;
  197. for (String tensorName : Transform_tensorNames) {
  198. MSTensor output1 = Transform_outputs.get(tensorName);
  199. if (output1 == null) {
  200. Log.e("MS_LITE", "Can not find Transform_session output " + tensorName);
  201. return null;
  202. }
  203. transform_results = output1.getFloatData();
  204. }
  205. ```
  206. - Process the output node data to obtain the final inference result.
  207. ```java
  208. float[][][][] outputImage = new float[1][][][]; // 1 384 384 3
  209. for (int x = 0; x < 1; x++) {
  210. float[][][] arrayThree = new float[CONTENT_IMAGE_SIZE][][];
  211. for (int y = 0; y < CONTENT_IMAGE_SIZE; y++) {
  212. float[][] arrayTwo = new float[CONTENT_IMAGE_SIZE][];
  213. for (int z = 0; z < CONTENT_IMAGE_SIZE; z++) {
  214. float[] arrayOne = new float[3];
  215. for (int i = 0; i < 3; i++) {
  216. int n = i + z * 3 + y * CONTENT_IMAGE_SIZE * 3 + x * CONTENT_IMAGE_SIZE * CONTENT_IMAGE_SIZE * 3;
  217. arrayOne[i] = transform_results[n];
  218. }
  219. arrayTwo[z] = arrayOne;
  220. }
  221. arrayThree[y] = arrayTwo;
  222. }
  223. outputImage[x] = arrayThree;
  224. }
  225. ```
  226. ```java
  227. Bitmap styledImage =
  228. ImageUtils.convertArrayToBitmap(outputImage, CONTENT_IMAGE_SIZE, CONTENT_IMAGE_SIZE);
  229. postProcessTime = SystemClock.uptimeMillis() - postProcessTime;
  230. fullExecutionTime = SystemClock.uptimeMillis() - fullExecutionTime;
  231. Log.d(TAG, "Time to run everything: $" + fullExecutionTime);
  232. return new ModelExecutionResult(styledImage,
  233. preProcessTime,
  234. stylePredictTime,
  235. styleTransferTime,
  236. postProcessTime,
  237. fullExecutionTime,
  238. formatExecutionLog());
  239. ```