概述

深度神经网络在训练过程中展现出惊人的**“频率原则”**(Frequency Principle,F-Principle):网络倾向于先快速学习数据中的低频成分,然后逐渐学习高频细节。1

这一原则深刻揭示了深度学习训练的隐含偏好,对于理解泛化能力、设计训练策略、以及分析对抗脆弱性都有重要意义。


实验发现

经典的频率原则实验

2019年,Xu等人首次系统地观察到这一现象1

实验设置

  • 函数:
  • 模型:多层全连接网络(ReLU激活)
  • 训练:标准梯度下降

观察结果

训练阶段拟合内容Fourier频谱
初期低频(5x)快速收敛只看到低频峰
中期中频(20x)逐渐出现低频+中频
后期高频(50x)缓慢逼近全部频率

关键发现:训练误差在频率域的衰减呈现明显的层级结构,低频成分始终先于高频收敛。

更一般的形式

频率原则不仅限于简单函数:

  1. 自然图像:DNN优先学习平滑的低频结构
  2. 语音信号:先学习基础频率,后学习谐波细节
  3. 函数逼近:无论目标函数形状如何,低频优先规律一致

理论分析

频率原则的数学刻画

设训练数据为 ,损失函数为

频率原则定理2

对于目标函数 ,其Fourier变换为 。训练得到的网络 满足:

其中 是与训练时间 相关的衰减常数。

解释:频率为 的成分,其误差以指数速度衰减,衰减速度与频率成正比。

神经网络作为低通滤波器

从频域视角,深度神经网络本质上是一个低通滤波器(Low-Pass Filter):

import torch
import torch.nn as nn
import numpy as np
 
class FrequencyAnalyzer:
    def __init__(self, model):
        self.model = model
        self.hooks = []
    
    def get_frequency_response(self, freq):
        """计算网络对特定频率的响应"""
        x = torch.linspace(0, 2*np.pi, 256)
        x = x.view(1, -1).repeat(len(freq), 1)
        
        # 创建不同频率的输入
        x_freq = torch.stack([torch.sin(f * x[i]) for i, f in enumerate(freq)])
        
        with torch.no_grad():
            y = self.model(x_freq)
        
        return y
    
    def plot_bode(self, freqs):
        """绘制Bode图(频率响应)"""
        responses = self.get_frequency_response(freqs)
        # 分析响应的幅度
        amplitudes = responses.abs().mean(dim=1)
        
        return freqs, amplitudes.numpy()

为什么是低频优先?

1. 损失景观的曲率差异

不同频率成分在损失函数中具有不同的曲率(Curvature):

  • 低频成分:曲率小,梯度方向稳定,易于优化
  • 高频成分:曲率高,梯度变化剧烈,收敛慢

2. 激活函数的频域特性

ReLU等激活函数的Fourier变换:

  • ReLU引入了高频响应,但高频成分的梯度较小
  • 网络通过叠加层逐渐积累低频信息

3. 谱偏差假说

谱偏差(Spectral Bias)是指神经网络学习与其Fourier谱中低频成分相关目标函数时,收敛速度更快。3


与网络架构的关系

深度 vs 宽度

架构特性对频率原则的影响
深度增加加速高频学习,但低频仍是主导
宽度增加提高各频率的学习效率
残差连接缓解高频衰减,改善深层网络训练

激活函数的影响

激活函数频率特性F-Principle强度
Sigmoid强低通
Tanh强低通
ReLU中等中等
GELU较宽频较弱
Swish可学习可调
def analyze_activation_freq(activation_fn, num_frequencies=50):
    """分析激活函数的频率响应"""
    freqs = np.linspace(0.1, 20, num_frequencies)
    x = np.linspace(-10, 10, 1000)
    
    responses = []
    for w in freqs:
        # 输入 sin(wx)
        y_in = np.sin(w * x)
        # 通过激活函数
        y_out = activation_fn(y_in)
        
        # 计算输出中原始频率的保留程度
        # 使用互相关测量
        corr = np.correlate(y_out, y_in, mode='valid')[0]
        responses.append(corr / len(x))
    
    return freqs, np.array(responses)

批归一化的影响

批归一化(BatchNorm)会加速高频学习:

  • 归一化改变了梯度尺度
  • 使各频率成分的梯度更均衡
  • 但仍保持低频优先的基本模式

频率原则与泛化

低频优先的双刃剑效应

频率原则对泛化有复杂的影响:

积极方面

  • 自然数据通常以低频为主,低频优先自然导致良好泛化
  • 避免过拟合高频噪声

消极方面

  • 可能导致对抗脆弱性:对抗样本是高频扰动
  • 限制了对高频细节的学习能力

频率视角的泛化界

从频率角度分析泛化能力:

其中 是目标函数的低频部分。

结论:当目标函数低频能量集中时,频率原则导致良好泛化。

对抗攻击的频率解释

对抗样本(Adversarial Examples)与频率原则密切相关:

正常样本:低频主导 + 中频细节
对抗扰动:高频噪声(人眼不可见)
     ↓
频率原则:DNN难以学习高频扰动
     ↓
结果:正常样本预测正确,对抗样本预测错误

防御启示

  • 增强高频学习能力可能提高对对抗样本的鲁棒性
  • 频率正则化是一种有效的防御方法

与其他理论的关系

与Neural Tangent Kernel的联系

神经正切核(NTK)理论提供了频率原则的另一视角:

  • NTK 的特征值分解
  • 特征值按频率排序:低频 → 大特征值
  • 梯度下降按特征值比例收敛
class NTKFrequencyAnalysis:
    def __init__(self, network):
        self.network = network
    
    def compute_ntk_spectrum(self, x):
        """计算NTK并分析其频率特性"""
        # 获取网络雅可比矩阵
        J = torch.func.jacfwd(self.network)(x)
        
        # NTK = J @ J.T
        ntk = J @ J.transpose(-2, -1)
        
        # 特征分解
        eigenvalues, eigenvectors = torch.linalg.eigh(ntk)
        
        return eigenvalues, eigenvectors
    
    def frequency_decomposition(self, ntk_eigenvectors, freqs):
        """分析NTK特征函数的频率特性"""
        # 对每个特征向量做Fourier变换
        freq_content = []
        for vec in ntk_eigenvectors:
            fft = torch.fft.fft(vec)
            freq_content.append(fft.abs())
        
        return torch.stack(freq_content)

与Implicit Regularization的联系

频率原则可视为隐式正则化的一种表现:

  • SGD/梯度下降倾向于收敛到损失景观中的”平坦”解
  • 平坦解往往对应于低频主导的函数
  • 因此训练过程隐式地偏好低频

实践应用

基于频率原则的训练策略

1. 课程学习(Curriculum Learning)

从低频到高频的渐进式训练:

class FrequencyCurriculum:
    def __init__(self, model, data_loader):
        self.model = model
        self.data_loader = data_loader
    
    def train_with_curriculum(self, epochs):
        for epoch in range(epochs):
            # 计算当前epoch应该学习的频率范围
            max_freq = self.get_max_freq(epoch, epochs)
            
            # 过滤训练数据
            filtered_loader = self.filter_by_frequency(
                self.data_loader, 
                max_freq
            )
            
            # 训练
            self.train_epoch(filtered_loader)
    
    def filter_by_frequency(self, loader, max_freq):
        """只保留低于max_freq的频率成分"""
        filtered_data = []
        for x, y in loader:
            # Fourier变换
            x_fft = torch.fft.fft(x, dim=-1)
            freqs = torch.fft.fftfreq(x.shape[-1])
            
            # 高频置零
            mask = freqs.abs() < max_freq
            x_filtered = torch.fft.ifft(x_fft * mask.float(), dim=-1).real
            
            filtered_data.append((x_filtered, y))
        
        return DataLoader(filtered_data, batch_size=loader.batch_size)

2. 频率感知的数据增强

增强高频信息的学习:

