PyTorch-Autoencoder
Ein Autoencoder (Autoencoder, AE)ist ein neuronales Netz für unüberwachtes Lernen, das Eingabedaten durch Lernen in einen niedrigdimensionalen latenten Raum komprimiert und anschließend die Originaldaten aus der komprimierten Repräsentation rekonstruiert.
Autoencoder werden häufig in Szenarien wie Dimensionsreduktion von Daten, Merkmalsextraktion, Anomalieerkennung, Bildentrauschung und generativen Modellen eingesetzt.
1. Grundprinzipien des Autoencoders
Die Grundstruktur eines Autoencoders besteht aus drei Teilen:
- Encoder: bildet Eingabedaten \(x\) auf eine niedrigdimensionale latente Repräsentation \(z\) ab
- Latenter Raum: der niedrigdimensionale Vektor, der vom Encoder ausgegeben wird, auch Bottleneck-Schicht genannt
- Decoder: rekonstruiert die latente Repräsentation \(z\) zur Ausgabe \(\hat{x}\)
1.1 Netzwerkstruktur
Das Ziel eines Autoencoders ist es, die Ausgabe \(\hat{x}\) so nah wie möglich an die Eingabe \(x\) zu bringen:
\[ \min_{\theta, \phi} \frac{1}{n} \sum_{i=1}^{n} \| x_i - D_\phi(E_\theta(x_i)) \|^2 \]
wobei \(\theta\) die Encoder-Parameter und \(\phi\) die Decoder-Parameter sind.
1.2 Effekt der Dimensionsreduktion
Autoencoder lernen eine komprimierte Repräsentation der Daten, indem sie die Daten durch eine Bottleneck-Schicht leiten, die kleiner als die Eingabedimension ist. Diese Kompression bewahrt die wesentlichen Informationen der Daten.
Im Vergleich zur Hauptkomponentenanalyse (PCA) können Autoencoder nichtlineare Dimensionsreduktion lernen und komplexere Datenstrukturen erfassen.
2. Grundlegende Autoencoder-Implementierung
2.1 Einfacher Autoencoder
Beispiel
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# ── Autoencoder-Modell ─────────────────────────────────
class Autoencoder(nn.Module):
"""
Einfacher Autoencoder: symmetrische Struktur
"""
def __init__(self, input_dim, hidden_dim, latent_dim):
super().__init__()
# Encoder
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, latent_dim), # Bottleneck-Schicht
)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
)
def forward(self, x):
z = self.encoder(x)
x_recon = self.decoder(z)
return x_recon
def encode(self, x):
"""Kodierung: latente Repräsentation erhalten"""
return self.encoder(x)
def decode(self, z):
"""Dekodierung: aus latenter Repräsentation rekonstruieren"""
return self.decoder(z)
# ── Anwendungsbeispiel ──────────────────────────────────────
INPUT_DIM = 784 # Zum Beispiel nach dem Abflachen eines MNIST-Bildes
HIDDEN_DIM = 256
LATENT_DIM = 32 # Dimension des latenten Raums, viel kleiner als die Eingabedimension
model = Autoencoder(INPUT_DIM, HIDDEN_DIM, LATENT_DIM)
print(f"Eingabedimension: {INPUT_DIM}")
print(f"Latente Dimension: {LATENT_DIM}")
print(f"Kompressionsrate: {INPUT_DIM / LATENT_DIM:.1f}x")
# Parameteranzahl anzeigen
total_params = sum(p.numel() for p in model.parameters())
print(f"Gesamtparameter: {total_params:,}")
2.2 Faltungs-Autoencoder
Für Bilddaten sind Autoencoder mit Faltungsschichten besser geeignet:
Beispiel
import torch.nn as nn
class ConvAutoencoder(nn.Module):
"""
Faltungs-Autoencoder: für Bilder geeignet
"""
def __init__(self, channels=3, latent_dim=128):
super().__init__()
# Encoder: Größe schrittweise verringern, Anzahl der Kanäle erhöhen
# Eingabe: (batch, channels, 64, 64)
self.encoder = nn.Sequential(
# 32 -> 16
nn.Conv2d(channels, 32, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
# 16 -> 8
nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
# 8 -> 4
nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
# 4 -> 2
nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
)
# Abbildung in den latenten Raum
self.to_latent = nn.AdaptiveAvgPool2d((1, 1))
# Decoder: Größe schrittweise erhöhen
# Eingabe: (batch, 256, 2, 2)
self.from_latent = nn.Sequential(
nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
nn.Conv2d(256, 128, kernel_size=3, padding=1),
nn.ReLU(),
nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
nn.Conv2d(128, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
nn.Conv2d(64, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
nn.Conv2d(32, channels, kernel_size=3, padding=1),
nn.Sigmoid() # Ausgabe [0, 1]
)
def forward(self, x):
z = self.encode(x)
x_recon = self.decode(z)
return x_recon
def encode(self, x):
"""Enkodieren"""
features = self.encoder(x)
z = self.to_latent(features)
z = z.view(z.size(0), -1) # (batch, 256)
return z
def decode(self, z):
"""Dekodieren"""
# Vektor zu Feature Map umformen
batch_size = z.size(0)
z = z.view(batch_size, 256, 1, 1)
z = z.expand(-1, -1, 2, 2) # Auf 2x2 hochskalieren
x_recon = self.from_latent(z)
return x_recon
# Test
model = ConvAutoencoder(channels=3, latent_dim=128)
x = torch.randn(4, 3, 64, 64)
x_recon = model(x)
print(f"Form der Eingabe: {x.shape}")
print(f"Ausgabeform: {x_recon.shape}")
print(f"Form des latenten Vektors: {model.encode(x).shape}")
2.3 Training und Rekonstruktion
Beispiel
import torch.nn as nn
import torch.optim as optim
# ── Trainingskonfiguration ─────────────────────────────────────
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = ConvAutoencoder(channels=3, latent_dim=128).to(device)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
# ── Trainingsschleife ─────────────────────────────────────
def train_autoencoder(model, dataloader, criterion, optimizer, num_epochs=10):
model.train()
for epoch in range(num_epochs):
total_loss = 0
for batch in dataloader:
images = batch[0].to(device)
# Vorwärtspropagierung
outputs = model(images)
loss = criterion(outputs, images)
# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
avg_loss = total_loss / len(dataloader)
print(f"Epoche [{epoch+1}/{num_epochs}], Verlust: {avg_loss:.6f}")
return model
# Angenommen, ein Datenlader existiert bereits
# train_autoencoder(model, train_loader, criterion, optimizer, num_epochs=10)
print("Autoencoder-Training abgeschlossen!")
3. Denoising-Autoencoder (DAE)
Denoising-Autoencoder (DAE)fügt während des Trainings dem Eingang Rauschen hinzu, lernt dann, das Rauschen zu entfernen und die ursprüngliche Eingabe wiederherzustellen. Dadurch kann das Modell robustere Merkmalsrepräsentationen erlernen.
3.1 Implementierung des Denoising-Autoencoders
Beispiel
import torch.nn as nn
class DenoisingAutoencoder(nn.Module):
"""
Denoising-Autoencoder
"""
def __init__(self, input_dim, hidden_dim, latent_dim):
super().__init__()
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, latent_dim),
)
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
nn.Sigmoid() # Ausgabe [0, 1]
)
def forward(self, x):
z = self.encode(x)
return self.decode(z)
def encode(self, x):
return self.encoder(x)
def decode(self, z):
return self.decoder(z)
def add_noise(x, noise_factor=0.3):
"""
Gaußsches Rauschen hinzufügen
"""
noise = torch.randn_like(x) * noise_factor
noisy_x = x + noise
return torch.clamp(noisy_x, 0.0, 1.0)
# Denoising-Autoencoder trainieren
def train_dae(model, dataloader, noise_factor=0.3, lr=1e-3):
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=lr)
model.train()
for epoch in range(10):
for batch in dataloader:
images = batch[0]
# Rauschen hinzufügen
noisy_images = add_noise(images, noise_factor)
noisy_images = noisy_images.to(next(model.parameters()).device)
images = images.to(next(model.parameters()).device)
# Vorwärtspropagierung
outputs = model(noisy_images)
loss = criterion(outputs, images) # Mit dem Originalbild vergleichen, nicht mit dem verrauschten Bild
# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()
return model
3.2 Andere Rauscharten
Beispiel
"""Salz-und-Pfeffer-Rauschen"""
random_mask = torch.rand_like(x)
noisy = x.clone()
noisy[random_mask < prob / 2] = 0.0
noisy[random_mask > 1 - prob / 2] = 1.0
return noisy
def mask_noise(x, prob=0.1):
"""Maskierungsrauschen (zufällig auf null gesetzt)"""
mask = torch.rand_like(x) > prob
return x * mask.float()
def dropout_noise(x, rate=0.2):
"""Dropout-Rauschen"""
mask = torch.rand_like(x) > rate
return x * mask.float() / (1 - rate)
4. Variational Autoencoder (VAE)
Variational Autoencoder (VAE)ist ein generatives Modell, das Daten in eine Wahrscheinlichkeitsverteilung im latenten Raum statt in einen festen Vektor kodiert. Dadurch können wir Stichproben aus dem latenten Raum ziehen, um neue Daten zu erzeugen.
4.1 Kernprinzipien von VAE
Die zentrale Innovation von VAE ist das Erlernen der Wahrscheinlichkeitsverteilung latenter Variablen:
- Der Encoder gibt den Mittelwert \(\mu\) und die Standardabweichung \(\sigma\) aus
- Ziehe den latenten Vektor \(z\) als Stichprobe aus der Normalverteilung \(\mathcal{N}(\mu, \sigma)\)
- Der Decoder rekonstruiert Daten aus \(z\)
Um einen differenzierbaren Sampling-Prozess zu erreichen, wird derReparametrisierungstrick verwendet.:
\[ z = \mu + \sigma \cdot \epsilon, \quad \epsilon \sim \mathcal{N}(0, 1) \]
4.2 VAE-Implementierung
Beispiel
import torch.nn as nn
import torch.optim as optim
class VAE(nn.Module):
"""
Variational Autoencoder
"""
def __init__(self, input_dim, hidden_dim, latent_dim):
super().__init__()
# Encoder: Mittelwert und Varianz ausgeben
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
)
self.fc_mu = nn.Linear(hidden_dim, latent_dim)
self.fc_logvar = nn.Linear(hidden_dim, latent_dim)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
nn.Sigmoid()
)
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):
"""Reparametrisierungstrick"""
std = torch.exp(0.5 * logvar)
eps = torch.randn_like(std)
return mu + eps * std
def decode(self, z):
return self.decoder(z)
def forward(self, x):
mu, logvar = self.encode(x)
z = self.reparameterize(mu, logvar)
x_recon = self.decode(z)
return x_recon, mu, logvar
def vae_loss(x_recon, x, mu, logvar, beta=1.0):
"""
VAE-Verlustfunktion
Rekonstruktionsverlust + KL-Divergenz
"""
# Rekonstruktionsverlust
recon_loss = nn.functional.mse_loss(x_recon, x, reduction='sum')
# KL-Divergenz: -0.5 * sum(1 + log(sigma^2) - mu^2 - sigma^2)
kl_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
return recon_loss + beta * kl_loss, recon_loss, kl_loss
# Verwendungsbeispiel
INPUT_DIM = 784
HIDDEN_DIM = 256
LATENT_DIM = 2 # Zweidimensionaler latenter Raum zur einfachen Visualisierung
model = VAE(INPUT_DIM, HIDDEN_DIM, LATENT_DIM)
# Test
x = torch.randn(32, 784)
x_recon, mu, logvar = model(x)
print(f"Form der Eingabe: {x.shape}")
print(f"Form der Rekonstruktion: {x_recon.shape}")
print(f"Form des Mittelwerts: {mu.shape}") # (32, 2)
print(f"Form der Varianz: {logvar.shape}") # (32, 2)
4.3 VAE-Generierung und Visualisierung
Beispiel
def visualize_latent_space(model, dataloader, device):
"""Visualisierung des latenten Raums"""
model.eval()
all_mu = []
all_labels = []
with torch.no_grad():
for batch in dataloader:
images, labels = batch[0].to(device), batch[1]
mu, _ = model.encode(images)
all_mu.append(mu.cpu())
all_labels.append(labels)
all_mu = torch.cat(all_mu, dim=0).numpy()
all_labels = torch.cat(all_labels, dim=0).numpy()
plt.figure(figsize=(10, 8))
scatter = plt.scatter(all_mu[:, 0], all_mu[:, 1], c=all_labels,
cmap='tab10', alpha=0.5, s=10)
plt.colorbar(scatter)
plt.xlabel('Latente Dimension 1')
plt.ylabel('Latente Dimension 2')
plt.title('VAE Latentraum')
plt.show()
def generate_from_latent(model, z, device):
"""Bilder aus latenten Vektoren generieren"""
model.eval()
with torch.no_grad():
z = z.to(device)
generated = model.decode(z)
return generated
def interpolate_latent(model, z1, z2, steps=10, device):
"""Generierung durch Interpolation im latenten Raum"""
model.eval()
# Lineare Interpolation
alphas = torch.linspace(0, 1, steps)
interpolated = []
with torch.no_grad():
for alpha in alphas:
z = z1 * (1 - alpha) + z2 * alpha
generated = model.decode(z)
interpolated.append(generated)
return torch.cat(interpolated, dim=0)
# Neue Bilder generieren
def generate_new_images(model, num_images, latent_dim, device):
"""Neue Bilder aus zufälligen latenten Vektoren generieren"""
model.eval()
with torch.no_grad():
# Stichprobe aus der Standardnormalverteilung ziehen
z = torch.randn(num_images, latent_dim).to(device)
generated = model.decode(z)
return generated
Der latente Raum von VAE ist kontinuierlich, was Interpolation im latenten Raum ermöglicht, um sanft übergehende Bilder zu erzeugen. Allerdings sind von VAE erzeugte Bilder oft unscharf, weil es eine untere Schranke statt der exakten Log-Likelihood optimiert.
5. Sparse Autoencoder
Sparse AutoencoderFüge der Verlustfunktion eine Sparsamkeitsbeschränkung hinzu, die die Anzahl der Aktivierungen im latenten Vektor begrenzt. Dadurch kann das Modell aussagekräftigere Merkmale lernen.
5.1 Implementierung des Sparse Autoencoders
import torch.nn as nn
import torch.nn.functional as F
class SparseAutoencoder(nn.Module):
"""
Sparse-Autoencoder
"""
def __init__(self, input_dim, hidden_dim, latent_dim):
super().__init__()
# Encoder
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
)
# Latente Schicht
self.bottleneck = nn.Linear(hidden_dim, latent_dim)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
nn.Sigmoid()
)
def forward(self, x):
h = self.encoder(x)
z = self.bottleneck(h)
z_activated = F.relu(z) # Sparse-Aktivierung
x_recon = self.decoder(z_activated)
return x_recon, z_activated
def sparse_loss(z, rho=0.05, beta=1.0):
"""
Sparse-Verlust: KL-Divergenz
rho: Ziel-Sparsamkeit (z. B. 0.05 bedeutet, dass nur 5% der Neuronen aktiv sein sollten)
beta: Gewicht des Sparsamkeitsterms
"""
# Durchschnittliche Aktivierung berechnen
rho_hat = torch.mean(z, dim=0)
# KL-Divergenz
kl = rho * torch.log(rho / (rho_hat + 1e-8)) + \
(1 - rho) * torch.log((1 - rho) / (1 - rho_hat + 1e-8))
return beta * torch.sum(kl)
def total_sparse_loss(x_recon, x, z, rho=0.05, beta=1.0):
"""Gesamtverlust = Rekonstruktionsverlust + Sparsitätsverlust"""
recon_loss = F.mse_loss(x_recon, x)
sparsity = sparse_loss(z, rho, beta)
return recon_loss + sparsity
6. Sequenz-zu-Sequenz-Autoencoder
Verwenden Sie für Sequenzdaten (wie Text, Zeitreihen) RNN/LSTM als Encoder und Decoder.
6.1 Implementierung eines Sequenz-Autoencoders
Beispiel
import torch.nn as nn
class Seq2SeqAutoencoder(nn.Module):
"""
Sequenz-zu-Sequenz-Autoencoder: wird für Sequenzdaten verwendet
"""
def __init__(self, input_size, hidden_size, latent_size, num_layers=2):
super().__init__()
# LSTM-Encoder
self.encoder = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
bidirectional=True
)
# Abbildung in den latenten Raum
# Die Ausgabe des bidirektionalen LSTM ist hidden_size * 2
self.to_latent = nn.Linear(hidden_size * 2, latent_size)
self.from_latent = nn.Linear(latent_size, hidden_size * 2)
# Decoder-LSTM
self.decoder = nn.LSTM(
input_size=hidden_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
bidirectional=True
)
# Ausgabezuordnung
self.output_proj = nn.Linear(hidden_size * 2, input_size)
def forward(self, x):
# Kodieren
_, (h_n, _) = self.encoder(x)
# Bidirektionale finale verborgene Zustände verketten
# h_n: (num_layers * 2, batch, hidden_size)
h_forward = h_n[-2]
h_backward = h_n[-1]
h_combined = torch.cat([h_forward, h_backward], dim=-1)
# In den latenten Raum abbilden
z = self.to_latent(h_combined)
# Vom latenten Raum zurück abbilden
decoder_init = self.from_latent(z)
decoder_init = decoder_init.view(2, decoder_init.size(0), -1) # (2, batch, hidden_size*2)
# Dekodieren (unter Verwendung der ursprünglichen Eingabelänge)
decoder_output, _ = self.decoder(
x,
(decoder_init, torch.zeros_like(decoder_init))
)
# Ausgabezuordnung
output = self.output_proj(decoder_output)
return output, z
# Verwendungsbeispiel
model = Seq2SeqAutoencoder(
input_size=128, # Dimension der Eingabemerkmale
hidden_size=256, # Verborgene Dimension des LSTM
latent_size=64, # Dimension des latenten Raums
num_layers=2
)
# Test
x = torch.randn(8, 20, 128) # (batch, seq_len, input_size)
output, z = model(x)
print(f"Form der Eingabe: {x.shape}") # (8, 20, 128)
print(f"Ausgabeform: {output.shape}") # (8, 20, 128)
print(f"Form des latenten Vektors: {z.shape}") # (8, 64)
7. Anwendungsszenarien von Autoencodern
7.1 Anomalieerkennung
Autoencoder können verwendet werden, um anomale Daten zu erkennen. Normale Daten haben einen kleinen Rekonstruktionsfehler, während anomale Daten einen großen Rekonstruktionsfehler haben:
Beispiel
import torch.nn as nn
def detect_anomalies(model, data_loader, threshold=None, device='cpu'):
"""
Erkennung von Anomalien mit Autoencodern
"""
model.eval()
reconstruction_errors = []
with torch.no_grad():
for batch in data_loader:
images = batch[0].to(device)
outputs = model(images)
# Rekonstruktionsfehler berechnen (mittlerer quadratischer Fehler)
errors = torch.mean((outputs - images) ** 2, dim=(1, 2, 3))
reconstruction_errors.extend(errors.cpu().numpy())
reconstruction_errors = torch.tensor(reconstruction_errors)
# Wenn kein Schwellenwert angegeben ist, statistische Methode verwenden
if threshold is None:
# 95%-Perzentil verwenden
threshold = torch.quantile(reconstruction_errors, 0.95).item()
# Anomalien markieren
anomalies = reconstruction_errors > threshold
return anomalies, reconstruction_errors, threshold
# Anomalieerkennungsmodell trainieren
def train_anomaly_detector(normal_data_loader):
"""Trainiere den Autoencoder nur mit normalen Daten"""
model = ConvAutoencoder(channels=1, latent_dim=32)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
model.train()
for epoch in range(10):
for batch in normal_data_loader:
images = batch[0]
outputs = model(images)
loss = criterion(outputs, images)
optimizer.zero_grad()
loss.backward()
optimizer.step()
return model
7.2 Bildkolorierung und Stilübertragung
Beispiel
"""
Bildkolorierungs-Autoencoder
Eingabe: Graustufenbild (batch, 1, H, W)
Ausgabe: Farbbild (batch, 2, H, W) (ab-Farbraum)
"""
def __init__(self):
super().__init__()
# Encoder: schrittweise Merkmale extrahieren
self.encoder = nn.Sequential(
nn.Conv2d(1, 64, kernel_size=4, stride=2, padding=1), # H/2
nn.ReLU(),
nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1), # H/4
nn.BatchNorm2d(128),
nn.ReLU(),
nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1), # H/8
nn.BatchNorm2d(256),
nn.ReLU(),
)
# Decoder: Upsampling zur Erzeugung von Farben
self.decoder = nn.Sequential(
nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(32, 2, kernel_size=3, padding=1), # Ausgabe der ab-Kanäle
nn.Sigmoid() # Wertebereich der ab-Kanäle [0, 1]
)
def forward(self, x):
z = self.encoder(x)
color = self.decoder(z)
return color
7.3 Visualisierung der Dimensionalitätsreduktion von Daten
Beispiel
def visualize_latent_2d(model, dataloader, device, num_samples=1000):
"""
Autoencoder verwenden, um Daten zur Visualisierung auf 2 Dimensionen zu reduzieren
"""
model.eval()
all_latents = []
all_labels = []
with torch.no_grad():
count = 0
for batch in dataloader:
if count >= num_samples:
break
images, labels = batch[0], batch[1]
images = images.to(device)
# Wenn es ein 2D-AE ist, direkt verwenden
# Wenn die Dimensionalität höher ist, zuerst auf 2D projizieren
z = model.encode(images)
all_latents.append(z.cpu())
all_labels.append(labels)
count += images.size(0)
latents = torch.cat(all_latents, dim=0)[:num_samples].numpy()
labels = torch.cat(all_labels, dim=0)[:num_samples].numpy()
plt.figure(figsize=(10, 8))
scatter = plt.scatter(latents[:, 0], latents[:, 1], c=labels,
cmap='tab10', alpha=0.6, s=20)
plt.colorbar(scatter)
plt.xlabel('Latente Dimension 1')
plt.ylabel('Latente Dimension 2')
plt.title('Visualisierung des 2D-Latent-Raums des Autoencoders')
plt.show()
8. API-Kurzreferenz
8.1 Gängige Autoencoder-Typen
| Type | Eigenschaften | Geeignete Szenarien |
|---|---|---|
| Einfacher Autoencoder | Einfache symmetrische Struktur | Dimensionsreduktion, Merkmalsextraktion |
| Faltungs-Autoencoder | Verwendet Faltungsschichten, um die räumliche Struktur zu erhalten | Bildverarbeitung |
| Entrauschungs-Autoencoder | Lernt, Rauschen zu entfernen | Bildentrauschung, robuste Merkmale |
| Variational Autoencoder | Erlernt Wahrscheinlichkeitsverteilungen, kann neue Daten generieren | Generative Modelle, Datengenerierung |
| Sparse-Autoencoder | Sparsamkeitsbedingung, erlernt interpretierbare Merkmale | Merkmalsentflechtung, Interpretierbarkeit |
| Sequenz-Autoencoder | Verwendet RNN/LSTM zur Verarbeitung von Sequenzen | Text, Zeitreihen |
8.2 Auswahl der Verlustfunktion
| Aufgabe | Empfohlene Verlustfunktion |
|---|---|
| Bildrekonstruktion | MSELoss、SSIMLoss |
| Binäre Bilder | BCELoss、BCEWithLogitsLoss |
| Textrekonstruktion | CrossEntropyLoss |
| VAE | MSE + KL-Divergenz |
| Anomalieerkennung | MSE, MAE |
8.3 Auswahl der latenten Dimension
数据维度低(<100维)
-> 潜在维度设为 2~10
数据维度中等(100~1000维)
-> 潜在维度设为 10~50
数据维度高(>1000维)
-> 潜在维度设为 50~200
生成任务(VAE)
-> 潜在维度 2~32(便于采样和可视化)
异常检测
-> 潜在维度 16~64(保留足够信息检测异常)
Weitere Erweiterungen