🐥

AutoMLで画像識別をするreactアプリの作り方と高額請求への注意喚起!

に公開

この記事では、Google Cloud Platform (GCP) のAutoMLを使って画像識別機能を持ったReactアプリケーションの開発方法について解説します。AutoMLでの画像認識モデルの構築からReactで画像識別を行うapiの構築までを紹介します。

実際に作成したアプリ

image.png

AutoMLとは

Vertex AI AutoMLは、専門的な機械学習の知識がなくても高精度なAIモデルを作成できるGCPのサービスです。コードを書かずに画像認識、自然言語処理、表形式データの分析などのモデルを簡単に構築・デプロイできます。

1. 学習データの準備とアップロード

Cloud Storageバケットの作成

  1. Google Cloudコンソールにアクセスし、Cloud Storageに移動
    image.png
  2. 「バケットの作成」ボタンをクリック
    スクリーンショット 2025-04-12 3.29.26.png
  3. 適切なバケット名を指定してバケットを作成(ここら辺の設定はよしなに行ってください。私の場合はコストがかからないように最低限の設定にしています)
    image.png
    image.png
    image.png
    image.png
    image.png

詳細はCloud Storageのバケット作成ドキュメントを参照してください。

画像データのアップロード

ひとつづつ画像をアップロードすることもできるのですが、後々のラベル付きデータセットの作成が面倒になるので、ローカル環境でラベル別にディレクトリを分けて画像を保存しておき、これを使います。
ディレクトリ名がそのままラベル名になります。

ディレクトリ構造

gsutilコマンドでまとめてアップロード:

gsutil -m cp -r ./ gs://artie_dataset/

artie_datasetはご自身のバケット名に置き換えてください。

gsutilコマンドが使えない場合は、以下の方法で環境を構築できます:

  1. Google Cloud SDKをインストール
  2. インストール後、以下のコマンドでgcloud CLIを初期化: gcloud init
  3. プロジェクトとアカウントの認証を行う
  4. 認証完了後、gsutilコマンドが使用可能になります
    詳しい手順は以下の記事も参考にしてください:
    https://cloud.google.com/storage/docs/gsutil_install?hl=ja#install
    https://blog.g-gen.co.jp/entry/basics-for-gcloud-storage
    https://cloud.google.com/storage/docs/gsutil?hl=ja

アップロード完了後、GCPコンソールで確認できます:

アップロード完了確認

2. AutoML用データセットの作成

  1. Vertex AI → トレーニングにアクセス
  2. 「データセットの作成」をクリック
  3. データセット名を入力し、「単一ラベル分類」を選択して作成へ進む
  4. 「Cloud Storageからインポート」を選択(一番めんどくさくない方法。)

スクリーンショット 2025-04-12 4.40.17.png

この方法では、Cloud strageの保存先とラベルのペアを表す以下のようなcsvファイルを使って一括でラベル付きデータセットの構築ができます。

image.png

CSVマニフェストファイルの作成

先ほども説明したCloud Storageの画像と対応するラベルを記述したCSVファイルが必要ですが、これも適当なpythonスクリプトで生成させました。base_dirで先ほどデータアップロードの際に作ったディレクトリを指定します。gcs_base_uriは自身のバケット名にしてください。
実行すると、ディレクトリ名がラベルとしてCSVマニフェストファイルが生成されます。

import os
import csv

# スクリプトファイルがあるディレクトリをベースディレクトリとする
base_dir = os.path.dirname(os.path.abspath(__file__))

# Cloud Storage のベース URI(事前に gsutil でアップロードした先)
gcs_base_uri = "gs://artie_dataset"  # ご自身のバケット名に変更

# 出力する CSV ファイル名
output_csv = "manifest.csv"

# CSV を UTF-8 エンコードで書き込み
with open(output_csv, "w", newline="", encoding="utf-8") as csvfile:
    writer = csv.writer(csvfile)
    
    # base_dir 以下を再帰的に走査
    for root, dirs, files in os.walk(base_dir):
        for file in files:
            # 画像ファイルのみを対象
            if file.lower().endswith((".jpg", ".jpeg", ".png")):
                # ファイルのフルパス
                file_full_path = os.path.join(root, file)
                # base_dir からの相対パス
                rel_path = os.path.relpath(file_full_path, base_dir)
                # OS依存のパス区切りをスラッシュに統一
                rel_path_unix = rel_path.replace(os.sep, "/")
                # Cloud Storage 上のファイル URI を組み立て
                gcs_uri = f"{gcs_base_uri}/{rel_path_unix}"
                # ラベルとして、相対パスの最上位ディレクトリ名を利用
                label = rel_path.split(os.sep)[0]
                # ラベルが20文字を超えないように切り詰め
                if len(label) > 20:
                    label = label[:20]
                # CSV に1行追加(URI, ラベル)
                writer.writerow([gcs_uri, label])

print(f"CSV manifest has been created: {output_csv}")

CSVファイルとバケット名を入力して、データセット作成を完了する:

スクリーンショット 2025-04-12 4.40.17.png

データセット作成が完了すると、ラベル付けされたデータセットが表示されます:

スクリーンショット 2025-04-12 4.43.25.png

注意: 学習に使うデータセットはひとつのラベルにつき最低20個以上必要です。今回は20個も用意するのが面倒だったので適当に色味や回転を加えてデータを盛りました。しかし、おそらくこのような処理でデータを増やすのはautoMLの学習の際に行なってそうなのであまりお勧めしないです。)

3. モデルのトレーニング

  1. Vertex AI → トレーニングへアクセス
    スクリーンショット 2025-04-09 0.20.18.png
  2. 「新しいモデルのトレーニング」を選択
    image.png
  3. 適切な設定を行う(よしなに設定してください。今回は一番コストがかからない設定にしました)
    スクリーンショット 2025-04-12 4.50.51.png
    トレーニング設定2
    トレーニング設定3
    トレーニング設定4
    トレーニング設定5
  4. 「トレーニング開始」をクリックして学習を開始
  5. 数時間後、トレーニングが完了

スクリーンショット 2025-04-12 4.51.45.png

トレーニングの詳細についてはVertex AI AutoMLのドキュメントを参照してください。

4. オンライン予測用エンドポイントの作成

  1. Vertex AI → オンライン予測へアクセス
    スクリーンショット 2025-04-09 0.20.18.png
  2. 「エンドポイント作成」をクリック
    image.png
  3. よしなに設定
    スクリーンショット 2025-04-09 0.20.57.png
  4. 先ほど作ったモデルを選択
    スクリーンショット 2025-04-12 4.52.42.png
  5. 設定を完了するとエンドポイントが作成される
    スクリーンショット 2025-04-12 4.49.08.png

詳細はオンライン予測のドキュメントを参照してください。

5. サービスアカウントの設定

注意: 一番手軽にできるサービスアカウントを使った方法を使いますが、適切な方法とは言えないので、実際に事業とかで使う場合はもっとセキュアな認証をしてください。

  1. IAMと管理 → サービスアカウントへアクセス
    スクリーンショット 2025-04-09 0.40.05.png

  2. 「サービスアカウントを作成」をクリック
    image.png

  3. よしなに設定してアカウント作成
    image.png

  4. 作成したアカウントを選択し、「鍵」タブから「新しい鍵を作成」を押す
    image.png
    image.png

  5. JSONファイルがダウンロードされるので保存

  6. IAMと管理 → IAMへアクセス
    スクリーンショット 2025-04-09 0.55.01.png

  7. 作成したサービスアカウントに適切なロールを付与(Vertex AI User や Vertex AI Prediction User など)
    ロール設定
    サービスアカウントの詳細はGCPのIAMドキュメントを参照してください。

6. Reactアプリからの接続設定

アクセストークン取得関数の作成

// src/lib/getAccessToken.ts
import { GoogleAuth } from "google-auth-library";

export const getAccessToken = async () => {
  const auth = new GoogleAuth({
    credentials: JSON.parse(
      process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON || "{}",
    ),
    scopes: ["https://www.googleapis.com/auth/cloud-platform"],
  });

  const client = await auth.getClient();
  const accessToken = await client.getAccessToken();
  return accessToken.token;
};

APIエンドポイントの作成(Next.js使用例)

// src/app/api/scan/route.ts
import { getAccessToken } from "@/lib/getAccessToken";
import { NextResponse } from "next/server";

const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT_ID;
const LOCATION = process.env.GOOGLE_CLOUD_LOCATION || "us-central1";
const ENDPOINT_ID = process.env.GOOGLE_CLOUD_MODEL_ID;

const ENDPOINT = `https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/endpoints/${ENDPOINT_ID}:predict`;

export async function POST(req: Request) {
  try {
    const body = await req.json();
    const { imageBase64 } = body;

    if (!imageBase64) {
      return NextResponse.json(
        { error: "画像データが提供されていません。" },
        { status: 400 }
      );
    }

    const accessToken = await getAccessToken();

    const response = await fetch(ENDPOINT, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        instances: [
          {
            content: imageBase64,
          },
        ],
      }),
    });

    if (!response.ok) {
      return NextResponse.json(
        { error: "予測リクエストが失敗しました。" },
        { status: response.status }
      );
    }

    const data = await response.json();
    const predictions = data.predictions?.[0];
    console.log(predictions);

    if (!predictions || !predictions.confidences || !predictions.ids) {
      return NextResponse.json(
        { error: "作品を認識できませんでした。再度近づいて撮影してください。" },
        { status: 200 }
      );
    }

    const maxConfidenceIndex = predictions.confidences.indexOf(
      Math.max(...predictions.confidences)
    );

    const maxConfidence = predictions.confidences[maxConfidenceIndex];
    const maxId = predictions.ids[maxConfidenceIndex];

    if (maxConfidence < 0.8) {
      return NextResponse.json(
        { error: "作品を認識できませんでした。再度近づいて撮影してください。" },
        { status: 200 }
      );
    }

    return NextResponse.json({ id: maxId }, { status: 200 });
  } catch (error) {
    console.error("API エラー:", error);
    return NextResponse.json(
      {
        error: "予期せぬエラーが発生しました。再度時間をおいて試してください。",
      },
      { status: 500 }
    );
  }
}

Vertex AI APIの詳細についてはVertex AI APIリファレンスを参照してください。

7. 環境変数の設定

.env.localファイルなどに以下の環境変数を設定します:

GOOGLE_CLOUD_PROJECT_ID=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1
GOOGLE_CLOUD_MODEL_ID=your-endpoint-id
GOOGLE_APPLICATION_CREDENTIALS_JSON={"type":"service_account",...} # ダウンロードしたJSONキーの内容

以上で簡単ではありますが、automlで画像識別をするreactアプリを作る方法になります。

しかし!ここからが本番です

重要: コスト管理について

AutoMLは非常に便利ですが、コストがかかるサービスです。特に注意すべき点:

  1. オンライン予測用のエンドポイントは常時稼働しているとコストが発生します(最低設定でも1日約4,000円程度)
  2. 不要になったらエンドポイントは必ず停止・削除してください
  3. 学習自体にもコストがかかります

コスト例

今回の場合はオンライン予測用のエンドポイントを6時間ほど動かしたけか、学習にかかった金額(5000円弱)と合わせて上記が請求金額でした。

エンドポイントの停止を忘れると平気で数万の請求がくると思います。マジで気をつけてください。

参考リンク

Discussion