概念
nn.MSELoss() 是 Mean Squared Error Loss(均方误差损失)的缩写,它的核心作用是计算模型预测值和真实标签之间的平均平方差
详见 链接
公式
\text{MSE} = \frac{1}{n} \sum_{i=1}^n (y_i - \hat{y}_i)^2
其中:
y_i 是真实标签值
\hat{y}_i 是模型预测值
n 是样本数量
它主要用于回归任务(比如预测房价、温度、销量等连续值),而不是分类任务。
语法
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
参数
nn.MSELoss() 有两个重要参数,决定了损失的计算方式:
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
size_average |
bool | True(已废弃) | 是否对损失取平均 |
reduce |
bool | True(已废弃) | 是否聚合损失(平均/求和) |
reduction |
str | ‘mean’ | 损失聚合方式:<br>- ‘mean’:取平均值(默认)<br>- ‘sum’:求和<br>- ‘none’:返回每个样本的损失 |
例子
import torch
import torch.nn as nn
# 1. 定义MSE损失函数实例
mse_loss = nn.MSELoss()
# 2. 模拟模型预测值和真实标签(注意:形状要匹配)
# 预测值(比如模型输出)
preds = torch.tensor([1.0, 2.0, 3.0, 4.0])
# 真实标签
targets = torch.tensor([1.5, 2.5, 3.5, 4.5])
# 3. 计算MSE损失
loss = mse_loss(preds, targets)
# 打印结果
print(f"预测值: {preds}")
print(f"真实值: {targets}")
print(f"MSE损失值: {loss.item()}") # item() 取出张量中的数值
输出结果:
预测值: tensor([1., 2., 3., 4.])
真实值: tensor([1.5000, 2.5000, 3.5000, 4.5000])
MSE损失值: 0.25
手动验证计算过程:
(1-1.5)² + (2-2.5)² + (3-3.5)² + (4-4.5)² = 0.25 + 0.25 + 0.25 + 0.25 = 1.0
平均后:1.0 / 4 = 0.25 → 和代码计算结果一致
不同 reduction 参数的示例:
# 1. reduction='sum':求和(不平均)
mse_sum = nn.MSELoss(reduction='sum')
loss_sum = mse_sum(preds, targets)
print(f"\n求和模式损失值: {loss_sum.item()}") # 输出 1.0
# 2. reduction='none':返回每个样本的损失
mse_none = nn.MSELoss(reduction='none')
loss_none = mse_none(preds, targets)
print(f"每个样本的损失值: {loss_none}") # 输出 tensor([0.2500, 0.2500, 0.2500, 0.2500])
快捷连接神经网络中查看损失
import torch
import torch.nn as nn
class GELU(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return 0.5 * x * (1 + torch.tanh(
torch.sqrt(torch.tensor(2.0 / torch.pi)) * (x + 0.044715 * torch.pow(x, 3))
))
class ExampleDeepNeuralNetwork(nn.Module):
def __init__(self, layer_sizes, use_shortcut):
super().__init__()
self.use_shortcut = use_shortcut
# 添加5个层
self.layers = nn.ModuleList([
nn.Sequential(nn.Linear(layer_sizes[0], layer_sizes[1]), GELU()),
nn.Sequential(nn.Linear(layer_sizes[1], layer_sizes[2]), GELU()),
nn.Sequential(nn.Linear(layer_sizes[2], layer_sizes[3]), GELU()),
nn.Sequential(nn.Linear(layer_sizes[3], layer_sizes[4]), GELU()),
nn.Sequential(nn.Linear(layer_sizes[4], layer_sizes[5]), GELU()),
])
def forward(self, x):
for layer in self.layers:
# 计算当前层的输出
layer_output = layer(x)
# 检查是否可以使用快捷连接,如果use_shortcut为True就使用快捷连接
if self.use_shortcut and x.shape == layer_output.shape:
x = x+layer_output
else:
x = layer_output
return x
"""
前4层为接受包含3个输入值的样本,并返回3个输出值。
最后1层会返回1个输出值:
"""
layer_sizes = [3, 3, 3, 3, 3, 1]
# 定义输入张量
sample_input = torch.tensor([[1., 0., -1.]])
# 指定随机种子,初始化权重,复现结果
torch.manual_seed(123)
# 初始化没有快捷连接的神经网络。
model_without_shortcut = ExampleDeepNeuralNetwork(layer_sizes, use_shortcut=False)
def print_gradients(model, x):
"""
用于在模型的反向传播过程中计算梯度的函数
:param model: 模型
:param x: 输入张量
:return:
"""
# 前向传播
output = model(x)
# 用户指定目标,为简化处理,这里设为0。
target = torch.tensor([[0.]])
loss = nn.MSELoss()
# 计算损失。计算模型输出与用户指定目标的接近程度
loss = loss(output, target)
# 反向传播,计算模型中每一层的损失梯度
loss.backward()
# 通过model.named_parameters()迭代权重参数
for name, param in model.named_parameters():
if 'weight' in name:
# 打印梯度值的平均绝对值,以得到每一层的单一梯度值,更容易比较层与层之间的梯度
print(f"{name} 平均梯度: {param.grad.abs().mean().item()}")
print("\n\n不包含跳跃连接的模型----------")
print_gradients(model_without_shortcut, sample_input)
# 实例化一个包含跳跃连接的模型
torch.manual_seed(123)
model_with_shortcut = ExampleDeepNeuralNetwork(
layer_sizes, use_shortcut=True
)
print("\n\n包含跳跃连接的模型----------")
print_gradients(model_with_shortcut, sample_input)
在完整模型训练中的使用
下面是一个结合模型、优化器和 MSE 损失的完整训练示例(回归任务):
import torch.optim as optim
# 定义一个简单的回归模型
class RegressionModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(1, 1) # 单输入单输出的线性回归
def forward(self, x):
return self.linear(x)
# 初始化模型、损失函数、优化器
model = RegressionModel()
criterion = nn.MSELoss() # 损失函数
optimizer = optim.SGD(model.parameters(), lr=0.01) # 优化器
# 模拟训练数据(y = 2x + 1,加一点噪声)
x_train = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_train = torch.tensor([[3.1], [5.0], [7.2], [9.1]]) # 真实标签:2*1+1=3, 2*2+1=5 等
# 单步训练过程
for epoch in range(100):
# 前向传播
outputs = model(x_train)
loss = criterion(outputs, y_train)
# 反向传播 + 优化
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新参数
# 每10轮打印一次损失
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/100], Loss: {loss.item():.4f}')
# 测试模型
x_test = torch.tensor([[5.0]])
y_pred = model(x_test)
print(f"\n测试输入 x=5.0,预测值: {y_pred.item():.2f}") # 接近 11.0(2*5+1)
总结
nn.MSELoss()是计算均方误差的损失函数,核心用于回归任务,计算预测值与真实值的平均平方差;reduction参数是核心:’mean’(默认,平均)、’sum’(求和)、’none’(保留每个样本损失);- 使用时需保证预测值和真实标签的形状完全匹配,且在训练中要配合
optimizer.zero_grad()、loss.backward()、optimizer.step()完成参数更新。