外部代码组件的多次评估使用相同的输入? OpenMDAO

时间:2018-03-13 10:51:54

标签: openmdao

我正在使用SLSQP,外部代码,显式补偿和FD区分设置三个组件的优化例程。

  • Comp1:IndepVarComp with output =' x'
  • Comp2:外部代码输入=' x' / output =' f',' g' - 衍生品 =' FD'
  • Comp3:明确的Comp输入=' f',' g' / 输出=' obj' - 分析 宣传衍生物

更具体地说,Comp2类似于抛物面示例,而Comp3只是一个线性函数。没有限制。

如果我在Comp2上使用中央FD,它会在改变之前用相同的输入值(x)评估外部代码4次,而前向FD则是两次。我模糊地理解优化器正在尝试做什么但是 重复相同的计算只是一个计算负担。

我的补救措施是使用相应的输入名称保存输出文件,并在第二次迭代中检查此文件是否存在,如果是,则跳过计算并从文件读入。这很好用。

我的问题是:

  • ---我想知道是否应该采用嵌入式方法来避免重新评估相同的功能?
  • ---尽管我声称我理解了优化器的作用,但不清楚为什么它试图找到没有步进的渐变。

重要说明: 如果Comp2有两个输入,一个输出,则不会发生这种情况。

如果Comp2有两个输入,两个输出

,它会再次发生

在前几次迭代的示例输出下面。

ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
OBJECTIVE 589362.0
----------------------------------------------------------------------
ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
OBJECTIVE 589362.0
----------------------------------------------------------------------
ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
ExtInX = [10.], , ExtOutF = 79.0, ExtOutG = 373.0 
ExtInX = [10.000001], , ExtOutF = 79.00001700000098, ExtOutG = 373.0001500000209 
ExtInX = [9.999999], , ExtOutF = 78.99998300000101, ExtOutG = 372.9998500000211 
ExtInX = [8.07102609], , ExtOutF = 49.928382692675996, ExtOutG = 154.61605669448198 
OBJECTIVE 250797.01369955452
----------------------------------------------------------------------
**ExtInX = [8.07102609], , ExtOutF = 49.928382692675996, ExtOutG = 154.61605669448198 
ExtInX = [8.07102609], , ExtOutF = 49.928382692675996, ExtOutG = 154.61605669448198 
ExtInX = [8.07102609], , ExtOutF = 49.928382692675996, ExtOutG = 154.61605669448198 
ExtInX = [8.07102609], , ExtOutF = 49.928382692675996, ExtOutG = 154.61605669448198** 
ExtInX = [8.07102709], , ExtOutF = 49.92839583472901, ExtOutG = 154.61613684041134 
ExtInX = [8.07102509], , ExtOutF = 49.92836955062501, ExtOutG = 154.61597654858318 
ExtInX = [4.88062761], , ExtOutF = 18.178645674383997, ExtOutG = 21.29321703417343 
OBJECTIVE 38811.35361617729

第一次回答后

感谢您的回答。 据我所知,在2.2中,缓存必须由用户完成 人们可以用不同的方式做到这一点。这可以。

你在2.3中提到的改进似乎解决了一件事。 一开始就有一个额外的电话。我更关心的是 在迭代期间使用相同输入进行多次调用。

我在下面添加了四个代码补丁。一个人应该能够运行优化器 只要其他人在同一个文件夹中。

在这种情况下,外部代码是纯python。但同时我也是 开发一个使用'实际'外部代码。它又来了 虽然包裹在python中。因此,一些系统调用被发送到可执行文件 和python处理外部代码的输出,python做一些帖子 处理并输出由OpenMDAO外部代码读取的文本文件 零件。所以不确定那个算是纯粹的python。

关于约束:在下面的代码中没有。在其他代码中 我已经解释过,汽车零部件有一些终身限制 (例如xx,lower = 20)。

代码: Optimizer.py:驱动程序 和其他3 .py文件 https://gist.github.com/anonymous/2c9d5d182cbb24a2334c97b57a954802

2 个答案:

答案 0 :(得分:0)

在OpenMDAO v2.2中,没有构建处理结果缓存的方法。所以你必须在那里推出自己的解决方案。您可以在内存中执行缓存,而只是存储最后的已知输入值,而不是保存完整的输出文件。如果它们没有改变,您可以将输出值保留在原来的位置。

在OpenMDAO V2.2中,驱动程序被编码为在开始优化之前进行一次额外的函数调用。这是因为OpenMDAO处理线性约束的方式。它将预先计算与线性约束相关的导数并存储它们。

在OpenMDAO V2.3中,我们修改了驱动程序,因此他们只会进行额外的调用,如果您的问题中存在线性约束。所以,至少,解释一个额外的函数调用。

在检查了测试问题之后,OpenMDAO对组件进行有限差分处理方式似乎存在错误。即使您使用正向模式,问题也会出现,并且它似乎与您声明部分的方式有关。 您声明它们的方式没有任何问题,但使用另一种声明方法我能够使其正常运行:

from openmdao.api import ExternalCode
import numpy as np
class ParaboloidExternalCode(ExternalCode):
    def setup(self):
        self.add_input('x', val=0.0)
        self.add_input('y', val=0.0)

        self.add_output('f_xy', val=0.0)
        self.add_output('g_xy', val=0.0)

        self.input_file = 'paraboloid_input.dat'
        self.output_file = 'paraboloid_output.dat'

        # providing these is optional; the component will verify that any input
        # files exist before execution and that the output files exist after.
        self.options['external_input_files'] = [self.input_file,]
        self.options['external_output_files'] = [self.output_file,]

        self.options['command'] = [
            'python', 'extcode_paraboloid.py', self.input_file, self.output_file
        ]
        # self.declare_partials(of='*', wrt='*', method='fd', form='central', step=1e-6)

        self.declare_partials(of='f_xy', wrt=['x','y'], method='fd', form='central', step=1e-6)
        self.declare_partials(of='g_xy', wrt=['x','y'], method='fd', form='central', step=1e-6)


    def compute(self, inputs, outputs):
        x = inputs['x']
        y = inputs['y']

        # generate the input file for the paraboloid external code
        with open(self.input_file, 'w') as input_file:
            input_file.write('%f\n%f\n' % (x,y))

        # the parent compute function actually runs the external code
        super(ParaboloidExternalCode, self).compute(inputs, outputs)

        file_contents = np.loadtxt(self.output_file)


        outputs['f_xy'] = file_contents [0] 
        outputs['g_xy'] = file_contents [1] 

        print('ExtInX = {}, ExtInY = {},, ExtOutF_XY = {}, ExtOutG_XY = {} '.format(x,y,file_contents [0],file_contents[1]) )

我摆脱了of='*', wrt='*'并将其替换为两个明确命名变量的独立调用。我还能够在没有外部代码的情况下复制这个问题,使用内存中的抛物面。我已将错误输入到开发积压中,我们将整理出来。与此同时,这种解决方法解决了这个问题。

答案 1 :(得分:0)

请注意,OpenMDAO V2.2中存在导致额外评估的错误。它是通过OpenMDAO PR # 553

修复的