開発者向けSalesforce Einstein Vision API深掘り解説:画像分類の実装

背景と応用シナリオ

Salesforce Developerの皆様、こんにちは。本日は、Salesforceプラットフォームの強力なAIレイヤーであるEinstein AI、その中でも特に開発者が直接利用可能なEinstein Vision APIに焦点を当て、その機能と実装方法について深掘りしていきます。

現代のビジネスアプリケーションにおいて、画像データはますます重要な役割を担っています。顧客がアップロードした製品の写真、現場の技術者が撮影した設備の状況、マーケティングキャンペーンで使用される画像素材など、多種多様な画像がSalesforce内に蓄積されています。これらの非構造化データを手動で分類・分析するには、膨大な時間とコストがかかります。

ここでEinstein Vision APIが活躍します。このAPIを利用することで、開発者はカスタムの深層学習(Deep Learning)モデルを容易に構築し、ビジネスプロセスに画像認識機能を組み込むことができます。プログラマティックにアクセス可能なため、Apex、LWC(Lightning Web Components)、または外部アプリケーションから直接呼び出すことが可能です。

応用シナリオの例

  • カスタマーサポートの自動化:顧客がサービスケースに添付した製品の画像から、製品モデルや損傷の有無を自動的に識別し、適切なサポートチームにケースをルーティングする。
  • 在庫管理の効率化:倉庫で撮影された棚の画像から、各製品を識別して在庫数をカウントし、Salesforceの在庫オブジェクトを自動更新する。
  • ブランドセーフティの確保:ユーザーがコミュニティサイトに投稿した画像に、不適切なコンテンツ(ロゴ、暴力的な表現など)が含まれていないかを自動で検出し、モデレーションを支援する。
  • 小売業における棚割り分析:店舗の棚の画像を分析し、自社製品が計画通りに陳列されているか(Planogram Compliance)を自動でチェックする。

この記事では、これらのシナリオを実現するための第一歩として、Einstein Vision APIの中でも基本となる画像分類(Image Classification)モデルの作成と利用方法を、具体的なコード例を交えながら解説します。


原理説明

Einstein Vision APIを利用した画像分類モデルの構築は、大きく分けて3つのステップで構成されます。APIはRESTfulであり、標準的なHTTPリクエストで操作します。

1. データセット (Dataset) の作成

モデルをトレーニングするための元となる、ラベル付けされた画像の集合をDataset(データセット)と呼びます。例えば、「猫」と「犬」を分類するモデルを作りたい場合、「猫」というラベルが付いた猫の画像群と、「犬」というラベルが付いた犬の画像群が必要になります。

Datasetは、APIを介して作成します。画像データは、URLのリストとして提供するか、ZIPファイルにまとめてアップロードする方法が一般的です。ZIPファイルの場合、フォルダ構造を利用してラベルを自動的に割り当てることができます。例えば、`cats`フォルダに猫の画像を、`dogs`フォルダに犬の画像を入れてZIP圧縮し、アップロードするだけでラベル付けが完了します。高品質なモデルを作成するためには、各ラベルに対して十分な数(公式ドキュメントでは最低20枚以上を推奨)の、多様性に富んだ画像を用意することが重要です。

2. モデル (Model) のトレーニング

作成したDatasetをもとに、画像の特徴を学習させ、分類器を構築するプロセスがModel(モデル)のトレーニングです。これもAPIコール一つで開始できます。

`POST /v2/vision/train` エンドポイントに、トレーニングの基となるDatasetのIDを指定してリクエストを送信します。トレーニングは非同期処理(Asynchronous Process)であり、完了までには数分から数時間かかる場合があります。これは、アップロードされた画像の数や複雑さに依存します。APIはリクエストを受け付けると、トレーニングジョブのIDを含むレスポンスを即座に返します。開発者は、このIDを使って定期的にトレーニングの進捗状況(ステータス)をポーリング(Polling)する必要があります。

3. 予測 (Prediction) の実行

トレーニングが完了し、モデルのステータスが `SUCCEEDED` になると、そのモデルを使って新しい未知の画像を分類(予測)できるようになります。

`POST /v2/vision/predict` エンドポイントに、利用したいModelのIDと、分類したい画像のデータ(Base64エンコードされた文字列、または公開URL)を送信します。APIからのレスポンスには、Dataset作成時に定義した各ラベルと、そのラベルである確率(Probability)がスコアとして含まれます。

{
  "probabilities": [
    {
      "label": "Dog",
      "probability": 0.987
    },
    {
      "label": "Cat",
      "probability": 0.013
    }
  ]
}

開発者は、この確率スコアが最も高いラベルを予測結果として採用したり、特定のしきい値(Threshold)を超えるラベルをすべて取得したりするなど、ビジネス要件に応じたロジックを実装します。


サンプルコード

ここでは、cURLコマンドを用いたAPIリクエストの例を示します。実際のアプリケーションでは、Apexの`HttpRequest`クラスや、任意のプログラミング言語のHTTPクライアントライブラリを使用して同様のリクエストを構築します。

前提:Einstein Platform Services APIを利用するには、まず接続アプリケーション経由でOAuth 2.0認証を行い、アクセストークンを取得する必要があります。以下の例では、取得したアクセストークンが `$TOKEN` 環境変数に設定されているものとします。

1. データセットの作成(ZIPファイルから)

ラベルごとにフォルダ分けされた画像を含むZIPファイルをアップロードして、データセットを作成します。

# curl -X POST -H "Authorization: Bearer $TOKEN" -H "Cache-Control: no-cache" -H "Content-Type: multipart/form-data" -F "path=mountain-vs-beach.zip" -F "type=image" https://api.einstein.ai/v2/vision/datasets/upload/sync

# ==========================================================
# 解説:
# -X POST: POSTメソッドでリクエストを送信します。
# -H "Authorization: Bearer $TOKEN": 認証用のアクセストークンをヘッダーに含めます。
# -H "Content-Type: multipart/form-data": ファイルアップロードのためのコンテントタイプを指定します。
# -F "path=mountain-vs-beach.zip": 'path'という名前のフォームフィールドに、ローカルにあるZIPファイルを指定します。
#   このZIPファイル内は、例えば 'mountain' フォルダと 'beach' フォルダに分かれています。
# -F "type=image": データセットのタイプが画像であることを指定します。
# https://api.einstein.ai/v2/vision/datasets/upload/sync: 同期的にアップロードし、データセットIDが返されるのを待つエンドポイントです。
# ==========================================================

# 正常なレスポンス(例)
# {
#   "id": 1014833,
#   "name": "mountain-vs-beach.zip",
#   "createdAt": "2023-10-27T05:39:56.000+0000",
#   "updatedAt": "2023-10-27T05:39:56.000+0000",
#   "labelSummary": {
#     "labels": [
#       { "datasetId": 1014833, "id": 18456, "name": "mountain", "numExamples": 50 },
#       { "datasetId": 1014833, "id": 18457, "name": "beach", "numExamples": 50 }
#     ]
#   },
#   "totalLabels": 2,
#   "totalExamples": 100,
#   "available": true,
#   "status": "SUCCEEDED",
#   "type": "image",
#   "object": "dataset"
# }

このレスポンスに含まれる`id`(この例では `1014833`)が、次のステップで使用するデータセットIDです。

2. モデルのトレーニング開始

上記で作成したデータセットIDを使って、モデルのトレーニングを開始します。

# curl -X POST -H "Authorization: Bearer $TOKEN" -H "Cache-Control: no-cache" -H "Content-Type: multipart/form-data" -F "name=MountainVsBeachClassifier" -F "datasetId=1014833" https://api.einstein.ai/v2/vision/train

# ==========================================================
# 解説:
# -F "name=MountainVsBeachClassifier": トレーニングするモデルに名前を付けます。
# -F "datasetId=1014833": トレーニングの基となるデータセットのIDを指定します。
# https://api.einstein.ai/v2/vision/train: トレーニングを開始するためのエンドポイントです。
# ==========================================================

# 正常なレスポンス(例)
# {
#   "datasetId": 1014833,
#   "modelId": "RBERT35272X6EP3J4TCR6L37Q",
#   "name": "MountainVsBeachClassifier",
#   "status": "QUEUED",
#   "progress": 0,
#   "createdAt": "2023-10-27T05:45:10.000+0000",
#   "updatedAt": "2023-10-27T05:45:10.000+0000",
#   "type": "image",
#   "object": "training"
# }

このレスポンスの`modelId`を使って、トレーニングのステータスを確認します。`status`が`SUCCEEDED`になるまで、定期的にGETリクエストでポーリングします。

3. 予測の実行

トレーニングが完了したモデル(`modelId`)を使って、新しい画像のURLを渡し、予測を実行します。

# curl -X POST -H "Authorization: Bearer $TOKEN" -H "Cache-Control: no-cache" -H "Content-Type: multipart/form-data" -F "modelId=RBERT35272X6EP3J4TCR6L37Q" -F "sampleLocation=https://www.example.com/images/new_scenery.jpg" https://api.einstein.ai/v2/vision/predict

