compute_totals занимает больше времени с аналитическим градиентом против сложного шага - PullRequest
0 голосов
/ 27 декабря 2018

ниже приведен фрагмент кода для задачи с одним компонентом.

setting self.flag --> 1  uses complex step    
setting self.flag --> 0  uses analytical gradients 

для аппроксимации / вычисления частных производных.

Расчетное время, необходимое для вычисления суммарных производных с опцией 1, составляет около 20 секунд, а опции 0 - около 60 секунд.

Я ожидал как-то обратного, потому что есть тысячи вызовов 'compute' функций со сложным шагом.

Я проверил вызовы функций, и они кажутся правильными.Я проверил аналитические части с 'cs', они также кажутся правильными.

Может кто-нибудь просветить меня, почему вычисление полной производной через аналитическую производную занимает больше времени?

import time
import numpy as np
dim1,dim2,dim3=10,40,30
ran1=np.random.random([dim1,dim2,dim3])*5
ran2=np.random.random([dim1,dim2,dim3])*10

from openmdao.api import Problem, Group, IndepVarComp, ExplicitComponent

class FDPartialComp(ExplicitComponent):

    def setup(self):
        dim1,dim2,dim3=10,40,30
        self.add_input('var1', val=np.ones([dim1,dim2,dim3]))
        self.add_input('var2', val=np.ones([dim1,dim2,dim3]))
        self.add_output('f', shape=(dim1,))
        self.flag=0 
        self.cou=0
        self.partcou=0
        if self.flag:
            self.declare_partials('*', '*', method='cs')
        else:
            self.declare_partials('f', 'var1',cols=np.arange(dim2*dim3*dim1),rows=np.repeat(np.arange(dim1),dim2*dim3))
            self.declare_partials('f', 'var2' ,cols=np.arange(dim2*dim3*dim1),rows=np.repeat(np.arange(dim1),dim2*dim3))

    def compute(self, inputs, outputs):
        self.cou+=1
        print(self.cou)
        var1 = inputs['var1']
        var2 = inputs['var2']
        m=3
        outputs['f'] = np.sum((var2*var1**m),axis=(1,2))        

    def compute_partials(self, inputs, partials):
        if self.flag:
            pass
        else:
            m=3
            var1 = inputs['var1']
            var2 = inputs['var2']        
            partials['f','var1'] =(var1**m*m*var2/var1).flatten()
            partials["f","var2" ]= (var1**m).flatten()
            self.partcou+=1
            print(self.partcou)

model = Group()
comp = IndepVarComp()

comp.add_output('var1', ran1)
comp.add_output('var2', ran2)
#comp.add_output('var1', np.ones([dim1,dim2,dim3])*5)
#comp.add_output('var2', np.ones([dim1,dim2,dim3])*10)
model.add_subsystem('input', comp,promotes=['*'])
model.add_subsystem('example', FDPartialComp(),promotes=['*'])

problem = Problem(model=model)
problem.setup(check=True)
#problem.run_model()
st=time.time()
totals = problem.compute_totals(['f'], ['var1','var2'])
#problem.setup(force_alloc_complex=True)
#problem.check_partials(compact_print=True,method='cs')
print(time.time()-st)

СЛЕДУЮЩИЙ ОТВЕТ Я ДОБАВИЛ ОБЗОР ДЛЯ ВЫЧИСЛИТЕЛЬНОГО ВРЕМЕНИ В РАЗЛИЧНЫХ ЧАСТЯХ КОДА

enter image description here

1 Ответ

0 голосов
/ 28 декабря 2018

Разница в производительности, которую вы видите, связана с внутренними структурами данных в OpenMDAO.Ваша модель, когда заданы аналитические производные, указывается с использованием разреженного формата (это хорошо, так как он очень разреженный!).Но для того, чтобы действительно воспользоваться этим преимуществом, вам нужно использовать формат собранной матрицы для хранения частичных производных данных и прямой решатель для вычисления разреженной факторизации LU.Как только вы добавите эти функции в свою модель, производительность для аналитики будет выше, чем в CS.

Расхождение возникает потому, что когда вы используете чистый CS, вы сохраняете производные в плотный формат, который ведет себя как собранная матрица.Но когда вы указали аналитические производные, вы не получили эту выгоду по умолчанию.таким образом, были некоторые основные различия в том, как фреймворк обрабатывал каждый случай.

Вот обновленный скрипт, который показывает правильную производительность (я сделал размер ввода меньше, чтобы он работал быстрее)

import time
import numpy as np

# dim1,dim2,dim3=10,40,30
dim1,dim2,dim3=10,40,5

ran1=np.random.random([dim1,dim2,dim3])*5
ran2=np.random.random([dim1,dim2,dim3])*10

from openmdao.api import Problem, Group, IndepVarComp, ExplicitComponent, DirectSolver

class FDPartialComp(ExplicitComponent):

    def setup(self):

        self.add_input('var1', val=np.ones([dim1,dim2,dim3]))
        self.add_input('var2', val=np.ones([dim1,dim2,dim3]))
        self.add_output('f', shape=(dim1,))
        self.flag=0
        self.cou=0
        self.partcou=0

        if self.flag:
            self.declare_partials('*', '*', method='cs')
        else:
            self.declare_partials('f', 'var1',cols=np.arange(dim2*dim3*dim1),rows=np.repeat(np.arange(dim1),dim2*dim3))
            self.declare_partials('f', 'var2' ,cols=np.arange(dim2*dim3*dim1),rows=np.repeat(np.arange(dim1),dim2*dim3))

    def compute(self, inputs, outputs):
        self.cou+=1
        # print(self.cou)
        var1 = inputs['var1']
        var2 = inputs['var2']
        m=3
        outputs['f'] = np.sum((var2*var1**m),axis=(1,2))

    def compute_partials(self, inputs, partials):
        if self.flag:
            pass
        else:
            m=3
            var1 = inputs['var1']
            var2 = inputs['var2']
            partials['f','var1'] = (var1**m*m*var2/var1).flatten()
            partials['f','var2' ]= (var1**m).flatten()
            self.partcou+=1
            # print(self.partcou)

model = Group()
comp = IndepVarComp()

comp.add_output('var1', ran1)
comp.add_output('var2', ran2)
#comp.add_output('var1', np.ones([dim1,dim2,dim3])*5)
#comp.add_output('var2', np.ones([dim1,dim2,dim3])*10)
model.add_subsystem('input', comp,promotes=['*'])
model.add_subsystem('example', FDPartialComp(),promotes=['*'])


model.linear_solver = DirectSolver(assemble_jac=True)

problem = Problem(model=model)
problem.setup(check=True, mode='fwd')

problem.final_setup()

# exit()
#problem.run_model()
st=time.time()
totals = problem.compute_totals(['f'], ['var1','var2'])
#problem.check_partials(compact_print=True,method='cs')
print(time.time()-st)
print(problem._mode)
...