8
5

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.

Flutter #2Advent Calendar 2019

Day 23

Cloud AutoML VisionとFlutterを組み合わせてサクッと画像認識アプリを作りたかったが作れなかった

Last updated at Posted at 2019-12-21

こんにちは、この記事は、Flutter Advent Calendar 21日目の記事です。(2時間遅れてしまって、上書きされてしまいました。。。とほほ。)
Flutter Advent Calendar #2 23日目が空いていたので、埋めさせていただきました。

概要

以下の構成で画像認識アプリを作ります。
flutter_automl.png

ポイントとしては、Cloud AutoML Visionから吐き出したTensorFlow Liteの形式のモデルを
Flutterで読み込ませて推論を行います。そのため、オフラインでも画像認識が行うことができます

ただ、現状、Flutter内で、推論を行おうとすると、アプリがクラッシュして落ちてしまいます...
(本記事の最後に原因の推測と対応策をまとめています。)

データセット_–_Vision_–_NullSuck_–_Google_Cloud_Platform.png

Cloud AutoML Visionで画像認識モデルをつくる

早速Flutterではなく、GCPをいじります。

AutoML APIの有効化

GCPのプロジェクト作成や請求先アカウントは作成済みの前提で進めます。
右のメニューから「Vision -> ダッシュボード」を選択すると、AutoML Visionのダッシュボードが開きます。

まず、ここでAutoML APIを有効化しましょう。

Vision_–_NullSuck_–_Google_Cloud_Platform.png

データセットのラベリング

AutoML APIを有効化するとデータセットの画面が開きます。

データセット_–_Vision_–_NullSuck_–_Google_Cloud_Platform.png

ここで、画像を含んだデータセットを登録することができます。
今回は、以下のペットのデータセットを使ってみましょう。

The Oxford-IIIT Pet Dataset

データセットをダウンロードすると以下のようなディレクトリ構成になっています。
一つのディレクトリにファイル名でラベリングしている形式です。

images
├── Abyssinian_1.jpg
├── Abyssinian_10.jpg
├── Abyssinian_100.jpg
...

AutoMLはファイル名ではなく、ディレクトリ名を元にラベリングを行うので、これだと一つのラベルしか付与されません。
そのため、ファイル名を元に以下のような形でディレクトリ毎にファイルを分けましょう。

自分は、人力でやりましたが、bash scriptなどを使うのがよいかと思います。

pets
├── Abyssinian
│   ├── Abyssinian_1.jpg
│   ├── Abyssinian_10.jpg
│   ├── Abyssinian_100.jpg
│    ...
├── American_bulldog
│   ├── american_bulldog_10.jpg
│   ├── american_bulldog_100.jpg
│   ├── american_bulldog_101.jpg
│    ...
├── Basset_Hound
│   ├── basset_hound_1.jpg
│   ├── basset_hound_10.jpg
│   ├── basset_hound_100.jpg
...

これをzipで固めてアップロードします。

データセットのアップロード

Vision -> データセット から新しいデータセットを選択します。
データセット_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

データセット名には適当な名前を、モデルの目的は「単一ラベル分類」を使いましょう。
データセット_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

「パソコンから画像をアップロード」で先程作成したzipファイルを選択。
画像はGoogle Cloud Storageに上がるので、バケットがない場合は、プロンプトに従ってバケットを作成しましょう。
既にGoogle Cloud Storageのバケットがある方はそれを選択します。

pets_1576730901896_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

画像のインポートは少々時間がかかるので他のことをして待ちましょう。
インポートが終わると、メールでお知らせしてくれます。
データセット_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

インポートが終わるとステータスが変わります。
データセット_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png
「警告: 画像のインポート」となったら取り込みが完了しています。
警告は一部の画像フォーマットが対応していないためで、特に気にしなくてよいです。

データセットをクリックして開くと、取り込まれた画像およびラベリングが確認できます。
pets_1576636901735_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

トレーニング

データセットを取り込み終わると学習を開始できます。
トレーニングから学習を開始しましょう。
pets_1576730901896_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

モデルの定義以下のように選択します。

  • モデルの定義: Edge
  • モデル最適化のオプション: Best Trade-Off(精度と速さのバランスをとったもの)
  • Node Hour Budget(トレーニングの上限時間): デフォルトで推測時間をセットしてくれてるのでそれを利用

ちなみに、Node Hour Budgetは最初の15時間は無料とのことです。

新しいモデルのトレーニング_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

トレーニング開始を押すと、学習を開始します。
これも時間がかかるのでしばらく待ちましょう。
(自分は、2,3時間ほどで学習が完了しました。)

データセット_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

モデルのトレーニングが完了するとモデルの評価も見ることができます。
pets_1576730901896_–_Vision_–_cloud-vision_–_Google_Cloud_Platform.png

