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



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

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

  2. 一般来说(不是在这个场景中),Openmdao会自动检测混合策略吗?或者我应该指定一些方式吗?

如果您能给我举一些使用混合衍生物的例子,我也将不胜感激。我自己没能找到它们。

编辑:添加示例。我无法在示例代码中重现该问题。此外,我不想在我的代码上浪费你的时间(有30多个显式组件和7个组)。所以我在下面做了一个简单的结构来更好地解释它。其中有7个组分A to G,只有NonlinearBlockGS0没有分析导数,使用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'),代码就会工作。(循环2没有问题。使用牛顿)

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

您提供的代码示例不可运行,因此我必须进行一些猜测。您同时调用run_model()run_driver()。不过,您在示例代码中添加了一个优化器,并且在模型层次结构的顶部显示了要调用的approx_totals。所以,当你说它不起作用时,我认为你的意思是优化器没有收敛。

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

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

是。你不会再使用混合方法了。您只是在对整个模型进行整体浏览。

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

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

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

它将"检测";它(它实际上没有检测到任何东西,但底层算法将使用混合策略,除非你告诉它不要使用approx_totals。同样,问题不是混合策略没有被使用,而是它不起作用。

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

我只能猜测,因为我不能运行代码。。。YMMV也是如此。您提到您正在对显式组件的部分使用复杂步骤。复阶是一种比FD更准确的近似方案,但它也有自己的缺陷。并非所有计算都是复杂安全的。有些可以重写为复杂安全,而另一些则不能。通过";复杂安全";我的意思是,计算正确地处理了复杂的部分,给出了导数。

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

非cs安全方法通常会发生的情况是,复杂部分以某种方式脱落,得到0个偏导数。错误的部分,错误的总数。

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

可供您使用的修复程序有:

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

最新更新