compute_totals возвращает неправильные итоговые производные, когда ок. - PullRequest
0 голосов
/ 18 февраля 2020

Я заметил, что prob.compute_totals() возвращает неправильный ответ, когда prob.model.approx_totals() не указан ранее. Если частная производная, определенная вручную или вычисленная с помощью конечных разностей, ничего не меняет, ответ остается неправильным, если ранее не вызывать prob.model.approx_totals(). Кроме того, вызов compute_totals на самом деле быстрее, когда approx_totals вызывается раньше, по сравнению с тем, когда это не так. Это кажется нелогичным с заданными вручную частями, поскольку предполагается, что approx_totals добавляет ненужные вычисления с конечными разностями.

Вот MWE с примером Sellar, взятым из документации OpenMDAO. Я также заметил такое же поведение в OpenAeroStruct, хотя различия меньше, чем в этом примере.

import openmdao.api as om
from openmdao.test_suite.components.sellar_feature import SellarMDA

prob = om.Problem()
prob.model = SellarMDA()

prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['tol'] = 1e-8

prob.model.add_design_var('x', lower=0, upper=10)
prob.model.add_design_var('z', lower=0, upper=10)
prob.model.add_objective('obj')
prob.model.add_constraint('con1', upper=0)
prob.model.add_constraint('con2', upper=0)

prob.setup()
prob.set_solver_print(level=0)

prob.model.approx_totals() # Commenting this line gives the wrong result

prob.run_driver()
totals = prob.compute_totals(of=['obj'],wrt=['x','z'])

print("""
Obj = {}
x = {}
z = {}
y1 = {}
y2 = {}
Totals = {}""".format(prob['obj'][0],prob['x'][0],prob['z'][0],prob['y1'][0],prob['y2'][0],totals))

Хороший результат с approx_totals:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 3.183393951729169
            Iterations: 6
            Function evaluations: 6
            Gradient evaluations: 6
Optimization Complete
-----------------------------------

Obj = 3.183393951729169
x = 0.0
z = 1.977638883487764
y1 = 3.1600000000897133
y2 = 3.755277766976125
Totals = OrderedDict([(('obj', 'x'), array([[0.94051147]])), (('obj', 'z'), array([[3.50849282, 1.72901602]]))])

Неправильный результат без approx_totals:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 3.1833939532752136
            Iterations: 11
            Function evaluations: 12
            Gradient evaluations: 11
Optimization Complete
-----------------------------------

Obj = 3.1833939532752136
x = 4.401421628747386e-15
z = 1.9776388839289216
y1 = 3.1600000016563765
y2 = 3.755277767857951
Totals = OrderedDict([(('obj', 'x'), array([[0.99341446]])), (('obj', 'z'), array([[3.90585351, 1.97002055]]))])

1 Ответ

1 голос
/ 18 февраля 2020

В этом примере проблема в том, что у вас есть цикл в SellarMDA, но модель не содержит линейного решателя, который может вычислить итоговые производные по циклу. Один из способов проверить это - запустить «openmdao check myfilename.py» в командной строке. Я запустил его на вашей модели и получил следующие предупреждения:

INFO: checking comp_has_no_outputs
INFO: checking dup_inputs
INFO: checking missing_recorders
WARNING: The Problem has no recorder of any kind attached
INFO: checking out_of_order
INFO: checking solvers
WARNING: Group 'cycle' contains cycles [['d1', 'd2']], but does not have an iterative linear solver.
INFO: checking system

Для этого есть несколько способов. Вы можете вручную добавить другой линейный решатель, такой как DirectSolver или PETScKrylov, в группу «цикл». Вы также можете импортировать SellarMDALinearSolver вместо SellarMDA. SellarMDALinearSolver использует решатель Ньютона для сходимости цикла и DirectSolver для вычисления производных. SellarMDA использует NonlinearBlockGS для сходимости цикла, но, к сожалению, не содержит соответствующего линейного решателя для вычисления производных. Эти компоненты используются в различных ролях тестирования, но я думаю, что в ретроспективе нам, вероятно, следует добавить LinearBlockGS в SellarMDA в будущем, чтобы суммарные производные можно было вычислять без изменений. Пока что вам придется использовать SellarMDALinearSolver или добавить решатель самостоятельно.

Кстати, я подозреваю, что оптимизация была медленнее, потому что производные были очень плохими. Потребовалось вдвое больше итераций, хотя все же каким-то образом удалось приблизиться к ответу.

Вы упомянули похожие симптомы в своей модели OpenAeroStruct. Я подозреваю, что либо 1) подкомпонент имеет ошибку в своих аналитических производных, либо 2) линейные решатели настроены неправильно (возможно, у вас есть цикл где-то без хорошего линейного решателя в этой группе или родительской группе). Я думаю, что Problem.check_partials и Problem.check_totals помогут вам лучше понять, где может быть проблема. Подробнее об этих можно узнать здесь.

...