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

如何使用PyTorch实现带参数约束的最大似然估计优化

PyTorch实现带正参数约束的正态分布最大似然估计

PyTorch原生优化器确实没有提供硬约束优化的内置接口,针对标准差sigma必须为正的要求,概率建模领域最通用、训练最稳定的方案是无约束重参数化,不需要修改优化器逻辑,也不会破坏梯度传播。


核心思路

不对参数本身做直接约束,而是把带约束的参数通过可逆变换映射到全实数域,直接优化无约束的变换后参数,每次计算损失时再把无约束参数映射回原参数空间即可。
针对必须取正值的参数,常用两个映射函数:

  • sigma = torch.exp(s_raw):变换完全可逆,正好匹配正态分布NLL里的对数项,梯度计算顺滑,是最常用的选择
  • sigma = torch.nn.functional.softplus(s_raw):映射曲线更平缓,不会因为无约束参数过大导致sigma数值爆炸,对大学习率的兼容性更好

注意:不推荐两种常见的低效方案:一是在损失里加违反约束的惩罚项,需要手动调惩罚权重,无法保证约束严格成立;二是优化步后直接把参数clamp到正数范围,会截断梯度,靠近参数边界时训练极易震荡、不收敛。


修改后的可运行代码

以下代码保留了你原本的初始值设置(初始sigma=5,初始mu=0.5),重参数化后可以用更大的学习率,收敛速度比原代码快很多:

##### 导入依赖
import numpy as np
import torch

##### 生成模拟样本
np.random.seed(3)
sample = np.random.normal(loc=5, scale=2, size=(1000, 1))

##### 初始化参数张量
X = torch.tensor(sample, dtype=torch.float64, requires_grad=False) # 观测样本
mu_ = torch.tensor(np.array([0.5]), dtype=torch.float64, requires_grad=True) # 均值可取任意实数,直接优化
# 初始化无约束参数s_raw,exp(s_raw)=5对应初始sigma=5,和原代码初始值一致
s_raw_ = torch.tensor(np.array([np.log(5)]), dtype=torch.float64, requires_grad=True)

##### 配置优化器
learning_rate = 0.01
OPT_OBJ = torch.optim.SGD([mu_, s_raw_], lr = learning_rate)

##### 优化循环
for t in range(2000):
    # 无约束参数映射到正实数域得到sigma
    sigma = torch.exp(s_raw_)
    # 计算负对数似然
    NLL = X.size()[0] * torch.log(sigma) + ((((X - mu_) / sigma).pow(2)) / 2).sum()
    
    OPT_OBJ.zero_grad()
    NLL.backward()

    if t % 200 == 0:
        print(f"负对数似然: {NLL.item():.2f}; 估计mu: {mu_.item():.3f}; 估计sigma: {sigma.item():.3f}")

    OPT_OBJ.step()

print(f"mu、sigma真实值: 5, 2")

运行后参数会稳定收敛到真实值附近,sigma全程保持正数,不会出现跑到负数导致log计算报错的问题。


快速验证用的简易方案

如果你只是做简单测试不想写重参数化,可以在每次OPT_OBJ.step()之后加一行参数截断:

OPT_OBJ.step()
s_.data.clamp_(min=1e-6) # 强制sigma不小于1e-6

这个方法实现成本极低,但训练稳定性差,只适合快速跑通逻辑的场景,正式训练还是推荐用重参数化方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:24:33