如何解决用混合分析策略逼近整个问题
我遇到了问题,我为某些组件实现了分析导数,而我对其余部分使用了复杂的步骤。它们之间存在循环依赖,所以我也使用求解器来收敛它们。当我使用 NonlinearBlockGS
时它会收敛。但是当我将 NewtonSolver
与线性求解器结合使用时,优化失败(超出迭代限制),即使迭代次数很高。但是我发现当我使用 prob.model.approx_totals()
时它很容易收敛并且工作得很好。我读到 approx_totals
使用 fd
或 cs
来查找模型梯度。所以我有两个问题。
-
一般来说,当我使用
approx_totals()
时,我会失去混合分析方法的好处吗?有没有办法用混合分析策略找到整个模型(或组)的导数? (无论如何,在我的情况下,耦合的explicitcomponents
使用“复杂步骤”。但我只是对此感到好奇。)
如果您能指出一些使用混合导数的例子,我也将不胜感激。我自己没有运气找到它们。
编辑:添加示例。我无法在示例代码中重现该问题。此外,我不想在我的代码上浪费您的时间(有 30 多个显式组件和 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,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,outputs):
# computation
class ComponentG(om.ExplicitComponent):
def setup(self):
#setup inputs and outputs
self.declare_partials(of='*',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(),'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',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()
时,我是否会失去我所拥有的分析导数的好处?
解决方法
您提供的代码示例无法运行,因此我必须进行一些猜测。您同时调用 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.norm
和 np.abs
。两者都会很乐意接受复数并给你一个答案,但当你需要导数时,这不是正确的答案。
因此,OpenMDAO 附带了一个 set of custom functions that are cs-safe --- 提供了自定义 norm
和 abs
。
非 cs-safe 方法通常会发生复杂部分以某种方式被丢弃并且您得到 0 偏导数。错误的部分,错误的总数。
要检查这一点,请确保使用有限差分检查对复杂步进的组件调用 check_partials。您可能会发现一些差异。
您可以使用的修复程序是:
- 将这些组件切换为使用 FD 分音。不太准确,但可能会起作用
- 纠正计算中导致代码不安全的任何问题。如果这是问题,请使用 OpenMDAO 的自定义函数,或者您可能需要更加小心如何在计算中分配和使用 numpy 数组(如果您要分配自己的数组,则需要小心确保它们很复杂还有!)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。