Flutter を使った Androidアプリ開発など：TensorFlow形式から変換した LiteRT（TensorFlow Lite）のモデルを使った際のメモ

以下でポストしていたアプリを動かす際にやったことなど雑なメモです。

https://x.com/youtoy/status/1885747839797744085

一連の手順を網羅した内容ではないのですが、部分的に何か後で役立つところが出てくるかもしれないと思い雑多なメモになるのは分かっていつつメモを残してみます。

## 雑多なメモ

### 元になるモデルの話

TensorFlow形式のモデルは、数値データ 4つを入力とした多クラス（3クラス）分類を行うモデルで、とある経緯で既に作られたものがありました。

今回のメモは、それをファイルとしてダウンロードした後の内容を残すものになり、この部分の詳細は省略します。

もう少しだけ書いておくと、学習データとなる数値データがあり、モデルは多層パーセプトロンで、オプティマイザ・損失関数のところは適応的モーメント推定・カテゴリカル交差エントロピーなどが使われている処理でした。
これにより TensorFlow/Keras のモデルが作成されていて、Google Colab上で推論の処理が動く状態のものになっていました。

#### 元のモデルの変換
上記のものが既にあり、自分はそのモデルの変換から始めました。

以下のように Colab上にモデルをいったん保存しつつ、変換の処理を行いました。

```python
model.save('/content/model/model.keras')

model_keras = tf.keras.models.load_model('/content/model/model.keras')
converter = tf.lite.TFLiteConverter.from_keras_model(model_keras)
tflite_model = converter.convert()

with open('/content/model/model.tflite', 'wb') as f:
    f.write(tflite_model)
print("モデルの変換が完了")
```

#### 変換後のモデルの動作テスト
そして、いったん Colab上で変換後のモデルを使った推論の動作確認も行っておきました。

具体的には、以下の処理を行いました。

```python
import numpy as np
import tensorflow.lite as tflite

# モデルのロードなど
interpreter = tflite.Interpreter(model_path='model.tflite')
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# 入力データを作成
sample_input = np.array([[【数値1】,【数値2】,【数値3】,【数値4】]], dtype=np.float32)

interpreter.set_tensor(input_details[0]['index'], sample_input)

# 推論の実行
interpreter.invoke()

# 出力
output_data = interpreter.get_tensor(output_details[0]['index'])
predicted_class = np.argmax(output_data, axis=1)
print(f"予測結果: {predicted_class[0]}")
```

このような処理を試し、モデルの変換前と後で同じ結果が得られることを確認し、次へ進みました。

### LiteRT（TensorFlow Lite）形式のモデルを Flutter で使う
次に上で作っていた LiteRT（TensorFlow Lite）形式のモデルを、Flutter で使えるようにやり方を調べたりしました。

#### tflite_flutter
Flutter は今年になってから環境を作るのを試した、という感じのレベル感なので既にある事例を調べてやり方を確認していきました。

https://x.com/youtoy/status/1874457716762284415

どうやら、以下を用いるやり方になるようで

●tflite_flutter | Flutter package
 https://pub.dev/packages/tflite_flutter

![2025-02-02_10-04-21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/abfdabaf-b6b6-b197-f794-076b633ad937.jpeg)

今回用いた環境は、上で動画を添付したポストに書かれているとおり Androidアプリを開発するためのものでした。

以下の記事でも書いた Android Studio を使ったものになります。

