DashVector + DashScope升級多模態檢索

DashVector發表於2024-05-21

本教程在前述教程(DashVector + ModelScope玩轉多模態檢索)的基礎之上,基於DashScope上新推出的ONE-PEACE通用多模態表徵模型結合向量檢索服務DashVector來對多模態檢索進行升級,接下來我們將展示更豐富的多模態檢索能力。

DashVector + ModelScope 玩轉多模態檢索

行車記錄儀

ONE-PEACE多模態模型

整體流程

image

主要分為兩個階段:

多模態資料Embedding入庫。透過ONE-PEACE模型服務Embedding介面將多種模態的資料集資料轉化為高維向量。

多模態Query檢索。基於ONE-PEACE模型提供的多模態Embedding能力,我們可以自由組合不同模態的輸入,例如單文字、文字+音訊、音訊+圖片等多模態輸入,獲取Embedding向量後透過DashVector跨模態檢索相似結果。

前提準備

1. API-KEY 準備
開通靈積模型服務,並獲得API-KEY:開通DashScope並建立API-KEY
開通DashVector向量檢索服務,並獲得API-KEY:API-KEY管理

2. 環境準備
本教程使用的多模態推理模型服務是DashScope最新的ONE-PEACE模型。ONE-PEACE是一個圖文音三模態通用表徵模型,在語義分割、音文檢索、音訊分類和視覺定位幾個任務都達到了新SOTA表現,在影片分類、影像分類圖文檢索、以及多模態經典benchmark也都取得了比較領先的結果。模型相關的環境依賴如下:

說明
需要提前安裝Python3.7 及以上版本,請確保相應的python版本。

# 安裝 dashscope 和 dashvector sdk
pip3 install dashscope dashvector

基本檢索

1. 資料準備
說明
由於DashScope的ONE-PEACE模型服務當前只支援URL形式的圖片、音訊輸入,因此需要將資料集提前上傳到公共網路儲存(例如 oss/s3),並獲取對應圖片、音訊的url地址列表。

當前示例場景使用ImageNet-1k的validation資料集作為入庫的圖片資料集,將原始圖片資料Embedding入庫。檢索時使用ESC-50資料集作為音訊輸入,文字和圖片輸入由使用者自定義,使用者也可對不同模態資料自由組合。

Dataset for ImageNet-1k

Dataset for ESC-50

2. 資料Embedding入庫
說明
本教程所涉及的 your-xxx-api-key 以及 your-xxx-cluster-endpoint,均需要替換為您自己的API-KAY及CLUSTER_ENDPOINT後,程式碼才能正常執行。

ImageNet-1k的validation資料集包含50000張標註好的圖片資料,其中包含1000個類別,每個類別50張圖片,這裡我們基於ONE-PEACE模型提取原始圖片的Embedding向量入庫,另外為了方便後續的圖片展示,我們也將原始圖片的url一起入庫。程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client, Doc, DashVectorException

dashscope.api_key = '{your-dashscope-api-key}'

# 由於 ONE-PEACE 模型服務當前只支援 url 形式的圖片、音訊輸入,因此使用者需要將資料集提前上傳到
# 公共網路儲存(例如 oss/s3),並獲取對應圖片、音訊的 url 列表。
# 該檔案每行儲存資料集單張圖片的公共 url,與當前python指令碼位於同目錄下
IMAGENET1K_URLS_FILE_PATH = "imagenet1k-urls.txt"


def index_image():
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 建立集合:指定集合名稱和向量維度, ONE-PEACE 模型產生的向量統一為 1536 維
    rsp = client.create('imagenet1k_val_embedding', 1536)
    if not rsp:
        raise DashVectorException(rsp.code, reason=rsp.message)

    # 呼叫 dashscope ONE-PEACE 模型生成圖片 Embedding,並插入 dashvector
    collection = client.get('imagenet1k_val_embedding')
    with open(IMAGENET1K_URLS_FILE_PATH, 'r') as file:
        for i, line in enumerate(file):
            url = line.strip('\n')
            input = [{'image': url}]
            result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                              input=input,
                                              auto_truncation=True)
            if result.status_code != 200:
                print(f"ONE-PEACE failed to generate embedding of {url}, result: {result}")
                continue
            embedding = result.output["embedding"]
            collection.insert(
                Doc(
                    id=str(i),
                    vector=embedding,
                    fields={'image_url': url}
                )
            )
            if (i + 1) % 100 == 0:
                print(f"---- Succeeded to insert {i + 1} image embeddings")


