【问题标题】:Cost function using absolute value and division by decision variables使用绝对值和除以决策变量的成本函数
【发布时间】:2020-05-13 20:58:25
【问题描述】:

我正在尝试在 pydrake 数学程序中实现成本函数,但是每当我尝试除以决策变量并使用 abs() 时都会遇到问题。我尝试实现的简化版本如下,我尝试仅包含我认为可能相关的内容。

    T = 50
    na = 3
    nq = 5

    prog = MathematicalProgram()
    h = prog.NewContinuousVariables(rows=T, cols=1, name='h')
    qd = prog.NewContinuousVariables(rows=T+1, cols=nq, name='qd')
    d = prog.NewContinuousVariables(1, name='d')
    u = prog.NewContinuousVariables(rows=T, cols=na, name='u')

    def energyCost(vars):
       assert vars.size == 2*na + 1 + 1
       split_at = [na, 2*na, 2*na + 1]
       qd, u, h, d = np.split(vars, split_at)
       return np.abs([qd.dot(u)*h/d])

    for t in range(T):
       vars = np.concatenate((qd[t, 2:], u[t,:], h[t], d))
       prog.AddCost(energyCost, vars=vars)

    initial_guess = np.empty(prog.num_vars())
    solver = SnoptSolver()
    result = solver.Solve(prog, initial_guess)

我得到的错误是:

RuntimeError                              Traceback (most recent call last)
<ipython-input-55-111da18cdce0> in <module>()
     22 initial_guess = np.empty(prog.num_vars())
     23 solver = SnoptSolver()
---> 24 result = solver.Solve(prog, initial_guess)
     25 print(f'Solution found? {result.is_success()}.')

RuntimeError: PyFunctionCost: Output must be of .ndim = 0 (scalar) and .size = 1. Got .ndim = 2 and .size = 1 instead.

据我所知,问题在于输出的尺寸,但我不确定如何进行。我花了很长时间试图解决这个问题,但收效甚微。我也尝试将 np.abs 更改为 pydrake.math.abs,但随后出现以下错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-56-c0c2f008616b> in <module>()
     22 initial_guess = np.empty(prog.num_vars())
     23 solver = SnoptSolver()
---> 24 result = solver.Solve(prog, initial_guess)
     25 print(f'Solution found? {result.is_success()}.')

<ipython-input-56-c0c2f008616b> in energyCost(vars)
     14     split_at = [na, 2*na, 2*na + 1]
     15     qd, u, h, d = np.split(vars, split_at)
---> 16     return pydrake.math.abs([qd.dot(u)*h/d])
     17 
     18 for t in range(T):

TypeError: abs(): incompatible function arguments. The following argument types are supported:
    1. (arg0: float) -> float
    2. (arg0: pydrake.autodiffutils.AutoDiffXd) -> pydrake.autodiffutils.AutoDiffXd
    3. (arg0: pydrake.symbolic.Expression) -> pydrake.symbolic.Expression

Invoked with: [array([<AutoDiffXd 1.691961398933386e-257 nderiv=8>], dtype=object)]

任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: python drake


    【解决方案1】:

    顺便说一句,正如 Tobia 所提到的,在成本函数中划分决策变量可能会有问题。有两种方法可以避免该问题

    1. 对您的决策变量施加一个界限,并且 0 不包含在此界限中。例如,假设您要优化
      min f(x) / y
      
      如果您可以施加y &gt; 1 的界限,那么SNOPT 将不会尝试使用y=0,从而避免除零问题。
    2. 一个技巧是引入另一个变量作为除法的结果,然后最小化这个变量。

      比如说你要优化

      min f(x) / y
      

      您可以引入一个松弛变量z = f(x) / y。并将这个问题表述为

      min z
      s.t f(x) - y * z = 0
      

    【讨论】:

      【解决方案2】:

      一些观察:

      • 您尝试使用的成本函数类型不需要强制使用 python 函数。您可以直接说(即使这样会引发其他错误)prog.AddCost(np.abs([qd[t, 2:].dot(u[t,:])*h[t]/d]))

      • prog.AddCost 的参数必须是 Drake 标量表达式。因此,请确保您的 numpy 矩阵乘法返回一个标量。在上述情况下,它们返回一个 (1,1) numpy 数组。

      • 要最小化绝对值,您需要一些比这更复杂的东西。在当前形式中,您传递的是不可微的目标函数:求解器不太喜欢那样。假设您要最小化abs(x)。优化的一个标准技巧是添加一个额外的(松弛)变量,比如s,并添加约束s &gt;= xs &gt;= -x,然后最小化s 本身。所有这些约束和这个目标都是可微的和线性的。

      • 关于目标除以优化变量。只要有可能,你就应该避免这种情况。例如(我有 90% 的把握)像 SNOPT 或 IPOPT 这样的求解器将初始猜测设置为零,如果您不提供的话。这意味着,如果您不提供自定义初始猜测,则在首次评估约束时,求解器将除以零并且会崩溃。

      【讨论】:

      • 以 Tobia 的回答为基础:np.abs([1.]) 它将是一个大小为 1 的向量 (.shape == (1,), .ndim == 1)。如果你改为使用np.abs(1.)(没有方括号),它应该是一个标量(.shape == (), .ndim == 0)。
      猜你喜欢
      • 1970-01-01
      • 2015-02-04
      • 1970-01-01
      • 2019-01-10
      • 1970-01-01
      • 2014-02-25
      • 2020-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多