すべてのプロダクト
Search
ドキュメントセンター

Platform For AI:マルチモーダルデータの管理と使用

最終更新日:Aug 26, 2026

マルチモーダルデータ管理は、大規模モデルを使用して、画像などのデータにスマートタギングとセマンティックインデキシングを適用します。これにより、モデルトレーニングとデータ分析のために、データサブセットを検索、フィルター、エクスポートできます。

1. 概要

マルチモーダルデータ管理では、マルチモーダル大規模言語モデルと埋め込みモデルを使用して、画像などのマルチモーダルデータを前処理できます。このプロセスは、スマートタギングとセマンティックインデックス作成を通じて豊富なメタデータを生成します。このメタデータを使用して、データアノテーションやトレーニングなどの下流タスク向けに、特定のデータサブセットを検索およびフィルターできます。さらに、Platform for AI (PAI) データセットは包括的な OpenAPI を提供し、カスタムプラットフォームとの統合を簡素化します。次の図は、製品アーキテクチャを示しています。

image

2. 制限

PAI のマルチモーダルデータ管理には、次の制限があります:

  • リージョン: この機能は、次のリージョンでサポートされています: China (Hangzhou)、China (Shanghai)、China (Shenzhen)、China (Ulanqab)、China (Beijing)、China (Guangzhou)、Singapore、Germany (Frankfurt)、US (Virginia)、China (Hong Kong)、Japan (Tokyo)、Indonesia (Jakarta)、US (Silicon Valley)、Malaysia (Kuala Lumpur)、Korea (Seoul)。

  • ストレージタイプ: PAI のマルチモーダルデータ管理は、Object Storage Service (OSS) に保存されているデータのみをサポートします。

  • ファイル形式: この機能は、jpg、jpeg、png、gif、bmp、tiff、webp 形式の画像ファイルのみをサポートします。

  • ファイル数: 単一のデータセットバージョンは、最大 1,000,000 ファイルをサポートします。この制限を引き上げるには、PAI のアカウントマネージャーにお問い合わせください。

  • モデル:

    • タギングモデル: Model Studio プラットフォームの Qwen-VL-Max/Plus モデルを使用できます。

    • インデックス作成モデル: tongyi-embedding-vision-plus などの Model Studio のマルチモーダル埋め込みモデルや、PAI モデルギャラリーの GME モデルを使用できます。これらのモデルは PAI-EAS にデプロイする必要があります。

  • メタデータストレージ:

    • メタデータ: PAI は、組み込みのメタデータベースにメタデータを安全に保存します。

    • 埋め込みベクトル: 埋め込みベクトルは、次のベクトルデータベースに保存できます:

      • Elasticsearch (Vector Search Edition、バージョン 8.17.0 以降)

      • OpenSearch (Vector Search Edition)

      • Milvus (バージョン 2.4 以降)

      • Hologres

      • Lindorm (Vector Engine Edition)

  • データセット処理モード: スマートタギングタスクとセマンティックインデックス作成タスクは、フルモードとインクリメンタルモードで実行できます。

3. ワークフロー

PAI多模态数据管理使用说明

3.1 前提条件

3.1.1 PAI の有効化と権限の付与

  1. ルートアカウントを使用して Platform for AI (PAI) を有効化し、ワークスペースを作成します。PAI コンソールにログオンし、左上隅でリージョンを選択してから、製品を承認して有効化します。

  2. アカウントを承認します。ルートアカウントを使用する場合は、この手順をスキップできます。RAM ユーザーを使用する場合は、ワークスペース管理者ロールが必要です。アカウント承認の詳細については、ワークスペースの作成と管理の「メンバーロールの設定」セクションをご参照ください。

3.1.2 Model Studio の API キーの取得

Model Studio を有効化して API キーを作成するには、API キーの取得をご参照ください。

3.1.3 ベクトルデータベースの作成

ベクトルデータベースインスタンスの作成

マルチモーダルデータセット管理は、現在、次の Alibaba Cloud ベクトルデータベースをサポートしています。

  • Elasticsearch (Vector Search Edition、バージョン 8.17.0 以降)

  • OpenSearch (Vector Search Edition)

  • Milvus (バージョン 2.4 以降)

  • Hologres (バージョン 4.0.9 以降)

  • Lindorm (Vector Engine Edition)

各ベクトルデータベースのインスタンスを作成するには、それぞれのクラウド製品のドキュメントをご参照ください。

ネットワークとホワイトリストの設定

  • パブリックネットワークアクセス

    ベクトルデータベースインスタンスにパブリックエンドポイントがある場合は、次の IP アドレスをインスタンスのパブリックネットワークアクセスホワイトリストに追加します。これにより、マルチモーダルデータ管理サービスがパブリックネットワーク経由でインスタンスにアクセスできるようになります。Elasticsearch のホワイトリストを設定するには、パブリックまたはプライベートネットワークアクセスの IP アドレスホワイトリストの管理をご参照ください。

    リージョン

    IP アドレス

    China (Hangzhou)

    47.110.230.142, 47.98.189.92

    China (Shanghai)

    47.117.86.159, 106.14.192.90

    China (Shenzhen)

    47.106.88.217, 39.108.12.110

    China (Ulanqab)

    8.130.24.177, 8.130.82.15

    China (Beijing)

    39.107.234.20, 182.92.58.94

  • プライベートネットワークアクセス

    このオプションを申請するには、チケットを送信してください。

