Was sind synthetische Daten?

Daten, die von einem Pc erstellt wurden, der vorhandene Daten replizieren oder erweitert.

Warum ist es nützlich?

Wir alle haben den Erfolg von Chatgpt, Lama und in jüngerer Zeit von Deepseek erlebt. Diese Sprachmodelle werden allgegenwärtig in der gesamten Gesellschaft verwendet und haben viele Behauptungen ausgelöst, dass wir uns schnell künstliche allgemeine Intelligenz nähern – KI, die in der Lage sind, jede menschliche Funktion zu replizieren.

Bevor wir je nach Ihrer Perspektive zu aufgeregt oder verängstigt sind, nähern wir uns auch schnell einer Hürde für die Weiterentwicklung dieser Sprachmodelle. Laut einer von einer Gruppe des Forschungsinstituts, Epoch, veröffentlichten Arbeit (1)Anwesend Wir haben keine Daten mehr. Sie schätzen, dass wir bis 2028 die Obergrenze der möglichen Daten erreicht haben werden, an denen Sprachmodelle geschult sind.

Bild des Autors. Diagramm basierend auf geschätzten Datensatzprojektionen. Dies ist eine rekonstruierte Visualisierung, die von der Epoch -Forschungsgruppe (1) inspiriert ist.

Was passiert, wenn uns die Daten ausgehen?

Nun, wenn uns die Daten ausgehen, werden wir nichts Neues haben, mit dem wir unsere Sprachmodelle trainieren können. Diese Modelle werden dann nicht mehr verbessert. Wenn wir künstliche allgemeine Intelligenz verfolgen wollen, müssen wir neue Möglichkeiten zur Verbesserung der KI finden, ohne nur das Volumen der realen Trainingsdaten zu erhöhen.

Ein potenzieller Retter sind synthetische Daten, die generiert werden können, um vorhandene Daten nachzuahmen, und wurde bereits zur Verbesserung der Leistung von Modellen wie Gemini und DBRX verwendet.

Synthetische Daten jenseits der LLMs

Über die Überwindung der Datenknappheit für Großsprachmodelle hinaus können synthetische Daten in den folgenden Situationen verwendet werden:

  • Wise Daten – Wenn wir keine sensiblen Attribute teilen oder verwenden möchten, können synthetische Daten generiert werden, die die Eigenschaften dieser Merkmale nachahmen und gleichzeitig die Anonymität aufrechterhalten.
  • Teure Daten-Wenn das Sammeln von Daten teuer ist, können wir ein großes Volumen von synthetischen Daten aus einer kleinen Menge an realen Daten erzeugen.
  • Datenmangel– Datensätze sind voreingenommen, wenn es eine unverhältnismäßig niedrige Anzahl einzelner Datenpunkte aus einer bestimmten Gruppe gibt. Synthetische Daten können verwendet werden, um einen Datensatz auszugleichen.

Unausgewogene Datensätze

Unausgeglichene Datensätze können (*, aber nicht immer*) problematisch sein, da sie möglicherweise nicht genügend Informationen enthalten, um ein prädiktives Modell effektiv zu schulen. Wenn beispielsweise ein Datensatz viel mehr Männer als Frauen enthält, kann unser Modell darauf verzerrt sein, Männer zu erkennen und zukünftige weibliche Proben als Männer falsch zu klassifizieren.

In diesem Artikel zeigen wir das Ungleichgewicht in der beliebten UCI Erwachsenen Datensatz (2), und wie wir a verwenden können Variations-Auto-Coder zu erzeugen Synthetische Daten Verbesserung der Klassifizierung in diesem Beispiel.

Wir laden zuerst den Datensatz für Erwachsene herunter. Dieser Datensatz enthält Funktionen wie Alter, Bildung und Beruf, mit denen das Zielergebnis „Einkommen“ vorhergesagt werden kann.

# Obtain dataset right into a dataframe
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/grownup/grownup.knowledge"
columns = (
   "age", "workclass", "fnlwgt", "schooling", "education-num", "marital-status",
   "occupation", "relationship", "race", "intercourse", "capital-gain",
   "capital-loss", "hours-per-week", "native-country", "earnings"
)
knowledge = pd.read_csv(url, header=None, names=columns, na_values=" ?", skipinitialspace=True)

# Drop rows with lacking values
knowledge = knowledge.dropna()

# Break up into options and goal
X = knowledge.drop(columns=("earnings"))
y = knowledge('earnings').map({'>50K': 1, '<=50K': 0}).values

# Plot distribution of earnings
plt.determine(figsize=(8, 6))
plt.hist(knowledge('earnings'), bins=2, edgecolor="black")
plt.title('Distribution of Revenue')
plt.xlabel('Revenue')
plt.ylabel('Frequency')
plt.present()

Im Datensatz für Erwachsene ist das Einkommen eine binäre Variable, die Personen, die oben und darunter 50.000 US -Greenback verdienen, repräsentiert. Wir zeichnen die Einkommensverteilung über den gesamten Datensatz unten dar. Wir können sehen, dass der Datensatz mit einer weitaus größeren Anzahl von Personen, die weniger als 50.000 US -Greenback verdienen, stark unausgewogen ist.

Bild des Autors. Authentic -Datensatz: Anzahl der Dateninstanzen mit der Etikett ≤ 50k und> 50k. Es gibt eine unverhältnismäßig größere Darstellung von Personen, die weniger als 50.000 im Datensatz verdienen.

Trotz dieses Ungleichgewichts können wir immer noch einen Klassifizierer für maschinelles Lernen für den Datensatz für Erwachsene schulen, mit dem wir feststellen können, ob unsichtbare oder Assessments Einzelpersonen wie oben oder unter 50 km klassifiziert werden sollten.

# Preprocessing: One-hot encode categorical options, scale numerical options
numerical_features = ("age", "fnlwgt", "education-num", "capital-gain", "capital-loss", "hours-per-week")
categorical_features = (
   "workclass", "schooling", "marital-status", "occupation", "relationship",
   "race", "intercourse", "native-country"
)

preprocessor = ColumnTransformer(
   transformers=(
       ("num", StandardScaler(), numerical_features),
       ("cat", OneHotEncoder(), categorical_features)
   )
)

X_processed = preprocessor.fit_transform(X)

# Convert to numpy array for PyTorch compatibility
X_processed = X_processed.toarray().astype(np.float32)
y_processed = y.astype(np.float32)
# Break up dataset in practice and check units
X_model_train, X_model_test, y_model_train, y_model_test = train_test_split(X_processed, y_processed, test_size=0.2, random_state=42)


rf_classifier = RandomForestClassifier(n_estimators=100, random_state=42)
rf_classifier.match(X_model_train, y_model_train)

# Make predictions
y_pred = rf_classifier.predict(X_model_test)

# Show confusion matrix
plt.determine(figsize=(6, 4))
sns.heatmap(cm, annot=True, fmt="d", cmap="YlGnBu", xticklabels=("Destructive", "Constructive"), yticklabels=("Destructive", "Constructive"))
plt.xlabel("Predicted")
plt.ylabel("Precise")
plt.title("Confusion Matrix")
plt.present()

Das Ausdrucken der Verwirrungsmatrix unseres Klassifikators zeigt, dass unser Modell trotz des Ungleichgewichts ziemlich intestine funktioniert. Unser Modell hat eine Gesamtfehlerrate von 16%, aber die Fehlerrate für die optimistic Klasse (Einkommen> 50.000) beträgt 36%, wobei die Fehlerrate für die destructive Klasse (Einkommen <50K) 8% beträgt.

Diese Diskrepanz zeigt, dass das Modell tatsächlich in der negativen Klasse voreingenommen ist. Das Modell klassifiziert häufig Personen, die mehr als 50.000 als weniger als 50.000 verdienen.

Im Folgenden zeigen wir, wie wir a verwenden können Variations -Autocoder So generieren synthetische Daten der positiven Klasse, um diesen Datensatz auszugleichen. Anschließend trainieren wir das gleiche Modell mit dem synthetisch ausgeglichenen Datensatz und reduzieren Modellfehler im Testsatz.

Bild des Autors. Verwirrungsmatrix für Vorhersagemodell auf dem ursprünglichen Datensatz.

Wie können wir synthetische Daten generieren?

Es gibt viele verschiedene Methoden zum Generieren von synthetischen Daten. Diese können traditionellere Methoden wie Smote und Gaußsche Rauschen umfassen, die neue Daten erzeugen, indem vorhandene Daten geändert werden. Alternativ generative Modelle wie variationsübergreifende Autoencoder oder allgemeine kontroverse Netzwerke sind prädisponiert, um neue Daten zu generieren, wenn ihre Architekturen die Verteilung realer Daten lernen und diese verwenden, um synthetische Proben zu generieren.

In diesem Tutorial verwenden wir einen variativen AutoCodierer, um synthetische Daten zu generieren.

