OpenMDAO v0.13: error only when trying to run optimization in parallel "IndexError: list index out of range"

OpenMDAO v0.13: error only when trying to run optimization in parallel "IndexError: list index out of range"

请查看底部添加的示例,他们比原始示例更准确地指出了错误。

我一直在尝试将附加代码并行获取到 运行。此代码旨在模仿我希望在大型集群上 运行 的更大优化代码的结构。这里的错误出现在我们尝试过的几个不同的脚本中,其中一个脚本并行工作,除非连接到在配置方法中从数组元素的循环中启动的组件。这个例子 运行 在串行中很好,但是当我 运行 命令 mpirun -n 4 python test2_forParallel_floats.py 我得到以下输出:

Traceback (most recent call last):
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 549, in run
    self._pre_execute()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 469, in _pre_execute
    self._setup()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1701, in _setup
    self.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1105, in setup_variables
    self._system.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2387, in setup_variables
    super(DriverSystem, self).setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2122, in setup_variables
    sub = list(self.local_subsystems())[0]
IndexError: list index out of range

Traceback (most recent call last):
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 549, in run
    self._pre_execute()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 469, in _pre_execute
    self._setup()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1701, in _setup
Traceback (most recent call last):
  File "test2_forParallel_floats.py", line 170, in <module>
    test.run()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 549, in run
    self._pre_execute()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 469, in _pre_execute
    self._setup()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1701, in _setup
    self.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1105, in setup_variables
    self.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1105, in setup_variables
    self._system.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2387, in setup_variables
    super(DriverSystem, self).setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2122, in setup_variables
    sub = list(self.local_subsystems())[0]
IndexError: list index out of range

    self._system.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2387, in setup_variables
Traceback (most recent call last):
  File "test2_forParallel_floats.py", line 170, in <module>
    test.run()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 549, in run
    super(DriverSystem, self).setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    self._pre_execute()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/component.py", line 469, in _pre_execute
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    self._setup()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1701, in _setup
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2122, in setup_variables
    self.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/assembly.py", line 1105, in setup_variables
    self._system.setup_variables()
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2387, in setup_variables
    super(DriverSystem, self).setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub = list(self.local_subsystems())[0]
IndexError: list index out of range
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 433, in setup_variables
    sub.setup_variables(resid_state_map)
  File "/Users/thomas95/OpenMDAO/openmdao-0.13.0/lib/python2.7/site-packages/openmdao.main-0.13.0-py2.7.egg/openmdao/main/systems.py", line 2122, in setup_variables
    sub = list(self.local_subsystems())[0]
IndexError: list index out of range

任何人都可以告诉我为什么这不会 运行 并行吗?


脚本

注意:注释掉的 q 元素是我们需要的附加功能。在这里一次去一件

from openmdao.main.api import Assembly, Component
from openmdao.lib.datatypes.api import Float, Array, List
from openmdao.lib.drivers.api import DOEdriver, SLSQPdriver, COBYLAdriver, CaseIteratorDriver
from pyopt_driver.pyopt_driver import pyOptDriver

import numpy as np


class component1(Component):

    x = Float(iotype='in')
    y = Float(iotype='in')
    term1 = Float(iotype='out')
    a = Float(iotype='in', default_value=1)

    def execute(self):
        x = self.x
        a = self.a

        term1 = a*x**2
        self.term1 = term1

        print "In comp1", self.name, self.a, self.x, self.term1

    def list_deriv_vars(self):
        return ('x',), ('term1',)

    def provideJ(self):

        x = self.x
        a = self.a
        dterm1_dx = 2.*a*x

        J = np.array([[dterm1_dx]])
        # print 'In comp1, J = %s' % J

        return J


class component2(Component):

    x = Float(iotype='in')
    y = Float(iotype='in')
    term1 = Float(iotype='in')
    f = Float(iotype='out')
    # q = Array(np.zeros(2), iotype='in', dtype='float')

    def execute(self):

        # y = self.y + self.q[0]
        # x = self.x + self.q[1]

        y = self.y
        x = self.x

        term1 = self.term1
        f = term1 + x + y**2
        # print 'in comp2 q = %s' % self.q
        self.f = f
        print "In comp2", self.name, self.x, self.y, self.term1, self.f



class summer(Component):


    total = Float(iotype='out', desc='sum of all f values')

    def __init__(self, size):
        super(summer, self).__init__()
        self.size = size

        self.add('fs', Array(np.zeros(size), iotype='in', desc='f values from all cases'))

    def execute(self):
        self.total = sum(self.fs)
        print 'In summer, fs = %s and total = %s' % (self.fs, self.total)


class assembly(Assembly):

    x = Float(iotype='in')
    y = Float(iotype='in')
    total = Float(iotype='out')

    def __init__(self, size):

        super(assembly, self).__init__()

        self.size = size
        for i in range(0, size):
            self.add('a_vals_%d' % i, Float(iotype='in'))
            # self.add('q_%d' % i, Array(np.zeros(2), iotype='in', dtype='float'))
            a = str()
            exec("a = self.a_vals_%d" % i)
            print 'in init, a_vals_%d = %s' % (i, a)

        self.add('fs', Array(np.zeros(size), iotype='out', dtype='float'))
        print 'in init, fs = %s' % self.fs

    def configure(self):

        self.add('driver', SLSQPdriver())
        # self.add('driver', pyOptDriver())
        # self.driver.optimizer = 'SNOPT'
        # self.driver.pyopt_diff = True

        #create this first, so we can connect to it
        self.add('summer', summer(size=self.size))
        self.connect('summer.total', 'total')

        for i in range(0, self.size):
            a = str()
            exec("a = self.a_vals_%d" % i)
            print 'in configure, a_vals_%d = %s' % (i, a)


        # create instances of components
        for i in range(0, self.size):
            c1 = self.add('comp1_%d' % i, component1())
            c1.missing_deriv_policy = 'assume_zero'

            c2 = self.add('comp2_%d'%i, component2())
            self.connect('a_vals_%d' % i, 'comp1_%d.a' % i)
            self.connect('x', ['comp1_%d.x' % i, 'comp2_%d.x' % i])
            self.connect('y', ['comp1_%d.y' % i, 'comp2_%d.y' % i])
            self.connect('comp1_%d.term1' % i, 'comp2_%d.term1' % i)
            # self.connect('q_%d' % i, 'comp2_%d.q' % i)

            self.connect('comp2_%d.f' % i, 'summer.fs[%d]' % i)

            self.driver.workflow.add(['comp1_%d' % i, 'comp2_%d' % i])

        # self.connect('summer.fs[:]', 'fs[:]')
        self.driver.workflow.add(['summer'])

        # set up main driver (optimizer)
        self.driver.iprint = 1
        self.driver.maxiter = 100
        self.driver.accuracy = 1.0e-6
        self.driver.add_parameter('x', low=-5., high=5.)
        self.driver.add_parameter('y', low=0., high=5.)
        # for i in range(0, self.size):
        #     self.driver.add_parameter('q_%d' % i, low=0., high=5.)
        self.driver.add_objective('summer.total')


if __name__ == "__main__":
    """ the result should be -1 at (x, y) = (-0.5, 0) """

    import time
    from openmdao.main.api import set_as_top
    a_vals = np.array([1., 1., 1., 1.])
    test = set_as_top(assembly(size=len(a_vals)))
    # test.a_vals = a_vals
    # print 'in main, test.a_vals = %s, test.fs = %s' % (test.a_vals, test.fs)
    test.x = 2.
    test.y = 5
    # q = np.tile(np.arange(1., 3.), (4, 1))
    for i in range(0, len(a_vals)):
        exec('test.a_vals_%d = a_vals[%d]' % (i, i))
    #     exec('test.q_%d = q[%d]' % (i, i))
    #     exec('print test.q_%d' % i)
        a = str()
        exec("a = test.a_vals_%d" % i)
        print 'in main, a_vals_%d = %s' % (i, a)

    tt = time.time()
    test = set_as_top(test)
    test.run()

    print "Elapsed time: ", time.time()-tt, "seconds"

    print 'result = ', test.summer.total
    print '(x, y) = (%s, %s)' % (test.x, test.y)
    print 'fs = %s' % test.fs
    print test.fs
    # for i in range(0, len(a_vals)):
    #     exec('print test.q_%d' % i)

更多示例

此示例更好地说明了导致错误的原因。以下脚本 运行 以串行或并行方式用于默认驱动程序,但在将 SLSLQPdriver 和 pyOptDriver 与 SNOPT 一起使用时失败。错误如下:

使用 SLSQPdriver():AttributeError: 'SerialSystem' object has no attribute 'options'

将 pyOptDriver() 与 SNOPT 结合使用:IndexError: index 0 is out of bounds for axis 1 with size 0

结果应该是 y* = 0 在 x* = [0, 0, 0]。

编辑:我现在收到一个不同的 SNOPT 错误:IOError: Failed to properly open SNOPT_print.out, ierror = 17。我不确定发生了什么变化

import numpy as np
import time

from openmdao.main.api import Component, Assembly
from openmdao.lib.datatypes.api import Float, Array
from openmdao.lib.drivers.api import FixedPointIterator, SLSQPdriver, COBYLAdriver
from pyopt_driver.pyopt_driver import pyOptDriver

class SimpleComp(Component):

    x = Float(iotype="in")
    y = Float(iotype="out")

    def execute(self):
        # print 'print'
        print 'In SimpleComp, x = %s' % self.x
        # time.sleep(2) #slow things down to make the parallization more clear

        self.y = self.x*self.x

class Summer(Component):

    def __init__(self, size):
        super(Summer, self).__init__()

        self.size = int(size)
        for i in xrange(size):
            self.add('y_%d'%i, Float(iotype="in"))

        self.add('tot', Float(iotype="out"))

    def execute(self):
        tot = 0
        for i in xrange(self.size):
            tot += getattr(self, 'y_%d'%i)
        self.tot = tot



class Sim(Assembly):

    def __init__(self, size):
        super(Sim, self).__init__()

        # self.add('x', Array(np.zeros(size), dtype='float', iotype='in'))
        # self.add('x', Float(iotype='in'))
        for i in range(0, size):
            self.add('x_%d' % i, Float(iotype='in'))

    def configure(self):

        #you'll need one process per point

        # self.add('driver', SLSQPdriver())
        self.add('driver', pyOptDriver())
        self.driver.optimizer = 'SNOPT'

        self.add('summer', Summer(size))
        # print self.x

        for i in xrange(size):
            # print 'x = ', self.x[i]
            self.add('point_%d'%i, SimpleComp())
            self.connect('x_%d' % i, 'point_%d.x' % i)
            self.connect('point_%d.y'%i, 'summer.y_%d'%i)
            self.driver.workflow.add('point_%d'%i)
            self.driver.add_parameter('x_%d' % i, high=10, low=-10)

        self.driver.workflow.add('summer')

        self.driver.add_objective('summer.tot')


if __name__ == "__main__":
    from openmdao.main.api import set_as_top

    size = 3

    x = np.arange(0, size)
    # x = 1.
    print x

    sim = set_as_top(Sim(size))

    for i in range(0, size):
        exec('sim.x_%d = x[%d]' % (i, i))
    st = time.time()
    sim.run()

    print "runtime: ", time.time() - st

    print 'y* = %s' % sim.summer.tot

所以,我 运行 你的模型看到了和你一样的东西。从那以后,我已经能够在进行以下更改的同时成功 运行(我修改后的代码在下面)。

  1. MPI 似乎不支持组件的有限差分。特别是,让它将模型分成块以进行有限差分会导致一些奇怪的并行错误。有两种解决方法。我选择为 SimpleCompSummer 组件定义解析导数,因为它们很简单。您还可以将 driver.gradient_options.force_fd 设置为 True 以对整个模型进行有限差分。

  2. 最初您使用的是 PyOptDriver,但对于某些优化器而言,该驱动程序无法并行工作。具体来说,SNOPT 写出一个文本文件,所以您看到的 ioError 是所有 3 个进程都试图写入同一个文件但不能写入的时候。我们有一个并行版本的 PyOptDriver(称为 mdolab-pyoptsparse),这是我使用的。 OpenMDAO 包装器隐藏在 pyMission 存储库中:

    https://github.com/OpenMDAO-Plugins/pyMission

    和 pyoptsparse 可以在这里找到:

    https://bitbucket.org/mdolab/pyoptsparse

    有了这些后,您可以在适当的位置提供 SNOPT。

  3. 最后,我需要更严格地控​​制要并行放置的组件,因此我在工作流层次结构中添加了另一个级别。驱动程序 parallel_stuff 只包含我们想要并行 运行 的 SimpleComps。然后我将 driversystem_type 设置为串行,这样它就不会尝试在并行组中放置任何其他内容。

通过这些修复,我让您的模型得到优化并达到 (0,0,0)。

import numpy as np
import time
from openmdao.main.api import Component, Assembly, Driver
from openmdao.lib.datatypes.api import Float, Array
from openmdao.lib.drivers.api import FixedPointIterator, SLSQPdriver, COBYLAdriver
from pyopt_driver.pyopt_driver import pyOptDriver
from pyoptsparse_driver.pyoptsparse_driver import pyOptSparseDriver

class SimpleComp(Component):
    x = Float(iotype="in")
    y = Float(iotype="out")
    def execute(self):
        # print 'print'
        print 'In SimpleComp, x = %s' % self.x
        # time.sleep(2) #slow things down to make the parallization more clear
        self.y = self.x*self.x
    def provideJ(self):
        J = np.zeros((1, 1))
        J[0][0] = 2.0*self.x
        return J
    def list_deriv_vars(self):
        return ('x', ), ('y', )

class Summer(Component):
    def __init__(self, size):
        super(Summer, self).__init__()
        self.size = int(size)
        for i in xrange(size):
            self.add('y_%d'%i, Float(iotype="in"))
        self.add('tot', Float(iotype="out"))
    def execute(self):
        tot = 0
        for i in xrange(self.size):
            tot += getattr(self, 'y_%d'%i)
        self.tot = tot
    def provideJ(self):
        J = np.ones((1, self.size))
        return J
    def list_deriv_vars(self):
        inputs = ['y_%d'%i for i in range(self.size)]
        return inputs, ('tot', )

class Sim(Assembly):
    def __init__(self, size):
        super(Sim, self).__init__()
        # self.add('x', Array(np.zeros(size), dtype='float', iotype='in'))
        # self.add('x', Float(iotype='in'))
        for i in range(0, size):
            self.add('x_%d' % i, Float(iotype='in'))
    def configure(self):
        #you'll need one process per point
        self.add('driver', pyOptSparseDriver())
        self.add('parallel_stuff', Driver())
        self.driver.optimizer = 'SNOPT'
        self.add('summer', Summer(size))
        # print self.x
        for i in xrange(size):
            # print 'x = ', self.x[i]
            self.add('point_%d'%i, SimpleComp())
            self.connect('x_%d' % i, 'point_%d.x' % i)
            self.connect('point_%d.y'%i, 'summer.y_%d'%i)
            self.parallel_stuff.workflow.add('point_%d'%i)
            self.driver.add_parameter('x_%d' % i, high=10, low=-10)
        self.driver.workflow.add(['parallel_stuff', 'summer'])
        self.driver.add_objective('summer.tot')

        # Don't try to parallelize anything except 'parallel_stuff'
        self.driver.system_type = 'serial'

if __name__ == "__main__":
    from openmdao.main.api import set_as_top
    size = 2
    x = np.arange(0, size)
    # x = 1.
    print x
    sim = set_as_top(Sim(size))
    for i in range(0, size):
        exec('sim.x_%d = x[%d]' % (i, i))
    st = time.time()
    sim._setup()

    sim.run()
    print "runtime: ", time.time() - st
    print 'y* = %s' % sim.summer.tot