Scaled paraboloid and derivatives checking

纵然是瞬间 提交于 2019-12-12 19:57:34

问题


I am surprised by the output of the check_partial_derivatives() method applied to the problem showed in my previous question : Paraboloid optimization requiring scaling. When I add the call to that method :

from __future__ import print_function
import sys

from openmdao.api import IndepVarComp, Component, Problem, Group, ScipyOptimizer

class Paraboloid(Component):

    def __init__(self):
        super(Paraboloid, self).__init__()

        self.add_param('x', val=0.0)
        self.add_param('y', val=0.0)

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

    def solve_nonlinear(self, params, unknowns, resids):

        x = params['x']
        y = params['y']

        #unknowns['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0
        unknowns['f_xy'] = (1000.*x-3.)**2 + (1000.*x)*(0.01*y) + (0.01*y+4.)**2 - 3.

    def linearize(self, params, unknowns, resids):
        """ Jacobian for our paraboloid."""
        x = params['x']
        y = params['y']
        J = {}

        #J['f_xy', 'x'] = 2.0*x - 6.0 + y
        #J['f_xy', 'y'] = 2.0*y + 8.0 + x
        J['f_xy', 'x'] = 2000000.0*x - 6000.0 + 10.0*y
        J['f_xy', 'y'] = 0.0002*y + 0.08 + 10.0*x

        return J

if __name__ == "__main__":

    top = Problem()

    root = top.root = Group()
    #root.fd_options['force_fd'] = True

    root.add('p1', IndepVarComp('x', 3.0))
    root.add('p2', IndepVarComp('y', -4.0))
    root.add('p', Paraboloid())

    root.connect('p1.x', 'p.x')
    root.connect('p2.y', 'p.y')

    top.driver = ScipyOptimizer()
    top.driver.options['optimizer'] = 'SLSQP'

    top.driver.add_desvar('p1.x', lower=-1000, upper=1000, scaler=1000.)
    top.driver.add_desvar('p2.y', lower=-1000, upper=1000, scaler=0.001)
    top.driver.add_objective('p.f_xy')


    top.setup()
    top.check_partial_derivatives()  # added line
    top.run()


    print('\n')
    print('Minimum of %f found at (%f, %f)' % (top['p.f_xy'], top['p.x'], top['p.y']))

I get the following output :

Partial Derivatives Check

----------------
Component: 'p'
----------------
  p: 'f_xy' wrt 'x'

    Forward Magnitude : 6.000000e+03
    Reverse Magnitude : 6.000000e+03
         Fd Magnitude : 2.199400e+07

    Absolute Error (Jfor - Jfd) : 2.200000e+07
    Absolute Error (Jrev - Jfd) : 2.200000e+07
    Absolute Error (Jfor - Jrev): 0.000000e+00

    Relative Error (Jfor - Jfd) : 1.000273e+00
    Relative Error (Jrev - Jfd) : 1.000273e+00
    Relative Error (Jfor - Jrev): 0.000000e+00

    Raw Forward Derivative (Jfor)

[[-6000.]]

    Raw Reverse Derivative (Jrev)

[[-6000.]]

    Raw FD Derivative (Jfor)

[[ 21994001.]]
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  p: 'f_xy' wrt 'y'

    Forward Magnitude : 8.000000e-02
    Reverse Magnitude : 8.000000e-02
         Fd Magnitude : 2.200000e+07

    Absolute Error (Jfor - Jfd) : 2.200000e+07
    Absolute Error (Jrev - Jfd) : 2.200000e+07
    Absolute Error (Jfor - Jrev): 0.000000e+00

    Relative Error (Jfor - Jfd) : 1.000000e+00
    Relative Error (Jrev - Jfd) : 1.000000e+00
    Relative Error (Jfor - Jrev): 0.000000e+00

    Raw Forward Derivative (Jfor)

[[ 0.08]]

    Raw Reverse Derivative (Jrev)

[[ 0.08]]

    Raw FD Derivative (Jfor)

[[ 22000000.08]]
Optimization terminated successfully.    (Exit mode 0)
            Current function value: [-27.33333333]
            Iterations: 4
            Function evaluations: 6
            Gradient evaluations: 4
Optimization Complete
-----------------------------------


Minimum of -27.333333 found at (0.006667, -733.333333)

The optimization is correct (i.e. proving almost certainly that the derivatives are correct), but the check_partial_derivatives output does not show consistent results between fd and forward/reverse methods.


回答1:


relf

So, you have encountered a limitation that has come up before, namely you can't calculate derivatives about a design point until you run your model at that point. The finite difference results are wrong because the model has never been run. To verify your partials, you need to move check_partial_derivatives to after the run. Also, I always comment out the optimizer when I am checking derivatives so that I am checking derivatives about the initial point. When I did these two things, I got good results (see code below).

top = Problem()

root = top.root = Group()
#root.fd_options['force_fd'] = True

root.add('p1', IndepVarComp('x', 3.0))
root.add('p2', IndepVarComp('y', -4.0))
root.add('p', Paraboloid())

root.connect('p1.x', 'p.x')
root.connect('p2.y', 'p.y')

#top.driver = ScipyOptimizer()
#top.driver.options['optimizer'] = 'SLSQP'

#top.driver.add_desvar('p1.x', lower=-1000, upper=1000, scaler=1000.)
#top.driver.add_desvar('p2.y', lower=-1000, upper=1000, scaler=0.001)
#top.driver.add_objective('p.f_xy')

top.setup()
top.run()
top.check_partial_derivatives()  # added line

print('\n')
print('Minimum of %f found at (%f, %f)' % (top['p.f_xy'], top['p.x'], top['p.y']))

There is a feature request on our github for the ability to run check_partial_derivatives without running the model first. I think it is feasible that we will can do this by just telling root to solve_nonlinear, ignoring the driver, so it will probably be added at some point.



来源:https://stackoverflow.com/questions/35627718/scaled-paraboloid-and-derivatives-checking

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!