if __name__ == '__main__':
    index_image()

說明
上述程式碼需要訪問DashScope的ONE-PEACE多模態Embedding模型,總體執行速度視使用者開通該服務的qps有所不同。

因圖片大小影響ONE-PEACE模型獲取Embedding的成功與否,上述程式碼執行後最終入庫資料可能小於50000條。

3. 模態檢索
3.1. 文字檢索
對於單文字模態檢索,可以透過ONE-PEACE模型獲取文字Embedding向量,再透過DashVector向量檢索服務的檢索介面,快速檢索相似的底庫圖片。這裡文字query是貓 “cat”,程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image(image_list):
    for img in image_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()


def text_search(input_text):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('imagenet1k_val_embedding')

    # 獲取文字 query 的 Embedding 向量
    input = [{'text': input_text}]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    text_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(text_vector, topk=3)
    image_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img = Image.open(urlopen(img_url))
        image_list.append(img)
    return image_list


if __name__ == '__main__':
    """文字檢索"""
    # 貓
    text_query = "cat"
    show_image(text_search(text_query))

執行上述程式碼,檢索結果如下:
image

3.2. 音訊檢索
單音訊模態檢索與文字檢索類似,這裡音訊query取自ESC-50的“貓叫聲”片段,程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image(image_list):
    for img in image_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()


def audio_search(input_audio):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('imagenet1k_val_embedding')

    # 獲取音訊 query 的 Embedding 向量
    input = [{'audio': input_audio}]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    audio_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(audio_vector, topk=3)
    image_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img = Image.open(urlopen(img_url))
        image_list.append(img)
    return image_list


if __name__ == '__main__':
    """音訊檢索"""
    # 貓叫聲
    audio_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/audio-dataset/esc-50/1-47819-A-5.wav"
    show_image(audio_search(audio_url))

執行上述程式碼,檢索結果如下:
image

3.3. 文字+音訊檢索
接下來,我們嘗試“文字+音訊”聯合模態檢索,同上,首先透過ONE-PEACE模型獲取“文字+音訊”輸入的Embedding向量,再透過DashVector向量檢索服務檢索結果。這裡的文字query選取的是草地“grass”,音訊query依然選擇的是ESC-50的“貓叫聲”片段。程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image(image_list):
    for img in image_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()


def text_audio_search(input_text, input_audio):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('imagenet1k_val_embedding')

    # 獲取文字+音訊 query 的 Embedding 向量
    input = [
        {'text': input_text},
        {'audio': input_audio},
    ]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    text_audio_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(text_audio_vector, topk=3)
    image_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img = Image.open(urlopen(img_url))
        image_list.append(img)
    return image_list


if __name__ == '__main__':
    """文字+音訊檢索"""
    # 草地
    text_query = "grass"
    # 貓叫聲
    audio_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/audio-dataset/esc-50/1-47819-A-5.wav"
    show_image(text_audio_search(text_query, audio_url))

執行上述程式碼,檢索結果如下:
image

3.4. 圖片+音訊檢索
我們再嘗試下“圖片+音訊”聯合模態檢索,與前述“文字+音訊”檢索類似,這裡的圖片選取的是草地影像(需先上傳到公共網路儲存並獲取 url),音訊query依然選擇的是ESC-50的“貓叫聲”片段。程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image(image_list):
    for img in image_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()


def image_audio_search(input_image, input_audio):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('imagenet1k_val_embedding')

    # 獲取圖片+音訊 query 的 Embedding 向量
    # 注意,這裡音訊 audio 模態輸入的權重引數 factor 為 2(預設為1)
    # 目的是為了增大音訊輸入(貓叫聲)對檢索結果的影響
    input = [
        {'factor': 1, 'image': input_image},
        {'factor': 2, 'audio': input_audio},
    ]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    image_audio_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(image_audio_vector, topk=3)
    image_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img = Image.open(urlopen(img_url))
        image_list.append(img)
    return image_list


if __name__ == '__main__':
    """圖片+音訊檢索"""
    # 草地
    image_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/image-dataset/grass-field.jpeg"
    # 貓叫聲
    audio_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/audio-dataset/esc-50/1-47819-A-5.wav"
    show_image(image_audio_search(image_url, audio_url))

