Einbettungen mit t-SNE visualisieren

Auf ai.google.dev ansehen In Google Colab ausführen Quelle auf GitHub ansehen

Überblick

In dieser Anleitung wird gezeigt, wie Sie das Clustering mit den Einbettungen aus der Gemini API visualisieren und ausführen. Sie visualisieren eine Teilmenge der 20 Newsgroup-Datasets mithilfe von t-SNE und gruppieren diese mit dem KMeans-Algorithmus.

Weitere Informationen zu den ersten Schritten mit Einbettungen, die über die Gemini API generiert wurden, finden Sie in der Python-Kurzanleitung.

Voraussetzungen

Sie können diese Kurzanleitung in Google Colab ausführen.

Um diese Kurzanleitung in Ihrer eigenen Entwicklungsumgebung auszuführen, achten Sie darauf, dass Ihre Umgebung die folgenden Anforderungen erfüllt:

  • Python 3.9 oder höher
  • Eine Installation von jupyter zum Ausführen des Notebooks.

Einrichtung

Laden Sie zuerst die Python-Bibliothek für die Gemini API herunter und installieren Sie sie.

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
import google.ai.generativelanguage as glm

# 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

API-Schlüssel abrufen

Bevor Sie die Gemini API verwenden können, müssen Sie zuerst einen API-Schlüssel abrufen. Falls Sie noch keinen Schlüssel haben, können Sie mit einem Klick in Google AI Studio einen Schlüssel erstellen.

API-Schlüssel anfordern

Fügen Sie den Schlüssel in Colab im linken Bereich unter „🚀“ zum Secret-Manager hinzu. Geben Sie ihr den Namen API_KEY.

Sobald Sie den API-Schlüssel haben, übergeben Sie ihn an das SDK. Dafür haben Sie die beiden folgenden Möglichkeiten:

  • Fügen Sie den Schlüssel in die Umgebungsvariable GOOGLE_API_KEY ein. Das SDK übernimmt ihn dort automatisch.
  • Schlüssel an genai.configure(api_key=...) übergeben
# Or use `os.getenv('API_KEY')` to fetch an environment variable.
API_KEY=userdata.get('API_KEY')

genai.configure(api_key=API_KEY)
for m in genai.list_models():
  if 'embedContent' in m.supported_generation_methods:
    print(m.name)
models/embedding-001
models/embedding-001

Dataset

Das 20 Newsgroups-Text-Dataset enthält 18.000 Newsgroups-Posts zu 20 Themen,die in Trainings- und Test-Datasets unterteilt sind. Die Aufteilung zwischen den Trainings- und Test-Datasets basiert auf Nachrichten, die vor und nach einem bestimmten Datum gepostet wurden. In dieser Anleitung verwenden Sie die Trainingsteilmenge.

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']

Hier ist das erste Beispiel im Trainings-Dataset.

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

Als Nächstes werden Sie Stichproben einiger Daten ziehen, indem Sie 100 Datenpunkte im Trainings-Dataset erstellen und einige der Kategorien löschen, die Sie in dieser Anleitung ausführen möchten. Wähle die Wissenschaftskategorien aus, die verglichen werden sollen.

# 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

Einbettungen erstellen

In diesem Abschnitt erfahren Sie, wie Sie mithilfe der Einbettungen aus der Gemini API Einbettungen für die verschiedenen Texte im DataFrame generieren.

API-Änderungen für Einbettungen mit Modelleinbettung-001

Für das neue Einbettungsmodell „embedding-001“ gibt es einen neuen Aufgabentypparameter und den optionalen Titel (nur gültig mit „task_type=RETRIEVAL_DOCUMENT“).

Diese neuen Parameter gelten nur für die neuesten Einbettungsmodelle.Die Aufgabentypen sind:

Aufgabentyp Beschreibung
RETRIEVAL_QUERY Gibt an, dass der gegebene Text eine Abfrage in einer Such-/Abrufeinstellung ist.
RETRIEVAL_DOCUMENT Gibt an, dass der gegebene Text ein Dokument in einer Such-/Abrufeinstellung ist.
SEMANTIC_SIMILARITY Gibt an, dass der angegebene Text für die Bestimmung der semantischen Textähnlichkeit (Semantic Textual Similarity, STS) verwendet wird.
KLASSIFIZIERUNG Gibt an, dass die Einbettungen zur Klassifizierung verwendet werden.
Gruppierung Gibt an, dass die Einbettungen für das Clustering verwendet werden.
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]

Dimensionalitätsreduktion

Die Länge des Dokumenteinbettungsvektors beträgt 768 Zeichen. Um zu visualisieren, wie die eingebetteten Dokumente gruppiert sind, müssen Sie die Dimensionalitätsreduzierung anwenden, da sich die Einbettungen nur im 2D- oder 3D-Raum visualisieren lassen. Vom Kontext her ähnliche Dokumente sollten im Weltraum näher beieinander sein, im Gegensatz zu Dokumenten, die weniger ähnlich sind.

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)

Sie wenden den Ansatz „t-Distributed Stochastic Neighbor Embedding“ (t-SNE) an, um die Dimensionalität zu reduzieren. Mit diesem Verfahren wird die Anzahl der Dimensionen reduziert, während Cluster erhalten bleiben (Punkte, die nah beieinander liegen, bleiben nah beieinander). Für die Originaldaten versucht das Modell, eine Verteilung zu konstruieren, über die andere Datenpunkte „Nachbarn“ sind (d.h. sie eine ähnliche Bedeutung haben). Anschließend wird eine Zielfunktion optimiert, um eine ähnliche Verteilung in der Visualisierung beizubehalten.

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)

png

Ergebnisse mit KMeans vergleichen

Das KMeans-Clustering ist ein beliebter Clustering-Algorithmus und wird häufig für unüberwachtes Lernen verwendet. Sie ermittelt iterativ die besten k Mittelpunkte und weist jedes Beispiel dem nächstgelegenen Schwerpunkt zu. Geben Sie die Einbettungen direkt in den KMeans-Algorithmus ein, um die Visualisierung der Einbettungen mit der Leistung eines Algorithmus für maschinelles Lernen zu vergleichen.

# 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)

png

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}

Rufen Sie die Mehrheit der Cluster pro Gruppe ab und sehen Sie, wie viele der tatsächlichen Mitglieder dieser Gruppe dem Cluster angehören.

# 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

Um die Leistung der auf Ihre Daten angewendeten KMeans besser zu visualisieren, können Sie eine Wahrheitsmatrix verwenden. Mit der Wahrheitsmatrix können Sie die Leistung des Klassifizierungsmodells über die Genauigkeit hinaus bewerten. Sie können sehen, wie falsch klassifizierte Punkte klassifiziert werden. Sie benötigen die tatsächlichen und die vorhergesagten Werte, die Sie im obigen DataFrame erfasst haben.

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)

png

Nächste Schritte

Sie haben jetzt Ihre eigene Visualisierung von Einbettungen mit Clustering erstellt! Verwenden Sie eigene Textdaten, um sie als Einbettungen zu visualisieren. Sie können eine Dimensionalitätsreduzierung durchführen, um den Schritt der Visualisierung abzuschließen. Beachten Sie, dass TSNE gut im Clustering von Eingaben ist, aber länger konvergieren kann oder bei lokalen Minima hängen bleibt. Wenn dieses Problem auftritt, können Sie auch die Hauptkomponentenanalyse (Hauptkomponentenanalyse, PCA) in Betracht ziehen.

Außerhalb von KMeans gibt es noch andere Clustering-Algorithmen, zum Beispiel das dichtebasierte räumliche Clustering (DBSCAN).

Informationen zur Verwendung anderer Dienste in der Gemini API finden Sie in der Python-Kurzanleitung. Weitere Informationen zur Verwendung der Einbettungen finden Sie in den Beispielen. In der TensorFlow-Anleitung Worteinbettungen erfahren Sie, wie Sie diese von Grund auf neu erstellen.