gpt4 book ai didi

wolfram-mathematica - 如何编译计算 Hessian 矩阵的函数?

转载 作者:行者123 更新时间:2023-12-04 00:16:17 26 4
gpt4 key购买 nike

我正在查看如何编译计算对数似然的 Hessian 矩阵的函数,以便它可以有效地用于不同的参数集。

这是一个例子。

假设我们有一个计算逻辑模型的对数似然函数,其中 y 是向量,x 是矩阵。 beta 是一个参数向量。

 pLike[y_, x_, beta_] :=
Module[
{xbeta, logDen},
xbeta = x.beta;
logDen = Log[1.0 + Exp[xbeta]];
Total[y*xbeta - logDen]
]

给定以下数据,我们可以按如下方式使用它

In[1]:= beta = {0.5, -1.0, 1.0};

In[2]:= xmat =
Table[Flatten[{1,
RandomVariate[NormalDistribution[0.0, 1.0], {2}]}], {500}];

In[3]:= xbeta = xmat.beta;

In[4]:= prob = Exp[xbeta]/(1.0 + Exp[xbeta]);

In[5]:= y = Map[RandomVariate[BernoulliDistribution[#]] &, prob] ;

In[6]:= Tally[y]

Out[6]= {{1, 313}, {0, 187}}

In[9]:= pLike[y, xmat, beta]

Out[9]= -272.721

我们可以把它的hessian写成如下

 hessian[y_, x_, z_] :=
Module[{},
D[pLike[y, x, z], {z, 2}]
]


In[10]:= z = {z1, z2, z3}

Out[10]= {z1, z2, z3}

In[11]:= AbsoluteTiming[hess = hessian[y, xmat, z];]

Out[11]= {0.1248040, Null}

In[12]:= AbsoluteTiming[
Table[hess /. {z1 -> 0.0, z2 -> -0.5, z3 -> 0.8}, {100}];]

Out[12]= {14.3524600, Null}

为了效率起见,我可以将原来的似然函数编译如下

pLikeC = Compile[{{y, _Real, 1}, {x, _Real, 2}, {beta, _Real, 1}},
Module[
{xbeta, logDen},
xbeta = x.beta;
logDen = Log[1.0 + Exp[xbeta]];
Total[y*xbeta - logDen]
],
CompilationTarget -> "C", Parallelization -> True,
RuntimeAttributes -> {Listable}
];

产生与 pLike 相同的答案

In[10]:= pLikeC[y, xmat, beta]

Out[10]= -272.721

我正在寻找一种简单的方法来获得类似的 hessian 函数的编译版本,因为我有兴趣多次评估它。

最佳答案

Leonid 已经打败了我,但我还是会发布我的想法,只是为了笑。

这里的主要问题是编译适用于数值函数,而 D 需要符号。因此,诀窍是首先使用与您打算使用的特定矩阵大小所需的相同数量的变量定义 pLike 函数,例如,

pLike[{y1, y2}, {{x1, x2, x3}, {x12, x22, x32}}, {z1, z2, z3}]

enter image description here

黑森州:

D[pLike[{y1, y2}, {{x1, x2, x3}, {x12, x22, x32}}, {z1, z2, z3}], {{z1, z2, z3}, 2}]

enter image description here

这个函数应该是可编译的,因为它只依赖于数值。

要推广各种向量,可以构建这样的东西:

Block[{ny = 2, nx = 3, z1, z2, z3},
hessian[
Table[ToExpression["y" <> ToString[i] <> "_"], {i, ny}],
Table[ToExpression["xr" <> ToString[i] <> "c" <> ToString[j] <> "_"],
{i, ny}, {j, nx}], {z1_, z2_, z3_}
] =
D[
pLike[
Table[ToExpression["y" <> ToString[i]], {i, ny}],
Table[ToExpression["xr" <> ToString[i] <> "c" <> ToString[j]],
{i, ny}, {j, nx}], {z1, z2, z3}
],
{{z1, z2, z3}, 2}
]
]

enter image description here

这当然可以很容易地推广到变量 nx 和 ny。


现在是编译部分。这是一段难看的代码,由上面的代码和编译代码组成,适合可变的 y 大小。比起我自己,我更喜欢 ruebenko 的代码。

ClearAll[hessianCompiled];
Block[{z1, z2, z3},
hessianCompiled[yd_] :=
(hessian[
Table[ToExpression["y" <> ToString[i] <> "_"], {i, yd}],
Table[ToExpression["xr" <> ToString[i]<>"c"<>ToString[j] <>"_"],{i,yd},{j,3}],
{z1_, z2_, z3_}
] =
D[
pLike[
Table[ToExpression["y" <> ToString[i]], {i, yd}],
Table[ToExpression["xr" <> ToString[i] <> "c" <> ToString[j]], {i,yd},{j,3}],
{z1, z2, z3}
], {{z1, z2, z3}, 2}
];
Compile[{{y, _Real, 1}, {x, _Real, 2}, {z, _Real, 1}},
hessian[Table[y[[i]], {i, yd}], Table[x[[i, j]], {i, yd}, {j, 3}],
Table[z[[i]], {i, 3}]]]// Evaluate] // Quiet
)
]

hessianCompiled[500][y, xmat, beta] // Timing

{1.497, {{-90.19295669, -15.80180276, 6.448357845},
{-15.80180276, -80.41058154, -26.33982586},
{6.448357845, -26.33982586, -72.92978931}}}

ruebenko's version (including my edits):

(cf = mkCHessian[500, 3]; cf[y, xmat, beta]) // Timing

{1.029, {{-90.19295669, -15.80180276, 6.448357845},
{-15.80180276, -80.41058154, -26.33982586},
{6.448357845, -26.33982586, -72.92978931}}}

请注意,这两个测试都包括编译时间。自行运行计算:

h = hessianCompiled[500];
Do[h[y, xmat, beta], {100}]; // Timing
Do[cf[y, xmat, beta], {100}]; // Timing

(* timing for 100 hessians:

==> {0.063, Null}

==> {0.062, Null}
*)

关于wolfram-mathematica - 如何编译计算 Hessian 矩阵的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8204784/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com