# ==========================================================
# 解説:
# -F "modelId=RBERT35272X6EP3J4TCR6L37Q": 予測に使用するモデルのIDを指定します。
# -F "sampleLocation=...": 分類したい画像の公開URLを指定します。ローカルファイルの場合は 'sampleContent' パラメータでBase64エンコードしたデータを渡します。
# https://api.einstein.ai/v2/vision/predict: 予測を実行するためのエンドポイントです。
# ==========================================================

# 正常なレスポンス(例)
# {
#   "probabilities": [
#     {
#       "label": "mountain",
#       "probability": 0.9984382
#     },
#     {
#       "label": "beach",
#       "probability": 0.0015618
#     }
#   ],
#   "object": "predictresponse"
# }

この結果から、提供された画像は99.8%の確率で「山(mountain)」であると予測されました。


注意事項

Einstein Vision APIを本番環境で利用する際には、以下の点に注意が必要です。

権限 (Permissions)

APIを利用するユーザーには、`Einstein Platform API User` 権限セットライセンスと、それに対応する権限セットが割り当てられている必要があります。これがないと、OAuth認証でトークンを取得できても、APIエンドポイントへのアクセスが拒否されます。

API制限 (API Limits)

Salesforceの他のAPIと同様に、Einstein Vision APIにも利用制限があります。例えば、月間の予測コール数、1時間あたりのトレーニング回数、データセットの最大サイズ、アップロードできる画像の最大ファイルサイズなどが定められています。自社のエディションとライセンスで許容される制限を確認し、制限を超えないようにアプリケーションを設計する必要があります。特に、バッチ処理で大量の予測を行う場合は、ガバナ制限を意識した設計が不可欠です。

非同期処理とエラーハンドリング

前述の通り、モデルのトレーニングは非同期で行われます。そのため、アプリケーション側には、トレーニングステータスを定期的に確認するポーリングの仕組みが必要です。ポーリングの際には、無限ループに陥らないよう、タイムアウト処理や最大試行回数の設定が重要です。また、APIからのレスポンスは常に成功するとは限りません。認証エラー(`401`)、不正なリクエスト(`400`)、サーバーエラー(`500`)など、HTTPステータスコードを適切にハンドリングし、エラーメッセージをログに記録するなどの堅牢なエラーハンドリングを実装してください。

データ品質

AIモデルの性能は、トレーニングデータの品質に大きく依存します。「Garbage In, Garbage Out(ゴミを入れれば、ゴミしか出てこない)」の原則は、ここでも当てはまります。各ラベルに偏りなく、様々な角度、背景、照明条件で撮影された高品質な画像を十分に用意することが、高精度なモデルを構築する鍵となります。


まとめとベストプラクティス

本記事では、Salesforce Developerの視点からEinstein Vision APIを利用した画像分類モデルの構築と利用方法を解説しました。APIを介して、データセットの作成、モデルのトレーニング、そして予測の実行という一連のプロセスをプログラムで自動化できることがお分かりいただけたかと思います。

最後に、Einstein Vision APIを効果的に活用するためのベストプラクティスをまとめます。

  1. 明確なユースケースから始める:AIを導入する目的を明確にし、どのようなビジネス課題を解決したいのかを定義します。これにより、必要なデータの種類や、モデルの精度目標が定まります。
  2. 質の高いトレーニングデータを準備する:ノイズの少ない、鮮明で、ラベル付けが正確な画像をできるだけ多く収集します。データセット内のラベルごとの画像数に大きな偏りがないように(バランスを取るように)注意してください。
  3. モデルを継続的に改善する:一度モデルを構築して終わりではありません。実際のビジネスプロセスで予測が外れたデータを収集し、それらを新しいトレーニングデータとして追加してモデルを再トレーニングすることで、精度を継続的に向上させることができます。
  4. APIの非同期性を考慮した設計を行う:トレーニングのような時間のかかる処理については、プラットフォームイベントなどを活用して、処理完了を非同期に通知するアーキテクチャを検討すると、よりスケーラブルなソリューションになります。
  5. コストと制限を監視する:APIの利用状況を定期的に監視し、組織の制限を超えないように管理します。特に予測コール数はコストに直結するため、無駄な呼び出しがないかコードを見直しましょう。

Einstein Vision APIは、Salesforceプラットフォームに蓄積された画像データを価値ある情報に変えるための強力なツールです。ぜひ本記事を参考に、皆様のアプリケーションにインテリジェンスを加えてみてください。

コメント