嵌入式學習入門

釋出於 2022 年 6 月 23 日
在 GitHub 上更新

檢視此教程和配套的 Notebook: 在 Colab 中開啟

理解嵌入

嵌入是對一段資訊的數值表示,例如文字、文件、影像、音訊等。這種表示捕獲了被嵌入內容的語義含義,使其在許多行業應用中具有魯棒性。

給定文字“投票的主要好處是什麼?”,該句子的嵌入可以表示在向量空間中,例如,一個包含 384 個數字的列表(例如,[0.84, 0.42, ..., 0.02])。由於這個列表捕獲了含義,我們可以做一些令人興奮的事情,例如計算不同嵌入之間的距離,以確定兩個句子的含義匹配程度。

嵌入不限於文字!您還可以建立影像的嵌入(例如,一個包含 384 個數字的列表),並將其與文字嵌入進行比較,以確定句子是否描述了影像。這個概念是影像搜尋、分類、描述等強大系統的基礎!

嵌入是如何生成的?一個名為 Sentence Transformers 的開源庫允許您免費從影像和文字建立最先進的嵌入。本部落格將展示一個使用此庫的示例。

嵌入的作用是什麼?

"[...] 一旦你理解了這個機器學習多功能工具(嵌入),你將能夠構建從搜尋引擎到推薦系統,再到聊天機器人等等。你不需要是具有機器學習專業知識的資料科學家才能使用它們,也不需要龐大的標註資料集。" - Dale Markowitz,Google Cloud

一旦一段資訊(一個句子、一個文件、一張圖片)被嵌入,創造力就開始了;一些有趣的工業應用使用了嵌入。例如,Google 搜尋使用嵌入來匹配文字到文字和文字到圖片;Snapchat 使用它們來“在正確的時間向正確的使用者投放正確的廣告”;Meta(Facebook)使用它們進行社交搜尋

在能夠從嵌入中獲取智慧之前,這些公司必須嵌入它們的資訊。一個嵌入式資料集允許演算法快速搜尋、排序、分組等等。然而,這可能很昂貴且技術複雜。在這篇文章中,我們使用簡單的開源工具來展示嵌入和分析資料集是多麼容易。

嵌入式學習入門

我們將建立一個小型常見問題解答(FAQs)引擎:接收使用者的查詢,並確定哪個常見問題最相似。我們將使用美國社會保障醫療保險常見問題解答

但首先,我們需要嵌入我們的資料集(其他文字可互換使用編碼和嵌入這兩個術語)。Hugging Face 推理 API 允許我們透過簡單的 POST 呼叫輕鬆嵌入資料集。

由於嵌入捕獲了問題的語義含義,因此可以比較不同的嵌入並檢視它們之間的差異或相似程度。因此,您可以獲得與查詢最相似的嵌入,這相當於找到最相似的常見問題解答。檢視我們的語義搜尋教程,瞭解此機制如何工作的更詳細解釋。

簡而言之,我們將

  1. 使用推理 API 嵌入 Medicare 的常見問題。
  2. 將嵌入式問題上傳到 Hub 進行免費託管。
  3. 將客戶的查詢與嵌入式資料集進行比較,以確定哪個是與查詢最相似的常見問題。

1. 嵌入資料集

第一步是選擇一個現有的預訓練模型來建立嵌入。我們可以從 Sentence Transformers 庫中選擇一個模型。在這種情況下,讓我們使用 "sentence-transformers/all-MiniLM-L6-v2",因為它是一個小而強大的模型。在未來的文章中,我們將研究其他模型及其權衡。

登入到 Hub。您必須在賬戶設定中建立一個寫入令牌。我們將把寫入令牌儲存在 `hf_token` 中。

model_id = "sentence-transformers/all-MiniLM-L6-v2"
hf_token = "get your token in https://huggingface.co/settings/tokens"

要生成嵌入,您可以使用 `https://api-inference.huggingface.co/pipeline/feature-extraction/{model_id}` 端點,並帶有頭資訊 `{"Authorization": f"Bearer {hf_token}"}`。下面是一個接收包含文字的字典並返回包含嵌入列表的函式。

import requests

api_url = f"https://api-inference.huggingface.co/pipeline/feature-extraction/{model_id}"
headers = {"Authorization": f"Bearer {hf_token}"}

首次生成嵌入時,API 返回嵌入可能需要一段時間(大約 20 秒)。我們使用 `retry` 裝飾器(透過 `pip install retry` 安裝),這樣如果在第一次嘗試時 `output = query(dict(inputs = texts))` 不起作用,則等待 10 秒並再嘗試三次。發生這種情況是因為在第一次請求時,模型需要下載並安裝到伺服器上,但隨後的呼叫會快得多。

def query(texts):
    response = requests.post(api_url, headers=headers, json={"inputs": texts, "options":{"wait_for_model":True}})
    return response.json()

當前的 API 不強制執行嚴格的速率限制。相反,Hugging Face 會在所有可用資源之間均勻分配負載,並傾向於穩定的請求流。如果您需要嵌入多個文字或影像,Hugging Face 加速推理 API 將加快推理速度,並允許您選擇使用 CPU 或 GPU。

texts = ["How do I get a replacement Medicare card?",
        "What is the monthly premium for Medicare Part B?",
        "How do I terminate my Medicare Part B (medical insurance)?",
        "How do I sign up for Medicare?",
        "Can I sign up for Medicare Part B if I am working and have health insurance through an employer?",
        "How do I sign up for Medicare Part B if I already have Part A?",
        "What are Medicare late enrollment penalties?",
        "What is Medicare and who can get it?",
        "How can I get help with my Medicare Part A and Part B premiums?",
        "What are the different parts of Medicare?",
        "Will my Medicare premiums be higher because of my higher income?",
        "What is TRICARE ?",
        "Should I sign up for Medicare Part B if I have Veterans' Benefits?"]

output = query(texts)

作為響應,您將獲得一個列表的列表。每個列表都包含一個常見問題解答的嵌入。模型 "sentence-transformers/all-MiniLM-L6-v2" 將輸入問題編碼為 13 個大小為 384 的嵌入。讓我們將該列表轉換為一個形狀為 (13x384) 的 Pandas `DataFrame`。

import pandas as pd
embeddings = pd.DataFrame(output)

它類似於這個矩陣

[[-0.02388945  0.05525852 -0.01165488 ...  0.00577787  0.03409787  -0.0068891 ]
 [-0.0126876   0.04687412 -0.01050217 ... -0.02310316 -0.00278466   0.01047371]
 [ 0.00049438  0.11941205  0.00522949 ...  0.01687654 -0.02386115   0.00526433]
 ...
 [-0.03900796 -0.01060951 -0.00738271 ... -0.08390449  0.03768405   0.00231361]
 [-0.09598278 -0.06301168 -0.11690582 ...  0.00549841  0.1528919   0.02472013]
 [-0.01162949  0.05961934  0.01650903 ... -0.02821241 -0.00116556   0.0010672 ]]

2. 在 Hugging Face Hub 上免費託管嵌入

🤗 Datasets 是一個用於快速訪問和共享資料集的庫。讓我們使用使用者介面(UI)在 Hub 中託管嵌入資料集。然後,任何人都可以用一行程式碼載入它。您還可以使用終端共享資料集;請參閱文件瞭解步驟。在本條目的配套筆記本中,您將能夠使用終端共享資料集。如果您想跳過本節,請檢視包含嵌入式常見問題的 `ITESM/embedded_faqs_medicare` 儲存庫

首先,我們將嵌入從 Pandas `DataFrame` 匯出到 CSV。您可以以任何您喜歡的方式儲存資料集,例如 zip 或 pickle;您不需要使用 Pandas 或 CSV。由於我們的嵌入檔案不大,我們可以將其儲存在 CSV 中,`datasets.load_dataset()` 函式在下一節中將輕鬆推斷出它(請參閱資料集文件),即我們不需要建立載入指令碼。我們將把嵌入儲存為 `embeddings.csv`。

embeddings.to_csv("embeddings.csv", index=False)

按照以下步驟在 Hub 中託管 `embeddings.csv`。

  • 點選 Hub UI 右上角的使用者圖示。
  • 使用“新建資料集”建立資料集。

  • 選擇資料集的所有者(組織或個人)、名稱和許可證。選擇您希望它是私有還是公開。建立資料集。

  • 轉到“檔案”選項卡(如下圖所示),然後單擊“新增檔案”和“上傳檔案”。

  • 最後,拖放或上傳資料集,並提交更改。

現在資料集已免費託管在 Hub 上。您(或任何您希望共享嵌入的人)都可以快速載入它們。讓我們看看如何操作。

3. 獲取與查詢最相似的常見問題

假設一位 Medicare 客戶詢問:“Medicare 如何幫助我?”。我們將**找到**我們的哪些常見問題最能回答使用者的查詢。我們將建立一個查詢的嵌入,它可以代表其語義含義。然後,我們將其與 FAQ 資料集中的每個嵌入進行比較,以確定在向量空間中哪個嵌入最接近查詢。

使用 `pip install datasets` 安裝 🤗 Datasets 庫。然後,從 Hub 載入嵌入式資料集並將其轉換為 PyTorch `FloatTensor`。請注意,這不是操作 `Dataset` 的唯一方法;例如,您可以使用 NumPy、Tensorflow 或 SciPy(請參閱文件)。如果您想使用真實資料集進行練習,`ITESM/embedded_faqs_medicare` 儲存庫包含嵌入式 FAQ,或者您可以使用本部落格的配套筆記本

import torch
from datasets import load_dataset

faqs_embeddings = load_dataset('namespace/repo_name')
dataset_embeddings = torch.from_numpy(faqs_embeddings["train"].to_pandas().to_numpy()).to(torch.float)

我們使用之前定義的查詢函式來嵌入客戶的問題,並將其轉換為 PyTorch `FloatTensor` 以便高效操作。請注意,載入嵌入資料集後,我們可以使用 `Dataset` 的 `add_faiss_index` 和 `search` 方法,使用 faiss 庫來識別最接近嵌入查詢的常見問題。這裡有一個不錯的替代教程

question = ["How can Medicare help me?"]
output = query(question)

query_embeddings = torch.FloatTensor(output)

您可以使用 Sentence Transformers 庫中的 `util.semantic_search` 函式來識別哪些常見問題(FAQs)與使用者的查詢最接近(最相似)。此函式預設使用餘弦相似度作為確定嵌入接近度的函式。但是,您也可以使用其他函式來測量向量空間中兩點之間的距離,例如點積。

使用 `pip install -U sentence-transformers` 安裝 `sentence-transformers`,並搜尋與查詢最相似的五個常見問題。

from sentence_transformers.util import semantic_search

hits = semantic_search(query_embeddings, dataset_embeddings, top_k=5)

`util.semantic_search` 識別 13 個常見問題中每個問題與客戶查詢的接近程度,並返回一個包含最靠前的 `top_k` 個常見問題的字典列表。`hits` 看起來像這樣

[{'corpus_id': 8, 'score': 0.75653076171875},
 {'corpus_id': 7, 'score': 0.7418993711471558},
 {'corpus_id': 3, 'score': 0.7252674102783203},
 {'corpus_id': 9, 'score': 0.6735571622848511},
 {'corpus_id': 10, 'score': 0.6505177617073059}]

`corpus_id` 中的值允許我們索引在第一部分中定義的 `texts` 列表,並獲得五個最相似的常見問題

print([texts[hits[0][i]['corpus_id']] for i in range(len(hits[0]))])

以下是與客戶查詢最接近的 5 個常見問題:

['How can I get help with my Medicare Part A and Part B premiums?',
 'What is Medicare and who can get it?',
 'How do I sign up for Medicare?',
 'What are the different parts of Medicare?',
 'Will my Medicare premiums be higher because of my higher income?']

此列表代表與客戶查詢最接近的 5 個常見問題。很棒!我們在這裡主要使用了 PyTorch 和 Sentence Transformers 作為數值工具。但是,我們也可以使用 NumPy 和 SciPy 等工具自行定義餘弦相似度和排名函式。

更多學習資源

如果您想了解更多關於 Sentence Transformers 庫的資訊

感謝閱讀!

社群

您好,
下面是我嘗試執行帖子中的程式碼時遇到的錯誤訊息,
{'error': "SentenceSimilarityPipeline.call() 缺少 1 個必需的位置引數:'sentences'"}

我的程式碼
model_id = "sentence-transformers/all-MiniLM-L6-v2"
api_url = f"https://api-inference.huggingface.co/models/{model_id}"

hf_token = os.environ['access_token']
headers = {"Authorization": f"Bearer {hf_token}"}

def query(texts)
response = requests.post(api_url, headers=headers, json={"inputs": texts, "options":{"wait_for_model":True}})
return response.json()

texts = ["我如何獲得補發的醫療保險卡?",
"醫療保險 B 部分的每月保費是多少?",
"我如何終止我的醫療保險 B 部分(醫療保險)?"]

output = query(texts)
print(output)

我在 claude.ai 的幫助下調整了我的查詢函式,如下所示,我可以看到免費層的輸出

def query(sentence_pairs)
response = requests.post(
api_url,
headers=headers,
json={"inputs": {"source_sentence": sentence_pairs[0], "sentences": sentence_pairs[1:]}}
)
return response.json()

請注意,我認為 all-MiniLM-L6-v2 轉換器的 API URL 現已更改,這意味著 Google Colab Notebook 無法按原樣執行。新的 URL 在此 Hugging Face 論壇帖子中提供,更新到新的 URL 似乎可以解決問題:https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/discussions/116

註冊登入以發表評論

© . This site is unofficial and not affiliated with Hugging Face, Inc.