为 drake::MathematicalProgram 提供自定义渐变
Provide custom gradient to drake::MathematicalProgram
Drake 有一个接口,你可以给它一个通用函数作为约束,它可以自动设置非线性约束数学程序(只要它支持 AutoDiff)。我有一种情况,我的约束不支持 AutoDiff(约束函数进行线搜索以逼近某个函数的最大值),但我有一个约束梯度的封闭形式表达式。在我的例子中,数学计算结果很难在这个函数上找到一个点,但一旦你有了那个点,就很容易围绕它进行线性化。
我知道许多优化库允许您在可用时提供自己的分析梯度;您也可以使用 Drake 的 MathematicalProgram 来做到这一点吗?我在 MathematicalProgram class 文档中找不到它的提及。
感谢任何帮助!
这绝对是可能的,但我承认我们还没有提供让它变得漂亮的辅助函数。请让我知道 if/how 这有帮助;我将计划对其进行整理并将其添加为我们可以在 drake 中引用的示例或代码片段。
考虑以下代码:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
print(x[0].value())
print(x[0].derivatives())
return x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
当我们以这种方式向 MathematicalProgram
注册成本或约束时,我们允许它可以通过 x
作为 float
或 x
是一个 AutoDiffXd
——它只是 Eigen's AutoDiffScalar 的包装(具有 double
类型的动态分配派生)。上面的代码片段大致向您展示了它是如何工作的——每个标量值都有一个与之相关联的(偏)导数向量。在进入该函数时,系统会向您传递 x
,其中 x
的 derivatives
设置为 dx/dx
(将为 1 或零)。
你的工作是 return 一个值,称之为 y
,值设置为你的 cost/constraint 的值,导数设置为 dy/dx
.通常,所有这一切都会神奇地发生在你身上。但听起来你得自己做。
这是一个非常简单的代码片段,我希望它能帮助您入门:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
y = AutoDiffXd(2*x[0].value(), 2*x[0].derivatives())
return [y]
return 2*x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
让我知道?
Drake 有一个接口,你可以给它一个通用函数作为约束,它可以自动设置非线性约束数学程序(只要它支持 AutoDiff)。我有一种情况,我的约束不支持 AutoDiff(约束函数进行线搜索以逼近某个函数的最大值),但我有一个约束梯度的封闭形式表达式。在我的例子中,数学计算结果很难在这个函数上找到一个点,但一旦你有了那个点,就很容易围绕它进行线性化。
我知道许多优化库允许您在可用时提供自己的分析梯度;您也可以使用 Drake 的 MathematicalProgram 来做到这一点吗?我在 MathematicalProgram class 文档中找不到它的提及。
感谢任何帮助!
这绝对是可能的,但我承认我们还没有提供让它变得漂亮的辅助函数。请让我知道 if/how 这有帮助;我将计划对其进行整理并将其添加为我们可以在 drake 中引用的示例或代码片段。
考虑以下代码:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
print(x[0].value())
print(x[0].derivatives())
return x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
当我们以这种方式向 MathematicalProgram
注册成本或约束时,我们允许它可以通过 x
作为 float
或 x
是一个 AutoDiffXd
——它只是 Eigen's AutoDiffScalar 的包装(具有 double
类型的动态分配派生)。上面的代码片段大致向您展示了它是如何工作的——每个标量值都有一个与之相关联的(偏)导数向量。在进入该函数时,系统会向您传递 x
,其中 x
的 derivatives
设置为 dx/dx
(将为 1 或零)。
你的工作是 return 一个值,称之为 y
,值设置为你的 cost/constraint 的值,导数设置为 dy/dx
.通常,所有这一切都会神奇地发生在你身上。但听起来你得自己做。
这是一个非常简单的代码片段,我希望它能帮助您入门:
from pydrake.all import AutoDiffXd, MathematicalProgram, Solve
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')
def cost(x):
return (x[0]-1.)*(x[0]-1.)
def constraint(x):
if isinstance(x[0], AutoDiffXd):
y = AutoDiffXd(2*x[0].value(), 2*x[0].derivatives())
return [y]
return 2*x
cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)
让我知道?