- [Flutter・Androidアプリの開発環境を作った時のメモ（Mac） - Qiita](https://qiita.com/youtoy/items/434020813fc4dde00131)
- [FVM で Windows上での Flutter の開発構築のメモ（＋ Androidアプリの開発環境も） - Qiita](https://qiita.com/youtoy/items/edca3e29ac3e39108579)

上記2つの記事にあるように、Mac と Windows の両方で環境を用意してみたのですが、今回は Windows環境で進めていきました。

### Flutter でモデルを扱う方法を確認
#### o3-mini-high を活用してみる

今回の内容を試しているタイミングで、ちょうど ChatGPT で o3-mini／o3-mini-high が使えるようになりました。

https://x.com/youtoy/status/1885474060978839940

o3-mini-high がコーディングに向いているという話があったのと、Flutter での LiteRT の利用は自分に知識・経験がなかったので、Web での情報調査と合わせて今回の内容で活用してみました。

#### 最低限のセッティングを確認

今回の内容は、Android Studio で Flutter用のプロジェクトを新規作成したところに、最低限必要となる部分のみ足したりなどしてやってみる方針にしていました。

それで、上記の o3-mini-high で必要な対応を確認してみました。

得られた回答はこの後に掲載している内容などでした。その回答を得られた後は、Web上の情報を調べたり実際に動かしてみたりしましたが、o3-mini-high から提示された情報で概ね問題はないという結果でした（今回のこの事例で、結果的にそうだっただけで、o3-mini-high の性能的な部分は未検証）。

細かく言うと、一部コマンドを使った対応で示されていて、そこは自分は Android Studio の GUI上で対応した、というのはあったりしました。

### Android Studio での対応を行う

Android Studio でモデルや関連する設定などを加えるところの話です。

#### モデルや関連する設定などを加える

まず、o3-mini-high で示された情報をベースに事例を書いていきます。

こちらは pubspec.yaml に関する部分です。

![2025-02-02_10-15-17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1ae35dbb-f767-7b47-bc96-12218f50a160.jpeg)

上記については、Web で調べた情報や現在のバージョン情報をもとに、最終的には以下としました。tflite_flutter のみにして、バージョンの部分を `^0.11.0` とした形です。

```yaml: pubspec.yaml の一部
dependencies:
  flutter:
    sdk: flutter

  tflite_flutter: ^0.11.0
```

依存関係のインストールは、以下の記事などにもあるような GUI操作で行いました。

●【Flutter】パッケージのインストール・使用方法 | ヒヨコ プログラミング（ヒヨプロ）
 https://hiyoko-programming.com/1242/

自分の環境の画面キャプチャで。GUI操作を行う部分を示した画像を掲載しておきます。

![2025-02-02_02-41-27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/5d009226-1eb3-9e94-daa4-701432f75651.jpeg)

さらに、以下の記載も追加しました。

![2025-02-02_10-25-15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/7291c2d8-67f3-4ebd-5ff1-94827455d429.jpeg)

合わせて、上記の中のモデルファイルの追加も行っています。
（プロジェクトのルート直下、 `assets/model.tflite` です）

他に o3-mini-high の出力で、「android/app/build.gradle の設定」という内容が示されていましたが、内容を見た感じ不要そうな内容だったのでスキップしました。

#### コード
そして、今回用いたコードは以下のとおりです。

o3-mini-high に、Google Colab上でテストしていた処理内容もプロンプトでわたしつつ、出力を依頼したものです。最初に示されたものはエラーになったので、以下はその後に情報を調べたり o3-mini-high を使ったやりとりなどをして、エラーが出ないように対応した最終版になります。

```dart
import 'package:flutter/material.dart';
import 'package:tflite_flutter/tflite_flutter.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Interpreter? _interpreter;
  String _result = "推論の実行前";

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

  // モデルのロード
  Future<void> _loadModel() async {
    try {
      _interpreter = await Interpreter.fromAsset('assets/model.tflite');
      print('モデルのロードが完了');
    } catch (e) {
      print('モデルのロードでエラーが発生: $e');
    }
  }

  // ボタン押下で固定の入力値に対する推論を実行
  void _runInference() {
    if (_interpreter == null) return;

    // 4つの値をテスト用にハードコーディング
    List<double> inputData = [【数値1】, 【数値2】, 【数値3】, 【数値4】];

    var input = [inputData];
    var output = List.filled(3, 0.0).reshape([1, 3]);
    // 推論の実行処理
    _interpreter!.run(input, output);
    print("出力: $output");

    // 推論で得られた結果のうち最上位のものを取得
    int predictedClass = output[0].indexWhere((element) {
      // 当初のコードでエラーが発生したので加えた部分で暫定対応、もっと良い書き方がありそうなところ
      double maxValue = (output[0] as List<dynamic>).reduce((a, b) => (a as double) > (b as double) ? a : b);
      return element == maxValue;
    });

    setState(() {
      _result = "Predicted class: $predictedClass";
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TFLite Flutter Demo',
      home: Scaffold(
        appBar: AppBar(title: Text('TFLite Flutter Demo')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(_result, style: TextStyle(fontSize: 24)),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _runInference,
                child: Text('推論を実行'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```

今回、最小限の変更などで LiteRT（TensorFlow Lite）のモデルを Flutter で動かせるか確認するというのが目的でした。

そのため、入力用の数値はハードコーディングになっていて自由度がない部分があったり、エラー解消のためとりあえずで実装した部分の見直しができてないところがあったりします。
（対応時間を短く、なおかつコードの分量・手順を小さくしたい背景があったのもあり）

これで冒頭に画像を掲載していた、Androidアプリ上での LiteRT（TensorFlow Lite）のモデルを使った推論を行うことができまｓ

## 余談
今回はとある事情で、既に用意されていた特定の作り方をされていた TensorFlow形式のモデルを、Flutter で動かすという流れをやりました。

その中で出てきた tflite_flutter を見ていた際、以下のサンプルを見かけて面白そうだと感じました。

●flutter-tflite/example at main · tensorflow/flutter-tflite · GitHub
 https://github.com/tensorflow/flutter-tflite/tree/main/example

機械学習まわりは、自分の個人的な好みで JavaScript を使ったものにいろいろ手を出していますが（Teachable Machine や、MediaPipe JavaScript版、TensorFlow.js関連）、上記を見ていてこれも試してみたくなりました。