class FrequencyAwareAugmentation:
    def __init__(self, high_freq_prob=0.3):
        self.high_freq_prob = high_freq_prob
    
    def augment(self, x):
        # 标准增强
        x = self.standard_augment(x)
        
        # 以一定概率增强高频
        if torch.rand(1) < self.high_freq_prob:
            x = self.enhance_high_frequency(x)
        
        return x
    
    def enhance_high_frequency(self, x):
        """增强高频成分"""
        # Fourier变换
        x_fft = torch.fft.fft2(x)
        
        # 创建高频滤波器
        H, W = x.shape[-2:]
        freqs_y = torch.fft.fftfreq(H).view(-1, 1).expand(H, W)
        freqs_x = torch.fft.fftfreq(W).view(1, -1).expand(H, W)
        freq_magnitude = (freqs_y**2 + freqs_x**2).sqrt()
        
        # 提升高频
        threshold = 0.3  # 频率阈值
        boost = torch.where(freq_magnitude > threshold, 1.5, 1.0)
        
        x_fft_boosted = x_fft * boost
        
        # 逆变换
        return torch.fft.ifft2(x_fft_boosted).real

3. 多尺度训练

同时训练多个频率尺度的目标:

class MultiScaleLoss(nn.Module):
    def __init__(self, model, scales=[1, 2, 4]):
        super().__init__()
        self.model = model
        self.scales = scales
    
    def forward(self, x, y):
        total_loss = 0
        
        for scale in self.scales:
            # 下采样
            x_scaled = F.avg_pool2d(x, kernel_size=scale)
            y_scaled = F.avg_pool2d(y, kernel_size=scale)
            
            # 预测
            y_pred = self.model(x_scaled)
            
            # 损失
            scale_weight = 1.0 / scale  # 低频权重更高
            total_loss += scale_weight * F.mse_loss(y_pred, y_scaled)
        
        return total_loss

频率原则的诊断工具

class FrequencyPrincipleAnalyzer:
    def __init__(self, model):
        self.model = model
        self.train_history = []
    
    def analyze_training(self, x_eval, freq_range):
        """分析训练过程中的频率响应变化"""
        self.model.eval()
        
        with torch.no_grad():
            y_pred = self.model(x_eval)
        
        # Fourier分析
        fft_pred = torch.fft.fft(y_pred)
        amp_spectrum = fft_pred.abs()
        
        # 提取各频率成分的幅度
        freq_amplitudes = {}
        for freq in freq_range:
            idx = self.freq_to_idx(freq, len(y_pred))
            freq_amplitudes[freq] = amp_spectrum[idx].item()
        
        self.train_history.append(freq_amplitudes)
        
        return freq_amplitudes
    
    def plot_convergence(self, freq_range):
        """绘制各频率成分的收敛曲线"""
        import matplotlib.pyplot as plt
        
        fig, ax = plt.subplots(figsize=(10, 6))
        
        for freq in freq_range:
            amplitudes = [h[freq] for h in self.train_history]
            ax.plot(amplitudes, label=f'{freq:.1f}Hz')
        
        ax.set_xlabel('Training Step')
        ax.set_ylabel('Frequency Amplitude')
        ax.set_title('Frequency Principle: Convergence by Frequency')
        ax.legend()
        
        return fig

总结

频率原则揭示了深度学习训练的基本规律

观察含义
低频先于高频训练有内在的”频率偏好”
指数衰减高频成分学习速度指数级慢
与架构相关深度、宽度、激活函数都影响频率特性

理论和实践意义

  1. 理论理解:解释了为什么DNN在自然数据上泛化良好
  2. 对抗脆弱性:揭示了对抗样本的频率特性
  3. 训练策略:指导课程学习、数据增强等实践
  4. 架构设计:影响激活函数、归一化等选择

频率原则是连接优化动力学泛化理论实践应用的重要桥梁。


参考

Footnotes

  1. Training behavior of deep neural network and frequency principle (Xu et al., NeurIPS 2019) 2

  2. A Rigorous Theory of the Frequency Principle and Beyond (ICML 2019)

  3. Spectral Bias in Neural Networks (Rahaman et al., ICML 2019)