ベクトルインデックステーブルの作成 (オプション)

システムが自動的にインデックステーブルを作成します。カスタムのインデックステーブルを作成する必要がない場合は、この手順をスキップできます。

一部のベクトルデータベースでは、ベクトルインデックステーブルはコレクションまたはインデックスとも呼ばれます。

インデックステーブルのスキーマは、次の定義と一致する必要があります。

テーブルスキーマ定義

{
    "id":"text",                    // プライマリキー ID。OpenSearch では必須。他のデータベースではデフォルトで存在し、定義する必要はありません。
    "index_set_id": "keyword",      // インデックスセット ID。インデックス作成をサポートしている必要があります。
    "file_meta_id": "text",         // ファイルメタデータ ID。   
    "dataset_id": "text",           // データセット ID。
    "dataset_version": "text",      // データセットバージョン。
    "uri": "text",                  // OSS ファイルの URI。
    "file_vector": {                // ベクトルフィールド。
        "type": "float",            // ベクトルタイプ: float。
        "dims": 1536,               // ベクトル次元 (カスタマイズ可能)。
        "similarity": "DotProduct"  // ベクトル距離アルゴリズム: コサインまたはドット積。
    }
}

このセクションでは、Elasticsearch でセマンティックインデックステーブルを作成する Python の例を示します。他のベクトルデータベースについては、それぞれの製品ドキュメントをご参照ください。

Elasticsearch でセマンティックインデックステーブルを作成するサンプルコード

from elasticsearch import Elasticsearch

# 1. Alibaba Cloud Elasticsearch インスタンスに接続します。
# 注意:
# (1) Python 3.9 以降が必要です: python3 -V
# (2) Elasticsearch クライアントはバージョン 8.x である必要があります: pip show elasticsearch
# (3) VPC エンドポイントを使用する場合、呼び出し元は Elasticsearch インスタンスの VPC と通信できる VPC 内にある必要があります。それ以外の場合は、パブリックエンドポイントを使用し、呼び出し元のパブリック IP アドレスを Elasticsearch ホワイトリストに追加してください。
# デフォルトのユーザー名は elastic です。
es_client = Elasticsearch(
    hosts=["http://es-cn-l4p***5z.elasticsearch.aliyuncs.com:9200"],
    basic_auth=("{userName}", "{password}"),
)

# 2. インデックス名と構造を定義します。デフォルトでは HNSW インデックスアルゴリズムを使用します。
index_name = "dataset_embed_test"
index_mapping = {
    "settings": {
        "number_of_shards": 1,          # シャード数
        "number_of_replicas": 1         # レプリカ数
    },
    "mappings": {
        "properties": {
            "index_set_id": {
                "type": "keyword"
            },
            "uri": {
                "type": "text"
            },
            "file_meta_id": {
                "type": "text"
            },
            "dataset_id": {
                "type": "text"
            },
            "dataset_version": {
                "type": "text"  
            },
            "file_vector": {
                "type": "dense_vector",  # file_vector を密ベクトル型として定義
                "dims": 1536,            # ベクトル次元: 1536
                "similarity": "dot_product"  # 類似度計算方法: ドット積
            }
        }
    }
}

# 3. インデックスを作成します。
if not es_client.indices.exists(index=index_name):
    es_client.indices.create(index=index_name, body=index_mapping)
    print(f"Index {index_name} created successfully!")
else:
    print(f"Index {index_name} already exists. It will not be created again.")

# 4. 作成したインデックステーブルのスキーマを表示します (オプション)。
# indexes = es_client.indices.get(index=index_name)
# print(indexes)

3.2 データセットの作成

  1. PAI ワークスペースに移動します。左側のナビゲーションペインで、AI 資産管理 > データセット > データセットの新規作成 を選択してデータセット設定ページに移動します。

  2. 次の主要なデータセットパラメータを設定します。その他のパラメータはデフォルト値のままにできます。

    1. [ストレージクラス]:Object Storage Service (OSS)。

    2. [タイプ]:[アドバンスト]。

    3. [コンテンツタイプ]: [画像]。

    4. [OSS パス]:データセットの OSS ストレージパスを選択します。データセットを準備していない場合は、サンプルデータセット retrieval_demo_data をダウンロードし、OSS にアップロードしてから、マルチモーダルデータ管理機能をお試しいただけます。

    説明

    ファイルまたはフォルダをインポートすると、そのパスのみを記録し、データはコピーしません。

    [インポート形式] には、[ファイル] または [フォルダー] を選択できます。[アプリケーション設定] では、[デフォルトのマウントパス] は /mnt/data/ です。

    OK をクリックしてデータセットを作成します。

3.3 接続の作成

3.3.1 インテリジェントタギング接続の作成

  1. PAI ワークスペースに移動し、左側のナビゲーションペインで AI 資産管理 > 接続 > モデルサービス > 接続の新規作成 を選択して、接続の作成ページを開きます。

  2. Model Studio 大規模言語モデル (LLM) サービス接続 を選択し、Model Studio の [API キー] を設定します。

  3. 接続が作成されると、Alibaba Cloud Model Studio Service がリストに表示されます。

