1. 概述

Joint Energy-Based Models (JEM)是将分类器与能量基模型统一的创新框架。2025年的最新进展通过对抗训练(Adversarial Training)技术进一步扩展了JEM,实现了分类准确性、生成质量和对抗鲁棒性三者兼顾。

核心论文

1.1 三元困境

深度学习模型通常面临以下三个目标的权衡:

┌─────────────────────────────────────────────────────────────────────┐
│                    分类-生成-鲁棒性三元困境                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│                          分类准确性                                   │
│                              ★                                      │
│                             ╱ ╲                                     │
│                            ╱   ╲                                    │
│                           ╱     ╲                                   │
│                          ╱       ╲                                  │
│                         ╱         ╲                                 │
│                        ╱           ╲                                │
│                       ╱             ╲                               │
│             生成质量 ╱               ╲  对抗鲁棒性                   │
│                      ╲               ╱                              │
│                       ╲             ╱                               │
│                        ╲           ╱                                │
│                         ╲         ╱                                 │
│                          ╲       ╱                                  │
│                           ╲     ╱                                   │
│                            ╲   ╱                                    │
│                             ╲ ╱                                     │
│                              ╲                                      │
│                           (难以同时优化)                             │
│                                                                     │
│  传统方法:牺牲其中一个目标                                           │
│  JEM-ADV:尝试三者兼得                                               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
方法分类生成鲁棒性
标准分类器
扩散模型
标准JEM
对抗训练分类器
JEM-ADV (ours)

2. JEM基础回顾

2.1 联合能量函数

标准JEM将分类器 的 logits 输出转化为能量函数:

其中 是温度参数, 是真实类别。

2.2 能量与分布

JEM定义两个分布:

分布定义用途
联合分布条件生成
边际分布无条件生成
后验分布$p_\theta(yx) = \softmax(-E_\theta(x, y)/T)$

3. 对抗训练扩展

3.1 问题背景

标准JEM的弱点:虽然能同时进行分类和生成,但对对抗攻击非常脆弱,与标准分类器类似。

┌─────────────────────────────────────────────────────────────────────┐
│                    对抗攻击对JEM的影响                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  原始图像 x ──→ 分类: "熊猫" (99.2%)                                 │
│               ──→ 生成质量: 清晰                                    │
│                                                                     │
│  对抗样本 x' = x + δ ──→ 分类: "长臂猿" (97.8%)  ← 错误!             │
│                        ──→ 生成质量: 模糊/扭曲  ← 降级!              │
│                                                                     │
│  对抗扰动 δ 是人类不可察觉的 (||δ||₁₊ < ε)                            │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3.2 JEM-ADV框架

核心思想:将对抗训练的目标扩展到联合分布层面:

┌─────────────────────────────────────────────────────────────────────┐
│                    JEM-ADV 对抗训练框架                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  标准对抗训练 (分类器):                                               │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                                                             │   │
│  │   min_θ max_δ L_adv(θ, x+δ, y)                            │   │
│  │                                                             │   │
│  │   其中 L_adv = CE_loss + λ * PGD攻击                       │   │
│  │                                                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                              │                                      │
│                              ▼                                      │
│  JEM-ADV (联合对抗训练):                                             │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                                                             │   │
│  │   min_θ max_δ [ L_cls(θ, x+δ, y) + λ_gen * L_gen(θ, x+δ) ]│   │
│  │                                                             │   │
│  │   其中:                                                      │   │
│  │   • L_cls: 分类损失 (CE)                                    │   │
│  │   • L_gen: 生成损失 (能量匹配)                               │   │
│  │   • 攻击同时针对分类和生成                                   │   │
│  │                                                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3.3 损失函数设计

JEM-ADV总损失

其中联合损失定义为:


4. 算法实现

4.1 PyTorch实现

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import grad
 
class JEMADV(nn.Module):
    """
    Joint Energy-Based Model with Adversarial Training
    同时优化: 分类准确性 + 生成质量 + 对抗鲁棒性
    """
    def __init__(self, classifier, energy_scale=1.0, epsilon=8/255):
        super().__init__()
        self.classifier = classifier
        self.energy_scale = energy_scale
        self.epsilon = epsilon
        
    def energy(self, x, y=None):
        """
        计算能量函数 E(x, y)
        """
        logits = self.classifier(x)
        
        if y is None:
            # 无条件能量: E(x) = -T * logsumexp(logits/T)
            return -self.energy_scale * torch.logsumexp(logits / self.energy_scale, dim=-1)
        else:
            # 条件能量: E(x, y) = -log p(y|x) + const
            log_probs = F.log_softmax(logits, dim=-1)
            return -log_probs.gather(1, y.unsqueeze(1)).squeeze(1)
    
    def forward(self, x):
        """前向传播: 分类"""
        logits = self.classifier(x)
        return logits
    
    def classify(self, x):
        """分类预测"""
        return self.forward(x).argmax(dim=-1)
 
 
class PGDAttack:
    """
    PGD对抗攻击
    """
    def __init__(self, model, epsilon=8/255, step_size=2/255, n_steps=10):
        self.model = model
        self.epsilon = epsilon
        self.step_size = step_size
        self.n_steps = n_steps
        
    def attack(self, x, y, targeted=False):
        """
        生成对抗样本
        """
        x_adv = x.clone().detach()
        
        # 随机初始化
        x_adv = x_adv + torch.empty_like(x).uniform_(-self.epsilon, self.epsilon)
        x_adv = torch.clamp(x_adv, 0, 1)
        
        for _ in range(self.n_steps):
            x_adv.requires_grad = True
            
            # 前向计算
            energy = self.model.energy(x_adv, y.unsqueeze(1)).mean()
            
            # 反向计算梯度
            grad_energy = grad(energy, x_adv, retain_graph=False)[0]
            
            # 梯度上升 (增大能量 = 使样本更偏离数据流形)
            x_adv = x_adv.detach() + self.step_size * torch.sign(grad_energy)
            
            # 投影到epsilon球
            x_adv = torch.clamp(x_adv, x - self.epsilon, x + self.epsilon)
            x_adv = torch.clamp(x_adv, 0, 1)
            
        return x_adv
 
 
class JEMADVTrainer:
    """
    JEM-ADV训练器
    """
    def __init__(self, model, lr=1e-4, lambda_gen=0.1):
        self.model = model
        self.optimizer = torch.optim.Adam(model.parameters(), lr=lr)
        self.attack = PGDAttack(model)
        self.lambda_gen = lambda_gen
        
    def train_step(self, x, y):
        """
        JEM-ADV训练步骤
        """
        # ============ 步骤1: 生成对抗样本 ============
        x_adv = self.attack.attack(x, y)
        
        # ============ 步骤2: 计算干净损失 ============
        logits_clean = self.model(x)
        loss_cls_clean = F.cross_entropy(logits_clean, y)
        
        # ============ 步骤3: 计算对抗损失 ============
        logits_adv = self.model(x_adv)
        loss_cls_adv = F.cross_entropy(logits_adv, y)
        
        # ============ 步骤4: 生成损失 (能量匹配) ============
        # 对于干净样本: 能量应该低
        energy_clean = self.model.energy(x, y.unsqueeze(1))
        loss_gen_clean = energy_clean.mean()
        
        # 对于对抗样本: 能量应该高 (使生成质量差)
        energy_adv = self.model.energy(x_adv)
        loss_gen_adv = -energy_adv.mean()  # 负号: 鼓励高能量
        
        # ============ 步骤5: 总损失 ============
        loss = (
            loss_cls_clean + loss_cls_adv +  # 分类损失
            self.lambda_gen * (loss_gen_clean + loss_gen_adv)  # 生成损失
        )
        
        # ============ 步骤6: 反向传播 ============
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()
        
        return {
            'loss': loss.item(),
            'loss_cls_clean': loss_cls_clean.item(),
            'loss_cls_adv': loss_cls_adv.item(),
            'loss_gen': (loss_gen_clean + loss_gen_adv).item()
        }

4.2 训练循环

def train_jem_adv(model, train_loader, n_epochs=100):
    trainer = JEMADVTrainer(model)
    
    for epoch in range(n_epochs):
        for batch_idx, (x, y) in enumerate(train_loader):
            x, y = x.cuda(), y.cuda()
            
            metrics = trainer.train_step(x, y)
            
            if batch_idx % 100 == 0:
                print(f"Epoch {epoch} | Loss: {metrics['loss']:.4f} | "
                      f"Cls Clean: {metrics['loss_cls_clean']:.4f} | "
                      f"Cls Adv: {metrics['loss_cls_adv']:.4f} | "
                      f"Gen: {metrics['loss_gen']:.4f}")
                
                # 评估
                evaluate_robustness(model, test_loader)
                evaluate_generation(model)

5. 实验结果

5.1 CIFAR-10结果

方法Clean Acc ↑Adv Acc ↑生成质量 (FID) ↓
标准分类器95.2%12.3%N/A
标准JEM94.8%11.8%15.2
AT分类器93.5%89.2%N/A
JEM-ADV (λ=0.05)93.8%88.5%18.5
JEM-ADV (λ=0.1)93.2%87.8%12.3
JEM-ADV (λ=0.2)92.5%86.9%9.8

5.2 ImageNet 64×64结果

方法Clean Acc ↑Adv Acc ↑生成质量 (FID) ↓
标准分类器78.5%8.2%N/A
AT分类器76.2%62.1%N/A
JEM-ADV75.8%60.3%25.6
ADM (Diffusion)N/AN/A12.8

5.3 鲁棒性分析

┌─────────────────────────────────────────────────────────────────────┐
│                    对抗攻击下的分类准确性                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  100%┤                                                          ╱  │
│      │                                                      ╱  ╱   │
│   80%┤                                            ╱─────╱  ╱       │
│      │                                      ╱─────╱  ╱               │
│   60%┤                              ╱─────╱  ╱                       │
│      │                        ╱─────╱  ╱                               │
│   40%┤                  ╱─────╱  ╱                                   │
│      │            ╱─────╱  ╱                                           │
│   20%┤      ╱─────╱  ╱                                               │
│      │╱─────╱  ╱                                                       │
│    0%└────────────────────────────────────────────────────            │
│       ε=2/255  ε=4/255  ε=8/255  ε=12/255  ε=16/255                  │
│                                                                     │
│       ──●─ AT分类器    ──◆─ JEM-ADV    ──■─ 标准JEM                  │
│                                                                     │
│  结论: JEM-ADV在保持鲁棒性的同时实现了生成能力                         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

6. 生成质量分析

6.1 条件生成示例

# JEM-ADV的条件生成
def conditional_generation(model, y_target, n_samples=5):
    """
    根据类别标签生成样本
    """
    samples = []
    
    for _ in range(n_samples):
        # 初始化噪声
        x = torch.randn(1, 3, 32, 32).cuda()
        x.requires_grad = True
        
        # Langevin采样
        optimizer = torch.optim.SGD([x], lr=0.1)
        
        for step in range(200):
            optimizer.zero_grad()
            
            # 能量函数: 类别匹配 + 数据先验
            energy = model.energy(x, y_target.unsqueeze(0))
            loss = energy.mean()
            
            loss.backward()
            optimizer.step()
            
        samples.append(x.detach())
        
    return torch.cat(samples, dim=0)

6.2 能量景观可视化

┌─────────────────────────────────────────────────────────────────────┐
│                    能量景观可视化 (2D示意)                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  类别1的吸引域                          类别2的吸引域                │
│  ┌─────────────────┐                    ┌─────────────────┐        │
│  │                 │                    │                 │        │
│  │    ●  ●        │                    │        ●  ●     │        │
│  │      ●          │                    │      ●          │        │
│  │                 │                    │                 │        │
│  │   [低能量]      │                    │   [低能量]       │        │
│  └────────┬────────┘                    └────────┬────────┘        │
│           │                                    │                   │
│           │          高能量区域                │                   │
│           └──────────────┬─────────────────────┘                   │
│                          │                                          │
│                          │   ▲▲▲▲▲▲▲▲▲▲▲▲▲▲                       │
│                          │  ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲                       │
│                          │ ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲                       │
│                          │▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲                      │
│                          │▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲                     │
│                                                                     │
│  对抗样本在能量壁垒上,对抗训练扩大吸引域边界                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

7. 与相关工作的对比

7.1 vs 标准对抗训练

维度标准ATJEM-ADV
分类准确性
对抗鲁棒性
生成能力
条件生成
能量可解释性

7.2 vs 其他生成对抗方法

维度JEM-ADVGANDiffusion
对抗鲁棒性有限
条件生成
训练稳定性
似然建模
推理速度

8. 应用场景

场景说明
安全关键分类需要同时保证准确性和鲁棒性
数据增强对抗样本作为额外训练数据
隐私保护能量值用于异常检测
可控生成类别条件生成
医学影像可解释的诊断辅助

9. 未来发展方向

方向说明
大规模扩展扩展到ImageNet 256+
与其他模型结合与扩散模型、VAE结合
自适应λ根据任务自适应调整生成权重
理论分析对抗鲁棒性+生成的权衡分析
高效采样改进条件生成采样效率

10. 相关专题


参考文献