Hoppa till innehållet
AI-grafen
E· Universitetdeep-learning· ca 60 min· utvecklande· verifierad 2026-09-20

Autoencoders

Kunna träna en autoencoder och tolka det latenta rummet.

Förkunskaper

Intuition

En autoencoder tränas att återskapa sin egen indata — vilket låter meningslöst tills man ser flaskhalsen:

indata (784) → encoder → latent (32) → decoder → utdata (784)
                              ↑
                        flaskhalsen

Eftersom all information måste passera genom 32 tal tvingas nätet att komprimera: behålla det väsentliga, kasta resten. Det som återstår i flaskhalsen är en inlärd representation.

Förlusten är bara avståndet mellan indata och utdata — ingen märkning behövs. Det är självövervakad inlärning i sin enklaste form.

Kopplingen till PCA: en autoencoder med linjära lager och kvadratisk förlust hittar samma underrum som PCA. Det är med olinjäriteterna den blir intressant — då kan den följa krökta grenrör som PCA inte kan.

Formellt

Fyra användningar, i fallande ordning efter hur ofta de faktiskt är rätt val:

AnvändningHurKommentar
Avbrusningträna på (brusig, ren)-parfungerar mycket bra
Anomalidetektionhögt rekonstruktionsfel = avvikarevanligaste produktionsanvändningen
Dimensionsreduktionanvänd flaskhalsen som featuresofta slagen av enklare metoder
Genereringsampla i det latenta rummetkräver VAE — se nedan

Varför en vanlig autoencoder inte kan generera. Det latenta rummet har inga garantier: mellan två tränade punkter kan det finnas hål där decodern producerar nonsens. Samplar du en slumpmässig punkt får du oftast skräp.

En VAE löser det genom att koda varje indata till en fördelning i stället för en punkt, och straffa avvikelsen från en normalfördelning (KL-termen). Det gör rummet sammanhängande och samplingsbart — till priset av suddigare rekonstruktioner.

Varianter:

VariantIdé
Denoisinglägg till brus i indata, kräv ren utdata
Sparsestraffa antalet aktiva latenta enheter
Contractivestraffa känsligheten för små indataändringar
VAEprobabilistisk latent, KL-straff
Masked (MAE)dölj 75 % av bilden, återskapa den

Den sista är den moderna varianten: masked autoencoders är en av de mest framgångsrika förtränings­metoderna för bildmodeller.

Glesa autoencoders i tolkningsforskning är en nutida tillämpning värd att känna till: man tränar en bredare men gles autoencoder på en språkmodells aktiveringar, för att bryta upp polysemantiska neuroner i monosemantiska riktningar. Flaskhalsen är där inte kompression utan gleshet.

Anomalidetektion i praktiken: träna bara på normala exempel, mät rekonstruktionsfelet, sätt tröskeln på till exempel 99:e percentilen av träningsfelet. Avvikare rekonstrueras dåligt eftersom nätet aldrig lärt sig dem. Fallgropen är att en tillräckligt stor autoencoder lär sig rekonstruera allt, inklusive avvikarna — flaskhalsen måste vara verkligt trång.

Kod

import torch, torch.nn as nn

class Autoencoder(nn.Module):
    def __init__(self, in_dim=784, latent=32):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(in_dim, 256), nn.ReLU(),
            nn.Linear(256, 64), nn.ReLU(),
            nn.Linear(64, latent),
        )
        self.decoder = nn.Sequential(
            nn.Linear(latent, 64), nn.ReLU(),
            nn.Linear(64, 256), nn.ReLU(),
            nn.Linear(256, in_dim), nn.Sigmoid(),
        )

    def forward(self, x):
        z = self.encoder(x)
        return self.decoder(z), z

# Denoising: brus in, rent ut
def trana_denoising(modell, dataloader, opt, brus=0.3, epoker=10):
    for _ in range(epoker):
        for x, _ in dataloader:
            x = x.flatten(1)
            xb = (x + brus * torch.randn_like(x)).clamp(0, 1)
            ut, _ = modell(xb)
            loss = nn.functional.mse_loss(ut, x)        # jämför mot den RENA bilden
            opt.zero_grad(); loss.backward(); opt.step()

# Anomalidetektion: träna bara på normala exempel
def anomalitroskel(modell, normal_loader, percentil=99):
    fel = []
    modell.eval()
    with torch.no_grad():
        for x, _ in normal_loader:
            x = x.flatten(1)
            ut, _ = modell(x)
            fel += ((ut - x) ** 2).mean(dim=1).tolist()
    return float(torch.tensor(fel).quantile(percentil / 100))

def ar_anomali(modell, x, troskel):
    with torch.no_grad():
        ut, _ = modell(x.flatten(1))
        return ((ut - x.flatten(1)) ** 2).mean(dim=1) > troskel

# Kontrollera flaskhalsen: för stor latent → nätet lär sig kopiera allt
for latent in (2, 8, 32, 128, 784):
    m = Autoencoder(latent=latent)
    komprimering = latent / 784
    print(f"latent {latent:>3}: {komprimering:.1%} av indata"
          + ("   ← ingen flaskhals alls" if latent >= 784 else ""))

# Linjär autoencoder ≈ PCA — kontrollera själv
import numpy as np
X = np.random.default_rng(0).normal(size=(500, 20)) @ np.random.default_rng(1).normal(size=(20, 20))
Xc = X - X.mean(0)
U, s, Vt = np.linalg.svd(Xc, full_matrices=False)
print("PCA behåller", np.round((s[:5]**2 / (s**2).sum()).sum(), 3), "av variansen med 5 komponenter")

Raden med latent=784 är poängen med flaskhalsen: är den latenta dimensionen lika stor som indata kan nätet lära sig identitetsavbildningen och har inte lärt sig något alls. För anomalidetektion är det särskilt förrädiskt, eftersom en tillräckligt stor autoencoder rekonstruerar även avvikarna perfekt.

Behärskning innebär

  • Tränar en autoencoder
  • Tolkar det latenta rummet
  • Vet när en autoencoder är rätt verktyg

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser