
イチゴかイチゴじゃないか?Android用MLKitで画像を分類する
少し前まで、機械学習(ML)は魔法の言葉のように聞こえていた。何を、どのように使うべきかについての詳細は、しばらくの間、私たちの多くにとって非常に曖昧だった。
それが当時の話だ。そして今、最もエキサイティングな発表のひとつがある。 グーグルI/O 2018私にとっては MLKit.簡単に説明すると、MLKitは一般的なMLのユースケースをいくつか取り上げ、それらを素晴らしいAPIで包み込んだものだ。
これに加えて、あなたのアプリが特定のユースケースを扱う場合、MLKitは便利なバージョン管理機能とともに、カスタムモデルを作成して使用することができます。
すぐに使える使用例のひとつは 画像ラベリング別名 画像分類.これは画像を取り込み、そこに含まれるエンティティ(動物、果物、活動など)を検出することを意味する。各画像入力は、エンティティ(ラベル)のリストと、そのエンティティが本当に画像に存在するかどうかの信頼度を表すスコアを出力します。これらのラベルは、コンテンツモデレーション、フィルタリング、検索などのアクションを実行するために使用することができます。
また、モバイルデバイスのリソースは限られており、データ消費を最小限に抑えることは、多くの場合、ありがたいことであるため、写真全体ではなくメタデータを扱うことは、パフォーマンス、プライバシー、帯域幅、オフラインサポートなどの問題に役立ちます。例えば、チャットアプリの場合、写真全体ではなく、ラベルだけを送信することができれば、多くのメリットがあります。
このチュートリアルでは、画像を取り込み、その中に含まれるエンティティを検出するモバイルアプリの書き方を説明します。このチュートリアルには3つのパートがあります:
世界で一番好きな食べ物はイチゴです!毎日、一日中食べても飽きない!
画像を撮影して、その中にイチゴが含まれているかどうかを検出するアプリを作ってみよう!
あなたが作るアプリ:
ユーザーは画像を選択し、それをどのように分類するかを選択するボタンを押す。
UIは画像(Bitmapオブジェクト)を ImageClassifierクラスに渡し、クラスは選択された特定のクラシファイア (LocalClassifier, CloudClassifierまたは CustomClassifier.このチュートリアルでは最初の2つのみを扱います)。それぞれのClassifierは入力を処理し、モデルを実行し、必要であれば出力を処理します。 ImageClassifierに送り、UIができるだけ簡単に表示できるように準備します。
始める前に
このプロジェクトをクローンして、コードとステップごとの実装を開始します。 https://github.com/brittBarak/MLKitDemo
アプリにFirebaseを追加する:
Firebase コンソールにログインします: https://console.firebase.google.com
新規プロジェクトの作成、または既存プロジェクトの選択
左側メニューの「設定」→「設定
一般」タブ→「アプリ」セクションで「アプリを追加」を選択。
Firebaseチュートリアルの手順に従って、アプリにFirebaseを追加してください。
追加
firebase-ml-visionライブラリをアプリに追加します。build.gradleファイルを追加する:
dependencies {
// …
implementation ‘com.google.firebase:firebase-ml-vision:17.0.0’
}前述したように、このチュートリアルではローカルとクラウドベースのディテクタの両方について説明します。それぞれ4つのステップがあります:
セッティング(これは不正行為ではない:ステップにはカウントされないが...)。
分類器のセットアップ
入力を処理する
出力を処理する
注:最終的なコードに長く従いたい場合は、ブランチにある 1.run_local_modelにあります。 リポジトリ.
ローカル(オンデバイス)モデルの実行
ローカルモデルの選択は、軽量でオフライン対応のオプションであり、無料である。その代わり、400以上のラベルを持つため、精度に限界があることを考慮しなければならない。
UIはビットマップを受け取る → 呼び出す ImageClassifier.executeLocal(bitmap)→ ImageClassifierを呼び出す LocalClassifier.execute()
最終的なコードを追いたい場合は、ブランチにある 1.run_local_model.
ステップ0:セットアップ
Firebase MLKitを使用して、ローカル検出器をアプリに追加します:
アプリレベルで build.gradleファイルに追加します:
dependencies {
// ...
implementation 'com.google.firebase:firebase-ml-vision-image-label-model:15.0.0'
}オプション、ただし推奨デフォルトでは,MLモデル自体は検出器を実行した時点でダウンロードされます.つまり、最初の実行時には、ネットワークへのアクセスと同様に、若干の待ち時間が発生します。これを回避し、Playストアからアプリをインストールする際にMLモデルをダウンロードするには、アプリのAndroidManifest.xmlファイルに以下の宣言を追加してください:
...
<!-- To use multiple models: android:value="label,barcode,face..." --> ステップ1: 分類器のセットアップ
作成 LocalClassifierクラスを作成します:
public class LocalClassifier {
detector = FirebaseVision.getInstance().getVisionLabelDetector();
}これが基本的なディテクターのインスタンスだ。返される出力についてもっとこだわることができ、次のように追加します。 信頼度しきい値を追加することができる。
class LocalClassifier {
//...
FirebaseVisionImage image;
public void execute(Bitmap bitmap) {
image = FirebaseVisionImage.fromBitmap(bitmap);
}
} ステップ2:入力を処理する
FirebaseVisionLabelDetector型の入力を扱う方法を知っている。 FirebaseVisionImage.インスタンスは FirebaseVisionImageインスタンスを得ることができる:
Bitmap(ここではこれを使う)、 Image Uri, MediaImage(メディアから、例えばデバイスのカメラから)、 ByteArrayまたは ByteBuffer.
を処理する。 Bitmapの処理はこのように行われる:
public class LocalClassifier {
//...
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
}チップ:ローカルモデルを使いたくなる理由のひとつは、実行がより速いからです。リアルタイムアプリケーションでモデルを使用する場合、より速い結果が必要になるかもしれません。次のステップに進む前にビットマップサイズを小さくすることで、モデルの処理時間を改善することができます。
ステップ3:モデルの実行
ここでマジックが起こる!?モデルには計算時間がかかるので、モデルを非同期で実行させ、リスナーを使って成功か失敗かの結果を返すようにします。
public class LocalClassifier {
//...
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
} ステップ4:出力を処理する
検出出力は OnSuccessListener.私は OnSuccessListenerから LocalClassifierから ImageClassifierとの間の通信を処理する。 LocalClassifier.
UIは次のように呼び出します。 ImageClassifier.executeLocal()を呼び出す:
オン ImageClassifier.java:
localClassifier = new LocalClassifier();
public void executeLocal(Bitmap bitmap, ClassifierCallback callback) {
successListener = new OnSuccessListener<List>() {
public void onSuccess(List labels) {
processLocalResult(labels, callback, start);
}
};
localClassifier.execute(bitmap, successListener, failureListener);
processLocalResult()は、UIに表示する出力ラベルを準備するだけである。
私の特定のケースでは、最も確率の高い3つの結果を表示することにしました。他の形式を選んでもよい。これが私の実装です:
OnImageClassifier.java:
void processLocalResult(List labels, ClassifierCallback callback) {
labels.sort(localLabelComparator);
resultLabels.clear();
FirebaseVisionLabel label;
for (int i = 0; i < Math.min(3, labels.size()); ++i) {
label = labels.get(i);
resultLabels.add(label.getLabel() + “:” + label.getConfidence());
}
callback.onClassified(“Local Model”, resultLabels);
}ClassifierCallbackは、結果をUIディスプレイに伝えるために私が作ったシンプルなインターフェースだ。このようなことをするために、他の方法を使うこともできた。好みの問題だ。
interface ClassifierCallback {
void onClassified(String modelTitle, List topLabels);
} それだけだ!
あなたは最初のMLモデルを使って画像を分類した!?なんて単純なんだ
アプリを実行し、結果を見てみよう!この部分の最終的なコードは、このデモの レポブランチ 1.run_local_model
なかなかいいね!食べ物」や「果物」のような一般的なラベルは、確かにイメージに合っている。いくつかのアプリのユースケースでは、このモデルは完璧にフィットする。画像をグループ化したり、検索を実行したりするのに役立つ。しかし、私たちのケースでは、どの果物が写真に写っているかを特定できるモデルを期待しています。
クラウドベースのディテクターには10,000以上のラベルが用意されている:
クラウドベースのモデルの実行
ステップ0:セットアップ
MLKitのクラウドベースのモデルは クラウドビジョンAPIに属しており、プロジェクトで有効になっていることを確認する必要があります:
クラウドベースのモデルを使用するには、毎月1000回以上の使用枠を超える支払いが必要です。デモや開発目的では、そのノルマに近づくことはないでしょう。しかし、Firebaseのプロジェクトプランをアップグレードする必要があります。アップグレード Sparkプランのプロジェクトを Blazeプランにアップグレードしてください。アップグレードは Firebaseコンソール.
Cloud Vision API を有効にします。 クラウドコンソールAPIライブラリ.トップメニューで、Firebase プロジェクトを選択し、まだ有効になっていなければ、Enable をクリックします。
注:開発段階では、この設定で十分です。しかし、本番環境にデプロイする前に、あなたのアカウントで不正な呼び出しが行われていないことを確認するための特別な手順を踏む必要があります。その場合は こちら.
ステップ1:分類器のセットアップ
検出器オブジェクトを保持する CloudClassifierクラスを作成する:
public class CloudClassifier {
detector = FirebaseVision.getInstance().getVisionCloudLabelDetector();
}これは上記とほぼ同じである。 LocalClassifier検出器のタイプを除いては。
ディテクターに設定できる追加オプションがいくつかある:
setMaxResults()- デフォルトでは10件の結果が返されます。それ以上必要な場合は、指定する必要がある。一方、デモ・アプリをデザインする際に、上位3つの結果だけを表示することにした。ここでそれを定義して、計算を少し速くすることができる。setModelType()- は次のいずれかである。 STABLE_MODELまたは LATEST_MODEL後者がデフォルトである。
public class CloudClassifier {
options = new FirebaseVisionCloudDetectorOptions.Builder()
.setModelType(FirebaseVisionCloudDetectorOptions.LATEST_MODEL)
.setMaxResults(ImageClassifier.RESULTS_TO_SHOW)
.build();
detector = FirebaseVision.getInstance().getVisionCloudLabelDetector(options);
} ステップ2:入力を処理する
同様に LocalDetector, FirebaseVisionCloudLabelDetectorの入力を使う。 FirebaseVisionImageの入力を使用する。 Bitmapから取得する;
public class CloudClassifier {
//...
FirebaseVisionImage image;
public void execute(Bitmap bitmap) {
image = FirebaseVisionImage.fromBitmap(bitmap);
}
} ステップ3:モデルの実行
前のステップと同様、このステップはローカルモデルを走らせるために行ったことと驚くほど似ている:
public class CloudClassifier {
public void execute(Bitmap bitmap, OnSuccessListener successListener, OnFailureListener failureListener) {
//...
detector.detectInImage(image)
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
} ステップ4:出力を処理する
ローカルモデルとクラウドベースのモデルは異なるため、その出力は異なる。 OnSuccessListener検出器ごとに異なる。しかし、扱うオブジェクトはまったく同じである。
オン ImageClassifier.java:
cloudClassifier = new CloudClassifier();
public void executeCloud(Bitmap bitmap, ClassifierCallback callback) {
successListener = new OnSuccessListener<List>() {
public void onSuccess(List labels) {
processCloudResult(labels, callback, start);
}
};
cloudClassifier.execute(bitmap, successListener, failureListener);
}繰り返しになるが、UIが提示する結果を処理するのは、UIが何を提示するかについてのあなた自身の判断による。この例では
processCloudResult(List labels, ClassifierCallback callback) {
labels.sort(cloudLabelComparator);
resultLabels.clear();
FirebaseVisionCloudLabel label;
for (int i = 0; i < Math.min(RESULTS_TO_SHOW, labels.size()); ++i) {
label = labels.get(i);
resultLabels.add(label.getLabel() + ":" + label.getConfidence());
}
callback.onClassified("Cloud Model", resultLabels);
} それだけだ?
結果を見てみよう:この記事のコードはレポジトリのブランチ 2.run_cloud_model
予想通り、モデルには少し時間がかかったが、画像に写っている特定の果物を見分けることができるようになった。また、ローカルモデルの信頼度が70~80%であるのに対し、90%以上の信頼度があります。
Firebase MLKitの使い方がいかにシンプルで楽しいか、ご理解いただけたと思います。顔検出、バーコードスキャンなど、他のモデルも同じように使えますので、ぜひ試してみてください!
さらに良い結果を得ることはできるだろうか?次回の投稿では、カスタム・モデルも使ってそれを探ってみよう。
次はどうする?
機械学習とは何か、どのように機能するのかについてもっと知りたい方は、開発者向けの入門ブログ記事をご覧ください: bit.ly/brittML-1, bit.ly/brittML-2, bit.ly/brittML-3