最大似然估计
最大似然估计(Maximum Likelihood Estimation, MLE)是机器学习中最核心的参数估计方法——几乎所有损失函数都是 MLE 的变体。二元交叉熵 BCE = 伯努利分布的负对数似然,用于逻辑回归和二分类 Sigmoid 输出层;多分类交叉熵 CE = Categorical 分布的负对数似然,GPT/BERT 的预训练目标都是最大化下一个 token 的对数似然(即最小化 CE);MSE 损失 = 假设高斯噪声下的负对数似然,线性回归、图像回归模型的默认选择。MAP(最大后验)= MLE + 正则化:L2 正则对应高斯先验 → 岭回归,L1 正则对应拉普拉斯先验 → Lasso。更进一步,EM 算法在高斯混合模型(GMM)中交替执行 E 步和 M 步来最大化不完全数据的似然;VAE 最大化证据下界 ELBO,本质也是似然估计的推广。理解 MLE 就掌握了“为什么用这个损失函数”以及“正则化项从哪来”的本质原因。
一、核心思想
似然 vs 概率:
概率 P(数据|参数):参数已知,数据是变化的
似然 L(参数|数据):数据已知,参数是变化的
MLE 原则:选择使观测数据出现概率最大的参数
θ̂_MLE = argmax_θ L(θ) = argmax_θ P(数据|θ)
对数似然(实际使用的形式):
假设 N 个样本独立同分布 (i.i.d.):
L(θ) = P(x₁|θ) × P(x₂|θ) × ... × P(xₙ|θ) = Πᵢ P(xᵢ|θ)
ln L(θ) = Σᵢ ln P(xᵢ|θ)(乘积→求和,数值稳定)
最大化似然 ↔ 最大化对数似然 ↔ 最小化负对数似然(NLL)
概率 P(数据|参数):参数已知,数据是变化的
似然 L(参数|数据):数据已知,参数是变化的
MLE 原则:选择使观测数据出现概率最大的参数
θ̂_MLE = argmax_θ L(θ) = argmax_θ P(数据|θ)
对数似然(实际使用的形式):
假设 N 个样本独立同分布 (i.i.d.):
L(θ) = P(x₁|θ) × P(x₂|θ) × ... × P(xₙ|θ) = Πᵢ P(xᵢ|θ)
ln L(θ) = Σᵢ ln P(xᵢ|θ)(乘积→求和,数值稳定)
最大化似然 ↔ 最大化对数似然 ↔ 最小化负对数似然(NLL)
二、伯努利分布的 MLE → 推导出交叉熵
场景:抛一枚不公平硬币 10 次,观察到 7 次正面 3 次反面。求正面概率 p。
步骤 1:写出似然函数
每次抛掷独立,Xi ~ Bernoulli(p)
L(p) = p⁷ × (1-p)³
步骤 2:对数似然
ln L(p) = 7·ln(p) + 3·ln(1-p)
步骤 3:求导并令为零
d(ln L)/dp = 7/p - 3/(1-p) = 0
7(1-p) = 3p
7 - 7p = 3p
7 = 10p
p̂ = 7/10 = 0.7
步骤 4:验证是最大值(二阶导 < 0)
d²(ln L)/dp² = -7/p² - 3/(1-p)² = -7/0.49 - 3/0.09 = -14.29 - 33.33 = -47.62 < 0 ✓
一般结论:伯努利分布的 MLE 就是 p̂ = 正面次数/总次数
步骤 1:写出似然函数
每次抛掷独立,Xi ~ Bernoulli(p)
L(p) = p⁷ × (1-p)³
步骤 2:对数似然
ln L(p) = 7·ln(p) + 3·ln(1-p)
步骤 3:求导并令为零
d(ln L)/dp = 7/p - 3/(1-p) = 0
7(1-p) = 3p
7 - 7p = 3p
7 = 10p
p̂ = 7/10 = 0.7
步骤 4:验证是最大值(二阶导 < 0)
d²(ln L)/dp² = -7/p² - 3/(1-p)² = -7/0.49 - 3/0.09 = -14.29 - 33.33 = -47.62 < 0 ✓
一般结论:伯努利分布的 MLE 就是 p̂ = 正面次数/总次数
从 MLE 推导出二元交叉熵损失:
N 个二分类样本,标签 yᵢ ∈ {0,1},模型输出 p(yᵢ=1|xᵢ) = σ(zᵢ) = p̂ᵢ
似然:L = Πᵢ p̂ᵢ^yᵢ × (1-p̂ᵢ)^(1-yᵢ)
负对数似然(NLL):
NLL = -Σᵢ [yᵢ ln(p̂ᵢ) + (1-yᵢ) ln(1-p̂ᵢ)]
这就是二元交叉熵!
数值示例(3 个样本):
y = [1, 0, 1], p̂ = [0.9, 0.2, 0.7]
NLL = -[1×ln(0.9) + 0×ln(0.2) + 0×ln(0.8) + 1×ln(0.2) + 1×ln(0.7) + 0×ln(0.3)]
= -[ln(0.9) + ln(0.8) + ln(0.7)]
= -[(-0.105) + (-0.223) + (-0.357)]
= -(-0.685) = 0.685
平均 BCE = 0.685/3 = 0.228
N 个二分类样本,标签 yᵢ ∈ {0,1},模型输出 p(yᵢ=1|xᵢ) = σ(zᵢ) = p̂ᵢ
似然:L = Πᵢ p̂ᵢ^yᵢ × (1-p̂ᵢ)^(1-yᵢ)
负对数似然(NLL):
NLL = -Σᵢ [yᵢ ln(p̂ᵢ) + (1-yᵢ) ln(1-p̂ᵢ)]
这就是二元交叉熵!
数值示例(3 个样本):
y = [1, 0, 1], p̂ = [0.9, 0.2, 0.7]
NLL = -[1×ln(0.9) + 0×ln(0.2) + 0×ln(0.8) + 1×ln(0.2) + 1×ln(0.7) + 0×ln(0.3)]
= -[ln(0.9) + ln(0.8) + ln(0.7)]
= -[(-0.105) + (-0.223) + (-0.357)]
= -(-0.685) = 0.685
平均 BCE = 0.685/3 = 0.228
三、高斯分布的 MLE → 推导出 MSE 损失
假设:回归目标 y 在模型预测 ŷ 附近服从高斯分布
y ~ N(ŷ, σ²),即 P(y|x,θ) = (1/(σ√(2π))) exp(-(y-ŷ)²/(2σ²))
步骤 1:N 个样本的对数似然
ln L = Σᵢ ln P(yᵢ|xᵢ,θ)
= Σᵢ [-½ln(2πσ²) - (yᵢ-ŷᵢ)²/(2σ²)]
= -N/2 × ln(2πσ²) - (1/(2σ²)) Σᵢ(yᵢ-ŷᵢ)²
步骤 2:对 ŷ 求 MLE
σ² 是常数,只看 ŷ 相关的部分:
最大化 ln L ↔ 最小化 Σᵢ(yᵢ-ŷᵢ)²
结论:在高斯噪声假设下,MLE 等价于最小化 MSE!
额外推导——对 σ² 的 MLE:
∂ln L/∂σ² = -N/(2σ²) + Σ(yᵢ-ŷᵢ)²/(2σ⁴) = 0
σ̂² = Σ(yᵢ-ŷᵢ)²/N = MSE
即:残差的方差就是高斯噪声 σ² 的 MLE 估计
y ~ N(ŷ, σ²),即 P(y|x,θ) = (1/(σ√(2π))) exp(-(y-ŷ)²/(2σ²))
步骤 1:N 个样本的对数似然
ln L = Σᵢ ln P(yᵢ|xᵢ,θ)
= Σᵢ [-½ln(2πσ²) - (yᵢ-ŷᵢ)²/(2σ²)]
= -N/2 × ln(2πσ²) - (1/(2σ²)) Σᵢ(yᵢ-ŷᵢ)²
步骤 2:对 ŷ 求 MLE
σ² 是常数,只看 ŷ 相关的部分:
最大化 ln L ↔ 最小化 Σᵢ(yᵢ-ŷᵢ)²
结论:在高斯噪声假设下,MLE 等价于最小化 MSE!
额外推导——对 σ² 的 MLE:
∂ln L/∂σ² = -N/(2σ²) + Σ(yᵢ-ŷᵢ)²/(2σ⁴) = 0
σ̂² = Σ(yᵢ-ŷᵢ)²/N = MSE
即:残差的方差就是高斯噪声 σ² 的 MLE 估计
完整数值示例——简单线性回归的 MLE:
模型:ŷ = wx + b,假设 y ~ N(wx+b, σ²)
5 个数据点(房屋面积 → 价格):
MLE 等价于最小化 MSE → 用正规方程求解:
w = [NΣxᵢyᵢ - ΣxᵢΣyᵢ] / [NΣxᵢ² - (Σxᵢ)²]
Σx = 410, Σy = 1200, Σxy = 104600, Σx² = 37400
N = 5
w = (5×104600 - 410×1200) / (5×37400 - 410²)
= (523000 - 492000) / (187000 - 168100)
= 31000 / 18900 = 1.640
b = (Σy - w×Σx) / N = (1200 - 1.640×410) / 5
= (1200 - 672.4) / 5 = 527.6/5 = 105.52
模型:ŷ = 1.640x + 105.52
验证:ŷ(50) = 82+105.52 = 187.52(实际150,误差37.52)
ŷ(100) = 164+105.52 = 269.52(实际290,误差-20.48)
残差方差 σ̂² = MSE = Σ(yᵢ-ŷᵢ)²/5
模型:ŷ = wx + b,假设 y ~ N(wx+b, σ²)
5 个数据点(房屋面积 → 价格):
| 面积 x(m²) | 价格 y(万) |
|---|---|
| 50 | 150 |
| 60 | 180 |
| 80 | 230 |
| 100 | 290 |
| 120 | 350 |
w = [NΣxᵢyᵢ - ΣxᵢΣyᵢ] / [NΣxᵢ² - (Σxᵢ)²]
Σx = 410, Σy = 1200, Σxy = 104600, Σx² = 37400
N = 5
w = (5×104600 - 410×1200) / (5×37400 - 410²)
= (523000 - 492000) / (187000 - 168100)
= 31000 / 18900 = 1.640
b = (Σy - w×Σx) / N = (1200 - 1.640×410) / 5
= (1200 - 672.4) / 5 = 527.6/5 = 105.52
模型:ŷ = 1.640x + 105.52
验证:ŷ(50) = 82+105.52 = 187.52(实际150,误差37.52)
ŷ(100) = 164+105.52 = 269.52(实际290,误差-20.48)
残差方差 σ̂² = MSE = Σ(yᵢ-ŷᵢ)²/5
四、多分类的 MLE → 推导出多分类交叉熵
K 分类,标签独热编码 y = (y₁,...,yₖ),Softmax 输出 p̂ = (p̂₁,...,p̂ₖ)
单个样本的似然:P(y|x) = Πₖ p̂ₖ^yₖ
单个样本的负对数似然:
-ln P(y|x) = -Σₖ yₖ ln(p̂ₖ)
由于 y 是独热编码,只有真实类别 c 的 yc=1:
-ln P(y|x) = -ln(p̂c)
10 分类 MNIST 具体计算:
真实标签:y = [0,0,0,1,0,0,0,0,0,0](数字 3)
Softmax 输出 p̂ = [0.01, 0.02, 0.05, 0.72, 0.04, 0.03, 0.02, 0.06, 0.03, 0.02]
交叉熵 = -ln(0.72) = 0.329
若模型更不确定:p̂₃ = 0.30
交叉熵 = -ln(0.30) = 1.204(损失增大 3.7 倍)
若模型预测错误类别最大:p̂₃ = 0.05
交叉熵 = -ln(0.05) = 2.996(损失非常大→强烈纠正方向)
单个样本的似然:P(y|x) = Πₖ p̂ₖ^yₖ
单个样本的负对数似然:
-ln P(y|x) = -Σₖ yₖ ln(p̂ₖ)
由于 y 是独热编码,只有真实类别 c 的 yc=1:
-ln P(y|x) = -ln(p̂c)
10 分类 MNIST 具体计算:
真实标签:y = [0,0,0,1,0,0,0,0,0,0](数字 3)
Softmax 输出 p̂ = [0.01, 0.02, 0.05, 0.72, 0.04, 0.03, 0.02, 0.06, 0.03, 0.02]
交叉熵 = -ln(0.72) = 0.329
若模型更不确定:p̂₃ = 0.30
交叉熵 = -ln(0.30) = 1.204(损失增大 3.7 倍)
若模型预测错误类别最大:p̂₃ = 0.05
交叉熵 = -ln(0.05) = 2.996(损失非常大→强烈纠正方向)
五、MAP 估计——加入先验 → 正则化
最大后验估计(MAP):
θ̂_MAP = argmax_θ P(θ|数据) = argmax_θ P(数据|θ) × P(θ)
ln L_MAP = ln P(数据|θ) + ln P(θ)
MLE:只看数据(可能过拟合)
MAP:数据 + 先验信念(带正则化)
θ̂_MAP = argmax_θ P(θ|数据) = argmax_θ P(数据|θ) × P(θ)
ln L_MAP = ln P(数据|θ) + ln P(θ)
MLE:只看数据(可能过拟合)
MAP:数据 + 先验信念(带正则化)
高斯先验 → L2 正则化的推导:
假设权重的先验:w ~ N(0, τ²)(权重应该在 0 附近不要太大)
ln P(w) = -½ Σⱼ wⱼ²/τ² + const
MAP 目标 = ln P(数据|w) + ln P(w)
= -½σ⁻² Σᵢ(yᵢ-ŷᵢ)² - ½τ⁻² Σⱼ wⱼ² + const
最小化负的 MAP:
= (1/(2σ²)) Σᵢ(yᵢ-ŷᵢ)² + (1/(2τ²)) Σⱼ wⱼ²
= MSE + λ × Σwⱼ²
其中 λ = σ²/τ²
结论:L2 正则化 = 高斯先验的 MAP 估计!
τ 越小 → 先验越强(认为权重应越小)→ λ 越大 → 正则化越强
类似地:拉普拉斯先验 → L1 正则化
w ~ Laplace(0, b),P(w) ∝ exp(-|w|/b)
ln P(w) = -Σ|wⱼ|/b + const
MAP 目标 → MSE + λ × Σ|wⱼ|(L1 正则化→稀疏解)
假设权重的先验:w ~ N(0, τ²)(权重应该在 0 附近不要太大)
ln P(w) = -½ Σⱼ wⱼ²/τ² + const
MAP 目标 = ln P(数据|w) + ln P(w)
= -½σ⁻² Σᵢ(yᵢ-ŷᵢ)² - ½τ⁻² Σⱼ wⱼ² + const
最小化负的 MAP:
= (1/(2σ²)) Σᵢ(yᵢ-ŷᵢ)² + (1/(2τ²)) Σⱼ wⱼ²
= MSE + λ × Σwⱼ²
其中 λ = σ²/τ²
结论:L2 正则化 = 高斯先验的 MAP 估计!
τ 越小 → 先验越强(认为权重应越小)→ λ 越大 → 正则化越强
类似地:拉普拉斯先验 → L1 正则化
w ~ Laplace(0, b),P(w) ∝ exp(-|w|/b)
ln P(w) = -Σ|wⱼ|/b + const
MAP 目标 → MSE + λ × Σ|wⱼ|(L1 正则化→稀疏解)
六、EM 算法与 MLE
场景:高斯混合模型(GMM)的参数估计
数据点 = [1.2, 1.8, 2.1, 5.3, 5.8, 6.2](看起来有两群)
模型:2 个高斯混合,参数 π₁,μ₁,σ₁,π₂,μ₂,σ₂
直接 MLE 无法求解(不知道每个点属于哪个群)→ 用 EM 算法
初始化:π₁=0.5, μ₁=2, σ₁=1, π₂=0.5, μ₂=5, σ₂=1
E 步(Expectation):计算每个点属于每个高斯的概率
γ₁(xᵢ) = π₁ N(xᵢ|μ₁,σ₁) / [π₁ N(xᵢ|μ₁,σ₁) + π₂ N(xᵢ|μ₂,σ₂)]
对 x=1.2:
N(1.2|2,1) = (1/√2π)exp(-(1.2-2)²/2) = 0.3989×exp(-0.32) = 0.290
N(1.2|5,1) = 0.3989×exp(-7.22) = 0.000296
γ₁(1.2) = 0.5×0.290 / (0.5×0.290+0.5×0.000296) = 0.145/0.14515 = 0.998
→ 几乎确定属于第 1 组
对 x=5.3:
N(5.3|2,1) = 0.3989×exp(-5.445) = 0.00173
N(5.3|5,1) = 0.3989×exp(-0.045) = 0.3814
γ₁(5.3) = 0.5×0.00173 / (0.5×0.00173+0.5×0.3814) = 0.0045
→ 几乎确定属于第 2 组
M 步(Maximization):用加权 MLE 更新参数
μ₁_new = Σ γ₁(xᵢ)xᵢ / Σ γ₁(xᵢ) ≈ (0.998×1.2+0.99×1.8+0.97×2.1+...) / (0.998+0.99+...)
→ μ₁ ≈ 1.7,μ₂ ≈ 5.77
→ 不断迭代直到收敛
数据点 = [1.2, 1.8, 2.1, 5.3, 5.8, 6.2](看起来有两群)
模型:2 个高斯混合,参数 π₁,μ₁,σ₁,π₂,μ₂,σ₂
直接 MLE 无法求解(不知道每个点属于哪个群)→ 用 EM 算法
初始化:π₁=0.5, μ₁=2, σ₁=1, π₂=0.5, μ₂=5, σ₂=1
E 步(Expectation):计算每个点属于每个高斯的概率
γ₁(xᵢ) = π₁ N(xᵢ|μ₁,σ₁) / [π₁ N(xᵢ|μ₁,σ₁) + π₂ N(xᵢ|μ₂,σ₂)]
对 x=1.2:
N(1.2|2,1) = (1/√2π)exp(-(1.2-2)²/2) = 0.3989×exp(-0.32) = 0.290
N(1.2|5,1) = 0.3989×exp(-7.22) = 0.000296
γ₁(1.2) = 0.5×0.290 / (0.5×0.290+0.5×0.000296) = 0.145/0.14515 = 0.998
→ 几乎确定属于第 1 组
对 x=5.3:
N(5.3|2,1) = 0.3989×exp(-5.445) = 0.00173
N(5.3|5,1) = 0.3989×exp(-0.045) = 0.3814
γ₁(5.3) = 0.5×0.00173 / (0.5×0.00173+0.5×0.3814) = 0.0045
→ 几乎确定属于第 2 组
M 步(Maximization):用加权 MLE 更新参数
μ₁_new = Σ γ₁(xᵢ)xᵢ / Σ γ₁(xᵢ) ≈ (0.998×1.2+0.99×1.8+0.97×2.1+...) / (0.998+0.99+...)
→ μ₁ ≈ 1.7,μ₂ ≈ 5.77
→ 不断迭代直到收敛
七、MLE 总结对照表
| 分布假设 | MLE 推导结果 | 等价的损失函数 | AI 应用 |
|---|---|---|---|
| y ~ Bernoulli(p̂) | -Σ[y ln p̂ + (1-y)ln(1-p̂)] | 二元交叉熵 (BCE) | 二分类(逻辑回归、Sigmoid 输出) |
| y ~ Categorical(p̂) | -Σ yₖ ln p̂ₖ | 多分类交叉熵 (CE) | 多分类(Softmax 输出) |
| y ~ N(ŷ, σ²) | Σ(y-ŷ)² | MSE / L2 损失 | 回归任务 |
| y ~ Laplace(ŷ, b) | Σ|y-ŷ| | MAE / L1 损失 | 鲁棒回归(对异常值不敏感) |
| w ~ N(0, τ²) 先验 | MLE + λΣwⱼ² | L2 正则化(权重衰减) | 防过拟合 |
| w ~ Laplace(0, b) 先验 | MLE + λΣ|wⱼ| | L1 正则化(稀疏化) | 特征选择 |
八、代码验证(C# / Rust)
C#(.NET 10)
// dotnet run 即可执行
// ===== 伯努利 MLE =====
int[] data = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 };
double pMle = data.Average();
Console.WriteLine($"伯努利 MLE: p̂ = {pMle}");
foreach (double p in new[] { 0.5, 0.6, 0.7, 0.8 })
{
double L = Math.Pow(p, 7) * Math.Pow(1 - p, 3);
Console.WriteLine($" L(p={p}) = {L:F6}");
}
// ===== 二元交叉熵 = 负对数似然 =====
double[] y = { 1, 0, 1 };
double[] pHat = { 0.9, 0.2, 0.7 };
double bce = 0;
for (int i = 0; i < 3; i++)
bce -= y[i] * Math.Log(pHat[i]) + (1 - y[i]) * Math.Log(1 - pHat[i]);
Console.WriteLine($"\n总 BCE = {bce:F4}, 平均 = {bce / 3:F4}");
// ===== 线性回归 MLE (正规方程) =====
double[] X = { 50, 60, 80, 100, 120 };
double[] Y = { 150, 180, 230, 290, 350 };
int N = 5;
double sumX = 0, sumY = 0, sumXX = 0, sumXY = 0;
for (int i = 0; i < N; i++)
{ sumX += X[i]; sumY += Y[i]; sumXX += X[i] * X[i]; sumXY += X[i] * Y[i]; }
double w = (N * sumXY - sumX * sumY) / (N * sumXX - sumX * sumX);
double b = (sumY - w * sumX) / N;
Console.WriteLine($"\n线性回归 MLE: w={w:F3}, b={b:F2}");
Console.Write("预测: ");
foreach (double xi in X) Console.Write($"{w * xi + b:F1} ");
Console.WriteLine();
// ===== 高斯 MLE 的 σ² =====
double sigma2 = 0;
for (int i = 0; i < N; i++) sigma2 += Math.Pow(Y[i] - (w * X[i] + b), 2);
sigma2 /= N;
Console.WriteLine($"噪声方差 σ̂² = {sigma2:F2}");
// ===== MAP = MLE + L2 (岭回归) =====
double lam = 10;
double a11 = sumXX + lam, a12 = sumX, a22 = N + lam;
double det = a11 * a22 - a12 * a12;
double wR = (a22 * sumXY - a12 * sumY) / det;
double bR = (-a12 * sumXY + a11 * sumY) / det;
Console.WriteLine($"\n岭回归(λ={lam}): w={wR:F3}, b={bR:F2}");
// ===== 多分类交叉熵 =====
double[] pSoftmax = { 0.01, 0.02, 0.05, 0.72, 0.04, 0.03, 0.02, 0.06, 0.03, 0.02 };
double ce = -Math.Log(pSoftmax[3]);
Console.WriteLine($"\n多分类 CE = {ce:F4}");
Rust
fn main() {
// ===== 伯努利 MLE =====
let data = [1, 1, 1, 1, 1, 1, 1, 0, 0, 0_i32];
let p_mle = data.iter().sum::<i32>() as f64 / data.len() as f64;
println!("伯努利 MLE: p̂ = {p_mle}");
for p in [0.5_f64, 0.6, 0.7, 0.8] {
let l = p.powi(7) * (1.0 - p).powi(3);
println!(" L(p={p}) = {l:.6}");
}
// ===== 二元交叉熵 =====
let y = [1.0, 0.0, 1.0_f64];
let p_hat = [0.9, 0.2, 0.7_f64];
let bce: f64 = (0..3)
.map(|i| -(y[i] * p_hat[i].ln() + (1.0 - y[i]) * (1.0 - p_hat[i]).ln()))
.sum();
println!("\n总 BCE = {bce:.4}, 平均 = {:.4}", bce / 3.0);
// ===== 线性回归 MLE =====
let xd = [50.0, 60.0, 80.0, 100.0, 120.0_f64];
let yd = [150.0, 180.0, 230.0, 290.0, 350.0_f64];
let n = 5.0_f64;
let (sx, sy, sxx, sxy) = xd.iter().zip(&yd)
.fold((0.0, 0.0, 0.0, 0.0), |(sx, sy, sxx, sxy), (&xi, &yi)|
(sx + xi, sy + yi, sxx + xi * xi, sxy + xi * yi));
let w = (n.mul_add(sxy, -(sx * sy))) / (n.mul_add(sxx, -(sx * sx)));
let b = (sy - w * sx) / n;
println!("\n线性回归 MLE: w={w:.3}, b={b:.2}");
print!("预测: ");
for xi in &xd { print!("{:.1} ", w.mul_add(*xi, b)); }
println!();
// 高斯 MLE σ²
let sigma2: f64 = xd.iter().zip(&yd)
.map(|(&xi, &yi)| (yi - w.mul_add(xi, b)).powi(2))
.sum::<f64>() / n;
println!("噪声方差 σ̂² = {sigma2:.2}");
// ===== Ridge 回归 =====
let lam = 10.0_f64;
let (a11, a12, a22) = (sxx + lam, sx, n + lam);
let det = a11 * a22 - a12 * a12;
let w_r = (a22 * sxy - a12 * sy) / det;
let b_r = (-a12 * sxy + a11 * sy) / det;
println!("\n岭回归(λ={lam}): w={w_r:.3}, b={b_r:.2}");
// ===== 多分类交叉熵 =====
let p_sm = [0.01, 0.02, 0.05, 0.72, 0.04, 0.03, 0.02, 0.06, 0.03, 0.02_f64];
let ce = -p_sm[3].ln();
println!("\n多分类 CE = {ce:.4}");
}