用混合分析策略逼近整个问题

Approximating the whole problem with Mixed Analytical strategy

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

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

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

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

编辑:添加示例。我无法在示例代码中重现该问题。另外,我不想在我的代码上浪费您的时间(有超过 30 个 ExplicitComponents 和 7 个组)。所以我在下面做了一个简单的结构来更好地解释它。其中有 7 个组件 A to G,只有 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 没有问题。与 Newton 一起工作)

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

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

您已经正确理解了 approx_totals 的行为。当您将其设置在模型的顶部时,OpenMDAO 将从组级别 FD 相关变量。在这种情况下,这意味着您还将对求解器本身进行 FD-ing。你说这个好像可以,但是混合解析的方法不行

In general, Will I lose the benefits from the mixed-analytical approach when I use approx_totals()?

是的。您不再使用混合方法。您只是整体地 FD-ing 整个模型。

Is there a way to find the derivatives of whole model (or group) with mixed analytical strategy ?

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

In general (not in this scenario), will Openmdao automatically detect the mixed strategy?

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

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

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

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

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

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

您可用的修复程序是:

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