【问题标题】:Approximating the whole problem with Mixed Analytical strategy用混合分析策略逼近整个问题
【发布时间】:2021-08-28 17:37:29
【问题描述】:

我遇到了一些问题,我为某些组件实现了分析导数,而我对其余部分使用了复杂的步骤。它们之间存在循环依赖关系,因此我还使用求解器来收敛它们。当我使用NonlinearBlockGS 时它会收敛。但是当我将NewtonSolver 与线性求解器结合使用时,即使迭代次数很高,优化也会失败(超出迭代限制)。但是我发现当我使用prob.model.approx_totals() 时,它很容易收敛并且工作得很好。我读到approx_totals 使用fdcs 来查找模型渐变。所以我有两个问题。

  1. 一般来说,当我使用approx_totals() 时,我会失去混合分析方法的好处吗?有没有办法用混合分析策略找到整个模型(或组)的导数? (无论如何,在我的情况下,explicitcomponents 耦合使用“复杂步骤”。但我只是对此感到好奇。)

  2. 一般情况下(不是在这种情况下),Openmdao 会自动检测混合策略还是我应该如何指定它?

如果您能指出一些使用混合衍生物的示例,我将不胜感激。我自己没有找到它们。

编辑:添加示例。我无法在示例代码中重现该问题。另外我不想在我的代码上浪费你的时间(有超过 30 个 ExplicitComponents 和 7 个组)。所以我在下面做了一个简单的结构来更好地解释它。其中A to G 有7 个分量,只有F and G 没有解析导数并使用FD

import openmdao.api as om
import numpy as np

class ComponentA_withDerivatives(om.ExplicitComponent):
    def setup(self):
        #setup inputs and outputs
    
    def setup_partials(self):
        #partial declaration

    def compute(self, inputs, outputs):

    def compute_partials(self, inputs, J):
        #Partial definition

class ComponentB_withDerivatives(om.ExplicitComponent):
    .....

class ComponentC_withDerivatives(om.ExplicitComponent):
    ......

class ComponentD_withDerivatives(om.ExplicitComponent):
    ......

class ComponentE_withDerivatives(om.ExplicitComponent):
    ......


class ComponentF(om.ExplicitComponent):
    def setup(self):
        #setup inputs and outputs

        self.declare_partials(of='*', wrt='*', method='fd')

    def compute(self,inputs,outputs):
        # Computation

class ComponentG(om.ExplicitComponent):
    def setup(self):
        #setup inputs and outputs

        self.declare_partials(of='*', wrt='*', method='fd')

    def compute(self,inputs,outputs):
        # Computation 

class GroupAB(om.Group):
    def setup(self):
        self.add_subsystem('A', ComponentA_withDerivatives(), promotes_inputs=['x','y'], promotes_outputs=['z'])
        self.add_subsystem('B', ComponentB_withDerivatives(), promotes_inputs=['x','y','w','u'], promotes_outputs=['k'])

class GroupCD(om.Group):
    def setup(self):
        self.add_subsystem('C', ComponentC_withDerivatives(), .....)
        self.add_subsystem('D', ComponentD_withDerivatives(), ...)


class Final(om.Group):
    def setup(self):
        cycle1 = self.add_subsystem('cycle1', om.Group(), promotes=['*'])
        cycle1.add_subsystem('GroupAB', GroupAB())
        cycle1.add_subsystem('ComponentF', ComponentF())

        cycle1.linear_solver = om.DirectSolver()
        cycle1.nonlinear_solver = om.NewtonSolver(solve_subsystems=True)

        cycle2 = self.add_subsystem('cycle2', om.Group(), promotes=['*'])
        cycle2.add_subsystem('GroupCD', GroupCD())
        cycle2.add_subsystem('ComponentE_withDerivatives', ComponentE_withDerivatives())

        cycle2.linear_solver = om.DirectSolver()
        cycle2.nonlinear_solver = om.NewtonSolver(solve_subsystems=True)

        self.add_subsystem('ComponentG', ComponentG(), promotes_inputs=['a1','a2','a3'], promotes_outputs=['b1'])


