OpenAIExpo2025/10/02 15:45

The future of AI apps is on the device: How to run AI models with React Native ExecuTorch

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

openaijamodel: gpt-5-mini-2025-08-07

デバイス上で動くAIの未来:React Native ExecuTorchでモデルを実行する方法

Key Points

  • デバイス上で完結するプライバシー
  • Whisper Tinyで約150MBの初回DL
  • 量子化とハイブリッド設計で現実運用可能

Summary

この記事は react-native-executorch を使い、ExecuTorch 上で実行されるオンデバイスAIを Expo/React Native アプリに組み込む手法を実践的に解説します。オンデバイスAIはプライバシー、低レイテンシ、オフライン動作といった利点がある一方、計算資源・ストレージ・熱・バッテリー消費などの制約があります。ライブラリはこれらの複雑さを抽象化し、Whisper 等のモデルをモバイルで動かすための実装例(リアルタイム音声文字起こし)を示します。

Key Points

  • ライブラリ/基盤
    • react-native-executorch は Meta の ExecuTorch を橋渡しし、PyTorch からのエクスポートや CoreML/Vulkan など複数バックエンドを活用できる。\n - 既製モデルを Hugging Face にホストし、簡単にダウンロードして利用可能。
  • いつ使うか/いつ避けるか
    • 選ぶべき場面:強いプライバシー要件、オフライン必須、超低レイテンシが必要なリアルタイム処理。\n - 避けるべき場面:全デバイスで均一な高性能が必要、大型モデル(20GB以上)が必要、アプリサイズ最小化が最優先の場合。
  • 制約と軽減策
    • 制約:メモリ/ストレージ上限、バッテリー消費、熱、デバイス間パフォーマンス差。\n - 軽減策:量子化(8-bit/4-bit)、プルーニング、知識蒸留、動的ロード、ハイブリッド(軽量処理は端末、重い処理はクラウド)設計。
  • 実装の実務的ポイント(Whisper 文字起こしデモ)
    • 推奨オーディオ設定:sampleRate = 16000、bufferLengthInSamples = 1600(100ms チャンク)。\n - モデル(WHISPER_TINY_EN)構成と容量:Encoder 約33MB、Decoder 約118MB、Tokenizer 約3MB、初回ダウンロード合計約150MB(キャッシュあり)。\n - ストリーミング:Whisper の30秒制限対策に、オーバーラップするチャンクで streamInsert/stream を使う実装。\n - ネイティブ権限:react-native-audio-api の Expo プラグインでマイク/フォアグラウンドサービス等を設定し、開発ビルドでネイティブ変更を反映する。\n - UX:モデルのダウンロード進行表示とエラーハンドリングを実装し、長時間処理時の停止・再開戦略を用意する。

Practical recommendations

  • まず小型モデル(tiny系)でプロトタイプを作り、実機でメモリ・バッテリー・速度を測定する。\n- ユーザーにモデルサイズと初回ダウンロードを明示するUIを用意する。\n- デバイス群ごとにフォールバック戦略(低速デバイスはサーバ処理)を用意する。\n- 最適化(量子化等)を CI に組み込み、モデルの精度低下を定量評価する。

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

openaijamodel: gpt-5-mini-2025-08-07

AIアプリの未来はデバイス上にある:React Native ExecuTorchでAIモデルを実行する方法

AIアプリの未来はデバイス上にある:React Native ExecuTorchでAIモデルを実行する方法

Development • React Native • October 2, 2025 • 14 minutes read

Norbert Klockiewicz(ゲスト著者)

Maciej Rys(ゲスト著者)

ユーザーのデータを安全かつプライベートに保ちながら、Expoアプリ内にAIモデルを統合する方法を学びます。

AIアプリは現在大人気で、何千もの開発者が取り組んでいます。しかし多くの開発者は、データをモデル提供者のAPIに送信したりアクセス料を支払ったりせずにAIを統合できることに気づいていません。かつてはオンデバイスAIは実験的な領域に過ぎませんでしたが、モデルが小型化・効率化し、デバイス側の処理能力が向上したことで、この技術は誰でも使えるものになりました。

オンデバイスAIとは何か

10年以上前(2011年)にSiriがモバイルAIの初期例として登場しました。数年後(2014年)には「Hey Siri」コマンドでSiriを呼び出せるようになり、これは初期のオンデバイスAI機能のひとつでした。本当のブレイクスルーは2017年、A11 Bionic(iPhone X)にNeural Engineが導入され、6000億(600 billion)オペレーション/秒の専用AI処理能力を提供したときです。それ以降、技術は単純な音声コマンドを超えて進化しました。最新のNPU(例:iPhone 16 Pro)は35兆(35 trillion)オペレーション/秒を実行可能で、洗練された言語モデルやリアルタイムの画像生成などが完全にデバイス上で動作します。

