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

如何在Python中拟合p维二次多项式并精准计算梯度与海森矩阵?

优雅计算多项式回归的梯度与海森矩阵方法

你完全可以利用model.coef_中的精确系数直接推导梯度和海森矩阵,无需依赖易受浮点误差影响的有限差分。以下是几种可行方案:

方案一:基于scikit-learn手动解析系数计算

scikit-learn的PolynomialFeatures支持获取特征对应的多项式项名称,结合model.coef_就能精准计算梯度和海森矩阵:

代码示例

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
import numpy as np

# 生成示例数据
np.random.seed(42)
X = np.random.rand(100, 2)  # 2维输入
y = 2 + 3*X[:,0] + 5*X[:,1] + 1.2*X[:,0]**2 + 0.8*X[:,0]*X[:,1] + 2.1*X[:,1]**2 + np.random.randn(100)*0.1

# 拟合多项式回归
poly = PolynomialFeatures(degree=2, include_bias=False)
Xp = poly.fit_transform(X)
model = LinearRegression()
model.fit(Xp, y)

# 获取多项式特征项与对应系数
feature_names = poly.get_feature_names_out(['x0', 'x1'])
coef = model.coef_

def compute_gradient(x):
    """计算给定点x的梯度"""
    grad = np.zeros_like(x)
    for name, c in zip(feature_names, coef):
        # 解析多项式项的变量与指数
        var_counts = {}
        for term in name.split(' '):
            if '^' in term:
                var, exp = term.split('^')
                var_counts[var] = int(exp)
            else:
                var_counts[term] = var_counts.get(term, 0) + 1
        # 计算每个变量的偏导贡献
        for var, exp in var_counts.items():
            idx = int(var[-1])
            if exp == 0:
                continue
            # 偏导系数:c * 指数
            deriv_c = c * exp
            # 偏导项的乘积部分
            deriv_term = 1.0
            for v, e in var_counts.items():
                if v == var:
                    deriv_term *= x[int(v[-1])] ** (e-1) if e > 1 else 1
                else:
                    deriv_term *= x[int(v[-1])] ** e
            grad[idx] += deriv_c * deriv_term
    return grad

def compute_hessian(x):
    """计算给定点x的海森矩阵"""
    p = len(x)
    hess = np.zeros((p, p))
    for name, c in zip(feature_names, coef):
        var_counts = {}
        for term in name.split(' '):
            if '^' in term:
                var, exp = term.split('^')
                var_counts[var] = int(exp)
            else:
                var_counts[term] = var_counts.get(term, 0) + 1
        # 1. 同一变量的二阶偏导
        for var, exp in var_counts.items():
            if exp >= 2:
                idx = int(var[-1])
                deriv_c = c * exp * (exp-1)
                deriv_term = 1.0
                for v, e in var_counts.items():
                    if v == var:
                        deriv_term *= x[int(v[-1])] ** (e-2) if e > 2 else 1
                    else:
                        deriv_term *= x[int(v[-1])] ** e
                hess[idx, idx] += deriv_c * deriv_term
        # 2. 不同变量的混合偏导
        vars_list = list(var_counts.keys())
        if len(vars_list) >= 2:
            for i in range(len(vars_list)):
                for j in range(i+1, len(vars_list)):
                    var1, var2 = vars_list[i], vars_list[j]
                    exp1, exp2 = var_counts[var1], var_counts[var2]
                    idx1, idx2 = int(var1[-1]), int(var2[-1])
                    deriv_c = c * exp1 * exp2
                    deriv_term = 1.0
                    for v, e in var_counts.items():
                        if v == var1:
                            deriv_term *= x[int(v[-1])] ** (e-1) if e > 1 else 1
                        elif v == var2:
                            deriv_term *= x[int(v[-1])] ** (e-1) if e > 1 else 1
                        else:
                            deriv_term *= x[int(v[-1])] ** e
                    hess[idx1, idx2] += deriv_c * deriv_term
                    hess[idx2, idx1] += deriv_c * deriv_term
    return hess

# 测试计算
x_test = np.array([0.5, 0.5])
print("梯度:", compute_gradient(x_test))
print("海森矩阵:\n", compute_hessian(x_test))

方案二:使用PyTorch自动求导(更简洁)

PyTorch的自动求导机制可以直接对拟合的多项式模型计算梯度和海森矩阵,无需手动推导偏导公式:

代码示例

import torch
import torch.nn as nn
import numpy as np
from sklearn.preprocessing import PolynomialFeatures

# 生成示例数据
np.random.seed(42)
X_np = np.random.rand(100, 2).astype(np.float32)
y_np = 2 + 3*X_np[:,0] + 5*X_np[:,1] + 1.2*X_np[:,0]**2 + 0.8*X_np[:,0]*X_np[:,1] + 2.1*X_np[:,1]**2 + np.random.randn(100)*0.1
y_np = y_np.reshape(-1, 1).astype(np.float32)

# 转换为PyTorch张量
X = torch.tensor(X_np)
y = torch.tensor(y_np)

# 定义多项式模型
class PolynomialModel(nn.Module):
    def __init__(self, degree=2, input_dim=2):
        super().__init__()
        self.poly = PolynomialFeatures(degree=degree, include_bias=False)
        self.linear = nn.Linear(self.poly.fit_transform(np.zeros((1, input_dim))).shape[1], 1)
    
    def forward(self, x):
        x_poly = torch.tensor(self.poly.transform(x.detach().numpy()), dtype=torch.float32)
        return self.linear(x_poly)

# 拟合模型
model = PolynomialModel(degree=2, input_dim=2)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

for epoch in range(1000):
    optimizer.zero_grad()
    outputs = model(X)
    loss = criterion(outputs, y)
    loss.backward()
    optimizer.step()

# 计算梯度与海森矩阵
x_test = torch.tensor([[0.5, 0.5]], requires_grad=True)
y_pred = model(x_test)

# 梯度
y_pred.backward(create_graph=True)
gradient = x_test.grad.clone()
print("梯度:", gradient.numpy())

# 海森矩阵
hessian = []
for i in range(x_test.shape[1]):
    grad_i = gradient[0, i]
    x_test.grad.zero_()
    grad_i.backward(retain_graph=True)
    hessian_row = x_test.grad.clone().numpy()[0]
    hessian.append(hessian_row)
hessian = np.array(hessian)
print("海森矩阵:\n", hessian)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:24:52