輸入示意圖如下:

image

執行程式碼,檢索結果如下:
image

進階使用

上述場景裡作為檢索底庫資料的是單模態的圖片資料,這裡我們也可以將多種模態的資料同時透過ONE-PEACE模型獲取Embedding向量,將Embedding向量作為檢索庫資料入庫檢索,觀察檢索效果。

1. 資料準備
本示例場景使用微軟COCO在Captioning場景下的validation資料集,將圖片以及對應的圖片描述caption文字兩種模態資料一起Embedding入庫。對於檢索時輸入的圖片、音訊與文字等多模態資料,使用者可以自定義,也可以使用公共資料集的資料。

Dataset for MSCOCO

2. 資料Embedding入庫
說明
本教程所涉及的 your-xxx-api-key 以及 your-xxx-cluster-endpoint,均需要替換為您自己的API-KAY及CLUSTER_ENDPOINT後,程式碼才能正常執行。

微軟COCO的Captioning validation驗證集包含5000張標註良好的圖片及對應的說明文字,這裡我們需要透過 DashScope的ONE-PEACE模型提取資料集的“圖片+文字”的Embedding向量入庫,另外為了方便後續的圖片展示,我們也將原始圖片url和對應caption文字一起入庫。程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client, Doc, DashVectorException

dashscope.api_key = '{your-dashscope-api-key}'

# 由於 ONE-PEACE 模型服務當前只支援 url 形式的圖片、音訊輸入,因此使用者需要將資料集提前上傳到
# 公共網路儲存(例如 oss/s3),並獲取對應圖片、音訊的 url 列表。
# 該檔案每行儲存資料集單張圖片的公共 url 和對應的 caption 文字,以`;`分割
COCO_CAPTIONING_URLS_FILE_PATH = "cocoval5k-urls-captions.txt"


def index_image_text():
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 建立集合:指定集合名稱和向量維度, ONE-PEACE 模型產生的向量統一為 1536 維
    rsp = client.create('coco_val_embedding', 1536)
    if not rsp:
        raise DashVectorException(rsp.code, reason=rsp.message)

    # 呼叫 dashscope ONE-PEACE 模型生成圖片 Embedding,並插入 dashvector
    collection = client.get('coco_val_embedding')
    with open(COCO_CAPTIONING_URLS_FILE_PATH, 'r') as file:
        for i, line in enumerate(file):
            url, caption = line.strip('\n').split(";")
            input = [
                {'text': caption},
                {'image': url},
            ]
            result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                              input=input,
                                              auto_truncation=True)
            if result.status_code != 200:
                print(f"ONE-PEACE failed to generate embedding of {url}, result: {result}")
                continue
            embedding = result.output["embedding"]
            collection.insert(
                Doc(
                    id=str(i),
                    vector=embedding,
                    fields={'image_url': url, 'image_caption': caption}
                )
            )
            if (i + 1) % 20 == 0:
                print(f"---- Succeeded to insert {i + 1} image embeddings")


if __name__ == '__main__':
    index_image_text()

說明
上述程式碼需要訪問DashScope的ONE-PEACE多模態Embedding模型,總體執行速度視使用者開通該服務的qps有所不同。

3. 模態檢索
3.1. 文字檢索
首先我們嘗試單文字模態檢索。程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image_text(image_text_list):
    for img, cap in image_text_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()
        print(cap)


def text_search(input_text):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('coco_val_embedding')

    # 獲取文字 query 的 Embedding 向量
    input = [{'text': input_text}]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    text_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(text_vector, topk=3)
    image_text_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img_cap = doc.fields['image_caption']
        img = Image.open(urlopen(img_url))
        image_text_list.append((img, img_cap))
    return image_text_list


if __name__ == '__main__':
    """文字檢索"""
    # 狗
    text_query = "dog"
    show_image_text(text_search(text_query))

執行上述程式碼,檢索結果如下:
image

3.2. 音訊檢索
我們再嘗試單音訊模態檢索。我們使用ESC-50資料集的“狗叫聲片段”作為音訊輸入,程式碼示例如下:

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image_text(image_text_list):
    for img, cap in image_text_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()
        print(cap)


def audio_search(input_audio):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('coco_val_embedding')

    # 獲取音訊 query 的 Embedding 向量
    input = [{'audio': input_audio}]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    audio_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(audio_vector, topk=3)
    image_text_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img_cap = doc.fields['image_caption']
        img = Image.open(urlopen(img_url))
        image_text_list.append((img, img_cap))
    return image_text_list


if __name__ == '__main__':
    """"音訊檢索"""
    # dog bark
    audio_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/audio-dataset/esc-50/1-100032-A-0.wav"
    show_image_text(audio_search(audio_url))

執行上述程式碼,檢索結果如下:

image

3.3. 文字+音訊檢索
進一步的,我們嘗試使用“文字+音訊”進行雙模態檢索。這裡使用ESC-50資料集的“狗叫聲片段”作為音訊輸入,另外使用“beach”作為文字輸入,程式碼示例如下:

``

點選檢視程式碼
import dashscope
from dashscope import MultiModalEmbedding
from dashvector import Client
from urllib.request import urlopen
from PIL import Image

dashscope.api_key = '{your-dashscope-api-key}'


def show_image_text(image_text_list):
    for img, cap in image_text_list:
        # 注意:show() 函式在 Linux 伺服器上可能需要安裝必要的影像瀏覽器元件才生效
        # 建議在支援 jupyter notebook 的伺服器上執行該程式碼
        img.show()
        print(cap)


def text_audio_search(input_text, input_audio):
    # 初始化 dashvector client
    client = Client(
      api_key='{your-dashvector-api-key}',
      endpoint='{your-dashvector-cluster-endpoint}'
    )

    # 獲取上述入庫的集合
    collection = client.get('coco_val_embedding')

    # 獲取文字+音訊 query 的 Embedding 向量
    input = [
        {'text': input_text},
        {'audio': input_audio},
    ]
    result = MultiModalEmbedding.call(model=MultiModalEmbedding.Models.multimodal_embedding_one_peace_v1,
                                      input=input,
                                      auto_truncation=True)
    if result.status_code != 200:
        raise Exception(f"ONE-PEACE failed to generate embedding of {input}, result: {result}")
    text_audio_vector = result.output["embedding"]

    # DashVector 向量檢索
    rsp = collection.query(text_audio_vector, topk=3)
    image_text_list = list()
    for doc in rsp:
        img_url = doc.fields['image_url']
        img_cap = doc.fields['image_caption']
        img = Image.open(urlopen(img_url))
        image_text_list.append((img, img_cap))
    return image_text_list


if __name__ == '__main__':
    """文字+音訊檢索"""
    text_query = "beach"
    # 狗叫聲
    audio_url = "http://proxima-internal.oss-cn-zhangjiakou.aliyuncs.com/audio-dataset/esc-50/1-100032-A-0.wav"
    show_image_text(text_audio_search(text_query, audio_url))

執行上述程式碼,檢索結果如下:
image

觀察上述檢索結果,發現後兩張圖的重點更多的是在展示 “beach” 文字輸入對應的沙灘,而 “狗叫聲片段”音訊輸入指示的狗的圖片形象則不明顯,其中第二張圖需要放大後才可以看到圖片中站立在水中的狗,第三張圖中基本沒有狗的形象。

對於上述情況,我們可以透過調整不同輸入的權重來設定mbedding向量中哪種模態佔更大的比重,從而在檢索中突出重點。例如對於上述程式碼,我們可以給予“狗叫聲片段”更大的權重,重點突出檢索結果裡狗的形象。

點選檢視程式碼
# 其他程式碼一致

# 透過 `factor` 引數來調整不同模態輸入的權重,預設為 1,這裡設定 audio 為 2
input = [
    {'factor': 1, 'text': input_text},
    {'factor': 2, 'audio': input_audio},
]

替換 後,執行上述程式碼,結果如下:input

image

寫在最後

本文結合DashScope的ONE-PEACE模型的和DashVector向量檢索服務向大家展示了豐富多樣的多模態檢索示例,得益於ONE-PEACE模型優秀的多模態Embedding能力和DashVector強大的向量檢索能力,我們能初步看到AI多模態檢索令人驚喜的效果。

本文的範例中,我們的向量檢索服務,模型服務以及資料均可以公開獲取,我們提供的示例也只是有限的展示了多模態檢索的效果,非常歡迎大家來體驗,自由發掘多模態檢索的潛力。


免費體驗阿里雲高效能向量檢索服務:https://www.aliyun.com/product/ai/dashvector
image

相關文章