随机矩阵理论与机器学习

随机矩阵理论(Random Matrix Theory, RMT)研究大维随机矩阵的谱性质,为分析神经网络的Hessian谱、泛化理论和初始化策略提供了有力工具。1


基本概念

Wigner矩阵

对称随机矩阵 ,满足:

  • 上三角元素独立同分布,均值为0,方差为1
  • 对角线元素与上三角元素同分布

Wishart矩阵

样本协方差矩阵:

其中 的元素独立同分布。


Marchenko-Pastur分布

定理

,元素独立同分布,均值为0,方差为 。当 时, 的特征值分布收敛到Marchenko-Pastur分布:

其中:

Python实现

import numpy as np
import matplotlib.pyplot as plt
 
def marchenko_pastur_pdf(lambda_vals, sigma=1.0, gamma=1.0):
    """
    Marchenko-Pastur 概率密度函数
    
    Args:
        lambda_vals: 特征值点
        sigma: 原始变量标准差
        gamma: p/n 比例
    """
    a = sigma**2 * (1 - np.sqrt(gamma))**2
    b = sigma**2 * (1 + np.sqrt(gamma))**2
    
    pdf = np.zeros_like(lambda_vals)
    
    # 在支持集内部
    mask = (lambda_vals > a) & (lambda_vals < b)
    pdf[mask] = (
        np.sqrt((b - lambda_vals[mask]) * (lambda_vals[mask] - a)) /
        (2 * np.pi * sigma**2 * gamma * lambda_vals[mask])
    )
    
    return pdf
 
def marchenko_pastur_cdf(lambda_vals, sigma=1.0, gamma=1.0):
    """
    Marchenko-Pastur 累积分布函数
    """
    # 数值积分
    lambda_grid = np.linspace(0, lambda_vals[-1], 10000)
    pdf = marchenko_pastur_pdf(lambda_grid, sigma, gamma)
    cdf = np.cumsum(pdf) * (lambda_grid[1] - lambda_grid[0])
    
    return np.interp(lambda_vals, lambda_grid, cdf)
 
# 示例:生成和可视化
def demo_marchenko_pastur():
    np.random.seed(42)
    
    # 参数设置
    n, p = 1000, 500  # n > p (wide matrix)
    gamma = p / n
    sigma = 1.0
    
    # 生成随机矩阵
    X = np.random.randn(n, p) * sigma
    S = (X.T @ X) / n  # Wishart 矩阵
    
    # 计算特征值
    eigenvalues = np.linalg.eigvalsh(S)
    
    # MP理论预测
    lambda_max = sigma**2 * (1 + np.sqrt(gamma))**2
    lambda_min = sigma**2 * (1 - np.sqrt(gamma))**2
    lambda_mean = sigma**2 * (1 + gamma)
    
    print(f"理论边界: [{lambda_min:.4f}, {lambda_max:.4f}]")
    print(f"理论均值: {lambda_mean:.4f}")
    print(f"经验最大: {eigenvalues.max():.4f}")
    print(f"经验最小: {eigenvalues.min():.4f}")
    print(f"经验均值: {eigenvalues.mean():.4f}")
    
    # 可视化
    fig, ax = plt.subplots(figsize=(10, 6))
    
    # 经验直方图
    ax.hist(eigenvalues, bins=100, density=True, alpha=0.5, label='经验分布')
    
    # MP理论曲线
    lambda_range = np.linspace(lambda_min - 0.5, lambda_max + 0.5, 1000)
    mp_pdf = marchenko_pastur_pdf(lambda_range, sigma, gamma)
    ax.plot(lambda_range, mp_pdf, 'r-', linewidth=2, label='MP理论')
    
    ax.axvline(lambda_max, color='g', linestyle='--', label=f'λ_max = {lambda_max:.3f}')
    ax.axvline(lambda_min, color='b', linestyle='--', label=f'λ_min = {lambda_min:.3f}')
    
    ax.set_xlabel('特征值 λ')
    ax.set_ylabel('概率密度')
    ax.set_title(f'Marchenko-Pastur 分布 (γ = {gamma:.2f})')
    ax.legend()
    plt.show()
    
    return eigenvalues, lambda_min, lambda_max

随机矩阵在神经网络中的应用

1. 初始化分析

随机初始化时,权重矩阵的元素独立同分布。网络的信号传播可以用随机矩阵理论分析。

class SignalPropagationRMT:
    """
    使用 RMT 分析信号传播
    """
    
    def __init__(self, layer_sizes):
        self.layer_sizes = layer_sizes
        self.gammas = []  # 每层的 p/n 比例
        self.eigenvalue_history = []
    
    def analyze_initialization(self, init_std=1.0):
        """
        分析不同初始化方差下的特征值分布
        """
        print("信号传播 RMT 分析:")
        print("=" * 50)
        
        for i in range(len(self.layer_sizes) - 1):
            n = self.layer_sizes[i]      # 当前层宽度
            p = self.layer_sizes[i+1]   # 下一层宽度
            
            gamma = p / n
            
            # 有效权重的 gamma
            # 对于线性变换 W @ x,W 形状为 (p, n)
            # 等价于考虑 W^T W 或 W W^T
            
            lambda_max = init_std**2 * (1 + np.sqrt(gamma))**2
            lambda_min = init_std**2 * (1 - np.sqrt(gamma))**2
            
            # 期望的谱半径
            expected_radius = init_std * np.sqrt(min(n, p))
            
            print(f"层 {i} -> {i+1}:")
            print(f"  维度: {n} -> {p}, γ = {gamma:.3f}")
            print(f"  特征值范围: [{lambda_min:.3f}, {lambda_max:.3f}]")
            print(f"  谱半径: {np.sqrt(lambda_max):.3f}")
            
            self.gammas.append(gamma)
    
    def critical_init_std(self, gamma):
        """
        计算临界初始化标准差
        
        使谱半径 = 1(临界初始化)
        """
        # (1 + sqrt(γ))^2 * σ² = 1
        # σ² = 1 / (1 + sqrt(γ))²
        critical = 1.0 / (1 + np.sqrt(gamma))**2
        return np.sqrt(critical)

2. Xavier/Kaiming初始化的RMT分析

class InitializationRMT:
    """
    Xavier 和 Kaiming 初始化的 RMT 验证
    """
    
    @staticmethod
    def xavier_init(n_in, n_out, gain=1.0):
        """
        Xavier 初始化
        
        Var(W) = 2 / (n_in + n_out)
        """
        var = gain * 2.0 / (n_in + n_out)
        return np.sqrt(var)
    
    @staticmethod
    def kaiming_init(n_in, n_out, mode='fan_in', nonlinearity='relu'):
        """
        Kaiming/He 初始化
        
        Var(W) = 2 / n_in  (for ReLU)
        """
        if mode == 'fan_in':
            fan = n_in
        elif mode == 'fan_out':
            fan = n_out
        else:
            fan = (n_in + n_out) / 2
        
        if nonlinearity == 'relu':
            std = np.sqrt(2.0 / fan)
        else:
            std = np.sqrt(1.0 / fan)
        
        return std
    
    @staticmethod
    def verify_initialization(layer_widths, init_std):
        """
        验证初始化后的谱性质
        """
        print("初始化验证:")
        
        for i, width in enumerate(layer_widths[:-1]):
            next_width = layer_widths[i + 1]
            
            # 随机初始化
            W = np.random.randn(next_width, width) * init_std
            
            # 谱半径
            if width <= next_width:
                # W @ W.T 的特征值
                WWt_eigenvalues = np.linalg.eigvalsh(W @ W.T) / width
            else:
                # W.T @ W 的特征值
                WtW_eigenvalues = np.linalg.eigvalsh(W.T @ W) / width
            
            print(f"  层 {i}: 谱半径 = {np.sqrt(max(WWt_eigenvalues.max(), WtW_eigenvalues.max() if len(WtW_eigenvalues) > 0 else 0)):.4f}")

Hessian 谱分析

神经网络的 Hessian

神经网络的 Hessian 矩阵 可以分解为:

RMT视角的Hessian分析

class HessianSpectrum:
    """
    使用 RMT 分析神经网络 Hessian 的谱
    """
    
    def __init__(self, model):
        self.model = model
        self.eigenvalues = None
    
    def compute_spectrum(self, dataloader, device='cpu'):
        """
        计算 Hessian 谱
        
        注意:这只适用于小型网络
        """
        self.model.to(device)
        self.model.eval()
        
        # 收集梯度
        params = [p for p in self.model.parameters() if p.requires_grad]
        n_params = sum(p.numel() for p in params)
        
        # 构建 Hessian(只适用于小型网络)
        H = torch.zeros(n_params, n_params, device=device)
        
        # 简化的 Hessian 计算(只计算对角块)
        # 实际中需要更复杂的计算
        
        return H
    
    def empirical_spectrum_analysis(self, eigenvalues):
        """
        经验谱分析
        """
        eigenvalues = np.array(eigenvalues)
        
        # 基本统计
        stats = {
            'n_eigenvalues': len(eigenvalues),
            'max': eigenvalues.max(),
            'min': eigenvalues.min(),
            'mean': eigenvalues.mean(),
            'median': np.median(eigenvalues),
            'std': eigenvalues.std()
        }
        
        # 比例
        positive = (eigenvalues > 0).sum()
        zero = (eigenvalues == 0).sum()
        negative = (eigenvalues < 0).sum()
        
        stats['positive_ratio'] = positive / len(eigenvalues)
        stats['zero_ratio'] = zero / len(eigenvalues)
        stats['negative_ratio'] = negative / len(eigenvalues)
        
        # 条件数
        if eigenvalues.min() > 0:
            stats['condition_number'] = eigenvalues.max() / eigenvalues.min()
        else:
            stats['condition_number'] = float('inf')
        
        return stats
    
    def fit_marchenko_pastur(self, eigenvalues, sigma=None):
        """
        将经验谱拟合到 MP 分布
        """
        n = len(eigenvalues)
        
        # 经验统计
        empirical_mean = np.mean(eigenvalues)
        empirical_var = np.var(eigenvalues)
        
        # MP 分布的性质
        # E[λ] = σ²(1 + γ)
        # Var[λ] = σ⁴γ(1 - γ)
        
        # 估计 σ²
        if sigma is None:
            sigma_sq = empirical_mean / 1.0  # 假设 γ = 1
            sigma = np.sqrt(sigma_sq)
        
        # 估计 γ
        gamma_est = empirical_var / (sigma**4)
        
        # 理论边界
        lambda_max_theory = sigma**2 * (1 + np.sqrt(gamma_est))**2
        lambda_min_theory = sigma**2 * (1 - np.sqrt(gamma_est))**2
        
        return {
            'sigma': sigma,
            'gamma': gamma_est,
            'lambda_max_theory': lambda_max_theory,
            'lambda_min_theory': lambda_min_theory,
            'lambda_max_empirical': eigenvalues.max(),
            'lambda_min_empirical': eigenvalues.min()
        }

泛化与RMT

谱范数与泛化

class RMTGeneralization:
    """
    使用 RMT 理论分析泛化
    """
    
    @staticmethod
    def spectral_risk_bound(n_samples, n_features, spectral_norm, delta=0.05):
        """
        基于谱范数的风险边界
        
        R(f) ≤ R_emp(f) + O(√(d/n))  使用 VC 维
        R(f) ≤ R_emp(f) + O(σ_谱/√n)  使用 RMT
        """
        complexity = np.sqrt(spectral_norm / n_samples)
        
        # 添加置信项
        confidence_term = np.sqrt(np.log(1/delta) / (2 * n_samples))
        
        return complexity + confidence_term
    
    @staticmethod
    def edge_of Chaos_parameter(n_in, n_out, weight_std):
        """
        混沌边缘参数
        
        使信号方差在层间保持稳定
        """
        # 对于方差保持:Var(W) = 1/n_in
        # 对于谱半径 = 1:需要更精细的分析
        
        # Xavier 初始化
        xavier_std = np.sqrt(2.0 / (n_in + n_out))
        
        # Kaiming 初始化(ReLU)
        kaiming_std = np.sqrt(2.0 / n_in)
        
        # 临界值(使谱半径 = 1)
        gamma = n_out / n_in
        critical_std = 1.0 / (1 + np.sqrt(gamma))
        
        return {
            'xavier_std': xavier_std,
            'kaiming_std': kaiming_std,
            'critical_std': critical_std,
            'current_std': weight_std,
            'is_edge_of_chaos': np.abs(weight_std - critical_std) < 0.01
        }

批量归一化的RMT分析

class BatchNormRMT:
    """
    批量归一化的 RMT 分析
    """
    
    @staticmethod
    def effective_covariance_after_bn(x, gamma, beta, running_mean, running_var, eps=1e-5):
        """
        批量归一化后的有效协方差
        
        BN 变换:y = γ * (x - μ) / √(σ² + ε) + β
        
        这使得每一层的输入具有单位方差
        """
        # 归一化后的方差
        var_normalized = 1.0
        
        # 反向变换后的方差
        var_output = gamma**2 * var_normalized
        
        return var_output
    
    @staticmethod
    def signal_propagation_with_bn(layer_widths):
        """
        有 BN 时的信号传播
        """
        print("批量归一化信号传播分析:")
        
        for i in range(len(layer_widths) - 1):
            n = layer_widths[i]
            p = layer_widths[i + 1]
            
            # 无 BN:谱半径 ≈ σ * √min(n, p)
            # 有 BN:每层输出方差被归一化
            
            print(f"  层 {i}: 输入方差 → 归一化为 1 → γ")
            print(f"    后续层受 γ 影响")

实践应用

1. 检测网络处于哪个学习阶段

class NetworkPhaseDetector:
    """
    检测网络是否处于 ordered/edge of chaos/chaotic 阶段
    """
    
    @staticmethod
    def detect_phase(eigenvalues, threshold=0.1):
        """
        根据 Hessian 谱检测网络阶段
        """
        mean_eigenvalue = np.mean(eigenvalues)
        max_eigenvalue = np.max(eigenvalues)
        
        # Ordered phase: 特征值集中在小值附近
        # Edge of chaos: 特征值均匀分布
        # Chaotic phase: 特征值有大的拖尾
        
        # 使用比例判断
        proportion_near_zero = np.mean(eigenvalues < threshold * mean_eigenvalue)
        
        if proportion_near_zero > 0.8:
            return "Ordered"
        elif np.max(eigenvalues) > 10 * mean_eigenvalue:
            return "Chaotic"
        else:
            return "Edge of Chaos"
    
    @staticmethod
    def training_phase_trajectory(spectral_history):
        """
        追踪训练过程中的相位变化
        """
        phases = []
        for eigenvalues in spectral_history:
            phase = NetworkPhaseDetector.detect_phase(eigenvalues)
            phases.append(phase)
        
        # 统计相位变化
        phase_counts = {}
        for phase in phases:
            phase_counts[phase] = phase_counts.get(phase, 0) + 1
        
        return phases, phase_counts

2. 自适应学习率调整

class AdaptiveLRFromSpectrum:
    """
    根据 Hessian 谱自适应调整学习率
    """
    
    @staticmethod
    def compute_adaptive_lr(eigenvalues, target_cond=100):
        """
        基于谱条件数调整学习率
        
        目标:将条件数控制在 target_cond
        """
        lambda_max = np.max(eigenvalues)
        lambda_min = np.max(np.abs(eigenvalues[eigenvalues > 0]))
        
        current_cond = lambda_max / lambda_min if lambda_min > 0 else float('inf')
        
        # 如果条件数太大,减小学习率
        if current_cond > target_cond:
            lr_factor = target_cond / current_cond
            return lr_factor
        
        return 1.0
    
    @staticmethod
    def hessian_free_lr_estimate(lambda_max, damping=1e-3):
        """
        Hessian-Free 风格的学习率估计
        
        使用 1/(λ_max + damping) 作为局部曲率估计
        """
        lr = 1.0 / (lambda_max + damping)
        return lr

进阶:Free Probability Theory

自由乘积

在 RMT 中,随机矩阵的乘积对应自由概率论中的自由乘法。

class FreeProbability:
    """
    自由概率论基础
    """
    
    @staticmethod
    def free_convolution_mp(eigenvalues1, eigenvalues2):
        """
        自由卷积(MP分布)
        
        当两个随机矩阵独立时,它们的和的谱分布
        """
        # 简化的近似
        # 实际需要自由概率的 S-变换
        
        return eigenvalues1 + eigenvalues2  # 简化
    
    @staticmethod
    def wasserstein_distance(eigenvalues1, eigenvalues2):
        """
        谱分布之间的 Wasserstein 距离
        """
        # 排序
        lambda1_sorted = np.sort(eigenvalues1)
        lambda2_sorted = np.sort(eigenvalues2)
        
        # 插值计算
        n = len(lambda1_sorted)
        m = len(lambda2_sorted)
        
        # 计算 Wasserstein-1 距离
        diff = 0
        i = j = 0
        while i < n and j < m:
            diff += np.abs(lambda1_sorted[i] - lambda2_sorted[j])
            # 简单近似
            if i / n < j / m:
                i += 1
            else:
                j += 1
        
        return diff / max(n, m)

参考

Footnotes

  1. Bai, Z., & Silverstein, J. W. (2010). Spectral analysis of large dimensional random matrices.