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

手动实现RNN训练Loss异常:先持平后逐epoch上升

手动实现RNN训练时Loss异常问题

我参考仓库手动实现RNN,训练时最初每个epoch的Loss始终保持不变。已确认参数在更新,且梯度未出现极小值,单步迭代中Loss会下降,但整个epoch的总Loss反而上升。修改损失函数后解决了Loss持平问题,但现在每个epoch的Loss持续上升。

训练循环代码如下:

# Hyper-parameters
num_epochs = 1000

# Initialize a new network
params = init_rnn(hidden_size=hidden_size, vocab_size=vocab_size)

# Initialize hidden state as zeros
hidden_state = np.zeros((hidden_size, 1))

# Track loss
training_loss, validation_loss = [], []

def check_if_params_updated(old_params, new_params):
    # This function checks if two sets of parameters are different
    for old_param, new_param in zip(old_params, new_params):
        if not np.array_equal(old_param, new_param):
            return True  # Parameters have been updated
    return False  # Parameters have not been updated


# For each epoch
for i in range(num_epochs):
    
    # Track loss
    epoch_training_loss = 0
    epoch_validation_loss = 0
    
     # For each sentence in validation set
    for inputs, targets in val_loader:
        
        # One-hot encode input and target sequence
        inputs_one_hot = one_hot_encode_sequence(inputs, vocab_size)
        targets_one_hot = one_hot_encode_sequence(targets, vocab_size)
        
        # Re-initialize hidden state
        hidden_state = np.zeros_like(hidden_state)

        # Forward pass
        outputs, hidden_states = forward_pass(inputs_one_hot, hidden_state, params)

        # Backward pass
        loss, _ = backward_pass(inputs_one_hot, outputs, hidden_states, targets_one_hot, params)
        
        # Update loss
        epoch_validation_loss += loss
    
    # For each sentence in training set
    for inputs, targets in train_loader:
        
        # One-hot encode input and target sequence
        inputs_one_hot = one_hot_encode_sequence(inputs, vocab_size)
        targets_one_hot = one_hot_encode_sequence(targets, vocab_size)
        
        # Re-initialize hidden state
        hidden_state = np.zeros_like(hidden_state)

        # Forward pass
        outputs, hidden_states = forward_pass(inputs_one_hot, hidden_state, params)

        # Backward pass
        loss, grads = backward_pass(inputs_one_hot, outputs, hidden_states, targets_one_hot, params)
        print(inputs_one_hot.shape)
        
        if np.isnan(loss):
            raise ValueError('Gradients have vanished/exploded!')
        
        # Update parameters
        params = update_parameters(params, grads, lr=1e-3)
        
        # Update loss
        epoch_training_loss += loss
        
    # Save loss for plot
    training_loss.append(epoch_training_loss/len(training_set))
    validation_loss.append(epoch_validation_loss/len(validation_set))

    # Print loss every 100 epochs
    if i % 100 == 0:
        print(f'Epoch {i}, training loss: {training_loss[-1]}, validation loss: {validation_loss[-1]}')


# Get first sentence in test set
inputs, targets = test_set[1]

# One-hot encode input and target sequence
inputs_one_hot = one_hot_encode_sequence(inputs, vocab_size)
targets_one_hot = one_hot_encode_sequence(targets, vocab_size)

# Initialize hidden state as zeros
hidden_state = np.zeros((hidden_size, 1))

# Forward pass
outputs, hidden_states = forward_pass(inputs_one_hot, hidden_state, params)
output_sentence = [idx_to_word[np.argmax(output)] for output in outputs]
print('Input sentence:')
print(inputs)

print('\nTarget sequence:')
print(targets)

print('\nPredicted sequence:')
print([idx_to_word[np.argmax(output)] for output in outputs])

# Plot training and validation loss
epoch = np.arange(len(training_loss))
plt.figure()
plt.plot(epoch, training_loss, 'r', label='Training loss',)
plt.plot(epoch, validation_loss, 'b', label='Validation loss')
plt.legend()
plt.xlabel('Epoch'), plt.ylabel('NLL')
plt.show()

排查方向

  • 学习率过高:当前使用的lr=1e-3对RNN来说可能偏大,尝试降低至1e-4或更小,观察Loss变化。
  • 损失平均逻辑错误:若backward_pass返回的是单样本的损失总和,按样本数量len(training_set)平均并不合理,应改为按所有样本的总序列步数来平均,因为不同样本的序列长度可能不同。
  • 梯度更新方向错误:检查update_parameters函数,确认是执行参数 -= 学习率 * 梯度,如果写成了加号,会导致Loss持续上升。
  • 反向传播逻辑漏洞:重点检查隐藏层梯度的传递是否正确,比如tanh激活函数的导数计算是否准确,是否遗漏了前一时刻隐藏状态的梯度累积。
  • 数据加载问题:确认训练集每个epoch是否打乱,固定顺序的样本可能导致模型学习异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:24:53