創建Auto-Sommelier
2019年8月,我投入了我的第一個自然語言處理(NLP)項目,並在我的網站上託管了自動侍酒師(Auto-Sommelier)。使用TensorFlow 1和Universal Sentence Encoder,我允許用戶描述他們理想的葡萄酒,並返回與查詢相似的描述的葡萄酒。該工具將葡萄酒評論和用戶輸入轉換為向量,並計算用戶輸入和葡萄酒評論之間的餘弦相似度,以找到最相似的結果。
餘弦相似度是比較文檔相似度的一種常用方法,因為它適用於詞頻等對分析非常重要的數據。它反映了單個矢量維度的相對比較,而不是絕對比較。在這篇文章中,我不會深入研究餘弦相似度背後的數學,但是要理解它是一個內積空間中兩個非零向量之間的相似性度量。

是時候改進了
儘管該模型仍然有效,但自2019年以來,自然語言處理已經取得了巨大的進步。使用像HuggingFace這樣的工具,將句子或段落轉換成向量,可以用於語義相似等自然語言處理任務,這是前所未有的簡單。使用最新的技術和語言模型重構我的代碼將使其性能更好。
在本教程中,我將解釋如何使用HuggingFace Transformers庫、Non-Metric Space庫和Dash庫來構建一個新的和改進的自動侍酒師。完整的代碼和GitHub鏈接可以在文章的底部找到。
數據
這些葡萄酒數據來自kaggle.com上的葡萄酒評論數據集。原始文件包含約13萬行數據,包括國家、描述、標題、品種、酒廠、價格和評級等列。。
在我把數據放入一個dataframe後,我刪除了包含重複描述的行和有空價格的行。我還將數據限制在獲得超過200條評論的葡萄酒品種上。
通過剔除評論數少於200的品種,我得到了54個葡萄酒品種。清理完null和重複的數據後,剩下100228行。通過谷歌搜索剩下的葡萄酒品種,我添加了一個「顏色」列,這樣用戶就可以根據想要的葡萄酒顏色來限制搜索。
導入依賴項和數據
由於數據已經是一個sqlite文件,所以很容易將數據連接並載入。按照三個步驟載入庫、數據和DataFrame。
- 導入pandas和sqlite3庫。
- 連接到sqlite文件。
- 將數據載入到一個pandas DataFrame中。
#Import dependencies
import numpy as np
import pandas as pd
import sqlite3
from sqlite3 import Error
import texthero as hero
from texthero import preprocessing
from sentence_transformers import SentenceTransformer, util
import nmslib
import time
import datetime
#Establish connection to sqlite database
conn = sqlite3.connect("wine_data.sqlite")#load the data into a pandas DataFrame
df = pd.read_sql("select * from wine_data", conn)
我還導入了本教程中將要使用的其他庫。我會更詳細地介紹它們。使用pandas read_sql函數使用原始SQL生成一個df。數據集中有16列和100228行。

注意:將所有文本轉換為矢量可能需要一些時間,所以如果你只是想嘗試一下,我建議只使用20,000條記錄來快速訓練。
HuggingFaceTransformers
如果你在過去的一年中參與了自然語言處理(NLP)領域,你可能已經聽說過HuggingFace。HuggingFace是一個專註於自然語言處理的人工智慧和深度學習平台,目標是普及人工智慧技術。他們簡化了應用和微調預先訓練的語言模型。
transformer是一個帶有模型的開源庫,允許用戶基於BERT、XLM、DistilBert等通用架構實現最先進的深度學習模型。它是建立在PyTorch、TensorFlow和Jax之上的,眾所周知,這些框架之間具有良好的互操作性。
pip install transformers
在本例中,我將使用distilBERT-base-uncase模型,因為它與我們的用例、語義相似性表現良好。它將文本轉換為768維的向量。如果你不想使用distilBERT,可以使用所有的HuggingFace模型來尋找句子相似度。這個模型是未知的,這意味著它不區分大小寫。關於模型的詳細信息,請查閱官方文件。
要實現該模型,請遵循以下步驟:
使用distilBERT-base-uncase模型實例化SentenceTransformer。
調用encode並將葡萄酒描述傳遞給它。設置convert_to_tensor = True參數。
#load the distilbert model
distilbert = SentenceTransformer('distilbert-base-uncased')#generate the embeddings for the wine reviews
embeddings = distilbert.encode(df['description'], convert_to_tensor=True)
注意:如果您以前從未下載過該模型,您將看到它下載並可能彈出一些消息。這是正常的。
一旦該過程完成,文本描述將被轉換為長度為768的向量。我們可以檢查長度和嵌入,以確保它看起來像預期的:

為了使向量更容易分析,使用numpy將數據從張量對象轉換為列表對象,然後將列表添加到pandas DataFrame。
#add embeddings to dataframe
df['distilbert'] = np.array(embeddings).tolist()
#show the top row
df.head(1)