しかしハードウェア能力は土台に過ぎません。オンデバイスAIはモバイルアプリに対して次のような利点を提供します:

  • プライバシー・バイ・デザイン:ユーザーデータはデバイスを出ません。機密文書の要約、個人写真の解析、機密情報の処理などでも完全なプライバシーが確保されます。
  • 無料化の可能性:継続的なAPIコストや予測できないクラウド費用を排除できます。クラウドで毎月何百ドルかかるモデルが、ユーザーのデバイス上で追加コストなしに動作します。
  • ユニバーサルな信頼性:機内モード、遠隔地、ネットワーク障害時でも動作します。クラウド依存のソリューションでは不可能なユースケースが可能になります。
  • 即時応答:ネットワーク往復がないため、サブ秒の応答が可能で、自然で即時の体験を提供します。

ただし、オンデバイスAIの実装には重大な課題もあります。モバイルデバイス上で直接AIモデルを動かすにはExecuTorchのような推論エンジンの統合が必要です。これらは巨大なプロジェクトで、複雑なビルドプロセスやドメイン固有の知識を要求します。そこで、react-native-executorchのようなライブラリが、開発者からこれらの複雑さを抽象化して橋渡しを行います。

react-native-executorchの紹介

react-native-executorchはSoftware Mansionによって作成されたライブラリです。目的は、React Native開発者が機械学習の専門知識や複雑なインフラ構築なしにAI機能を実装できるようにすることです。ライブラリは包括的な開発エコシステムを提供します:

  • Hugging Faceにホストされた事前エクスポート済みモデルがあり、すぐに利用可能。
  • 前処理・後処理を抽象化した直感的なAPI。
  • 既存のReact Nativeワークフローへのシームレスな統合。

技術的な深掘り

内部では、react-native-executorchはMetaの推論エンジンであるExecuTorchを活用しています。ExecuTorchはInstagramやFacebookアプリのオンデバイスAI機能を支えるエンジンで、エッジデバイスへのAI展開に対するエンドツーエンドのソリューションを提供します。主な利点は次の通りです:

  • PyTorchエコシステムの統合:開発者は馴染みのあるPyTorch環境でモデルを構築・学習し、それをモバイル向けに直接エクスポートできます。
  • クロスプラットフォームの汎用性:スマートフォンに限らず、マイクロコントローラ、スマートウォッチ、AR/VRヘッドセット、IoTデバイスなど、エッジコンピューティング全体をサポートします。
  • 最適化されたパフォーマンス:CoreML(iOSのNeural Engineアクセラレーション)やVulkan(クロスプラットフォームGPU計算)、およびモバイルGPU向けの専用バックエンドなど、様々なバックエンドをサポートしてハードウェア利用を最大化します。これにより、デバイス能力に依らずモデルを効率的に動作させられます。

Figure 1: Communication flow between react-native-executorch and ExecuTorch.

しかし課題もある(現実的な制約)

オンデバイスAIは万能ではありません。利点は魅力的ですが、制約を無視するとユーザー体験に重大な影響を与えます。

オンデバイスAIが問題になる場面

  • リソース消費:AI推論は計算集約的です。AI処理が多いとバッテリー消耗が早まり、長時間の処理でデバイスが明らかに熱くなることがあります。現代のチップは効率的ですが、物理法則の制約は残ります。計算量が増えればエネルギー消費も増えます。
  • ハードウェア制約:フラッグシップ端末でさえ限界があります。多くのスマートフォンは6〜12GBのRAMを提供しますが、その一部しかアプリに割けません。20GB以上を必要とする大規模言語モデルは、最適化してもローカル実行は不可能です。
  • ストレージと配布の課題:モデルは数十MBから数GBに及ぶことがあります。これにより配布のジレンマが発生します:アプリにバンドルすればダウンロードサイズが増え、ストアの制限に触れる可能性があります。あるいは複雑なダウンロード戦略を実装すると初回ユーザー体験が悪化します。
  • パフォーマンス差:API応答時間はデバイス間で比較的一貫しますが、オンデバイスのパフォーマンスは機種ごとに大きく異なります。あるモデルがフラッグシップ機で50 tokens/secondで生成できても、ミドルレンジ機では5 tokens/secondしか出ない、というようにユーザー体験が不均一になります。

軽減戦略

  • 量子化と最適化:量子化などの手法により、モデルサイズを50〜75%削減しつつ許容できる精度を保てます。重み精度を32-bitから8-bit、あるいは4-bitに減らすことで、モデルは高速かつメモリ効率が良くなります。その他、モデルプルーニング、知識蒸留、ダイナミックロード方式なども効果的です。
  • ハイブリッドアーキテクチャ:シンプルで頻繁なタスクはデバイスで、複雑な処理はクラウドで行うなど、パフォーマンス、プライバシー、リソース制約をバランスさせる戦略が有効です。

いつオンデバイスAIを選ぶべきか

  • オンデバイスAIを避けるべき場合:全てのデバイスで一貫したパフォーマンスが必要な場合、最新の大規模モデルが必要な場合、あるいはアプリのフットプリントを最小化したい場合。
  • オンデバイスAIを選ぶ場合:プライバシーが最優先、オフライン機能が必須、あるいは超低レイテンシでリアルタイムなインタラクションが求められる場合。