正答率は100%-90%を出せていて優秀ですね。

TensorFlow Liteモデルのダウンロード

モデルができたので、TensorFlow Liteのモデルをダウンロードしましょう。
「テストと使用」をクリックすると様々な種類のモデルをダウンロードできます。

pets_1576730901896 – Vision – cloud-vision – Google Cloud Platform - Google Chrome 2019-12-21 12.37.08.png

この中から「TF Lite」を選択しましょう。クリックするとGoogle Cloud Storageにエクスポートするダイアログが出るので、エクスポートしましょう。
エクスポートすると、GCSの中に、tfliteとラベルのtxtファイルがあるのでそれをダウンロードします。(jsonファイルは利用しません。)
バケットの詳細 - cloud-vision - Google Cloud Platform - Google Chrome 2019-12-21 13.04.01.png

Flutterで画像認識アプリをつくる

モデルを配置する

ダウンロードしてきたTensorFlow Liteをassetsフォルダに配置します。

assets
└── custom
    ├── dict.txt
    └── model.tflite

pubspec.ymlにも以下の通り記載します。

pubspec.yml
# To add assets to your application, add an assets section, like this:
assets:
  - assets/custom/model.tflite
  - assets/custom/dict.txt

必要なプラグインを読み込む

FlutterでTensorFlow Liteのモデルを読み込めるプラグインがあるので、それを使ってみます。
https://github.com/shaqian/flutter_tflite

プロジェクトを作成して、pubspec.ymlに以下のとおり、プラグインを追加しましょう。
(image_pickerは、画像を選択できるピッカーのプラグインです。)

pubspec.yml
 dev_dependencies:
   flutter_test:
     sdk: flutter
+  tflite: 1.0.4
+  image_picker: 0.6.2+3

画面をつくる

main.dartで画面を作っていきます。
非常にシンプルなので、説明は省略します。

main.dart
import 'dart:async';
import 'dart:io';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Image Picker Example',
      theme: new ThemeData(
        primarySwatch: Colors.red,
      ),
      home: new MyHomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _HomePageState extends State<HomePage> {
  File _image;

  @override
  void initState() {
    super.initState();
  }

  Future getImage() async {
     var image = await ImagePicker.pickImage(source: ImageSource.gallery);

     setState(() {
       _image = image;
     });
   }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Picker Example'),
      ),
      body: Center(
        child: _image == null
            ? Text('No image selected.')
            : Image.file(_image),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: getImage,
        tooltip: 'Pick Image',
        child: Icon(Icons.add_a_photo),
      ),
    );
  }
}

立ち上げ時にモデルを読み込む

_HomePageStateinitState時にモデルを読み込むように処理を追加します。
TfliteloadModelメソッドを呼び出すと、モデルを読み込むことができます。

main.dart
 import 'package:flutter/material.dart';
 import 'package:image_picker/image_picker.dart';
+import 'package:tflite/tflite.dart';

 class MyHomePage extends StatefulWidget {
 (省略...)
    @override
    void initState() {
      super.initState();
+     loadModel();
   }

+  Future loadModel() async {
+    String res = await Tflite.loadModel(
+        model: "assets/custom/model.tflite",
+        labels: "assets/custom/dict.txt",
+    );
+    print(res);
+  }
 (省略...)
 }

画像選択時に推論するようにする

画像選択したときにモデルから推論を行うようにします。

main.dart
+  Future detectImage(File in_image) async {
+    var predictions = await Tflite.runModelOnImage(path: in_image.path);
+    print(predictions);
+  }

   Future getImage() async {
     var image = await ImagePicker.pickImage(source: ImageSource.gallery);
+    detectImage(image);

     setState(() {
       _image = image;
     });
   }

これで、アプリは完成しました。
ただし前述の通り、現状だと画像を読み込ませて、runModelOnImage時になにもログを吐かずにアプリが終了します。

動かない原因の推測

現状、flutterのtfliteプラグインがCloud AutoML Visionのモデルに対応していない可能性が高いです。
実際、モデルをtfliteのリポジトリ内のサンプルモデルに差し替えて動かすと、動きます。

実際、このIssueでも「Cloud AutoML VisionのモデルはQuantized Modelのため利用できない可能性が高い」という旨の言及があります。

対応策

以下のような対応策が考えられます。

最初からやり直すなら、最後のFirebase AutoML Vision Edgeを使うのがいいかな、と思いました。
Firebaseといっても、ほぼほぼGoogle Cloud版と機能は同じですし、Firebaseで勝手にモデルの更新もやってくれるみたいですし、非常に便利そうです。
次回はこれで、成功させてみたいな、と思ってます。

参考資料

Real-Time Object Detection with Flutter, TensorFlow Lite and Yolo -Part 1
Cross-Platform On-Device ML Inference TensorFlow Lite ft. Flutter

8
5
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
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?