Android機械学習入門

# Androidアプリにおける機械学習概要
アプリ開発における機械学習（ML）は、アプリがアプリ内の体験や経験に基づいて、学習と改善を自動的に実行できるようにします。
Androidでは、機械学習用のさまざまなツールと手法がサポートされています。
Android用MLアプリの開発でやることは主に以下の４つです。
1. 機械学習対応の設計: 製品の目標を明確にして、MLのデザインパターンを活用し、設計を行う
2. モデルの構築とトレーニング: MLモデルを作成するか、既存の学習済みモデルを追加する
3. 推論: Android端末またはクラウド上で動作する学習済みモデルを使用してデータを分析する
4. デプロイ: アプリのMLモデルのインストールと更新をする
## 機械学習対応の設計
製品の目標を明確にして、それを達成するためにMLのデザインパターンを活用し、設計を行います。これを繰り返し行う必要があります。
詳細を知りたい方は、Googleでは機械学習に関する２つのガイドがあるので、そちらを参照ください。
- [人間と AI に関するガイドブック](https://design.google/ai-guidebook?hl=ja&utm_source=developer.android.com&utm_medium=referral)
- [機械学習用のマテリアル デザインの仕様](https://material.io/collections/machine-learning?utm_source=developer.android.com&utm_medium=referral)
## モデル構築とトレーニング
特定のタスクを実行する用にトレーニングされたモデルが必要です。
モデルの作成とトレーニングは開発マシン上で行うか、クラウドインフラを利用して行います。
### 事前学習済みのモデル
- [ML Kit](https://firebase.google.com/docs/ml-kit/?hl=ja&utm_source=developer.android.com&utm_medium=referral) : Googleのオンデバイス機械学習の専門知識をモバイルアプリで利用できるようにするSDK
    - Vision API : 画像にラベルをつけて、バーコード、テキスト、顔、オブジェクトを検出するAPI
    - Natural Language API : 58言語間の翻訳を識別して翻訳して、返信を提案する自然言語処理API
- [Google Cloud](https://cloud.google.com/products/ai/?hl=ja&utm_source=developer.android.com&utm_medium=referral) : CloudクライアントライブラリからCloud APIにアクセスして、学習済みモデルを利用する
### 独自のモデル
- [TensorFlow](https://www.tensorflow.org/?hl=ja&utm_source=developer.android.com&utm_medium=referral)：機械学習用のオーブンソースのライブラリ
    - 特徴として、データの読み込み、前処理、計算、状態、出力といった処理に対してテンソル（多次元配列）を扱っている
※事前トレーニング済みのモデルと独自モデルを導入する実装例は以下に記載します。
## 推論
特定のタスクを実行するためにすでにトレーニングされた機械学習モデルを使用するプロセスです。ここで、推論をデバイス上で実行するか、リモートからアクセスされるクラウドサービスを使用するか決める必要があります。
各種類の推論で代表的な開発オプションを以下に記載します。
### デバイスでの推論
ML Kit
- [画像ラベル付け](https://firebase.google.com/docs/ml-kit/label-images?hl=ja)
- [顔検出（顔輪郭検出を含む）](https://firebase.google.com/docs/ml-kit/detect-faces?hl=ja)
- [バーコード スキャン](https://firebase.google.com/docs/ml-kit/read-barcodes?hl=ja)
- [翻訳](https://firebase.google.com/docs/ml-kit/translation?hl=ja)
TensorFlow Lite
- [物体検出](https://github.com/tensorflow/examples/blob/master/lite/examples/object_detection/android/README.md)
- [ジェスチャー分類](https://github.com/tensorflow/examples/blob/master/lite/examples/gesture_classification/android/README.md)
### クラウドベースの推論
ML Kit
- [画像ラベル付け](https://firebase.google.com/docs/ml-kit/label-images?hl=ja&utm_source=developer.android.com&utm_medium=referral)
- [テキスト認識（OCR）](https://firebase.google.com/docs/ml-kit/recognize-text?hl=ja)
Google Cloud API
• [Cloud Video Intelligence](https://cloud.google.com/video-intelligence/?hl=ja) : ラベル付け、シーンや明示的なコンテンツの検出
• [Cloud 音声認識](https://cloud.google.com/speech-to-text/?hl=ja&utm_source=developer.android.com&utm_medium=referral)
## デプロイ
デバイス上で推論する際に Android で使用する ML モデルをパッケージ化および更新するプロセスのことです。
デプロイには以下の3つの方法があります。
- MLモデルをAndroidアプリに含める
- 実行時にモデルを提供する
- 両方を組み合わせる
## 実装
ここからは実際に事前学習済みのモデル(今回: ML Kit)と独自モデル(今回: TensorFlow Lite)の導入方法について説明していきます。
### ML Kitの導入
ML KitのAPIはすべてデバイス上で実行されるので、ライブカメラの写真をリアルタイムで処理します。今回は既存のオブジェクトの検出とトラッキングを追加します。
導入する手順はわずか3ステップです。(デバイスのカメラアプリで写真を撮るための機能の実装は割愛します)
1. `app/build.gradle` ファイルに以下のコードを追加します。
```kotlin
dependencies {
  // ...
  implementation 'com.google.mlkit:object-detection:17.0.0'
}
```
2.　画像上のオブジェクト検出の機能を追加する
ML Kitのオブジェクト検出トラッキングを設定するステップは3つです。
- 画像の準備
    - `BitMap` から `InputImage` を作成
- 検出用インスタンスを作成
    - 単一オブジェクト(複数のオブジェクトの検出と分類)が対象
- 検出器に画像をフィード
    ```kotlin
    private fun runObjectDetection(bitmap: Bitmap) {
    	// 画像の準備
    	val image = InputImage.fromBitmap(bitmap, 0)
    	// 検出用インスタンスの作成
    	val options = ObjectDetectorOptions.Builder()
    	   .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)
    	   .enableMultipleObjects()
    	   .enableClassification()
    	   .build()
    	val objectDetector = ObjectDetection.getClient(options)
    	// 検出器に画像をフィード
    	objectDetector.process(image)
    }
    ```
    
3.　ML Kitの検出結果を可視化する
可視化ユーティリティを使用して、入力画像の上にML Kitのオブジェクト検出結果を描写します。
```kotlin
private fun runObjectDetection(bitmap: Bitmap) {
        val image = InputImage.fromBitmap(bitmap, 0)

        val options = ObjectDetectorOptions.Builder()
            .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)
            .enableMultipleObjects()
            .enableClassification()
            .build()
        val objectDetector = ObjectDetection.getClient(options)

        objectDetector.process(image).addOnSuccessListener { results ->
            debugPrint(results)

            // ML Kitの検出を可視化します
					  val detectedObjects = results.map {
                var text = "Unknown"

                if (it.labels.isNotEmpty()) {
                    val firstLabel = it.labels.first()
                    text = "${firstLabel.text}, ${firstLabel.confidence.times(100).toInt()}%"
                }
                BoxWithText(it.boundingBox, text)
            }

            val visualizedResult = drawDetectionResult(bitmap, detectedObjects)

            inputImageView.setImageBitmap(visualizedResult)
        }
```

#### 実際の画面
![Screenshot_20221212-045715319.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532100/7c2c8d87-5566-530f-3b78-39608b60966d.jpeg)
### TensorFlow Liteの導入
[TensorFlow Lite](https://www.tensorflow.org/lite/guide/model_maker?hl=ja&utm_source=developers.google.com&utm_medium=referral)のモデルを作成し、アプリにモデルをデプロイします。
今回はTensorFlow Liteのモデルの導入を説明するため、学習モデルの作成方法は別の記事で解説したいと思います。
今回は[TensorFlow Hub](https://tfhub.dev/) にある利用可能な[オブジェクト検出モデル](https://tfhub.dev/tensorflow/collections/lite/task-library/object-detector/1)を利用していきたいと思います。
導入するまでのステップは４ステップです。
1. 学習済みモデル（今回: [EfficientDet-Lite オブジェクト検出モデル](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite0/detection/metadata/1?utm_source=developers.google.com&utm_medium=referral)）を `assets` フォルダに追加する
```kotlin
Project/
├ .gradle/
├ .idea/
├ app/
| ├ src
| | ├ main
| | | ├ assets/
| | | ├ java/
| | | ├ res/
| | | ├ AndroidManifest.xml
| ├ build.gradle
| ├ proguard-rules.pro
├ gradle/
├ build.gradle
├ gradle.properties
├ gradlew
├ gradlew.bat
├ loval.properites
├ settings.gradle
```
2.`app/build.gradle` ファイルに以下のコードを追加します。
```kotlin
dependencies {
  // ...
	implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.2'
}
```
3.画像上のオブジェクト検出を設定機能を追加します。(ML Kitでやったものと同じ)
```kotlin
private fun runObjectDetection(bitmap: Bitmap) {
        // 画像オブジェクトの生成
        val image = TensorImage.fromBitmap(bitmap)

        // 検出オブジェクトの作成
        val options = ObjectDetector.ObjectDetectorOptions.builder()
                .setMaxResults(5)
                .setScoreThreshold(0.3f)
                .build()
        val detector = ObjectDetector.createFromFileAndOptions(
                this,
                "model.tflite",
                options
        )

        // 検出器に画像をフィード
        val results = detector.detect(image)
}
```
4.入力画像に検出結果を描写します。

```kotlin
private fun runObjectDetection(bitmap: Bitmap) {
    val image = TensorImage.fromBitmap(bitmap)
    val options = ObjectDetector.ObjectDetectorOptions.builder()
            .setMaxResults(5)
            .setScoreThreshold(0.3f)
            .build()
    val detector = ObjectDetector.createFromFileAndOptions(
            this,
            "model.tflite",
            options
    )
    val results = detector.detect(image)

    // 検出結果をパースして、表示する
    val resultToDisplay = results.map{
        val category =it.categories.first()
        val text = "${category.label}, ${category.score.times(100).toInt()}%"

        // 検出結果を示すデータオブジェクトを生成
        DetectionResult(it.boundingBox, text)
}
// ビットマップ上に検索結果を描写し、表示する
    val imgWithResult = drawDetectionResult(bitmap, resultToDisplay)
    runOnUiThread{
			inputImageView.setImageBitmap(imgWithResult)
		}
}
```

#### 実際の画面
![Screenshot_20221212-054934.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532100/db80415b-10a4-094d-6c47-505565db2072.jpeg)


## まとめ

SDKやライブラリが充実しているので、機械学習について詳しくない自分でも簡単にAndroidアプリに機械学習を導入することができました。機械学習興味あるけど、あまり詳しくない人にもおすすめなので、ぜひさわってみてください！

## 参考

- [https://developer.android.com/ml?hl=ja](https://developer.android.com/ml?hl=ja)
- [https://developers.google.com/learn/pathways/get-started-object-detection?hl=ja](https://developers.google.com/learn/pathways/get-started-object-detection?hl=ja)
- [https://developers.google.com/learn/pathways/going-further-object-detection?hl=ja](https://developers.google.com/learn/pathways/going-further-object-detection?hl=ja)
- [https://developers.google.com/ml-kit/guides](https://developers.google.com/ml-kit/guides)