10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

15分で作る機械学習Androidアプリ ! !

Last updated at Posted at 2020-12-05

今回やること

15分で機械学習(画像分類)アプリを作ってみる!
Android Studio 4.1でリリースされたML関連の機能を使用してサクっと作ってみます。
作るものはこんな感じ↓

↑見て分かる通り、精度的にまだまだ改善の余地ありですが、、、
githubとapkを今記事最下部に置いていますのでとりあえず試したいという方はそちらからどうぞ。

Android Studio 4.1 ML-Binding

皆さんご存じの通り最近いろいろML関連のサポートが充実し始めてきました。
Android Studio 4.1 では tensorflow liteモデルを簡単に組み込めるようにする機能が追加されました。(公式リリースノート)
内容としてはリリースノートの通りなんですがpick upすると

  • built-inでtensorflow liteモデルを動かす
  • gradleが自動で推論パイプラインを生成してくれる
  • tensorflow lite モデルの情報(input shape, output shape, label)をAndroid Studio上で確認できる
  • ラベルのマッピングを自動でやってくれる
  • tensorflow lite モデルのmetadataが必要(tensoflow liteからエクスポートできる、ただしまだ未対応のモデルも多数あるよう)
  • Android Studio 4.1 で対応しているのは画像分類スタイル変換のモデルのみ。物体検知とかはまだ未対応。(ただしAndroid Studio 4.2からは物体検知もサポートされ始める)
  • コード量が格段に減る

こんな感じになります。
推論パイプライン自動生成を使えば今までbitmapをbufferにallocateしてサイズ合わせてとかの実装をやらなくてもよくなるのでカスタマイズ性は下がりますが、実装の手間は大幅に減ります。
あとは、IDEでモデルの情報を見れるのはそこそこ便利だと感じました。outputとかの把握が大事なのでそれをandroid studioで確認できるのはwikiの整理とかも最小限で済むのでアリですね。
ただし、まだ対応しているモデルが少ないのでそこは今後に期待といったところかと思いますが、そもそもtensorflow liteに対応しているモバイルアーキテクチャのモデルが圧倒的に少ないのでやっぱり、「このモデル対応してない」みたいなある程度の制約は覚悟しておく必要があります。

モバイルはリソースの制限があるのでモデルサイズ、パラメータを小さくする必要があるのですが、まぁ、でっかいモデルをモバイル向けに設計するのって簡単じゃないよね。。。

公式ドキュメントより

Let's 15 min 実装

では、さっそく実装していきましょう

使用するモデルを用意

まずは推論に使用したい学習済みモデルTensorflow hubから探してダウンロードします。基本的にapache license 2.0です
ML-bindingは上述したように画像分類と画像変換しか対応していないので画像分類 Classificationのモバイルネットワークモデルを探しましょう。基本的にmetadataとセットになったモデルですがたまにmetadataがない場合があります。その時は自分で作る必要があります。

なお、今回はこのMobileNetV2 224x224を使用します。
MobileNetV2 224x224 tfliteモデルをダウンロードして適当なフォルダにおいて用意します。
キャプチャ.PNG

ML-binding

Android Studio 上でプロジェクトを右クリックして [New] > [Other] > [TensorFlow Lite Model]を選択し先ほどインストールしたモデルをAndroid Studio にインポートします。
成功すると、mlリソースフォルダが新しくresと同じ階層に生成されそこからモデルの情報が見れます。metadataが情報不足、またはない場合はここで見れるモデル情報が最小限になるみたいです。
これで準備は終了です。

推論の実装

必要に応じてAACをgradleに追加しておきます。
あとは、gradle:4.1 以上が必要になります。

build.gradle
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"

推論コードを書く

MainActivity.kt
/**
 * モデルをロードして画像分類を行う
 */
private suspend fun classifyImage(targetBitmap: Bitmap) = withContext(Dispatchers.IO) {
    val model = MobilenetV2.newInstance(this@MainActivity)  // モデルをロード
    val image = TensorImage.fromBitmap(targetBitmap)    // bitmapをテンソルに変換
    val output = model.process(image)  // 推論
    val categoryList : List<Category> = output.probabilityAsCategoryList
    model.close()
    return@withContext categoryList
}

この数行で終了です。。。
見たまんまなのですが、インポートしたファイル名でモデルをロードするためのクラスが生成されるのでそれを使ってprocess関数を呼び推論し結果を取得するだけです。
当然かもですが、一般にパラメータたくさん持つモデルにデータ渡して推論するのは重い処理なのでコルーチン等使ってメインスレッドでは実行しないようにしましょう。

このoutputとして得られるCategoryクラスですが、内容的には

public final class Category {
    private final String label;
    private final float score;
}

こんな感じで正解ラベルとマッピングされたラベルスコアが入っています。
スコアはいつも見たくソフトマックスにでも突っ込んで見やすい表示にするかって思ってましたが、おそらくすでに処理されていたのでそのまま使えました。

あとは、普通に関数をコールしてフォーマット整えてviewに反映させるだけです。

MainActivity.kt
// RUN ボタンクリックで推論結果を表示
inferrenceBtn.setOnClickListener {
    if (bitmap == null) return@setOnClickListener
    lifecycleScope.launch {
        // 推論結果を取得
        val outputs = classifyImage(bitmap!!)
        // viewにフォーマットした推論結果を15個表示
        resultTextView.text = outputs.sortedByDescending { it.score }
            .take(15)
            .joinToString("\n") { category ->
                "Label: ${category.label}, Score: ${"%.2f".format(category.score * 100)}%"
            }
    }
}

後は、推論する画像の用意ですが今回は適当にintentでも発行してギャラリーから画像を取得しましょう

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    // ギャラリーから画像を取得
    showGalleryBtn.setOnClickListener {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            setType("image/*")
        }
        startActivityForResult(intent, GALLERY_REQUEST_CODE)
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        GALLERY_REQUEST_CODE -> {
            // ギャラリーから画像データの取得
            bitmap = MediaStore.Images.Media.getBitmap(contentResolver, data?.data ?: return)
            previewImg.setImageBitmap(bitmap)
        }
    }
}

以上で終わりです
問題なければ冒頭で紹介したものと同じ機能を持つものが作れているはずです。

おわり

思った以上に簡単に実装できてしまって、mlサポートもここまで来たかぁって感じに思いました。
まだまだ、サポートが始まったばかりで対応している範囲は極々狭いので実際にこのml-bindingを使用してプロダクト作るとかはまだ先になりそうですが、お試しでやる分には手軽で楽しいですね。
2020/12時点でAndroid Studio 4.2-beta1が来ておりそちらを使えば、おそらく物体検知モデルもSSDモバイルアーキテクチャに限り使用できると思います。自分はwindowsでupdateがマニュアルインストールしかまだなかったのであきらめて今回は画像分類にしましたが。mac版1clickでアップデート可能っぽい?

今回のコード: https://github.com/SY-BETA/Simple-Image-Classification-Android-App
サンプルapk インストール(deploy gate): https://dply.me/9wprnq

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?