You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

采用逐层预训练的深度去噪自编码器损失发散问题求助

解决深度自编码器预训练损失发散的方案

1. 归一化编码特征,控制输入范围

前一层编码后的ReLU输出未做归一化,数值范围会随层数加深逐渐扩大,直接导致MSE损失被放大。在传递data_in时,需将编码结果缩放到0-1区间:

with torch.no_grad():
    data_in = ae.encode(data_in)
    # 归一化到0-1区间,稳定后续层输入范围
    data_in = (data_in - data_in.min()) / (data_in.max() - data_in.min())

2. 优化中间层激活函数与参数初始化

  • 中间层解码器使用ReLU易出现神经元死亡问题,替换为LeakyReLU保证梯度流通;同时对线性层做He初始化(适配ReLU类激活函数),避免初始输出数值过大:
    修改Autoencoder类:
class Autoencoder(nn.Module):
  def __init__(self, input_dim, enc_dim, last_layer=True):
    super(Autoencoder, self).__init__()
    self.last_layer = last_layer
    self.input_dim = input_dim
    self.enc_dim = enc_dim
    self.encoder = nn.Linear(input_dim, enc_dim)
    self.decoder = nn.Linear(enc_dim, input_dim)

    # 替换为LeakyReLU,避免神经元死亡
    self.enc_activation = nn.LeakyReLU(0.2)
    if self.last_layer:
      self.dec_act = nn.Sigmoid()
    else:
      # 中间层解码器同步使用LeakyReLU
      self.dec_act = nn.LeakyReLU(0.2)
    
    # He初始化线性层参数,适配LeakyReLU
    nn.init.kaiming_normal_(self.encoder.weight, mode='fan_in', nonlinearity='leaky_relu')
    nn.init.zeros_(self.encoder.bias)
    nn.init.kaiming_normal_(self.decoder.weight, mode='fan_in', nonlinearity='leaky_relu')
    nn.init.zeros_(self.decoder.bias)

3. 针对后续层降低学习率

深层特征的学习需要更精细的参数更新,固定0.001的学习率易导致震荡发散。修改fit函数支持自定义学习率:

def fit(epochs, model, X_train, lr=0.001):
  print(X_train.shape)
  train_loader = torch.utils.data.DataLoader(X_train, batch_size=20, shuffle=True)
  criterion = nn.MSELoss()
  optimizer = torch.optim.Adam(model.parameters(), lr=lr)
  # 其余逻辑保持不变

预训练时逐层降低学习率:

data_in = X_train
hidden_layers = [512, 256, 128]
deep_ae = DeepAutoEncoder(X_train.shape[1], hidden_layers)
# 第一层用0.001,后续层用更小的0.0001
lrs = [0.001, 0.0001, 0.0001]
for idx, ae in enumerate(deep_ae.model):
  fit(5, ae, data_in, lr=lrs[idx])  # 增加训练轮数到5轮,确保收敛
  with torch.no_grad():
    data_in = ae.encode(data_in)
    data_in = (data_in - data_in.min()) / (data_in.max() - data_in.min())

4. 调整噪声强度,匹配输入特征范围

当前对所有层使用相同噪声强度,但中间层特征的数值范围和像素(0-1)差异大,噪声过强会破坏特征结构。修改add_noise逻辑,根据输入自身标准差动态调整噪声:

def add_noise(x, mean=0, std_scale=0.1):
    # 用输入自身的标准差乘以缩放因子作为噪声强度
    noise_std = x.std() * std_scale
    return x + torch.randn_like(x) * noise_std + mean

或者仅在第一层(像素数据)添加固定噪声,中间层预训练时暂时关闭噪声——去噪逻辑可在整个深度模型联合训练阶段再启用。

5. 增加预训练轮数,确保每层收敛

当前每层仅训练2轮,不足以让模型稳定收敛。将每层训练轮数增加到5-10轮,观察损失曲线,直到损失不再明显下降再进入下一层训练。


内容的提问来源于stack exchange,提问作者JayJona

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 20:45:34