你可以在使用cvxpy库中的solve函数时,通过访问每次迭代的成本来实现吗?

huangapple go评论64阅读模式
英文:

How can I access the cost at each iteration when using the solve function in the cvxpy library?

问题

如果您想使用cvxpy库解决凸优化问题,只能计算并返回最后一次迭代的成本,而在过程中会打印其他中间成本和相关值。请看下面的代码示例,该示例来自cvxpy库的官方文档:

import cvxpy

x = cvxpy.Variable(2)
objective = cvxpy.Minimize(x[0] + cvxpy.norm(x, 1))
constraints = [x >= 2]
problem = cvxpy.Problem(objective, constraints)

problem.solve(solver=cvxpy.ECOS, verbose=True)

以及打印的结果:

ECOS 2.0.10 - (C) embotech GmbH, Zurich Switzerland, 2012-15. Web: www.embotech.com/ECOS

It     pcost       dcost      gap   pres   dres    k/t    mu     step   sigma     IR    |   BT
 0  +6.667e-01  +7.067e-01  +6e+00  6e-01  1e-02  1e+00  9e-01    ---    ---    1  1  - |  -  - 
 1  +3.500e+00  +3.925e+00  +1e+00  3e-01  4e-03  8e-01  2e-01  0.9890  2e-01   1  1  1 |  0  0
 2  +5.716e+00  +5.825e+00  +2e-01  6e-02  8e-04  2e-01  4e-02  0.9091  8e-02   1  1  1 |  0  0
 3  +5.997e+00  +5.998e+00  +3e-03  7e-04  1e-05  2e-03  5e-04  0.9881  1e-04   1  1  1 |  0  0
 4  +6.000e+00  +6.000e+00  +3e-05  8e-06  1e-07  3e-05  5e-06  0.9890  1e-04   1  1  1 |  0  0
 5  +6.000e+00  +6.000e+00  +3e-07  9e-08  1e-09  3e-07  6e-08  0.9890  1e-04   1  0  0 |  0  0
 6  +6.000e+00  +6.000e+00  +4e-09  1e-09  1e-11  3e-09  6e-10  0.9890  1e-04   1  0  0 |  0  0

OPTIMAL (within feastol=9.9e-10, reltol=6.2e-10, abstol=3.7e-09).
Runtime: 0.000061 seconds.

我们只能使用objective.valueproblem.value来评估最后一次迭代的最终成本值。

英文:

If you want to solve a convex optimization problem using the cvxpy library, only the last iteration cost can be calculated and returned, while other intermediate costs and related values are printed during the process. Take a look at the following code, which is obtained from the cvxpy library itself:

import cvxpy

x = cvxpy.Variable(2)
objective = cvxpy.Minimize(x[0] + cvxpy.norm(x, 1))
constraints = [x >= 2]
problem = cvxpy.Problem(objective, constraints)

problem.solve(solver=cvxpy.ECOS, verbose=True)

And the printed result:

ECOS 2.0.10 - (C) embotech GmbH, Zurich Switzerland, 2012-15. Web: www.embotech.com/ECOS

It     pcost       dcost      gap   pres   dres    k/t    mu     step   sigma     IR    |   BT
 0  +6.667e-01  +7.067e-01  +6e+00  6e-01  1e-02  1e+00  9e-01    ---    ---    1  1  - |  -  - 
 1  +3.500e+00  +3.925e+00  +1e+00  3e-01  4e-03  8e-01  2e-01  0.9890  2e-01   1  1  1 |  0  0
 2  +5.716e+00  +5.825e+00  +2e-01  6e-02  8e-04  2e-01  4e-02  0.9091  8e-02   1  1  1 |  0  0
 3  +5.997e+00  +5.998e+00  +3e-03  7e-04  1e-05  2e-03  5e-04  0.9881  1e-04   1  1  1 |  0  0
 4  +6.000e+00  +6.000e+00  +3e-05  8e-06  1e-07  3e-05  5e-06  0.9890  1e-04   1  1  1 |  0  0
 5  +6.000e+00  +6.000e+00  +3e-07  9e-08  1e-09  3e-07  6e-08  0.9890  1e-04   1  0  0 |  0  0
 6  +6.000e+00  +6.000e+00  +4e-09  1e-09  1e-11  3e-09  6e-10  0.9890  1e-04   1  0  0 |  0  0

OPTIMAL (within feastol=9.9e-10, reltol=6.2e-10, abstol=3.7e-09).
Runtime: 0.000061 seconds.

We can only evaluate the final cost value of the last iteration using the objective.value or problem.value.

There is a similar question here but I don't need the other variables, I only need the costs which are printed by the library itself.

答案1

得分: 0

以下是翻译好的部分:

在对 `cvxpy` 内部进行广泛搜索后,我发现它利用了一个底层库(比如 [ecos](https://github.com/embotech/ecos))来进行求解,但不幸的是,它缺乏有关中间迭代的任何数据。我还确认打印的日志是由底层库生成的,而不是由 `cvxpy` 本身生成的。随后,我对 `ecos` 库的调查显示它也不存储中间信息。相反,它维护一个简单的 `info` 结构,在每次迭代后更新。

最后,我决定捕获输出流,然后使用正则表达式解析结果以提取所需信息。我知道这种方法有些棘手和脆弱,但它有效地解决了我的问题:

    import re

    import cvxpy
    import wurlitzer
    
    # 凸问题定义 ...
    
    with wurlitzer.pipes() as (out, err):
        problem.solve(solver=cvxpy.ECOS, verbose=True)
    
    matches = re.findall(
        "^\s*(?P<iteration>\d+)\s+(?P<pcost>\S+)\s+.*$",
        out.getvalue(),
        re.MULTILINE
    )
    
    data = []
    for iteration, pcost in matches:
        data.append(float(pcost))
    
    print(data)

我得到了:

    [0.6667, 3.5, 5.716, 5.997, 6.0, 6.0, 6.0]

我只需要 `pcost` 值,但请随时改进正则表达式模式以适应您的特定需求。

我不得不使用 [wurlitzer](https://pypi.org/project/wurlitzer/),因为表格是在 C 级别打印的,常见的方法,如 `contextlib.redirect_stdout`,无法使用。
英文:

After an extensive search through cvxpy internals, I discovered that it utilizes an underlying library (such as ecos) for solving, but unfortunately, it lacks any data on the intermediate iterations. I also confirmed that the printed log is generated by the underlying library and not by cvxpy itself. Subsequently, my investigation of the ecos library revealed that it also does not store the intermediate information. Instead, it maintains a simple info struct that gets updated after each iteration.

Finally, I made the decision to capture the output stream and subsequently parse the result using the regex to extract the required information. I am aware that this approach is somewhat tricky and fragile, but it effectively solves my problem:

import re

import cvxpy
import wurlitzer

# The convex problem definition ...

with wurlitzer.pipes() as (out, err):
    problem.solve(solver=cvxpy.ECOS, verbose=True)

matches = re.findall(
    &quot;^\s*(?P&lt;iteration&gt;\d+)\s+(?P&lt;pcost&gt;\S+)\s+.*$&quot;,
    out.getvalue(),
    re.MULTILINE
)

data = []
for iteration, pcost in matches:
    data.append(float(pcost))

print(data)

And I get:

[0.6667, 3.5, 5.716, 5.997, 6.0, 6.0, 6.0]

I only need the pcost value, but feel free to improve the regex pattern to suit your specific requirements.

I had to use wurlitzer because the table is printed at the C-level, and the common approaches, such as contextlib.redirect_stdout, cannot be used.

huangapple
  • 本文由 发表于 2023年7月23日 19:55:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748095.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定