3.3.2 セマンティックインデックス作成接続の作成

  1. Model Studio セマンティックインデックスモデルサービスを使用する予定の場合は、この手順をスキップできます。左側のナビゲーションペインで、[モデルギャラリー] をクリックし、GME マルチモーダル検索モデルを見つけてデプロイし、EAS サービスを取得します。デプロイには約 5 分かかります。デプロイは、ステータスが 実行中 に変わると完了です。

    重要

    インデックスモデルが不要になったら、サービスを停止して削除し、追加料金が発生しないようにしてください。

    GME-2B 検索モデル (2B パラメーター) または GME-7B 検索モデルを選択し、対応する[デプロイ] ボタンをクリックしてデプロイを開始できます。

  2. PAI ワークスペースに移動し、左側のナビゲーションペインで AI 資産管理 > 接続 > モデルサービス > 接続の新規作成 を選択して [接続の作成] ページを開きます。

  3. Model Studio セマンティックインデックス作成モデルまたはカスタムデプロイされた EAS セマンティックインデックス作成モデルのどちらを選択したかに基づいて、モデル接続情報を設定します。

    Model Studio セマンティックインデックス作成モデルを使用

    • 接続タイプ: 汎用マルチモーダル埋め込みモデルサービス接続 を選択します。

    • [サービスプロバイダー]:[サードパーティモデルサービス] を選択します。

    • [モデル名]: tongyi-embedding-vision-plus

    • [base_url]:https://dashscope.aliyuncs.com/api/v1/services/embeddings/multimodal-embedding/multimodal-embedding

    • [API キー]:API キーを取得して入力します。

    カスタムデプロイされた EAS セマンティックインデックス作成モデルを使用

    • [接続タイプ]: 汎用マルチモーダル埋め込みモデルサービス接続 を選択します。

    • [サービスプロバイダー]: PAI-EAS モデルサービス を選択します。

    • [EAS サービス]: デプロイしたばかりの GME マルチモーダル検索モデルを選択します。サービスプロバイダーが自身のアカウントにない場合は、[サードパーティモデルサービス] を選択します。

    [EAS サービスの選択] ダイアログボックスで、ステータスが [実行中] である対象のモデルサービスを選択します。

  4. 接続が作成されると、モデル接続サービスがリストに表示されます。

3.3.3 ベクトルデータベース接続の作成

  1. 左側のナビゲーションペインで、AI 資産管理 > 接続 > データベース > 接続の新規作成 を選択して、[接続の作成] ページを開きます。

  2. マルチモーダル検索サービスは、Milvus、Lindorm、OpenSearch、Elasticsearch、Hologres などのベクトルデータベースをサポートしています。このセクションでは Elasticsearch を例として、データベース接続の作成方法について説明します。検索分析サービス - Elasticsearch を選択し、uri、password などのパラメーターを設定します。詳細については、「データベース接続を作成する」をご参照ください。

    各ベクトルデータベースの接続形式は次のとおりです。

    Milvus

    uri: http://xxx.milvus.aliyuncs.com:19530
    database: {your_database}
    token: root:{password}

    OpenSearch

    uri: http://xxxx.ha.aliyuncs.com
    username: {username}
    password: {password}

    Hologres

    host: xxxx.hologres.aliyuncs.com
    port: {port}
    database: {your_database}
    access_key_id: {your_access_key_id}
    access_key_secret: {your_access_key_secret}

    Elasticsearch

    uri: http://xxxx.elasticsearch.aliyuncs.com:9200
    username: {username}
    password: {password}

    Lindorm

    uri: xxxx.lindorm.aliyuncs.com:{port}
    username: {username}
    password: {password}
  3. 接続が作成されると、リストにベクトルデータベース接続が表示されます。

3.4 インテリジェントタギングジョブの作成

3.4.1 インテリジェントタグ定義の作成

左側のナビゲーションウィンドウで、AI 資産管理 > データセット > DataQ スマートタグサービス の 定義 > DataQ スマートタグサービス定義の新規作成 を選択してタグ設定ページを開きます。以下に設定例を示します。

  • [ガイドプロンプト]:あなたは、高速道路と一般道の両方で豊富な経験を持つベテランドライバーです。

  • [タグの定義]:

    自動運転のサンプルタグ定義

    {
        "反射テープ": "通常は黄色、または黄色と黒の交互で、角や他の永続的な突出した障害物に貼り付けられ、ドライバーに避けるよう警告します。これらは帯状であり、交通コーンや駐車ロック、水入りバリアではありません。",
        "駐車ロック": "駐車スペースロックとも呼ばれ、駐車スペースが占有されるのを防ぐために上げることができます。駐車ロックが存在する場合は、上がった状態か下がった状態かを指定する必要があります。上がったフレームがある場合は上がった状態、それ以外は下がった状態です。",
        "点灯した工事車両": "対象は、左右に矢印型のライトが 2 つ点灯している車両です。それ以外の場合は、点灯した工事車両とは見なしません。",
        "横転した車両": "地面に横転している車両。",
        "倒れた水入りバリア": "水入りバリアは、道路表面を分割したり、遮断を形成したりするために使用するプラスチック製シェル障害物で、通常は赤いプラスチック壁の形をしています。道路交通設備でよく使用し、高速道路、都市道路、高架橋の交差点でよく見かけます。交通コーンよりもかなり大きく、シート状の構造をしています。水入りバリアは通常直立しています。地面に横たわっている場合は、明確に示す必要があります。",
        "倒れた交通コーン": "円錐形交通標識またはパイロンとも呼ばれ、一般的にロードコーンまたはセーフティコーンと呼ばれ、円錐形の一時的な道路標識です。棒状またはシート状の障害物は、円錐形ではないため交通コーンではありません。交通コーンは車が倒す可能性があります。画像に交通コーンが存在し、倒れているかどうかを判断する必要がある場合は、コーンの底部(コーンの底面)が地面に接触しているかどうかを観察してください。接触している場合は倒れていません。それ以外の場合は倒れています。",
        "充電スペース": "充電ガン、充電パイル設備が見える壁際の駐車スペース、または新エネルギー車スペースとしてマークされている場合、充電スペースです。このタグは、駐車場(屋内または屋外)内のスペースにのみ適用されます。駐車ロックは充電とは関係ありません。",
        "速度低減帯": "通常は黄色と黒、または黄色だけで、道路を横切る狭い隆起した帯で、道路の端に垂直で、車両の速度を落とすために使用されます。駐車スペース内には見られません。",
        "減速車線": "車線の両側、実線の内側に魚の骨のパターンで描かれた破線。両側に存在する必要があり、減速車線と見なします。",
        "ランプ": "このタグは、高速道路の明確な大きなカーブが見える場合にのみ使用してください。ランプは通常、高速道路の本線の右側にあり、料金所への出入りに使用されます。",
        "地面の影": "地面に明確な影があります。",
        "曇り": "このタグは、空が見え、明確な雲が含まれている場合にのみ使用してください。",
        "まぶしい車": "前方の車のライトがまぶしさを引き起こしています(光が単一の点から光の線に変わります)、通常は夜間または雨の日に発生します。",
        "左折、右折、Uターン矢印": "道路表面に描かれた乳白色の矢印マーキング(一部は黄色)であり、右カーブを示す高速道路標識の緑と白の矢印ではありません。これらの矢印の存在を判断する場合、道路車線の中央にある明確な矢印マーキングのみがターゲットです。路側のものはターゲットではありません。地面に矢印がある場合、方向は次のように決定されます。右折矢印は基部から先端まで時計回りに回転します。左折矢印は基部から先端まで反時計回りに回転します。U字型の矢印はUターン矢印です。",
        "横断歩道": "このタグは、道路表面(駐車場を含む)および交差点の横断歩道に適用されます。歩行者が横断するために道路の端に平行に繰り返し間隔で配置された白い線である必要があります。高速道路、高速道路のランプ、またはトンネル内には見られません。",
        "露出オーバー": "日中、直射日光によってレンズが露出オーバーになります(日中のみ発生する可能性があります)。",
        "自動車": "視野内に他の自動車があります。",
        "合流または分流": "高速道路で複数の車線が 1 つに合流する場所、または 1 つの車線が複数の車線に分かれる場所。",
        "交差点": "交差点内に車線がない交差点(交差点自体内に線がないことを指します。交差点外の線は関係ありません)。",
        "駐車禁止標識": "「駐車禁止」という言葉または円の中に「P」があり、斜線が引かれた記号が描かれた、吊り下げられているか地面に立っている標識。",
        "車線": "道路上の車線で、ぼやけた車線に特に注意してください。",
        "道路上の落石またはタイヤ": "交通に影響を与える道路上の障害物。",
        "トンネル": "トンネルへの進入と退出の区別に注意してください。",
        "雨の日の濡れた地面": "雨のために地面が滑りやすくなっています。",
        "非自動車": "自転車、電動自転車、車椅子、一輪車、ショッピングカートなどの非自動車オブジェクトを含み、路側、駐車スペースに駐車されているか、道路上を移動している可能性があります。"
      }

3.4.2 オフラインインテリジェントタギングジョブの作成

  1. データセット をクリックし、データセット名をクリックして、データセットタスク タブをクリックします。

  2. 「ジョブ」ページで、タスクを作成 > スマートタギング をクリックし、タスクパラメーターを設定します。

    • [データセットバージョン]:v1 など、ラベル付けするバージョンを選択します。

    • [スマートタギングモデル接続]: 作成した Model Studio モデル接続を選択します。

    • [インテリジェントタギングモデル]:対応モデルには Qwen-VL-Max および Qwen-VL-Plus が含まれます。

    • [最大同時実行数]: この値は、EAS モデルサービスの仕様によって決まります。1 つの GPU の場合、推奨される最大同時実行数は 5 です。

    • [DataQ スマートタグサービス の 定義]:作成したばかりのスマートタグ定義を選択します。

    • [タグ付けパターン]: 増分 と フル モードをサポートしています。

  3. インテリジェントタギングジョブが作成されると、ジョブリストに表示されます。[操作] 列のリンクをクリックして、ログを表示したり、ジョブを停止したりできます。

    説明

    インテリジェントタギングジョブを初めて開始すると、システムがメタデータを構築します。このプロセスには時間がかかる場合があります。

3.5 セマンティックインデックス作成ジョブの作成

  1. データセット名をクリックして詳細ページを開き、インデックスの設定 セクションで編集アイコンをクリックします。

  2. インデックスを設定します。

    保存 をクリックし、次に 即時パージ をクリックします。 これにより、選択したデータセットバージョン内のすべてのファイルのセマンティックインデックスを更新するセマンティックインデックス作成タスクが作成されます。 データセット詳細ページの右上隅にある セマンティクスインデックスタスク をクリックすると、タスク詳細を表示できます。

    説明

    セマンティックインデックス作成ジョブを初めて開始すると、システムがメタデータを構築します。このプロセスには時間がかかる場合があります。

    [今すぐ更新] ではなく [キャンセル] をクリックした場合は、次の手順に従って手動でジョブを作成できます。

    データセット詳細ページで、データセットタスク タブをクリックしてジョブページに移動します。

    タスクを作成 > セマンティクスインデックス をクリックして、データセットバージョンを設定し、EAS モデルサービスの仕様に基づいて最大同時実行数を設定します。単一の GPU の場合、推奨される最大同時実行数は 5 です。[確認] をクリックして、セマンティックインデックスタスクを作成します。

3.6 データのプレビュー

  1. スマートタギングとセマンティックインデックス作成のタスクが完了したら、データセット詳細ページに移動し、データを表示 をクリックして、そのデータセットバージョンの画像をプレビューします。

  2. [データの表示] ページでは、データセットバージョンの画像をプレビューできます。「ギャラリービュー」と「リストビュー」を切り替えることができます。

  3. 特定の画像をクリックすると、拡大版が表示され、それに含まれるタグが表示されます。

    詳細ページには、画像の[メタデータ] (ファイル名、ファイルタイプ、ストレージパス、ファイルサイズ、最終更新日時) と[スマートタグ] ([アルゴリズムタグ]と[ユーザータグ]を含む) が表示されます。

  4. サムネイルの左上隅にあるチェックボックスをクリックして選択します。Shift キーを押しながらチェックボックスをクリックすると、複数行のデータを一度に選択することもできます。

    選択を行うと、ページ下部に選択項目数が表示され、[手動ラベリング] または [選択をキャンセル] を実行できます。

3.7 基本データ検索 (複合検索)

  1. 「データ表示」ページの左側のツールバーで、インデックス検索 と タグ検索 を実行できます。Enter キーを押すか、検索 をクリックして開始します。

  2. テキストキーワードによる インデックス検索: セマンティックインデックス作成の結果に基づき、キーワードベクトルと画像インデックスベクトルを照合して検索します。[詳細設定] では、top-k やスコアしきい値などのパラメーターを設定できます。

  3. [インデックス検索] (画像による): セマンティックインデックス作成の結果に基づき、ローカルコンピューターから画像をアップロードするか、OSS から 1 つ選択し、ベクトルを比較することでデータセット内の一致する画像を検索します。[詳細設定] では、top-k やスコアのしきい値などのパラメーターを設定できます。

  4. タグ検索:スマートタギングの結果に基づき、キーワードと画像タグを照合して画像を検索する機能です。次の検索ロジックを組み合わせることができます:以下のいずれかのタグを含む (OR)、以下のタグをすべて含む (AND)、および以下のいずれかのタグを除外 (NOT)。

  5. [メタデータ]: ファイル名、ストレージパス、最終更新日時でファイルを検索できます。

    上記のすべての検索条件は、AND 演算子で結合されます。

3.8 高度なデータ検索 (DSL)

詳細検索 では、DSL 取得 を使用できます。 DSL は、複雑な取得条件を表現するためのドメイン固有言語です。 高度な取得シナリオに最適で、グループ化、ブール論理 (AND/OR/NOT)、範囲比較 (>、>=、<、<=)、プロパティの存在 (HAS/NOT HAS)、トークン一致 (:)、完全一致 (=) などの機能をサポートしています。 構文の詳細については、「データセットファイルメタデータのリストを取得する」をご参照ください。

たとえば、次の DSL クエリを入力して画像ファイルをフィルタリングできます:(FileType = "image" OR ContentType = "application/json") AND ThumbnailMode = "h_200" AND MaxResults = 50

3.9 検索結果のエクスポート

説明

この手順の目的は、検索結果をファイルリストインデックスとしてエクスポートし、その後のモデルトレーニングやデータ分析に使用することです。

検索が完了すると、ページの下部にある検索結果のエクスポート ボタンをクリックできます。2 つのエクスポートモードがサポートされています:

3.9.1 ファイルとしてエクスポート

  1. ファイルにエクスポート をクリックします。設定ページで、エクスポート内容と出力先 OSS ディレクトリを設定し、OK をクリックします。

    エクスポート設定ページで、[エクスポート内容] には [テキスト]、[画像]、[音声]、[動画]、および [人間によるラベル] を選択できます。[エクスポートタイプ] で [エクスポートファイル] を選択し、[エクスポートパス] を宛先の OSS ディレクトリに設定します。

  2. エクスポートの進捗状況を表示するには、左側のナビゲーションペインでAI 資産管理 > タスク > データセットタスクを選択します。

  3. エクスポートした結果を使用します。エクスポートが完了したら、エクスポートした結果ファイルと元のデータセットを、DLC や DSW インスタンスなどの適切なトレーニング環境にマウントできます。その後、コードを記述してエクスポートした結果ファイルのインデックスを読み取り、元のデータセットからターゲットファイルをロードして、モデルトレーニングや分析を行うことができます。

3.9.2 論理データセットバージョンへのエクスポート

Premium データセットの検索結果を、別の論理データセットのバージョンにインポートできます。その後、データセット SDK を使用して、その論理データセットバージョンのデータを使用できます。

  1. 論理データセットへのエクスポート をクリックしてターゲット論理データセットを選択し、OK をクリックします。

    「エクスポート」ダイアログボックスで、[ターゲットデータセット] と [ベースデータセットバージョン] を選択し、[インポート範囲] (すべてのファイルまたは選択したファイル) を設定します。[インポートモード] では、[マージして上書き] を選択し、インポートするタグタイプ ([スマートタグ] または [手動ラベル]) を選択できます。

    選択可能な論理データセットがない場合は、次のセクションの説明に従って作成します。

    論理データセットの作成

    論理データセットを作成します。左側のナビゲーションペインで、AI 資産管理 > データセット > データセットの新規作成 を選択し、次の主要なパラメーターを設定します。その他のパラメーターは必要に応じて設定します。

    • [タイプ]:  論理型 を選択します。

    • [メタデータ OSS パス]: エクスポート用の OSS パスを選択します。

    • [メタデータインポート方式]:後でインポート を選択します。

    OK をクリックしてデータセットを作成します。

  2. 論理データセットを使用します。インポートジョブが完了すると、ターゲット論理データセットにエクスポートしたメタデータが含まれます。SDK を使用してデータをロードして使用できます。SDK の使用方法については、データセット詳細ページをご参照ください。

    from pai_datasets.load import load_dataset
    
    dataset = load_dataset(dataset_id="xxx",
        dataset_version="v1",
        region="cn-hangzhou",
        cache_dir=CACHE_DIR,
        keep_in_memory=True)

    SDK をインストールするには、次のコマンドを実行します。

    pip install https://pai-sdk.oss-cn-shanghai.aliyuncs.com/dataset/pai_dataset_sdk-1.0.0-py3-none-any.whl

4. カスタムセマンティックインデックス作成モデルのファインチューニング (任意)

カスタムのセマンティック検索モデルをファインチューニングできます。モデルが EAS に正常にデプロイされた後、「3.3.2」の手順に従ってモデル接続を作成し、その後のマルチモーダルデータ管理で使用できます。

4.1. データ準備

このトピックではサンプルデータを提供しています。retrieval_demo_data をクリックしてダウンロードできます。

4.1.1. データフォーマット

各データサンプルは、dataset.jsonl ファイルに JSON フォーマットで 1 行ずつ保存されます。各サンプルには、次のフィールドを含める必要があります:

  • image_id:画像名や一意の ID など、画像の一意の識別子。

  • tags:画像に関連付けられたテキストタグのリスト。タグは文字列の配列です。

フォーマット例:

{  
    "image_id": "c909f3df-ac4074ed",  
    "tags": ["silver sedan", "white SUV", "city street", "snowing", "night"], 
}

4.1.2. ファイル構造

すべての画像ファイルを images フォルダーに配置します。dataset.jsonl ファイルは、images フォルダーと同じディレクトリに配置します。

ディレクトリ構造の例:

├── images
│   ├── image1.jpg
│   ├── image2.jpg
│   └── image3.jpg
└── dataset.jsonl  
重要

ファイル名 dataset.jsonl とフォルダー名 images は必須であり、変更できません。

4.2. モデルトレーニング

  1. モデルギャラリーで、検索関連のモデルを探します。必要なモデルサイズとコンピューティングリソースに基づいて、ファインチューニングとデプロイに適したモデルを選択します。

    ファインチューニング VRAM (bs=4)

    ファインチューニング (4 × A800) train_samples/second

    デプロイ VRAM

    ベクトル次元

    GME-2B

    14 GB

    16.331

    5 GB

    1536

    GME-7B

    35 GB

    13.868

    16 GB

    3584

  2. たとえば、GME-2B モデルをトレーニングするには、トレーニング をクリックし、データアドレスとモデル出力パスを入力してトレーニングを開始します。

    トレーニング設定ページでは、[Training Dataset] フィールドのデフォルト値は、サンプルデータのパスです。カスタムの [Model Name] と [Version Description] を指定し、[Model Output Path] を OSS ディレクトリに設定できます。

4.3. モデルデプロイ

トレーニングが完了したら、トレーニングタスクの デプロイメント をクリックしてモデルをデプロイします。

元の GME モデルをデプロイするには、モデルギャラリーにあるモデルのタブで デプロイメント ボタンをクリックします。

デプロイが完了すると、ページで EAS の [エンドポイント] と [トークン] を確認できます。[View Invocation Information] をクリックすると、パブリックエンドポイント呼び出し と VPC エンドポイント呼び出し の詳細が表示されます。

4.4. サービス呼び出し

入力パラメーター

パラメーター

タイプ

必須

例

説明

model

String

必須

pai-multimodal-embedding-v1

モデルタイプを指定します。このフィールドは、カスタムモデルとベースモデルの将来のバージョンにも対応します。

contents.input

list(dict) または list(str)

いいえ

input = [{'text': text}]

input=[xxx,xxx,xxx,...]

input = [{'text': text}, {'image': f"data:image/{image_format};base64,{image64}"}]

埋め込み対象のコンテンツ。

現在、text と image のみがサポートされています。

レスポンスパラメーター

パラメーター

タイプ

例

説明

status_code

Integer

200

HTTP ステータスコード。

200:リクエスト成功

204:リクエスト一部成功

400:リクエスト失敗

message

list(str)

['Invalid input data: must be a list of strings or dict']

エラーメッセージ。

output

dict

次の表をご参照ください。

埋め込み結果。

DashScope から返される結果は {"output": {"embeddings": list(dict), "usage": xxx, "request_id":xxx}} です。現時点では、「usage」と「request_id」フィールドは無視できます。

入力項目が失敗した場合、失敗の理由がトップレベルの message フィールドに追加されます。

パラメーター

タイプ

例

説明

index

Integer

0

入力 contents リスト内の対応する項目のインデックス。

embedding

List[Float]

[0.0391846,0.0518188,.....,-0.0329895,

0.0251465]

1536

結果として得られる埋め込みベクトル。

type

String

"text"

埋め込まれたコンテンツのタイプ。たとえば、text または image。

サンプルコード

import base64
import json
import os
import sys
from io import BytesIO

import requests
from PIL import Image, PngImagePlugin
import numpy as np

ENCODING = 'utf-8'

hosts = 'EAS URL'
head = {
    'Authorization': 'EAS TOKEN'
}

def encode_image_to_base64(image_path):
    """
    画像ファイルを Base64 文字列にエンコードします。
    """
    with open(image_path, "rb") as image_file:
        # 画像ファイルのバイナリデータを読み取ります。
        image_data = image_file.read()
        # Base64 文字列にエンコードします。
        base64_encoded = base64.b64encode(image_data).decode('utf-8')
    
    return base64_encoded

if __name__=='__main__':
    image_path = "path_to_your_image"
    text = 'prompt'

    image_format = 'jpg'
    input_data = []
    
    image64 = encode_image_to_base64(image_path)
    input_data.append({'image': f"data:image/{image_format};base64,{image64}"})

    input_data.append({'text': text})

    datas = json.dumps({
        'input': {
            'contents': input_data
        }
    })
    r = requests.post(hosts, data=datas, headers=head)
    data = json.loads(r.content.decode('utf-8'))

    if data['status_code']==200:
        if len(data['message'])!=0:
            print('Some items failed for the following reasons:')
            print(data['message'])

        for result_item in data['output']['embeddings']:
            print('The following item succeeded:')
            print('index', result_item['index'])
            print('type', result_item['type'])
            print('embedding', len(result_item['embedding']))
    else:
        print('Processing failed:')
        print(data['message'])

サンプル出力:

{
    "status_code": 200,
    "message": "",
    "output": {
        "embeddings": [
            {
                "index": 0,
                "embedding": [
                    -0.020782470703125,
                    -0.01399993896484375,
                    -0.0229949951171875,
                    ...
                ],
                "type": "image"
            }
        ]
    }
}

4.5. モデル評価

次の表は、この 評価ファイル を使用した、サンプルデータでの評価結果を示しています:

元のモデルの適合率

ファインチューニング済みモデルの適合率 (1 エポック)

GME-2B

Precision@1 0.3542

Precision@5 0.5280

Precision@10 0.5923

Precision@50 0.5800

Precision@100 0.5792

Precision@1 0.4271

Precision@5 0.6480

Precision@10 0.7308

Precision@50 0.7331

Precision@100 0.7404

GME-7B

Precision@1 0.3958

Precision@5 0.5920

Precision@10 0.6667

Precision@50 0.6517

Precision@100 0.6415

Precision@1 0.4375

Precision@5 0.6680

Precision@10 0.7590

Precision@50 0.7683

Precision@100 0.7723

評価スクリプト

import base64
import json
import os
import requests
import numpy as np
import torch
from tqdm import tqdm
from collections import defaultdict

# 定数
ENCODING = 'utf-8'
HOST_URL = 'http://1xxxxxxxx4.cn-xxx.pai-eas.aliyuncs.com/api/xxx'
AUTH_HEADER = {'Authorization': 'ZTg*********Mw=='}

def encode_image_to_base64(image_path):
    """画像ファイルを Base64 文字列にエンコードします。"""
    with open(image_path, "rb") as image_file:
        image_data = image_file.read()
        base64_encoded = base64.b64encode(image_data).decode(ENCODING)
    return base64_encoded

def load_image_features(feature_file):
    print("特徴量の読み込みを開始します...")
    image_ids, image_feats = [], []
    with open(feature_file, "r") as fin:
        for line in tqdm(fin):
            obj = json.loads(line.strip())
            image_ids.append(obj['image_id'])
            image_feats.append(obj['feature'])
    image_feats_array = np.array(image_feats, dtype=np.float32)
    print("特徴量の読み込みが完了しました。")
    return image_ids, image_feats_array

def precision_at_k(predictions, gts, k):
    """
    適合率@K を計算します。
    
    :param predictions: [(image_id, similarity_score), ...]
    :param gts: グラウンドトゥルース image_id のセット
    :param k: int, 上位 k 件の結果
    :return: float, 適合率
    """
    if len(predictions) > k:
        predictions = predictions[:k]
    
    predicted_ids = {p[0] for p in predictions}
    relevant_and_retrieved = predicted_ids.intersection(gts)
    precision = len(relevant_and_retrieved) / k
    return precision

def main():
    root_dir = '/mnt/data/retrieval/data/'
    data_dir = os.path.join(root_dir, 'images')
    tag_file = os.path.join(root_dir, 'meta/test.jsonl')
    model_type = 'finetune_gme7b_final'
    save_feature_file = os.path.join(root_dir, 'features', f'features_{model_type}_eas.jsonl')
    final_result_log = os.path.join(root_dir, 'results', f'retrieval_{model_type}_log_eas.txt')
    final_result = os.path.join(root_dir, 'results', f'retrieval_{model_type}_log_eas.jsonl')

    os.makedirs(os.path.join(root_dir, 'features'), exist_ok=True)
    os.makedirs(os.path.join(root_dir, 'results'), exist_ok=True)

    tag_dict = defaultdict(list)
    gt_image_ids = []
    with open(tag_file, 'r') as f:
        lines = f.readlines()
        for line in lines:
            data = json.loads(line.strip())
            gt_image_ids.append(data['image_id'])
            img_id = data['image_id'].split('.')[0]
            for caption in data['tags']:
                tag_dict[caption.strip()].append(img_id)

    print('合計タグ数:', len(tag_dict.keys()))

    prefix = ''
    texts = [prefix + text for text in tag_dict.keys()]
    images = [os.path.join(data_dir, i+'.jpg') for i in gt_image_ids]
    print('合計画像数:', len(images))

    encode_images = True
    if encode_images:
        with open(save_feature_file, "w") as fout:
            for image_path in tqdm(images):
                image_id = os.path.basename(image_path).split('.')[0]
                image64 = encode_image_to_base64(image_path)
                input_data = [{'image': f"data:image/jpg;base64,{image64}"}]

                datas = json.dumps({'input': {'contents': input_data}})
                r = requests.post(HOST_URL, data=datas, headers=AUTH_HEADER)

                data = json.loads(r.content.decode(ENCODING))
                if data['status_code'] == 200:
                    if len(data['message']) != 0:
                        print('一部の項目が失敗しました:', data['message'])
                    for result_item in data['output']['embeddings']:
                        fout.write(json.dumps({"image_id": image_id, "feature": result_item['embedding']}) + "\n")
                else:
                    print('処理に失敗しました:', data['message'])

    image_ids, image_feats_array = load_image_features(save_feature_file)

    top_k_list = [1, 5, 10, 50, 100]
    top_k_list_precision  = [[] for _ in top_k_list]

    with open(final_result, 'w') as f_w, open(final_result_log, 'w') as f:
        for tag in tqdm(texts):
            datas = json.dumps({'input': {'contents': [{'text': tag}]}})
            r = requests.post(HOST_URL, data=datas, headers=AUTH_HEADER)
            data = json.loads(r.content.decode(ENCODING))

            if data['status_code'] == 200:
                if len(data['message']) != 0:
                    print('一部の項目が失敗しました:', data['message'])

                for result_item in data['output']['embeddings']:
                    text_feat_tensor = result_item['embedding']
                    idx = 0
                    score_tuples = []
                    batch_size = 128
                    while idx < len(image_ids):
                        img_feats_tensor = torch.from_numpy(image_feats_array[idx:min(idx + batch_size, len(image_ids))]).cuda()
                        batch_scores = torch.from_numpy(np.array(text_feat_tensor)).cuda().float() @ img_feats_tensor.t()
                        for image_id, score in zip(image_ids[idx:min(idx + batch_size, len(image_ids))], batch_scores.squeeze(0).tolist()):
                            score_tuples.append((image_id, score))
                        idx += batch_size
                    
                    predictions = sorted(score_tuples, key=lambda x: x[1], reverse=True)
            else:
                print('処理に失敗しました:', data['message'])

            gts = tag_dict[tag.replace(prefix, '')]

            # 結果を書き込みます
            predictions_tmp = predictions[:10]
            result_dict = {'tag': tag, 'gts': gts, 'preds': [pred[0] for pred in predictions_tmp]}
            f_w.write(json.dumps(result_dict, ensure_ascii=False, indent=4) + '\n')

            for top_k_id, k in enumerate(top_k_list):
                need_exit = False

                if k > len(gts):
                    k = len(gts)
                    need_exit = True

                prec = precision_at_k(predictions, gts, k)

                f.write(f'Tag {tag}, Len(GT) {len(gts)}, Precision@{k} {prec:.4f} \n')
                f.flush()

                if need_exit:
                    break
                else:
                    top_k_list_precision[top_k_id].append(prec)
                    
    for idx, k in enumerate(top_k_list):
        print(f'Precision@{k} {np.mean(top_k_list_precision[idx]):.4f}')

if __name__ == "__main__":
    main()

4.6. モデルの使用

ファインチューニング済みの埋め込みモデルが EAS に正常にデプロイされた後は、「3.3.2」の手順に従ってモデル接続を作成し、後続のマルチモーダルデータ管理で使用できます。