【问题标题】:Autoencoder very weird loss spikes when training训练时自动编码器非常奇怪的损失峰值
【发布时间】:2021-08-26 07:37:55
【问题描述】:

简介:

我正在尝试让自动编码器在 32 个时间步长内学习 32 个特征,如位置、速度等 => 32x32“图像”。 为此,我只是制作了一个简单的线性模型,在每一层都使用 Tanh 函数以及对称的编码器和解码器。

在训练期间,我添加了自己的 dropout 版本,仅用于输入。 (以后我会使用nn.Dropout


问题:

我的损失函数“sqrt(MSE)”以不规则的时间间隔出现大峰值。 (Batch_Size = 6000)

Loss Graph

我尝试过的:(小测试,最大 1000 个 epoch)

  1. clip_grad_norm_(model.parameters(), max_norm = 0.5)
  2. 试过ReLuELU
  3. 激活函数Batch = N / 2(我想做N但是我的gpu内存不够)。
  4. 不添加噪声或丢失(我认为噪声/丢失有助于但不能解决问题)。
  5. 去除 MSE 损失的平方根。

有人可以向我解释为什么会发生这种情况以及如何解决它吗?

def rand_bin_array(p_zeros, shape):
    size = 1
    for e in shape:
        size *= e
    arr = np.ones(size)
    arr[:int(size * p_zeros)] = 0
    np.random.shuffle(arr)
    arr = arr.reshape(shape)
    return arr

class Autoencoder_Liniar(nn.Module):
  def __init__(self):
    super().__init__()
    self.encoder = nn.Sequential(
        nn.Linear(1024, 921),
        nn.Tanh(),
        nn.Linear(921, 736),
        nn.Tanh(),
        nn.Linear(736, 515),
        nn.Tanh(),
        nn.Linear(515, 309),
        nn.Tanh(),
        nn.Linear(309, 128),
        nn.Tanh(),
        nn.Linear(128, 64),
        nn.Tanh(),
    )

    self.decoder = nn.Sequential(
        nn.Linear(64, 128),
        nn.Tanh(),
        nn.Linear(128, 309),
        nn.Tanh(),
        nn.Linear(309, 515),
        nn.Tanh(),
        nn.Linear(515, 736),
        nn.Tanh(),
        nn.Linear(736, 921),
        nn.Tanh(),
        nn.Linear(921, 1024),
        nn.Tanh()
    )
  
  def forward(self, x):
    enc = self.encoder(x)
    dec = self.decoder(enc)
    return dec

torch.manual_seed(0)
model = Autoencoder_Liniar().cuda()

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

random.seed(0)
epochs = 10000
batch_size = 6000
test_b_size = 5000

train_losses = []
test_losses = []
for i in range(epochs):
  avg_loss = 0
  random.shuffle(train_data)
  for b in range(train_nr // batch_size):
    start = b * batch_size
    data = torch.FloatTensor(train_data[start : start + batch_size]).cuda()

    noise_power = max(0.8 - i/epochs, 0.1)
    noise = torch.FloatTensor(rand_bin_array(noise_power, data.shape)).cuda()
    y_pred = model(data * noise)
    loss = torch.sqrt(criterion(y_pred, data))

    optimizer.zero_grad()
    loss.backward()
    #torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=0.5)
    optimizer.step()

    avg_loss += loss.item()
    if b % 20 == 0:
      print(f'EPOCH: {i} BATCH: {b} LOSS: {loss.item()}')
  
  train_losses.append(avg_loss / (train_nr // batch_size))

  with torch.no_grad():
    avg_loss = 0
    for b in range(test_nr // test_b_size):
        start = b * test_b_size
        data = np.array(test_data[start : start + test_b_size])
        data = torch.FloatTensor(data).cuda()

        y_pred = model(data)
        loss = torch.sqrt(criterion(y_pred, data))
        avg_loss += loss.item()

  test_losses.append(avg_loss / (test_nr // test_b_size))

添加了获取gradient's norm over epochs graph 的代码(无噪音/丢失)

Gradient clipped at 0.3

    total_norm = 0
    for p in model.parameters():
        param_norm = p.grad.detach().data.norm(2)
        total_norm += param_norm.item() ** 2
    total_norm = total_norm ** 0.5
    avg_grad += total_norm
    
    optimizer.step()

【问题讨论】:

  • 你为什么要解决你的损失?有可能是因为在你 sqrt 之后,你的损失在 y_pred = y_true 处变得不可微分,导致这个奇怪的尖峰。
  • 刚才我试过不带sqrt,还是一样。
  • 你能画出不同时期的梯度范数吗?通过这种方式,您将了解如何正确剪辑渐变。随意选择使用max_norm=0.5 没有意义...
  • @Ivan 抱歉让您久等了(我的电脑很慢)。我已经添加了渐变图。
  • 如果你看一下梯度图上的那些尖峰:我的想法是你可能应该尝试以较低的值进行剪辑(至少低于 0.5)。

标签: python pytorch autoencoder loss


【解决方案1】:

答案是用clip_grad_norm_ 剪裁渐变,但值较低。

该值是在对 epochs 图进行梯度范数后确定的。

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 1970-01-01
    • 2020-02-25
    • 2020-06-13
    • 2017-06-26
    • 2017-12-15
    • 2018-05-29
    • 1970-01-01
    • 2022-10-18
    相关资源
    最近更新 更多