「AIって、クラウドやサーバーがないと使えないんじゃないの?」そう思っている方、多いんじゃないでしょうか。

実は今、マイコン(Arduino)の上で直接AIの推論を動かす「エッジAI」が注目されています。クラウドに頼らず、デバイス単体でリアルタイムに判断できるので、通信遅延もなく、プライバシーも守られる。IoTの世界をガラッと変える技術です。

今回は、Googleが開発したTensorFlow Lite(TFLite)を使って、Arduinoの上でAI推論を動かす方法を、ゼロから一緒に試してみましょう!

🤖 エッジコンピューティングとは?まずイメージをつかもう

Arduino microcontroller AI
Arduino microcontroller AI / Photo by Lisha Dunlap via Pexels

従来のAIシステムは、センサーのデータをクラウドに送って、サーバー側で判断して、結果を返す……という流れでした。

イメージとしては、「現場の担当者が上司に電話して指示を仰ぐ」感じですね。

一方、エッジコンピューティングは「現場の担当者が自分で判断する」イメージです。データをクラウドに送らず、デバイス(エッジ)の上で処理を完結させます。

メリットをまとめるとこんな感じです。

  • 低遅延:ネットワーク往復がないので即座に反応できる
  • オフライン動作:インターネット不要で動く
  • プライバシー保護:センサーデータを外に送らない
  • 低コスト:クラウドAPIの通信費・利用料が不要

🔧 TensorFlow Liteとは?

TensorFlow Lite(TFLite)は、Googleが開発したTensorFlowの「軽量版」です。スマホやマイコンなど、リソースが限られたデバイスでAIモデルを動かすために最適化されています。

さらにその中でも、TensorFlow Lite for Microcontrollers(TFLM)というサブセットが、ArduinoなどのマイコンボードでTFLiteモデルを動かすための専用ライブラリです。

つまり、流れはこうなります。

  1. PCでTensorFlowを使ってAIモデルを学習
  2. TFLite形式(.tflite)に変換・量子化して軽量化
  3. そのモデルをArduinoのスケッチに組み込んで推論

難しく聞こえますが、ひとつひとつ見ていくと「なるほど!」と思えるはずです。

📦 必要なもの

  • Arduino Nano 33 BLE Sense(TFLMに対応した推奨ボード。加速度センサー・マイクなどが内蔵)
  • Arduino IDE(最新版)
  • Pythonが動くPC(モデル学習・変換に使用)
  • 必要なPythonライブラリ:tensorflow, numpy

⚠️ Arduino UNO(ATmega328P)はメモリが少なすぎてTFLMには向きません。Arduino Nano 33 BLE SenseまたはArduino Nano RP2040 Connectなど、より高性能なボードを使いましょう。

🧠 STEP1:PCでシンプルなモデルを学習&TFLite変換する

まずは、Pythonで超シンプルなモデルを作って、TFLite形式に変換してみましょう。ここでは「サイン波を予測するモデル」で動作確認します。

# train_and_convert.py
import numpy as np
import tensorflow as tf

# ---- 1. 学習データの作成 ----
# 0〜2πのサンプル点を1000個生成してサイン波を学習させる
X = np.linspace(0, 2 * np.pi, 1000).reshape(-1, 1).astype(np.float32)
Y = np.sin(X).astype(np.float32)

# ---- 2. モデルの定義 ----
model = tf.keras.Sequential([
    tf.keras.layers.Dense(16, activation='relu', input_shape=(1,)),
    tf.keras.layers.Dense(16, activation='relu'),
    tf.keras.layers.Dense(1)  # 出力は1値(サイン波の値)
])

model.compile(optimizer='adam', loss='mse')
model.fit(X, Y, epochs=200, batch_size=32, verbose=0)
print("学習完了!")

# ---- 3. TFLite形式に変換 ----
converter = tf.lite.TFLiteConverter.from_keras_model(model)

# 量子化オプション:モデルをint8に圧縮してさらに軽量化
converter.optimizations = [tf.lite.Optimize.DEFAULT]

tflite_model = converter.convert()

# ---- 4. ファイルに保存 ----
with open('sine_model.tflite', 'wb') as f:
    f.write(tflite_model)

print(f"TFLiteモデルを保存しました(サイズ: {len(tflite_model)} bytes)")

ポイントをまとめるとこんな感じです。

  • converter.optimizations = [tf.lite.Optimize.DEFAULT] を指定することで、ポスト学習量子化が有効になり、モデルサイズが大幅に削減されます
  • 出力される sine_model.tflite が数KB〜数十KB程度になれば成功です
  • Arduinoのフラッシュメモリ(Nano 33 BLE Sense は1MB)に収まるサイズにすることが重要です

🔁 STEP2:TFLiteモデルをCヘッダファイルに変換する

Arduinoはファイルシステムを持たないので、.tfliteファイルを直接読み込めません。バイナリデータをC言語の配列として埋め込む必要があります。

# convert_to_header.py
# sine_model.tflite を Cヘッダファイルに変換する

with open('sine_model.tflite', 'rb') as f:
    data = f.read()

# C言語の配列形式に変換
hex_values = ', '.join([f'0x{b:02x}' for b in data])

header_content = f"""// 自動生成: sine_model_data.h
#ifndef SINE_MODEL_DATA_H
#define SINE_MODEL_DATA_H

const unsigned char sine_model_data[] = {{
  {hex_values}
}};
const int sine_model_data_len = {len(data)};

#endif  // SINE_MODEL_DATA_H
"""

with open('sine_model_data.h', 'w') as f:
    f.write(header_content)

print(f"ヘッダファイルを生成しました({len(data)} bytes)")

生成された sine_model_data.h を、次のArduinoスケッチと同じフォルダに置いておきましょう。

⚡ STEP3:ArduinoスケッチでTFLite推論を実行する


Arduino向けTFLMライブラリをインストールしてから、以下のスケッチを書き込みます。

⚠️ ライブラリのインストールについて重要な注意: かつてライブラリマネージャーで配布されていた Arduino_TensorFlowLite はすでに削除されており、ライブラリマネージャーからは検索・インストールできません。現在は以下のいずれかの方法を利用してください。

  • GitHubからの手動インストール(公式): tflite-micro-arduino-examples をArduinoのlibrariesフォルダへ git clone する(※2025年2月にアーカイブ済み・読み取り専用のため最新メンテナンスはなし)
  • ライブラリマネージャーから代替ライブラリを利用: Chirale_TensorFlowLite など、コミュニティがメンテナンスしている互換ライブラリを「ライブラリマネージャー」で検索してインストールする方法もあります
// sine_inference.ino
// TFLiteでサイン波を推論してシリアルモニターに出力するスケッチ

#include <TensorFlowLite.h>
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "sine_model_data.h"  // PCで生成したヘッダファイル

// テンソルアリーナ:推論に使うメモリ領域(サイズは要調整)
constexpr int kTensorArenaSize = 10 * 1024;  // 10KB
uint8_t tensor_arena[kTensorArenaSize];

// TFLiteオブジェクト
const tflite::Model* model = nullptr;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;
TfLiteTensor* output = nullptr;

void setup() {
  Serial.begin(9600);
  while (!Serial);  // シリアル接続を待つ

  // ---- モデルのロード ----
  model = tflite::GetModel(sine_model_data);
  if (model->version() != TFLITE_SCHEMA_VERSION) {
    Serial.println("モデルのバージョンが一致しません!");
    return;
  }

  // ---- インタープリタの初期化 ----
  static tflite::AllOpsResolver resolver;  // 必要な演算子を自動解決
  static tflite::MicroInterpreter static_interpreter(
      model, resolver, tensor_arena, kTensorArenaSize);
  interpreter = &static_interpreter;

  // テンソルメモリの割り当て
  if (interpreter->AllocateTensors() != kTfLiteOk) {
    Serial.println("テンソルの割り当てに失敗しました!");
    return;
  }

  input  = interpreter->input(0);
  output = interpreter->output(0);

  Serial.println("TFLite推論エンジン 起動完了!");
}

void loop() {
  // 0〜2πを少しずつ動かしながら推論する
  for (float x = 0.0f; x <= 2.0f * 3.14159f; x += 0.1f) {
    // ---- 入力テンソルにデータをセット ----
    input->data.f[0] = x;

    // ---- 推論実行 ----
    if (interpreter->Invoke() != kTfLiteOk) {
      Serial.println("推論に失敗しました!");
      return;
    }

    // ---- 推論結果を取得 ----
    float predicted = output->data.f[0];
    float expected  = sin(x);  // 正解値(Arduinoの組み込みsin関数)

    // シリアルモニターに出力
    Serial.print("x=");
    Serial.print(x, 3);
    Serial.print("  predicted=");
    Serial.print(predicted, 4);
    Serial.print("  expected=");
    Serial.println(expected, 4);

    delay(50);
  }

  Serial.println("--- 1サイクル完了 ---");
  delay(1000);
}

ここが重要です。

  • kTensorArenaSize:推論に必要なワーク用メモリです。モデルが大きいほど多く必要です。不足すると AllocateTensors() が失敗するので、エラーが出たら値を増やしてみてください
  • AllOpsResolver:すべての演算子を含む便利なリゾルバです。本番では使う演算子だけを登録する MicroMutableOpResolver を使うとさらに軽量化できます
  • input->data.f[0] = x:float型テンソルへの入力セットです。量子化モデルの場合は .int8.uint8 を使います

📊 シリアルモニターで結果を確認しよう


スケッチを書き込んでシリアルモニターを開くと、こんな出力が流れていきます。

予測値(predicted)と正解値(expected)がほぼ一致していれば、Arduino上でAI推論が動いている証拠です!🎉

マイコンの上でこれが動いているというのは、なかなか感動しますよ。

🚀 実用的な応用例

サイン波の予測だけじゃもったいないですよね。TFLMを使うと、こんなことが実現できます。

  • 🏃 ジェスチャー認識:加速度センサーのデータから「振る」「叩く」などの動作をリアルタイム分類
  • 🔊 音声キーワード検出:マイクから「yes/no」などの単語を認識(Wake Word検出)
  • 🌡️ 異常検知:センサーの時系列データから機器の異常をその場で判定
  • 🌿 植物の状態分類:土壌センサーの数値からAIが水やりタイミングを判断

Arduino Nano 33 BLE Senseには加速度・ジャイロ・温湿度・マイクなど多彩なセンサーが内蔵されているので、ハードウェアをほぼ追加せずに試せるのが嬉しいポイントです。

💡 モデルを小さくするコツ

マイコンのリソースは限られているので、モデルの軽量化が命です。押さえておきたいポイントをまとめます。

  • 量子化(Quantization):float32 → int8 にすることでサイズを約75%削減
  • レイヤー数を絞る:隠れ層は16〜32ユニット程度に抑える
  • AllOpsResolverを使わない:使う演算子だけ登録してフラッシュ使用量を節約
  • テンソルアリーナを必要最小限にinterpreter->arena_used_bytes() で実際の使用量を確認できる

まとめ

今回は、TensorFlow LiteとArduinoを組み合わせたエッジAIの基本的な流れをご紹介しました。

  • ✅ PCでTensorFlowモデルを学習 → TFLite形式に変換・量子化
  • ✅ バイナリをCヘッダファイルとしてArduinoスケッチに組み込む
  • ✅ TFLMのAPIで推論を実行してリアルタイムに結果を取得

「AIはクラウドのもの」という先入観が、少し変わったんじゃないでしょうか。手のひらサイズのマイコンの上でAIが判断する──これがエッジAIの面白さです。

まずはサイン波のサンプルを動かしてみて、次は加速度センサーのデータを使ったジェスチャー認識にチャレンジしてみてください。ぜひ試してみてください!💪

📡 Arduinoをもっと深く学ぼう!

Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。

Arduinoロボット入門のおすすめコース・部品を見る →

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

Arduinoをはじめよう 第4版 (Make: PROJECTS)

もしも

Arduinoをはじめよう 第4版 (Make: PROJECTS)

Arduino公式推薦の定番入門書

Amazonで見る

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。