Variations Autoencoder

Variational Autocoders (VAEs) eignen sich hervorragend für die Erzeugung der synthetischen Daten, da sie reale Daten verwenden, um einen kontinuierlichen latenten Raum zu erlernen. Wir können diesen latenten Raum als einen magischen Eimer betrachten, aus dem wir synthetische Daten probieren können, die den vorhandenen Daten stark ähneln. Die Kontinuität dieses Raums ist eines ihrer großen Verkaufsargumente, da das Modell das Modell intestine verallgemeinert und sich nicht nur den latenten Raum spezifischer Eingaben auswendig merkt.

Ein VAE besteht aus einer Encoder die Eingabedaten in eine Wahrscheinlichkeitsverteilung (Mittelwert und Varianz) und a abbilden Decoder die die Daten aus dem latenten Raum rekonstruiert.

Für diesen kontinuierlichen latenten Raum verwenden Vaes einen Reparameterizing -TrickAnwesend wobei ein zufälliger Rauschvektor unter Verwendung des gelernten Mittelwerts und der Varianz skaliert und verschoben wird, um reibungslose und kontinuierliche Darstellungen im latenten Raum zu gewährleisten.

Unten konstruieren wir a Basicvae Klasse, der diesen Prozess mit einer einfachen Architektur implementiert.

  • Der EncoderKomprimiert die Eingabe in eine kleinere, verborgene Darstellung und erzeugt sowohl eine Mittelwert- als auch eine logarithmische Varianz, die eine Gaußsche Verteilung definiert, auch wenn wir unseren magischen Stichproben -Eimer erstellen. Anstelle einer direkten Abtastung wendet das Modell den Reparameterisierungstrick an, um latente Variablen zu erzeugen, die dann an den Decoder übergeben werden.
  • Der DecoderRekonstruiert die ursprünglichen Daten aus diesen latenten Variablen und stellt sicher, dass die generierten Daten die Eigenschaften des ursprünglichen Datensatzes beibehalten.
class BasicVAE(nn.Module):
   def __init__(self, input_dim, latent_dim):
       tremendous(BasicVAE, self).__init__()
       # Encoder: Single small layer
       self.encoder = nn.Sequential(
           nn.Linear(input_dim, 8),
           nn.ReLU()
       )
       self.fc_mu = nn.Linear(8, latent_dim)
       self.fc_logvar = nn.Linear(8, latent_dim)
      
       # Decoder: Single small layer
       self.decoder = nn.Sequential(
           nn.Linear(latent_dim, 8),
           nn.ReLU(),
           nn.Linear(8, input_dim),
           nn.Sigmoid()  # Outputs values in vary (0, 1)
       )

   def encode(self, x):
       h = self.encoder(x)
       mu = self.fc_mu(h)
       logvar = self.fc_logvar(h)
       return mu, logvar

   def reparameterize(self, mu, logvar):
       std = torch.exp(0.5 * logvar)
       eps = torch.randn_like(std)
       return mu + eps * std

   def decode(self, z):
       return self.decoder(z)

   def ahead(self, x):
       mu, logvar = self.encode(x)
       z = self.reparameterize(mu, logvar)
       return self.decode(z), mu, logvar

Angesichts unserer BasicVae -Architektur konstruieren wir unsere Verlustfunktionen und unsere Modelltraining unten.

def vae_loss(recon_x, x, mu, logvar, tau=0.5, c=1.0):
   recon_loss = nn.MSELoss()(recon_x, x)
 
   # KL Divergence Loss
   kld_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
   return recon_loss + kld_loss / x.measurement(0)

def train_vae(mannequin, data_loader, epochs, learning_rate):
   optimizer = optim.Adam(mannequin.parameters(), lr=learning_rate)
   mannequin.practice()
   losses = ()
   reconstruction_mse = ()

   for epoch in vary(epochs):
       total_loss = 0
       total_mse = 0
       for batch in data_loader:
           batch_data = batch(0)
           optimizer.zero_grad()
           reconstructed, mu, logvar = mannequin(batch_data)
           loss = vae_loss(reconstructed, batch_data, mu, logvar)
           loss.backward()
           optimizer.step()
           total_loss += loss.merchandise()

           # Compute batch-wise MSE for comparability
           mse = nn.MSELoss()(reconstructed, batch_data).merchandise()
           total_mse += mse

       losses.append(total_loss / len(data_loader))
       reconstruction_mse.append(total_mse / len(data_loader))
       print(f"Epoch {epoch+1}/{epochs}, Loss: {total_loss:.4f}, MSE: {total_mse:.4f}")
   return losses, reconstruction_mse

combined_data = np.concatenate((X_model_train.copy(), y_model_train.cop
y().reshape(26048,1)), axis=1)

# Prepare-test break up
X_train, X_test = train_test_split(combined_data, test_size=0.2, random_state=42)

batch_size = 128

# Create DataLoaders
train_loader = DataLoader(TensorDataset(torch.tensor(X_train)), batch_size=batch_size, shuffle=True)
test_loader = DataLoader(TensorDataset(torch.tensor(X_test)), batch_size=batch_size, shuffle=False)

basic_vae = BasicVAE(input_dim=X_train.form(1), latent_dim=8)

basic_losses, basic_mse = train_vae(
   basic_vae, train_loader, epochs=50, learning_rate=0.001,
)

# Visualize outcomes
plt.determine(figsize=(12, 6))
plt.plot(basic_mse, label="Fundamental VAE")
plt.ylabel("Reconstruction MSE")
plt.title("Coaching Reconstruction MSE")
plt.legend()
plt.present()

VAE_LOSS besteht aus zwei Komponenten: Wiederaufbauverlustwas misst, wie intestine die generierten Daten mit dem ursprünglichen Eingang mit dem mittleren Quadratfehler (MSE) übereinstimmen, und KL -Divergenzverlustwas sicherstellt, dass der gelehrte latente Raum einer Normalverteilung folgt.

Train_vaeOptimiert die VAE mit dem Adam -Optimierer über mehrere Epochen. Während des Trainings nimmt das Modell Minibatches von Daten, rekonstruiert sie und berechnet den Verlust mithilfe VAE_LOSS. Diese Fehler werden dann über die Backpropagation korrigiert, bei der die Modellgewichte aktualisiert werden. Wir trainieren das Modell für 50 Epochen und zeichnen, wie der Rekonstruktionsmittel -quadratische Fehler beim Coaching abnimmt.

Wir können sehen, dass unser Modell schnell lernt, wie wir unsere Daten rekonstruieren und ein effizientes Lernen belegen.

Bild des Autors. Rekonstruktion MSE von BasicVae im Erwachsenendatensatz.

Jetzt haben wir unsere Basicvae geschult, um den Datensatz für Erwachsene genau zu rekonstruieren, den wir jetzt verwenden können, um synthetische Daten zu generieren. Wir möchten mehr Proben der positiven Klasse (Personen, die über 50.000 verdienen) generieren, um die Klassen auszugleichen und die Verzerrung aus unserem Modell zu entfernen.

Dazu wählen wir alle Stichproben aus unserem VAE -Datensatz aus, in dem das Einkommen die optimistic Klasse ist (verdienen mehr als 50.000). Anschließend codieren wir diese Proben in den latenten Raum. Da wir nur Proben der positiven Klasse ausgewählt haben, um zu codieren, spiegelt dieser latente Raum die Eigenschaften der positiven Klasse wider, aus der wir synthetische Daten erstellen können.

Wir probieren 15000 neue Proben aus diesem latenten Raum und dekodieren diese latenten Vektoren als unsere synthetischen Datenpunkte wieder in den Eingangsdatenraum.

# Create column names
col_number = sample_df.form(1)
col_names = (str(i) for i in vary(col_number))
sample_df.columns = col_names

# Outline the function worth to filter
feature_value = 1.0  # Specify the function worth - right here we set the earnings to 1

# Set all earnings values to 1 : Over 50k
selected_samples = sample_df(sample_df(col_names(-1)) == feature_value)
selected_samples = selected_samples.values
selected_samples_tensor = torch.tensor(selected_samples, dtype=torch.float32)

basic_vae.eval()  # Set mannequin to analysis mode
with torch.no_grad():
   mu, logvar = basic_vae.encode(selected_samples_tensor)
   latent_vectors = basic_vae.reparameterize(mu, logvar)

# Compute the imply latent vector for this function
mean_latent_vector = latent_vectors.imply(dim=0)


num_samples = 15000  # Variety of new samples
latent_dim = 8
latent_samples = mean_latent_vector + 0.1 * torch.randn(num_samples, latent_dim)

with torch.no_grad():
   generated_samples = basic_vae.decode(latent_samples)

Jetzt haben wir synthetische Daten der positiven Klasse generiert. Wir können diese mit den ursprünglichen Trainingsdaten kombinieren, um einen ausgewogenen synthetischen Datensatz zu generieren.

new_data = pd.DataFrame(generated_samples)

# Create column names
col_number = new_data.form(1)
col_names = (str(i) for i in vary(col_number))
new_data.columns = col_names

X_synthetic = new_data.drop(col_names(-1),axis=1)
y_synthetic = np.asarray((1 for _ in vary(0,X_synthetic.form(0))))

X_synthetic_train = np.concatenate((X_model_train, X_synthetic.values), axis=0)
y_synthetic_train = np.concatenate((y_model_train, y_synthetic), axis=0)

mapping = {1: '>50K', 0: '<=50K'}
map_function = np.vectorize(lambda x: mapping(x))
# Apply mapping
y_mapped = map_function(y_synthetic_train)

plt.determine(figsize=(8, 6))
plt.hist(y_mapped, bins=2, edgecolor="black")
plt.title('Distribution of Revenue')
plt.xlabel('Revenue')
plt.ylabel('Frequency')
plt.present()
Bild des Autors. Synthetischer Datensatz: Anzahl der Dateninstanzen mit der Etikett ≤ 50 Okay und> 50k. Es gibt jetzt eine ausgewogene Anzahl von Personen, die mehr und weniger als 50.000 verdienen.

Wir können jetzt unseren ausgewogenen Trainings -synthetischen Datensatz verwenden, um unseren zufälligen Waldklassifizierer zu übertreffen. Anschließend können wir dieses neue Modell für die ursprünglichen Testdaten bewerten, um zu sehen, wie effektiv unsere synthetischen Daten bei der Reduzierung der Modellverzerrung sind.

rf_classifier = RandomForestClassifier(n_estimators=100, random_state=42)
rf_classifier.match(X_synthetic_train, y_synthetic_train)

# Step 5: Make predictions
y_pred = rf_classifier.predict(X_model_test)

cm = confusion_matrix(y_model_test, y_pred)

# Create heatmap
plt.determine(figsize=(6, 4))
sns.heatmap(cm, annot=True, fmt="d", cmap="YlGnBu", xticklabels=("Destructive", "Constructive"), yticklabels=("Destructive", "Constructive"))
plt.xlabel("Predicted")
plt.ylabel("Precise")
plt.title("Confusion Matrix")
plt.present()

Unser neuer Klassifizierer, der auf dem ausgewogenen synthetischen Datensatz trainiert wurde, macht weniger Fehler im Authentic -Testsatz als unser ursprünglicher Klassifikator, der auf dem unausgeglichenen Datensatz trainiert wurde, und unsere Fehlerrate wird nun auf 14percentreduziert.

Bild des Autors. Verwirrungsmatrix für das Vorhersagemodell auf dem synthetischen Datensatz.

Wir konnten jedoch nicht die Diskrepanz der Fehler um einen signifikanten Betrag reduzieren. Unsere Fehlerrate für die optimistic Klasse beträgt immer noch 36%. Dies könnte an die folgenden Gründe zurückzuführen sein:

  • Wir haben diskutiert, wie einer der Vorteile von Vaes das Erlernen eines kontinuierlichen latenten Raums ist. Wenn die Mehrheitsklasse jedoch dominiert, kann der latente Raum der Mehrheitsklasse zugute kommen.
  • Das Modell hat aufgrund des Mangels an Daten möglicherweise keine eindeutige Darstellung für die Minderheitenklasse richtig gelernt, wodurch es schwierig ist, aus diesem Bereich genau zu probieren.

In diesem Tutorial haben wir eine BasicVae -Architektur eingeführt und erstellt, mit der synthetische Daten generiert werden können, die die Klassifizierungsgenauigkeit auf einem unausgeglichenen Datensatz verbessert.

Folgen Sie zukünftigen Artikeln, in denen ich zeigen werde, wie wir anspruchsvollere VAE -Architekturen aufbauen können, die die oben genannten Probleme mit unausgeglichener Stichproben und vielem mehr angehen.

(1) Villalobos, P., Ho, A., Sevilla, J., Besiroglu, T., Heim, L. & Hobbhahn, M. (2024). Werden uns die Daten ausgehen? Grenzen der LLM-Skalierung basierend auf Daten von Menschen erzeugten Daten. Arxiv Preprint Arxiv: 2211.04325Anwesend 3.

(2) Becker, B. & Kohavi, R. (1996). Erwachsener (Datensatz). UCI maschinelles Lernen Repository. https://doi.org/10.24432/c5xw20.


Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert