PyTorch オートエンコーダー (Autoencoder)

オートエンコーダー(Autoencoder,AE)は、入力データを低次元の潜在空間に圧縮し、その圧縮表現から元のデータを再構成することを学習する、教師なし学習のニューラルネットワークです。

オートエンコーダーは、データの次元削減、特徴抽出、異常検知、画像ノイズ除去、生成モデルなどのシーンで広く利用されています。


1. オートエンコーダーの基本原理

オートエンコーダーの基本構造は3つの部分で構成されます:

  • エンコーダー(Encoder):入力データ \(x\) を低次元の潜在表現 \(z\) にマッピングします
  • 潜在空間(Latent Space):エンコーダーが出力する低次元ベクトルで、ボトルネック層とも呼ばれます
  • デコーダー(Decoder):潜在表現 \(z\) を出力 \(\hat{x}\) に再構成します

1.1 ネットワーク構造

オートエンコーダーの目標は、出力 \(\hat{x}\) を入力 \(x\) に可能な限り近づけることです:

\[ \min_{\theta, \phi} \frac{1}{n} \sum_{i=1}^{n} \| x_i - D_\phi(E_\theta(x_i)) \|^2 \]

ここで \(\theta\) はエンコーダーのパラメータ、\(\phi\) はデコーダーのパラメータです。

1.2 次元削減の効果

オートエンコーダーは、入力をより小さな次元のボトルネック層に強制的に通すことで、データの圧縮表現を学習します。この圧縮によってデータの主要な情報が保持されます。

主成分分析(PCA)と比較して、オートエンコーダーは非線形の次元削減を学習でき、より複雑なデータ構造を捉えることができます。


2. 基本オートエンコーダーの実装

2.1 シンプルなオートエンコーダー

例

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# ── オートエンコーダーモデル ─────────────────────────────────
class Autoencoder(nn.Module):
    """
基本オートエンコーダー:対称構造
    """

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

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

    def encode(self, x):
        """エンコード:潜在表現を取得"""
        return self.encoder(x)

    def decode(self, z):
        デコード:潜に表現から再構成
        return self.decoder(z)


# ── 使用例 ──────────────────────────────────────
INPUT_DIM = 784   # 例:MNIST画像をフラットにした後
HIDDEN_DIM = 256
LATENT_DIM = 32   # 潜在空間の次元は、入力次元よりもはるかに小さい

model = Autoencoder(INPUT_DIM, HIDDEN_DIM, LATENT_DIM)
print(f"入力次元: {INPUT_DIM}")
print(f潜に次元: {LATENT_DIM})
print(f"圧縮率: {INPUT_DIM / LATENT_DIM:.1f}x")

# パラメータ数を確認
total_params = sum(p.numel() for p in model.parameters())
print(f"総パラメータ数: {total_params:,}")

2.2 畳み込みオートエンコーダー

画像データには、畳み込み層を使用したオートエンコーダーの方が効果的です:

例

import torch
import torch.nn as nn

class ConvAutoencoder(nn.Module):
    """
畳み込みオートエンコーダー:画像に適用
    """

    def __init__(self, channels=3, latent_dim=128):
        super().__init__()

        # エンコーダー:サイズを段階的に縮小し、チャネル数を増加
        # 入力: (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(),
        )

        # 潜在空間へのマッピング
        self.to_latent = nn.AdaptiveAvgPool2d((1, 1))

        # デコーダー:サイズを段階的に拡大
        # 入力: (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()  # 出力 [0, 1]
        )

    def forward(self, x):
        z = self.encode(x)
        x_recon = self.decode(z)
        return x_recon

    def encode(self, x):
        """エンコード"""
        features = self.encoder(x)
        z = self.to_latent(features)
        z = z.view(z.size(0), -1)  # (batch, 256)
        return z

    def decode(self, z):
        """デコード"""
        # ベクトルを特徴マップに reshape
        batch_size = z.size(0)
        z = z.view(batch_size, 256, 1, 1)
        z = z.expand(-1, -1, 2, 2)  # 2x2 にアップサンプリング
        x_recon = self.from_latent(z)
        return x_recon


# テスト
model = ConvAutoencoder(channels=3, latent_dim=128)
x = torch.randn(4, 3, 64, 64)
x_recon = model(x)

print(f"入力形状: {x.shape}")
print(f"出力形状: {x_recon.shape}")
print(f潜にベクトル形状: {model.encode(x).shape})

2.3 トレーニングと再構成

例

import torch
import torch.nn as nn
import torch.optim as optim

# ── トレーニング設定 ─────────────────────────────────────
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)

# ── トレーニングループ ─────────────────────────────────────
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)

            # 順伝播
            outputs = model(images)
            loss = criterion(outputs, images)

            # 逆伝播
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            total_loss += loss.item()

        avg_loss = total_loss / len(dataloader)
        print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.6f}")

    return model


# データローダーが既にあると仮定
# train_autoencoder(model, train_loader, criterion, optimizer, num_epochs=10)
print(オートエンコーダーのトレーニングが完了しました!)

3. デノイジングオートエンコーダー (DAE)

デノイジングオートエンコーダー(Denoising Autoencoder,DAE)トレーニング時に入力にノイズを追加し、ノイズを除去して元の入力を復元することを学習します。これにより、モデルはよりロバストな特徴表現を学習できます。

3.1 デノイジングオートエンコーダーの実装

例

import torch
import torch.nn as nn

class DenoisingAutoencoder(nn.Module):
    """
デノイジングオートエンコーダー
    """

    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()  # 出力 [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):
    """
ガウスノイズを追加
    """

    noise = torch.randn_like(x) * noise_factor
    noisy_x = x + noise
    return torch.clamp(noisy_x, 0.0, 1.0)


# デノイジングオートエンコーダーのトレーニング
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]

            # ノイズを追加
            noisy_images = add_noise(images, noise_factor)
            noisy_images = noisy_images.to(next(model.parameters()).device)
            images = images.to(next(model.parameters()).device)

            # 順伝播
            outputs = model(noisy_images)
            loss = criterion(outputs, images)  # ノイズ画像ではなく、元の画像と比較

            # 逆伝播
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

    return model

3.2 その他のノイズタイプ

例

def salt_pepper_noise(x, prob=0.1):
    """ソルト・アンド・ペッパー・ノイズ"""
    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):
    """遮蔽ノイズ(ランダムにゼロ化)"""
    mask = torch.rand_like(x) > prob
    return x * mask.float()


def dropout_noise(x, rate=0.2):
    """Dropout ノイズ"""
    mask = torch.rand_like(x) > rate
    return x * mask.float() / (1 - rate)

4. 変分オートエンコーダー (VAE)

変分オートエンコーダー(Variational Autoencoder,VAE)は生成モデルであり、データを固定ベクトルではなく潜在空間内の確率分布としてエンコードします。これにより、潜在空間からサンプリングして新しいデータを生成できます。

4.1 VAEの核心原理

VAEの重要な革新は、潜在変数の確率分布を学習することです:

  • エンコーダーは平均 \(\mu\) と標準偏差 \(\sigma\) を出力します
  • 正規分布 \(\mathcal{N}(\mu, \sigma)\) からサンプリングして潜在ベクトル \(z\) を取得します
  • デコーダーは \(z\) からデータを再構成します

微分可能なサンプリングプロセスを実現するために、次が使用されます:再パラメータ化トリック(Reparameterization Trick):

\[ z = \mu + \sigma \cdot \epsilon, \quad \epsilon \sim \mathcal{N}(0, 1) \]

4.2 VAEの実装

例

import torch
import torch.nn as nn
import torch.optim as optim

class VAE(nn.Module):
    """
変分オートエンコーダー
    """

    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(),
        )
        self.fc_mu = nn.Linear(hidden_dim, latent_dim)
        self.fc_logvar = 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()
        )

    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 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損失関数
再構成損失 + KLダイバージェンス
    """

    # 再構成損失
    recon_loss = nn.functional.mse_loss(x_recon, x, reduction='sum')

    # KLダイバージェンス:-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


# 使用例
INPUT_DIM = 784
HIDDEN_DIM = 256
LATENT_DIM = 2  # 2次元の潜在空間は可視化に便利

model = VAE(INPUT_DIM, HIDDEN_DIM, LATENT_DIM)

# テスト
x = torch.randn(32, 784)
x_recon, mu, logvar = model(x)

print(f"入力形状: {x.shape}")
print(f"再構成形状: {x_recon.shape}")
print(f"平均形状: {mu.shape}")       # (32, 2)
print(f"分散形状: {logvar.shape}")   # (32, 2)

4.3 VAEの生成と可視化

例

import matplotlib.pyplot as plt

def visualize_latent_space(model, dataloader, device):
    潜在空間の可視化
    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('Latent Dimension 1')
    plt.ylabel('Latent Dimension 2')
    plt.title('VAE Latent Space')
    plt.show()


def generate_from_latent(model, z, device):
    潜在ベクトルから画像を生成
    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):
    潜在空間の補間生成
    model.eval()

    # 線形補間
    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)


# 新しい画像を生成
def generate_new_images(model, num_images, latent_dim, device):
    ランダムな潜在ベクトルから新しい画像を生成
    model.eval()
    with torch.no_grad():
        # 標準正規分布からサンプリング
        z = torch.randn(num_images, latent_dim).to(device)
        generated = model.decode(z)
    return generated

VAEの潜在空間は連続的であり、潜在空間内で補間を行うことで、滑らかに遷移する画像を生成できます。しかし、VAEが生成する画像は通常ぼやけます。これは、正確な対数尤度ではなく下界を最適化しているためです。


5. スパースオートエンコーダー

スパースオートエンコーダ(Sparse Autoencoder)損失関数にスパース性制約を追加し、潜在ベクトルの活性化数を制限します。これにより、モデルはより意味のある特徴を学習できます。

5.1 スパースオートエンコーダーの実装

< h2 class="example">例
import torch
import torch.nn as nn
import torch.nn.functional as F

class SparseAutoencoder(nn.Module):
    """
スパースオートエンコーダ
    """

    def __init__(self, input_dim, hidden_dim, latent_dim):
        super().__init__()

        # エンコーダ
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
        )
        # 潜在層
        self.bottleneck = nn.Linear(hidden_dim, latent_dim)

        # デコーダ
        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)  # スパース活性化
        x_recon = self.decoder(z_activated)
        return x_recon, z_activated


def sparse_loss(z, rho=0.05, beta=1.0):
    """
スパース損失:KLダイバージェンス
rho: 目標スパース度(例: 0.05 は 5% のニューロンのみが活性化すべきことを示す)
beta: スパース項の重み
    """

    # 平均活性化を計算
    rho_hat = torch.mean(z, dim=0)

    # KLダイバージェンス
    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):
    """総損失 = 再構築損失 + スパース損失"""
    recon_loss = F.mse_loss(x_recon, x)
    sparsity = sparse_loss(z, rho, beta)
    return recon_loss + sparsity

6. シーケンス・ツー・シーケンスオートエンコーダー

シーケンスデータ(テキスト、時系列など)に対しては、RNN/LSTMをエンコーダおよびデコーダとして使用します。

6.1 シーケンスオートエンコーダーの実装

例

import torch
import torch.nn as nn

class Seq2SeqAutoencoder(nn.Module):
    """
シーケンス・ツー・シーケンス・オートエンコーダ:シーケンスデータ用
    """

    def __init__(self, input_size, hidden_size, latent_size, num_layers=2):
        super().__init__()

        # エンコーダ LSTM
        self.encoder = nn.LSTM(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=num_layers,
            batch_first=True,
            bidirectional=True
        )

        # 潜在空間へのマッピング
        # 双方向LSTMの出力は hidden_size * 2
        self.to_latent = nn.Linear(hidden_size * 2, latent_size)
        self.from_latent = nn.Linear(latent_size, hidden_size * 2)

        # デコーダ LSTM
        self.decoder = nn.LSTM(
            input_size=hidden_size,
            hidden_size=hidden_size,
            num_layers=num_layers,
            batch_first=True,
            bidirectional=True
        )

        # 出力マッピング
        self.output_proj = nn.Linear(hidden_size * 2, input_size)

    def forward(self, x):
        # エンコード
        _, (h_n, _) = self.encoder(x)

        # 双方向の最後の隠れ状態を結合
        # 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)

        # 潜在空間へマッピング
        z = self.to_latent(h_combined)

        # 潜在空間からマッピングし直す
        decoder_init = self.from_latent(z)
        decoder_init = decoder_init.view(2, decoder_init.size(0), -1)  # (2, batch, hidden_size*2)

        # デコード(元の入力長を使用)
        decoder_output, _ = self.decoder(
            x,
            (decoder_init, torch.zeros_like(decoder_init))
        )

        # 出力マッピング
        output = self.output_proj(decoder_output)
        return output, z


# 使用例
model = Seq2SeqAutoencoder(
    input_size=128,   # 入力特徴量の次元
    hidden_size=256,  # LSTM隠れ次元
    latent_size=64,   # 潜在空間の次元
    num_layers=2
)

# テスト
x = torch.randn(8, 20, 128)  # (batch, seq_len, input_size)
output, z = model(x)

print(f"入力形状: {x.shape}")        # (8, 20, 128)
print(f"出力形状: {output.shape}")  # (8, 20, 128)
print(f"潜在ベクトル形状: {z.shape}")    # (8, 64)

7. オートエンコーダーの応用シーン

7.1 異常検知

オートエンコーダは異常データの検出に使用できます。正常データの再構築誤差は小さく、異常データの再構築誤差は大きくなります:

例

import torch
import torch.nn as nn

def detect_anomalies(model, data_loader, threshold=None, device='cpu'):
    """
オートエンコーダを使った異常検知
    """

    model.eval()
    reconstruction_errors = []

    with torch.no_grad():
        for batch in data_loader:
            images = batch[0].to(device)
            outputs = model(images)

            # 再構築誤差を計算(平均二乗誤差)
            errors = torch.mean((outputs - images) ** 2, dim=(1, 2, 3))
            reconstruction_errors.extend(errors.cpu().numpy())

    reconstruction_errors = torch.tensor(reconstruction_errors)

    # しきい値が指定されていない場合は統計的手法を使用
    if threshold is None:
        # 95%分位数を使用
        threshold = torch.quantile(reconstruction_errors, 0.95).item()

    # 異常をマーク
    anomalies = reconstruction_errors > threshold

    return anomalies, reconstruction_errors, threshold


# 異常検知モデルを訓練
def train_anomaly_detector(normal_data_loader):
    """正常データのみでオートエンコーダを訓練"""
    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 画像の色付けとスタイル変換

例

class ColorizationAutoencoder(nn.Module):
    """
画像彩色オートエンコーダ
入力:グレースケール画像 (batch, 1, H, W)
出力:カラー画像 (batch, 2, H, W)(ab色空間)
    """

    def __init__(self):
        super().__init__()

        # エンコーダ:段階的に特徴を抽出
        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(),
        )

        # デコーダ:アップサンプリングして色を生成
        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),  # abチャンネルを出力
            nn.Sigmoid()  # abチャンネルの範囲 [0, 1]
        )

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

7.3 データ次元削減の可視化

例

import matplotlib.pyplot as plt

def visualize_latent_2d(model, dataloader, device, num_samples=1000):
    """
オートエンコーダでデータを2次元に削減して可視化する
    """

    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)

            # 2D AEの場合はそのまま使用
            # 次元がより高い場合は、まず2Dに射影する必要がある
            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('Latent Dimension 1')
    plt.ylabel('Latent Dimension 2')
    plt.title('Autoencoder 2D Latent Space Visualization')
    plt.show()

8. APIクイックリファレンス

8.1 一般的なオートエンコーダーの種類

種類 特徴 適用シーン
基本オートエンコーダ シンプルな対称構造 次元削減、特徴抽出
畳み込みオートエンコーダ 畳み込み層を使用して空間構造を保持 画像処理
デノイジングオートエンコーダ ノイズ除去を学習 画像のノイズ除去、ロバストな特徴
変分オートエンコーダ 確率分布を学習し、新しいデータを生成可能 生成モデル、データ生成
スパースオートエンコーダ スパース制約、解釈可能な特徴を学習 特徴の分離、解釈可能性
シーケンスオートエンコーダ RNN/LSTMを使用してシーケンスを処理 テキスト、時系列

8.2 損失関数の選択

タスク 推奨損失関数
画像再構築 MSELoss、SSIMLoss
二値画像 BCELoss、BCEWithLogitsLoss
テキスト再構築 CrossEntropyLoss
VAE MSE + KL Divergence
異常検知 MSE、MAE

8.3 潜在次元の選択

数据维度低(<100维)
    -> 潜在维度设为 2~10

数据维度中等(100~1000维)
    -> 潜在维度设为 10~50

数据维度高(>1000维)
    -> 潜在维度设为 50~200

生成任务(VAE)
    -> 潜在维度 2~32(便于采样和可视化)

异常检测
    -> 潜在维度 16~64(保留足够信息检测异常)
その他の拡張