我們昨天提到,transformer 也可以拿來做 embedding,而在開源的生態系中,最受歡迎的 embedding 模型是 all-MiniLM-L6-v2
,有 384 個維度。有興趣的雙殺可以去看這篇論文。 https://arxiv.org/abs/2012.15828
我們一樣可以使用使用前幾天學到的 hugging face 的 from_pretrained
的方式,載入模型和分詞器的方式,來做 embedding。
下面程式碼很長很複雜,可以好好閱讀其中的註解理解在做什麼。
from transformers import AutoTokenizer, AutoModel
import torch
import torch.nn.functional as F
#Mean Pooling - Take attention mask into account for correct averaging
def mean_pooling(model_output, attention_mask):
#第一個 model_output 的元素包含所有 token embeddings
token_embeddings = model_output[0]
# 對注意力遮罩進行擴展,在最後一個維度添加一個大小為 1 的新維度,使其形狀與單詞嵌入相同。這樣我們就可以逐個元素地將它們相乘。
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
# 單詞嵌入和擴展後的注意力遮罩進行逐元素相乘。1 表示沿著第二個維度求和,並除以每個句子中的實際單詞數量(由input_mask_expanded.sum(1)給出)。torch.clamp用於防止除以零。
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
# 要 embedding 的句字
sentences = ["我會披星戴月的想你,我會奮不顧身的前進,遠方煙火越來越唏噓,凝視前方身後的距離",
"鯊魚寶寶 doo doo doo doo doo doo, 鯊魚寶寶"]
# Load model
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
# # 把模型存到本地端
# tokenizer.save_pretrained("nlp_models/all-MiniLM-L6-v2")
# model.save_pretrained("nlp_models/all-MiniLM-L6-v2")
# 分詞
encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')
# 計算 token embeddings
with torch.no_grad():
model_output = model(**encoded_input)
# 使用 mean_pooling
sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])
# dim 1 表示沿著第二個維度,並使用 L2 正規化
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
print("Sentence embeddings:")
print(sentence_embeddings)
Sentence-transformers 是 Hugging Face 上很熱門做 embedding 的套件,由 sbert 團隊所提出的。用這個套件,就可以不用寫上面又臭又長一堆數學的程式碼了!
使用指令 poetry add sentence-transformers
創建一個 python 檔叫 embedding.py
,貼上下面的程式碼。
from sentence_transformers import SentenceTransformer
sentences = ["我會披星戴月的想你,我會奮不顧身的前進,遠方煙火越來越唏噓,凝視前方身後的距離",
"鯊魚寶寶 doo doo doo doo doo doo, 鯊魚寶寶"]
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
embeddings = model.encode(sentences)
print(embeddings)
使用 SentenceTransformer,是不是方便很多呢?
明天我們再來講怎麼使用 Azure Open AI 做 embedding,這個又是更方便了。