prob = om.Problem()
prob.model = Final()

prob.driver = om.pyOptSparseDriver()
prob.driver.options['optimizer'] = 'SNOPT'
prob.driver.options['print_results']= True

## Design Variables

## Costraints

## Objectives

# Setup
prob.setup()

##prob.model.approx_totals(method='fd')

prob.run_model()

prob.run_driver()

这不起作用。 cycle1 不收敛。当我完全删除 cycle1 或使用 NonlinearBlockGS 而不是 Newton 或取消注释 prob.model.approx_total(method='FD') 时,该代码有效。 (cycle2没问题。和牛顿一起工作)

所以如果我不使用approx_totals(),我假设 Openmdao 使用混合策略。或者我应该以某种方式手动提及它?当我使用 approx_totals() 时,我会失去我拥有的分析导数的好处吗?

【问题讨论】:

  • 您能否添加更多有关您的问题设置的详细信息。当您说它收敛时,您是在谈论求解器收敛还是有顶级优化器?求解器在模型层次结构中的什么位置?也是顶级的吗?也许提供一个显示模型结构和运行文件的概念示例,即使它没有给出相同的确切行为?
  • 您好,我已经添加了一个代码结构来更好地解释它。抱歉之前的事。

标签: openmdao


【解决方案1】:

您提供的代码示例无法运行,因此我必须进行一些猜测。你打电话给run_model()run_driver()。不过,您费心在示例代码中包含一个优化器,并且您已显示 approx_totals 在模型层次结构的顶部被调用。 所以当你说它不起作用时,我会假设你的意思是优化器没有收敛。

您已经正确理解了approx_totals 的行为。当您在模型顶部设置它时,OpenMDAO 将从组级别 FD 相关变量。在这种情况下,这意味着您还将在求解器本身上进行 FD-ing。你说这似乎行得通,但混合分析方法行不通。

一般来说,当我使用 approx_totals() 时,我会失去混合分析方法的好处吗?

是的。您不再使用混合方法。您只是在整体上对模型进行 FD-ing。

有没有办法用混合分析策略找到整个模型(或组)的导数?

当您不使用approx_totals 时,OpenMDAO 正在使用混合策略计算总导数。问题是对于您的模型,它似乎不起作用。

一般情况下(不是这个场景),Openmdao会自动检测混合策略吗?

它将“检测”它(它实际上并没有检测到任何东西,但底层算法将使用混合策略,除非您告诉它不要使用 approx_totals。同样,问题不在于混合策略不是正在使用,但它不起作用。

那么为什么混合策略不起作用?

我只能猜测,因为我无法运行代码......所以 YMMV。 您提到您正在对显式组件的部分使用复杂步骤。 Complex-step 是一种比 FD 更准确的近似方案,但它并非没有自身的缺陷。并非每个计算都是复杂安全的。有些可以重写为复杂安全的,有些则不能。 “复杂安全”是指计算正确处理复杂部分以给出导数。

两种常用的复杂安全方法是np.linalg.normnp.abs。两者都会很乐意接受复数并给你一个答案,但当你需要导数时,这不是正确的答案。 因此,OpenMDAO 附带了一个 set of custom functions that are cs-safe --- 提供了自定义 normabs

使用非 cs 安全方法通常会发生复杂部分以某种方式被丢弃并且您得到 0 个偏导数。错误的部分,错误的总数。

要检查这一点,请确保使用有限差分检查对正在执行复杂步进的组件调用 check_partials。您可能会发现一些差异。

可供您使用的修复是:

  1. 切换这些组件以使用 FD 部分。不太准确,但可能会起作用
  2. 纠正计算中导致代码非 cs 安全的任何问题。如果这是问题,请使用 OpenMDAO 的自定义函数,或者您可能需要更加小心如何在计算中分配和使用 numpy 数组(如果您要分配自己的数组,那么您需要小心确保它们是复杂的也!)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    • 2013-02-13
    • 1970-01-01
    相关资源
    最近更新 更多