🤖

Cloudflare Workers AI 使ってみた「画像分類編」

2024/12/25に公開

はじめに

こんにちは、ikechanこといけがわです。

前回の記事では、Cloudflare Workers AIを活用して、テキストから画像を生成する方法を試しました。今回はその続きとして、「生成した画像をどのように分類できるか」というテーマに取り組みます。具体的には、Cloudflare Workers AIのresnet-50モデルを使用して画像分類を試してみました。

普段のプロジェクトや開発では、画像が何であるかを自動で識別する必要がある場面はそれほど多くないかもしれません。しかし、生成した画像や外部からアップロードされた画像データを分類する仕組みを実装し、resnet-50モデルでどのような結果が得られるのか確認することで、その応用可能性を探ってみました。


前提条件

この記事を進めるにあたり、以下の知識とツールが必要です:

  • Cloudflare アカウント
  • Node.js 開発環境(Bun を使用)
  • Hono フレームワークの基本操作
  • 前回の記事の実装環境

画像分類の実装手順

1. 環境設定

まず、resnet-50 モデルを利用するために、Cloudflare Workers AI のエンドポイントを設定します。このモデルは画像データを入力として受け取り、ラベル付きで分類結果を返します。

resnet-50 モデルの公式ドキュメントはこちらを参照してください:
Cloudflare Workers AI Models: ResNet-50


2. エンドポイントの実装

以下のコードで画像分類を行うエンドポイントを実装します。画像データを受け取り、分類結果をJSON形式で返す仕組みを構築します。

サーバーのエンドポイント定義

app.post("/judge", async (c) => {
  try {
    const imageBuffer = await c.req.arrayBuffer();
    if (!imageBuffer) throw new Error("Image data is required");

    const result = await classifyImage(new Uint8Array(imageBuffer));
    return c.json({ success: true, result });
  } catch (error: unknown) {
    if (error instanceof Error) {
      return c.json({ success: false, error: error.message }, 400);
    }
    return c.json({ success: false, error: "Unknown error occurred" }, 400);
  }
});

このエンドポイントではクライアントから送信された画像データ(バイナリ形式)を受け取り、classifyImage 関数を呼び出して分類を行います。

画像分類関数の実装

export const classifyImage = async (
  imageData: Uint8Array
): Promise<Response> => {
  const response = await makeApiRequest({
    endpoint: "/@cf/microsoft/resnet-50",
    data: imageData,
    contentType: "application/octet-stream",
  });

  return response;
};

APIリクエスト送信関数

export const makeApiRequest = async ({
  endpoint,
  data,
  contentType,
}: ApiRequestParams): Promise<Response> => {
  const response = await fetch(`${config.url}${endpoint}`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${config.key}`,
      "Content-Type": contentType,
    },
    body: data,
  });

  if (!response.ok) {
    throw new Error(`API Error: ${response.statusText}`);
  }

  return response;
};

3. 動作確認

$ bun run index.ts
$ curl -X POST http://localhost:8080/judge \
-H "Content-Type: application/octet-stream" \
--data-binary {前回作成したファイルを配置しているパス}

4. 分類結果の確認

レスポンス例を以下に示します:

{
  "message": "Image classified successfully",
  "result": {
    "result": [
      { "label": "DOBERMAN", "score": 0.1834 },
      { "label": "ENTLEBUCHER", "score": 0.1794 },
      { "label": "SOMBRERO", "score": 0.1313 },
      { "label": "MINIATURE PINSCHER", "score": 0.1132 },
      { "label": "COONHOUND", "score": 0.0678 }
    ],
    "success": true,
    "errors": [],
    "messages": []
  }
}

結果をわかりやすく整形すると以下のようになります。

ラベル スコア
DOBERMAN 0.1834
ENTLEBUCHER 0.1794
SOMBRERO 0.1313
MINIATURE PINSCHER 0.1132
COONHOUND 0.0678

まとめ

結果のトップには「DOBERMAN(ドーベルマン)」や「ENTLEBUCHER(エントレブッハー・キャトル・ドッグ)」が挙げられていますが、興味深いことに、最初に指定した期待値(例:ダックスフンド)はどれにも該当しませんでした。プロンプトの精度やモデルの学習データの影響で、こうしたズレが生じたと考えられます。

これからさらにモデルの動作を試行錯誤しながら、プロンプト設計や前処理を改善することで、より望ましい結果が得られる可能性を探りたいと思います。

お知らせ

最後に、toraco株式会社では2024年11月1日にエンジニア向けのコミュニティを立ち上げました。
Discord のサーバーで運営しており、以下のリンクから無料で参加できます。コミュニティ内では以下のような投稿・活動がされます!

https://discord.gg/bga8nEfjfD

  • もくもく会・作業ラジオ・雑談部屋などオンライン上での交流
  • オフラインイベントの案内
  • 代表の稲垣(トラハック)が公開するコンテンツの説明・質問回答
  • toraco株式会社からの副業や案件の紹介
  • フロントエンド関連技術の情報共有および議論
  • 生成AI関連技術のキャッチアップ
  • その他、技術領域にこだわらない情報共有および議論

参考リンク

toraco株式会社のテックブログ

Discussion