重要なのは技術的アプローチをプロダクト要件に合わせることです。すべてのAI機能がローカルで動作する必要はなく、逆に全てをクラウドに置くべきでもありません。

実践アプリの構築:オンデバイスAIによる音声文字起こし

利点と制約を把握したところで、実用的なものを作ってみましょう。Siriの話から始めたので、リアルタイムの音声文字起こしアプリをオンデバイスで構築します。アプリはマイクから音声をキャプチャし、OpenAIのWhisperモデルを完全にローカルで動作させてテキストに変換します。これは、音声データを外部サーバーに送信せずに音声をテキスト化する、現代の音声アシスタントの重要な要素を示します。

依存関係のセットアップ

ベアなExpoアプリから始め、コア依存関係をインストールします:

yarn add react-native-executorch
yarn add react-native-audio-api

ライブラリの概要:

  • react-native-executorch - MetaのExecuTorchランタイムへのブリッジで、オンデバイス推論を可能にします。
  • react-native-audio-api - web audio api仕様に基づいたReact Native向けの高性能オーディオエンジン。

権限の設定

音声録音には明示的なユーザー許可が必要です。app.jsonでreact-native-audio-apiのExpoプラグインを使って設定します:

{
  "plugins": [
    [
      "react-native-audio-api",
      {
        "iosBackgroundMode": true,
        "iosMicrophonePermission": "This app requires access to the microphone to record audio.",
        "androidPermissions": [
          "android.permission.MODIFY_AUDIO_SETTINGS",
          "android.permission.FOREGROUND_SERVICE",
          "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"
        ],
        "androidForegroundService": true,
        "androidFSTypes": ["mediaPlayback"]
      }
    ]
  ]
}

この設定を追加したら、ネイティブ変更を反映するために開発ビルドを再構築してください。

オーディオキャプチャの実装

音声認識の基礎は高品質なオーディオキャプチャです。ここでは音声認識に最適化したパラメータでオーディオレコーダーを構成します:

import { AudioManager, AudioRecorder } from 'react-native-audio-api';

function App() {
  const [recorder] = useState(() => new AudioRecorder({
    sampleRate: 16000, // Whisper's expected sample rate
    bufferLengthInSamples: 1600, // 100ms chunks for real-time processing
  }));

  useEffect(() => {
    // Configure audio session for optimal speech recording
    AudioManager.setAudioSessionOptions({
      iosCategory: 'playAndRecord',
      iosMode: 'spokenAudio', // Optimized for speech
      iosOptions: ['allowBluetooth', 'defaultToSpeaker'],
    });

    // Request recording permissions at runtime
    AudioManager.requestRecordingPermissions();
  }, []);
}

設定の詳細

  • 16kHzサンプルレート:Whisperのネイティブ入力フォーマットで、処理オーバーヘッドを削減します。
  • 100msバッファチャンク:レスポンシブなフィードバックを提供しつつ品質を維持します。
  • spokenAudioモード:ノイズ抑制を含むiOSの音声最適化モードです。

Whisperモデルの読み込み

Whisper Tiny Englishを例に、useSpeechToTextフックを使います。モバイル展開にバランスの良い選択です:

import { useSpeechToText, WHISPER_TINY_EN } from 'react-native-executorch';

const model = useSpeechToText({
  model: WHISPER_TINY_EN,
});

モデルのアーキテクチャ:選択したモデルは自動的にダウンロードされる3つのコンポーネントで構成されます:

  • Encoder:音声特徴を処理(~33MB)。
  • Decoder:テキストトークンを生成(~118MB)。
  • Tokenizer:テキストのエンコード/デコード(~3MB)。

初回利用時の合計ダウンロードは約150MBで、以後はローカルにキャッシュされます。

代替モデル:多言語対応が必要ならWHISPER_TINYを使用できます。

ダウンロード進捗を表示してユーザー体験を向上させます:

return (
  <View style={styles.container}>
    {!model.isReady ? (
      <>
        <Text>Loading Whisper model ...</Text>
        <Text>{Math.round(model.downloadProgress * 100)}%</Text>
      </>
    ) : (
      ...
    )}
  </View>
);

リアルタイム文字起こしの実装

Whisperの30秒のオーディオ処理制限は、無制限長のストリーム処理に対して特別な取り扱いを必要とします。ここでは、whisper-streamingに適応したオーバーラップするオーディオチャンクを使う実装で、途中で文が切れるのを防ぎつつ一貫した文字起こしを実現します。

アプリでの使用例:

const handleStartStreaming = async () => {
  // Set up audio buffer processing
  recorder.onAudioReady(async ({ buffer }) => {
    // Convert Float32Array to regular array for model processing
    const bufferArray = Array.from(buffer.getChannelData(0));
    model.streamInsert(bufferArray);
  });

  // Begin recording
  recorder.start();

  try {
    // Start streaming transcription with overlapping chunks
    await model.stream();
  } catch (error) {
    console.error('Transcription error:', error);
    // Handle model errors gracefully
    handleStopStreaming();
  }
};

const handleStopStreaming = () =>

(記事ソースはここで途中まで提供されています。上記は提供された内容の正確な日本語訳およびコード例の保持です。)