一、损失函数是啥?大白话讲明白
想象你在猜朋友的身高,想尽量猜准。每次猜完,裁判说:“偏了5厘米!”这个“偏了多少”就是损失函数的活儿——它算预测和真实的差距。模型靠这个反馈调整,直到猜得跟真的一样。
但不同任务,裁判的规矩不同。预测身高是比数字,识图是做选择题,找肿瘤是拼细节。我们挑几个常见任务,拆解损失函数怎么优化它们,配上完整代码直接上手!
二、回归任务:预测房价
任务:预测房价(单位:万元),数据比如[100, 110, 150],模型要贴近真实值。
均方误差 (Mean Squared Error, MSE):严格的精确教练
怎么打分?
MSE把误差平方后平均,小错小罚,大错大罚。
公式:
(
L
=
1
n
∑
(
y
−
y
^
)
2
)
( L = \frac{1}{n} \sum (y - \hat{y})^2 )
(L=n1∑(y−y^)2)
完整模型代码 (PyTorch):
import torch
import torch.nn as nn
# 定义简单线性回归模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1) # 输入1个特征,输出1个预测值
def forward(self, x):
return self.linear(x)
# MSE损失函数
def mse_loss(pred, target):
return torch.mean((pred - target) ** 2)
# 数据准备
X = torch.tensor([[1.0], [2.0], [3.0]]) # 假设输入特征(比如房子面积)
y = torch.tensor([[100.0], [110.0], [150.0]]) # 真实房价
# 初始化模型和优化器
model = LinearRegression()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练
for epoch in range(100):
pred = model(X) # 前向传播
loss = mse_loss(pred, y) # 计算MSE损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
if epoch % 20 == 0:
print(f"Epoch {epoch}, MSE Loss: {loss.item():.4f}")
# 测试
test_X = torch.tensor([[4.0]])
pred = model(test_X)
print(f"预测房价: {pred.item():.4f}")
生活比喻:你猜房价100万,实际110万,MSE说:“差10万,扣100分!”猜成50万,直接扣3600分,够狠。
任务优化:房价波动小(100-200万),MSE逼模型精确预测,避免大偏差。训练100次后,模型能根据面积合理猜价。
优点:精确,优化顺畅。
缺点:遇到怪价(比如1000万),会被拖垮。
三、 分类任务:猫狗图像分类
任务:判断图片是猫(1)还是狗(0),输出概率比如[0.9, 0.2, 0.8]。
交叉熵损失 (Cross-Entropy Loss):挑自信的刺
怎么打分?
看预测概率和真实标签差距,越自信错越扣得多。
公式:
(
L
=
−
1
n
∑
[
y
log
(
y
^
)
+
(
1
−
y
)
log
(
1
−
y
^
)
]
)
( L = -\frac{1}{n} \sum [y \log(\hat{y}) + (1 - y) \log(1 - \hat{y})] )
(L=−n1∑[ylog(y^)+(1−y)log(1−y^)])
完整模型代码:
import torch
import torch.nn as nn
# 定义简单分类模型
class SimpleClassifier(nn.Module):
def __init__(self):
super(SimpleClassifier, self).__init__()
self.fc = nn.Linear(2, 1) # 假设2个特征输入,输出1个概率
self.sigmoid = nn.Sigmoid()
def forward(self, x):
return self.sigmoid(self.fc(x))
# 数据准备
X = torch.tensor([[1.0, 2.0], [2.0, 1.0], [3.0, 3.0]]) # 假设特征(比如像素值)
y = torch.tensor([1, 0, 1]) # 真实标签:1=猫,0=狗
# 初始化模型和优化器
model = SimpleClassifier()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
loss_fn = nn.BCELoss() # 二分类交叉熵
# 训练
for epoch in range(100):
pred = model(X) # 前向传播,输出概率
loss = loss_fn(pred.squeeze(), y.float()) # 计算交叉熵损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
if epoch % 20 == 0:
print(f"Epoch {epoch}, Cross-Entropy Loss: {loss.item():.4f}")
# 测试
test_X = torch.tensor([[2.5, 2.5]])
pred = model(test_X)
print(f"预测猫的概率: {pred.item():.4f}")
生活比喻:你90%确定是猫,真的是猫,扣分少。90%说是猫,其实是狗,交叉熵说:“太自信了,重罚!”
任务优化:猫狗各一半,交叉熵推模型把猫概率拉到0.99,狗到0.01。训练后,模型能根据特征判断猫狗。
优点:分类王牌。
缺点:猫少狗多时,可能偏狗。
四、目标检测任务:找图里的车
任务:预测车的边界框坐标,比如真实[50, 50, 20, 20](x, y, 宽, 高),预测[52, 55, 22, 18]。
Huber损失:边界框的优化神器
怎么打分?
小误差平方,大误差线性,用delta控制切换。
完整模型代码:
import torch
import torch.nn as nn
# 定义边界框回归模型
class BoxRegressor(nn.Module):
def __init__(self):
super(BoxRegressor, self).__init__()
self.fc = nn.Linear(2, 4) # 假设2个特征输入,输出4个坐标
def forward(self, x):
return self.fc(x)
# Huber损失函数
def huber_loss(pred, target, delta=5.0):
error = pred - target
abs_error = torch.abs(error)
return torch.where(abs_error <= delta, 0.5 * error ** 2, delta * abs_error - 0.5 * delta ** 2).mean()
# 数据准备
X = torch.tensor([[1.0, 2.0], [2.0, 1.0]]) # 假设特征
y = torch.tensor([[50.0, 50.0, 20.0, 20.0], [60.0, 60.0, 25.0, 25.0]]) # 真实坐标
# 初始化模型和优化器
model = BoxRegressor()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练
for epoch in range(100):
pred = model(X) # 前向传播
loss = huber_loss(pred, y, delta=5.0) # 计算Huber损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
if epoch % 20 == 0:
print(f"Epoch {epoch}, Huber Loss: {loss.item():.4f}")
# 测试
test_X = torch.tensor([[1.5, 1.5]])
pred = model(test_X)
print(f"预测边界框: {pred.detach().numpy()}")
生活比喻:框偏2像素,Huber说:“小事,轻罚。”偏50像素,它说:“大了,但线性扣,不崩溃。”
任务优化:目标检测中,框得准,但偶尔有怪预测。设delta=5,Huber兼顾精度和稳定性,训练后能合理预测车框。
优点:适合坐标回归。
缺点:delta要调准。
五、分割任务:找医学图像里的肿瘤
任务:分割肿瘤,真实掩码[1, 0, 1](1=肿瘤),预测概率[0.9, 0.1, 0.8]。
Dice损失:重叠率的王牌
怎么打分?
算预测和真实的交集除以并集,关注重叠。
完整模型代码:
import torch
import torch.nn as nn
# 定义简单分割模型
class SegmentationNet(nn.Module):
def __init__(self):
super(SegmentationNet, self).__init__()
self.fc = nn.Linear(2, 3) # 假设2个特征输入,输出3个像素概率
self.sigmoid = nn.Sigmoid()
def forward(self, x):
return self.sigmoid(self.fc(x))
# Dice损失函数
def dice_loss(pred, target, smooth=1e-5):
intersection = (pred * target).sum()
union = pred.sum() + target.sum()
return 1 - (2. * intersection + smooth) / (union + smooth)
# 数据准备
X = torch.tensor([[1.0, 2.0]]) # 假设特征
y = torch.tensor([[1.0, 0.0, 1.0]]) # 真实掩码
# 初始化模型和优化器
model = SegmentationNet()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
# 训练
for epoch in range(100):
pred = model(X) # 前向传播
loss = dice_loss(pred, y) # 计算Dice损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
if epoch % 20 == 0:
print(f"Epoch {epoch}, Dice Loss: {loss.item():.4f}")
# 测试
test_X = torch.tensor([[1.5, 1.5]])
pred = model(test_X)
print(f"预测掩码概率: {pred.detach().numpy()}")
生活比喻:圈中80%肿瘤,Dice说:“不错,扣20分。”漏一半,它说:“50%罚,加油!”
任务优化:肿瘤占5%,背景95%,Dice只看重叠,不被背景干扰。训练后,模型能精准圈肿瘤。
优点:抗不平衡。
缺点:边界细节不敏感。
六、任务配对裁判
损失函数是模型的“教练”,各有绝活:
- MSE:严格,房价稳定时用。
- Huber:中庸,边界框稳准狠。
- 交叉熵:自信王,猫狗平衡时强。
- Dice:重叠专家,分割肿瘤无敌。
代码跑起来,调调参数(比如delta),任务效果蹭蹭涨。想优化啥具体项目,比如预测租金、找鸟?告诉我,我再细化!