創建搜索索引
當使用谷歌或Bing這樣的搜索引擎時,用戶希望很快得到結果。為了以閃電速度搜索結果集,我們可以使用輕量級和高效的非度量空間庫(NMSLIB)。
使用pip安裝:
pip install nmslib
如前所述,我們希望使用餘弦相似度作為度量,用於比較用戶輸入和葡萄酒描述。我們需要找到最接近搜索向量的向量。使用暴力循環技術搜索和排序數據可能代價昂貴且速度緩慢。相反,為數據點創建一個索引則會快很多。
創建搜索餘弦相似度指數是非常流程化的:
初始化一個新的索引,方法為hnsw,空間為餘弦。
使用addDataPointBatch方法向索引添加嵌入項。
使用createIndex方法使用數據點創建索引。
# initialize a new index, using a HNSW index on Cosine Similarity
distilbert_index = nmslib.init(method='hnsw', space='cosinesimil')
distilbert_index.addDataPointBatch(embeddings)
distilbert_index.createIndex({'post': 2}, print_progress=True)
如果你想保存索引並稍後載入它(比如在生產伺服器上),請使用下面的樣板代碼:
#Save a meta index and the data
index.saveIndex('index.bin', save_data=True)
#Re-intitialize the library, specify the space
newIndex = nmslib.init(method='hnsw', space='cosinesimil_sparse')
#Re-load the index and the data
newIndex.loadIndex('sparse_index.bin', load_data=True)
創建搜索功能
現在已經對數據進行了向量化,並且填充了搜索索引,現在應該創建接受用戶查詢並返回類似葡萄酒的函數。
search_wine函數將接受兩個輸入:DataFrame和UserQuery。用戶查詢將使用encode轉換為一個向量,就像我們對葡萄酒描述所做的那樣。然後,可以使用NMSLIB返回用戶查詢向量的k個最近鄰。我把k設為20,但你可以隨意實驗。
def search_wine(dataframe, userQuery):
if dataframe is not None and userQuery is not None:
df = dataframe.copy()
query = distilbert.encode([userQuery], convert_to_tensor=True)
ids, distances = distilbert_index.knnQuery(query, k=20)
matches = []
for i, j in zip(ids, distances):
matches.append({'country':df.country.values[i]
, 'winery' : df.winery.values[i]
, 'title' : df.title.values[i]
, 'variety': df.variety.values[i]
, 'color' : df.color.values[i]
, 'description': df.description.values[i]
, 'price': df.price.values[i]
, 'rating': df.rating.values[i]
, 'distance': j
})
return pd.DataFrame(matches)
注意,返回的結果作為字典添加到列表中。這使得將結果轉換回df變得很容易。對於距離值,越小越好。例如,距離為0意味著兩個向量是相同的。
測試:

可視化
除了文本搜索之外,我們還可以使用降維技術在二維空間中繪製葡萄酒。使用Texthero庫,很容易應用t-SNE演算法來降低向量的維數並將它們可視化。實際上,Texthero使用Plotly來製作互動式圖表。
t-SNE (t-分散式隨機鄰域嵌入)是一種用於高維數據可視化的機器學習演算法。t-SNE技術採用非線性降維。
對數據中的蒸餾器向量列應用t-SNE。
df['tsnedistilbert'] = hero.tsne(df['distilbert'])
使用texthero創建散點圖。
#create scatter plot of wines using the
hero.scatterplot(df, col='tsnedistilbert'
, color='variety'
, title="Wine Explorer"
, hover_data = ['title','variety','price','description'])

數據中有很多不同的類型散點圖看起來就像宇宙背景輻射,但這沒關係。將滑鼠懸停在圓點上將顯示更多信息。用戶可以點擊各種圖標將其從圖表中刪除。

有趣的是,我們可以看到一些品種是如何聚集在一起的,而另一些則是如何分散在各處的。
創建界面
為了讓用戶能夠與搜索功能進行互動,我們可以使用Plotly的Dash構建一個簡單的用戶界面。Dash是一個基於Flask, plot .js和React.js的Python框架。

安裝Dash、Dash Bootstrap組件和jupyter- Dash,如果你想在jupyter筆記本中構建一個Dash應用程序。
pip install dash
pip install dash-bootstrap-components
pip install jupyter-dash #if you want to build in a jupyter notebook
Dash應用程序由布局和回調組成:
布局:布局由描述應用程序外觀和用戶如何體驗內容的組件樹組成。
回調:回調功能使Dash應用具有交互性。回調函數是每當輸入屬性發生變化時自動調用的Python函數。
對於這部分內容我們就不詳細介紹了,有興趣的讀者可以閱讀原文
最後的想法和完整的代碼
與我在2019年創建的最初的Auto-Sommelier相比,這個版本要快得多,也簡單得多。通過像HuggingFace這樣的框架來利用最先進的語言模型的強大力量,為像我這樣的機器學習愛好者打開了一扇門,他們可以只用幾行代碼就構建出一些很棒的應用程序。現在是時候做一些分析了,看看與原始工具相比,結果是如何改進的!

本文代碼
:github/bendgame/MediumWineRecommend2
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/277125.html