Wyświetl na ai.google.dev | Wypróbuj notatnik Colab | Wyświetl notatnik na GitHubie |
Omówienie
Ten samouczek pokazuje, jak wizualizować i grupować wektory dystrybucyjne z Gemini API. Zwizualizujesz podzbiór zbioru danych 20 grup wiadomości za pomocą argumentu t-SNE, a klaster ten uzyskasz za pomocą algorytmu KMeans.
Więcej informacji o tym, jak zacząć korzystać z reprezentacji właściwościowych wygenerowanych za pomocą interfejsu Gemini API, znajdziesz w krótkim wprowadzeniu do Pythona.
Wymagania wstępne
Możesz uruchomić to krótkie wprowadzenie w Google Colab.
Aby ukończyć to krótkie wprowadzenie we własnym środowisku programistycznym, upewnij się, że środowisko spełnia te wymagania:
- Python w wersji 3.9 lub nowszej
- Instalacja programu
jupyter
w celu uruchomienia notatnika.
Konfiguracja
Najpierw pobierz i zainstaluj bibliotekę Pythona Gemini API.
pip install -U -q google.generativeai
import re
import tqdm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import google.generativeai as genai
# Used to securely store your API key
from google.colab import userdata
from sklearn.datasets import fetch_20newsgroups
from sklearn.manifold import TSNE
from sklearn.cluster import KMeans
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
Pobierz klucz interfejsu API
Aby móc korzystać z Gemini API, musisz najpierw uzyskać klucz API. Jeśli nie masz jeszcze klucza, utwórz go jednym kliknięciem w Google AI Studio.
Uzyskiwanie klucza interfejsu API
W Colab dodaj klucz do menedżera obiektów tajnych w sekcji „🔑” w panelu po lewej stronie. Nazwij go API_KEY
.
Po uzyskaniu klucza interfejsu API przekaż go do pakietu SDK. Można to zrobić na dwa sposoby:
- Umieść ten klucz w zmiennej środowiskowej
GOOGLE_API_KEY
(pakiet SDK automatycznie go stamtąd pobierze). - Przekaż klucz urządzeniu
genai.configure(api_key=...)
genai.configure(api_key=GOOGLE_API_KEY)
for m in genai.list_models():
if 'embedContent' in m.supported_generation_methods:
print(m.name)
models/embedding-001 models/embedding-001
Zbiór danych
Zbiór danych tekstowych grup dyskusyjnych z 20 zawiera 18 000 postów na 20 tematów podzielonych na zbiory treningowe i testowe. Podział między zbiorami danych treningowych i testowych jest oparty na wiadomościach opublikowanych przed określoną datą i po niej. W tym samouczku będziesz używać podzbioru treningowego.
newsgroups_train = fetch_20newsgroups(subset='train')
# View list of class names for dataset
newsgroups_train.target_names
['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']
Oto pierwszy przykład w zbiorze treningowym.
idx = newsgroups_train.data[0].index('Lines')
print(newsgroups_train.data[0][idx:])
Lines: 15 I was wondering if anyone out there could enlighten me on this car I saw the other day. It was a 2-door sports car, looked to be from the late 60s/ early 70s. It was called a Bricklin. The doors were really small. In addition, the front bumper was separate from the rest of the body. This is all I know. If anyone can tellme a model name, engine specs, years of production, where this car is made, history, or whatever info you have on this funky looking car, please e-mail. Thanks, - IL ---- brought to you by your neighborhood Lerxst ----
# Apply functions to remove names, emails, and extraneous words from data points in newsgroups.data
newsgroups_train.data = [re.sub(r'[\w\.-]+@[\w\.-]+', '', d) for d in newsgroups_train.data] # Remove email
newsgroups_train.data = [re.sub(r"\([^()]*\)", "", d) for d in newsgroups_train.data] # Remove names
newsgroups_train.data = [d.replace("From: ", "") for d in newsgroups_train.data] # Remove "From: "
newsgroups_train.data = [d.replace("\nSubject: ", "") for d in newsgroups_train.data] # Remove "\nSubject: "
# Put training points into a dataframe
df_train = pd.DataFrame(newsgroups_train.data, columns=['Text'])
df_train['Label'] = newsgroups_train.target
# Match label to target name index
df_train['Class Name'] = df_train['Label'].map(newsgroups_train.target_names.__getitem__)
# Retain text samples that can be used in the gecko model.
df_train = df_train[df_train['Text'].str.len() < 10000]
df_train
Następnie próbkujesz część danych, biorąc 100 punktów danych w zbiorze danych treningowych i upuszczając kilka kategorii, które chcesz zrealizować w tym samouczku. Wybierz kategorie naukowe, które chcesz porównać.
# Take a sample of each label category from df_train
SAMPLE_SIZE = 150
df_train = (df_train.groupby('Label', as_index = False)
.apply(lambda x: x.sample(SAMPLE_SIZE))
.reset_index(drop=True))
# Choose categories about science
df_train = df_train[df_train['Class Name'].str.contains('sci')]
# Reset the index
df_train = df_train.reset_index()
df_train
df_train['Class Name'].value_counts()
sci.crypt 150 sci.electronics 150 sci.med 150 sci.space 150 Name: Class Name, dtype: int64
Tworzenie wektorów dystrybucyjnych
W tej sekcji dowiesz się, jak generować wektory dystrybucyjne dla różnych tekstów w ramce DataFrame przy użyciu wektorów dystrybucyjnych z interfejsu Gemini API.
Zmiany w interfejsie API dotyczące reprezentacji właściwościowych z osadzeniem modelu 001
W nowym modelu wektorów dystrybucyjnych – wektora dystrybucyjnego 001 dostępny jest nowy parametr typu zadania i opcjonalny tytuł (tylko w przypadku parametru event_type=RETRIEVAL_DOCUMENT
).
Te nowe parametry mają zastosowanie tylko do najnowszych modeli wektorów dystrybucyjnych.Typy zadań to:
Typ zadania | Opis |
---|---|
RETRIEVAL_QUERY | Określa, że dany tekst jest zapytaniem w ustawieniach wyszukiwania/pobierania. |
RETRIEVAL_DOCUMENT | Określa, że dany tekst jest dokumentem w ustawieniu wyszukiwania/pobierania. |
SEMANTIC_SIMILARITY | Określa, który tekst będzie używany na potrzeby funkcji podobieństwo semantycznego (STS). |
KLASYFIKACJA | Określa, że wektory dystrybucyjne będą używane do klasyfikacji. |
KLASTEROWANIE | Określa, że wektory dystrybucyjne będą używane do grupowania. |
from tqdm.auto import tqdm
tqdm.pandas()
from google.api_core import retry
def make_embed_text_fn(model):
@retry.Retry(timeout=300.0)
def embed_fn(text: str) -> list[float]:
# Set the task_type to CLUSTERING.
embedding = genai.embed_content(model=model,
content=text,
task_type="clustering")
return embedding["embedding"]
return embed_fn
def create_embeddings(df):
model = 'models/embedding-001'
df['Embeddings'] = df['Text'].progress_apply(make_embed_text_fn(model))
return df
df_train = create_embeddings(df_train)
0%| | 0/600 [00:00<?, ?it/s]
Redukcja wymiarów
Długość wektora dystrybucyjnego dokumentu wynosi 768. Aby wizualizować grupy umieszczonych dokumentów, trzeba zastosować redukcję wymiarów, ponieważ wektory dystrybucyjne można wizualizować tylko w przestrzeni 2D lub 3D. Dokumenty podobne pod względem kontekstu powinny znajdować się bliżej w przestrzeni, w odróżnieniu od dokumentów, które nie są do siebie zbyt podobne.
len(df_train['Embeddings'][0])
768
# Convert df_train['Embeddings'] Pandas series to a np.array of float32
X = np.array(df_train['Embeddings'].to_list(), dtype=np.float32)
X.shape
(600, 768)
Aby przeprowadzić redukcję wymiarów, zastosujesz metodę t-Distributed Stochastic Neighbor Embedding (t-SNE). Ta metoda zmniejsza liczbę wymiarów, jednocześnie zachowując klastry (punkty znajdujące się blisko siebie pozostają blisko siebie). W przypadku danych oryginalnych model próbuje utworzyć rozkład, według którego inne punkty danych są „sąsiadami” (na przykład mają podobne znaczenie). Następnie optymalizuje funkcję celu, aby zachować podobny rozkład na wizualizacji.
tsne = TSNE(random_state=0, n_iter=1000)
tsne_results = tsne.fit_transform(X)
df_tsne = pd.DataFrame(tsne_results, columns=['TSNE1', 'TSNE2'])
df_tsne['Class Name'] = df_train['Class Name'] # Add labels column from df_train to df_tsne
df_tsne
fig, ax = plt.subplots(figsize=(8,6)) # Set figsize
sns.set_style('darkgrid', {"grid.color": ".6", "grid.linestyle": ":"})
sns.scatterplot(data=df_tsne, x='TSNE1', y='TSNE2', hue='Class Name', palette='hls')
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1))
plt.title('Scatter plot of news using t-SNE');
plt.xlabel('TSNE1');
plt.ylabel('TSNE2');
plt.axis('equal')
(-46.191162300109866, 53.521015357971194, -39.96646995544434, 37.282975387573245)
Porównaj wyniki z KMeans
Grupowanie KMeans to popularny algorytm grupowania i często używany w przypadku uczenia nienadzorowanego. Określa ona najlepsze punkty środkowe osi k i przypisuje każdy przykład najbliższemu centroidowi. Wstaw wektory dystrybucyjne bezpośrednio do algorytmu KMeans, aby porównać wizualizację wektorów dystrybucyjnych ze skutecznością algorytmu systemów uczących się.
# Apply KMeans
kmeans_model = KMeans(n_clusters=4, random_state=1, n_init='auto').fit(X)
labels = kmeans_model.fit_predict(X)
df_tsne['Cluster'] = labels
df_tsne
fig, ax = plt.subplots(figsize=(8,6)) # Set figsize
sns.set_style('darkgrid', {"grid.color": ".6", "grid.linestyle": ":"})
sns.scatterplot(data=df_tsne, x='TSNE1', y='TSNE2', hue='Cluster', palette='magma')
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1))
plt.title('Scatter plot of news using KMeans Clustering');
plt.xlabel('TSNE1');
plt.ylabel('TSNE2');
plt.axis('equal')
(-46.191162300109866, 53.521015357971194, -39.96646995544434, 37.282975387573245)
def get_majority_cluster_per_group(df_tsne_cluster, class_names):
class_clusters = dict()
for c in class_names:
# Get rows of dataframe that are equal to c
rows = df_tsne_cluster.loc[df_tsne_cluster['Class Name'] == c]
# Get majority value in Cluster column of the rows selected
cluster = rows.Cluster.mode().values[0]
# Populate mapping dictionary
class_clusters[c] = cluster
return class_clusters
classes = df_tsne['Class Name'].unique()
class_clusters = get_majority_cluster_per_group(df_tsne, classes)
class_clusters
{'sci.crypt': 1, 'sci.electronics': 3, 'sci.med': 2, 'sci.space': 0}
Pozyskaj większość klastrów w grupie i sprawdź, ilu faktycznych członków danej grupy znajduje się w danym klastrze.
# Convert the Cluster column to use the class name
class_by_id = {v: k for k, v in class_clusters.items()}
df_tsne['Predicted'] = df_tsne['Cluster'].map(class_by_id.__getitem__)
# Filter to the correctly matched rows
correct = df_tsne[df_tsne['Class Name'] == df_tsne['Predicted']]
# Summarise, as a percentage
acc = correct['Class Name'].value_counts() / SAMPLE_SIZE
acc
sci.space 0.966667 sci.med 0.960000 sci.electronics 0.953333 sci.crypt 0.926667 Name: Class Name, dtype: float64
# Get predicted values by name
df_tsne['Predicted'] = ''
for idx, rows in df_tsne.iterrows():
cluster = rows['Cluster']
# Get key from mapping based on cluster value
key = list(class_clusters.keys())[list(class_clusters.values()).index(cluster)]
df_tsne.at[idx, 'Predicted'] = key
df_tsne
Aby lepiej wizualizować wydajność wskaźników KMeans zastosowanych do Twoich danych, możesz użyć tabeli pomyłek. Tablica pomyłek umożliwia ocenę skuteczności modelu klasyfikacji wykraczającej poza dokładność. Możesz zobaczyć, jak klasyfikowane są błędnie sklasyfikowane punkty. Potrzebujesz wartości rzeczywistych i prognozowanych, które zostały zebrane w ramach powyższej ramki danych.
cm = confusion_matrix(df_tsne['Class Name'].to_list(), df_tsne['Predicted'].to_list())
disp = ConfusionMatrixDisplay(confusion_matrix=cm,
display_labels=classes)
disp.plot(xticks_rotation='vertical')
plt.title('Confusion Matrix for Actual and Clustered Newsgroups');
plt.grid(False)
Dalsze kroki
Udało Ci się utworzyć własną wizualizację wektorów dystrybucyjnych z grupowaniem. Spróbuj wykorzystać własne dane tekstowe, aby zwizualizować je jako wektory dystrybucyjne. Aby ukończyć etap wizualizacji, możesz przeprowadzić redukcję wymiarów. Pamiętaj, że TSNE dobrze radzi sobie z grupowaniem danych wejściowych, ale ich uzgadnianie może potrwać dłużej lub może utknąć na lokalnym poziomie. Jeśli natrafisz na ten problem, możesz też rozważyć analizę komponentów głównych (PCA).
Poza KMeans istnieją również inne algorytmy grupowania, na przykład klastra przestrzenne na podstawie gęstości (DBSCAN).
Więcej informacji na temat korzystania z wektorów dystrybucyjnych można znaleźć w innych samouczkach: