BP神经网络中价值函数与损失函数的异同:从原理到实践指南

1次阅读
没有评论

共计 2458 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景痛点:为什么我们需要区分这两者?

刚开始接触 BP 神经网络时,我也经常搞混价值函数(Value Function)和损失函数(Loss Function)。直到有一次训练模型时,遇到了奇怪的震荡收敛问题——损失值忽高忽低,模型就是不肯稳定下来。后来才发现,原来在强化学习任务中错误地使用了均方误差(MSE)作为损失函数,而实际上应该用基于 TD-error 的价值函数。

BP 神经网络中价值函数与损失函数的异同:从原理到实践指南

这类混淆会导致:

  • 梯度消失或爆炸(尤其在使用 sigmoid 激活函数时)
  • 训练过程出现周期性震荡
  • 模型最终收敛到次优解

数学本质:它们到底在计算什么?

损失函数(监督学习)

衡量当前预测值与真实标签的差异,目标是最小化即时误差:

$$ L(\theta) = \frac{1}{N}\sum_{i=1}^N (y_i – f_\theta(x_i))^2 $$

经典例子包括:

  • 分类任务:交叉熵损失
  • 回归任务:均方误差(MSE)

价值函数(强化学习)

评估状态或动作的长期收益,目标是最大化未来回报的期望:

$$ V^\pi(s) = \mathbb{E}\pi[\sum | s_t = s] $$}^\infty \gamma^k r_{t+k

关键区别在于:

  • 时间维度:损失函数看单步,价值函数看多步
  • 优化方向:一个最小化,一个最大化

代码实战:PyTorch 中的不同实现

案例 1:分类任务的交叉熵损失

import torch.nn as nn

# 定义网络和损失函数
model = nn.Sequential(nn.Linear(784, 128),
    nn.ReLU(),
    nn.Linear(128, 10)
)
criterion = nn.CrossEntropyLoss()  # 内置自动 softmax

# 训练循环片段
for x, y in dataloader:
    outputs = model(x)
    loss = criterion(outputs, y)  # 计算当前 batch 损失
    loss.backward()               # 误差反向传播
    optimizer.step()              # 参数更新 

案例 2:DQN 中的价值函数

import torch
import numpy as np

class DQN(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.q_network = nn.Sequential(nn.Linear(state_dim, 64),
            nn.ReLU(),
            nn.Linear(64, action_dim)
        )

    def forward(self, state):
        return self.q_network(state)

# Bellman 方程实现
def compute_q_target(rewards, next_states, dones, gamma=0.99):
    with torch.no_grad():
        # 下个状态的最大 Q 值
        next_q_values = target_network(next_states).max(1)[0]
        # 考虑游戏是否结束
        q_targets = rewards + gamma * next_q_values * (1 - dones)
    return q_targets

# TD-error 计算
current_q_values = q_network(states).gather(1, actions)
loss = nn.MSELoss()(current_q_values, q_targets)  # 注意这里用 MSE 计算 TD-error

关键差异点:

  1. 损失函数直接比较输出与标签
  2. 价值函数需要通过 Bellman 方程迭代计算目标值

可视化诊断:TensorBoard 实战

安装 TensorBoard 后,可以同时监控两种函数:

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter()

# 在训练循环中添加
writer.add_scalar('Loss/train', loss.item(), global_step)
writer.add_scalar('Value/avg_q', current_q_values.mean(), global_step)

健康训练的特征:

  • 损失函数曲线应单调递减(可能有小幅波动)
  • 价值函数曲线应逐步上升并趋于稳定

三大常见错误及修复方案

错误 1:在 DQN 中直接使用原始损失函数

  • 现象:模型无法学习有效策略
  • 修复:改用 TD-error 计算(即预测 Q 值与目标 Q 值的差)

错误 2:价值函数学习率设置过高

  • 现象:训练过程剧烈震荡
  • 修复:降低学习率,或使用 target network 稳定目标值

错误 3:混淆最大化与最小化方向

  • 现象:模型性能越训越差
  • 修复:检查优化器设置,价值函数通常需要梯度上升

进阶思考:混合使用会怎样?

在 Actor-Critic 框架中:

  • Critic 使用价值函数评估状态价值
  • Actor 使用策略梯度更新参数

可以尝试的实验:

  1. 在 Critic 中同时加入 L2 正则化损失
  2. 比较纯价值函数与混合损失的效果
  3. 调整两种函数的权重比例
# 混合损失示例
def actor_critic_loss(states, actions, rewards, next_states):
    # 价值函数部分
    values = critic(states)
    next_values = critic(next_states)
    td_targets = rewards + gamma * next_values
    value_loss = F.mse_loss(values, td_targets)

    # 策略梯度部分
    log_probs = actor(states).log_prob(actions)
    policy_loss = -(log_probs * (td_targets - values.detach())).mean()

    return value_loss + policy_loss  # 可以添加权重系数 

通过这样的对比实践,相信你能更清晰地把握两者的适用场景。当遇到训练异常时,第一反应就应该是检查:我当前该用价值函数还是损失函数?这个习惯能帮你避开很多坑。

正文完
 0
评论(没有评论)