Я пытаюсь запустить оптимизацию большой модели, содержащей MetaModelUnstructuredComps
(MMUC), где выходные данные оцениваются с использованием ReponseSurfaces
. Сначала я уже создал эту модель вручную, и она работает, как и ожидалось. Однако в этой модели все переменные были масштабированы (также входы и выходы поверхностей отклика и других компонентов). Частицы для MMUC выполняются с использованием конечной разницы с настройками по умолчанию. Во второй реализации (которая автоматически создается с использованием пакета OpenLEGO) входы и выходы компонентов (суррогатные модели, ограничения и т. Д.) Не масштабируются (хотя переменные проекта масштабируются для драйвера с использованием ref
и ref0
аргументы и ограничения + цель также масштабируются в их уравнении). Когда я пытаюсь оптимизировать эту модель (pyOptSparse/SLSQP
), оптимизация не увенчается успехом, и ей трудно выполнить несколько ограничений равенства. Интересно, что когда я использую approx_totals(step_calc='rel')
на модели, тогда оптимизация работает. Это создало у меня впечатление, что что-то не так с вычисляемыми и объединенными частями.
Итак, я попытался отладить эту проблему, используя compute_totals()
, чтобы посмотреть, каково общее количество производных в начале оптимизации. Вот некоторые типичные значения для двух ответов FR
и Gc.WE
:
of / wrt | approx_totals | partials |
---------------------------------------------
FR / w_WE -2824914,296 3166,669425
FR / w_ESF -7039070,86 -3447,735199
FR / D -1416,834424 1,718097909
FR / w_L -1594560,102 11755399102
FR / ESF -10741467,19 -71835372264
FR / w_D -305835126,1 190116092,9
FR / h -132,8664739 -1053392,711
FR / Theta -7663550,5 76607039579
FR / w_Theta -2458516,552 42170,96747
FR / M -5692867,582 -1,02E+11
FR / Lambda -114534,707 2831614491
FR / L -176,6461801 728,0673131
FR / WE -833,5583125 3240,452002
FR / tc -132833949,9 -17828405236
FR / w_WT -2606083,221 99243,27639
FR / WT -176,646275 1663865,719
FR / AR -3220216,113 -3,03E+11
FR / Sref -5339,233451 340740598,7
Gc.WE / w_WE -354442,2873 -10,94512505
Gc.WE / w_ESF -883192,9447 -7,231199285
Gc.WE / D -177,7706417 0,2982562
Gc.WE / w_L -200069,6665 0
Gc.WE / ESF -1347733,361 0
Gc.WE / w_D -38373164,66 0
Gc.WE / h -16,6709147 -0,689845824
Gc.WE / Theta -961539,6393 0
Gc.WE / w_Theta -308470,3246 0
Gc.WE / M -714285,1914 13180,76857
Gc.WE / Lambda -14370,66473 0
Gc.WE / L -22,16381204 0
Gc.WE / WE -104,5865158 1
Gc.WE / tc -16666686,96 0
Gc.WE / w_WT -326985,5298 0
Gc.WE / WT -22,16381204 0
Gc.WE / AR -404040,8959 0
Gc.WE / Sref -669,9145362 0
---------------------------------------------
К моему удивлению, итоговые значения с approx_totals()
не всегда соответствуют ожидаемым (например, 0 ожидается для Gc.WE / D
), но оптимизация работает с использованием approx_totals()
. Кроме того, в конце оптимизации эти итоговые значения равны или близки к нулю, поэтому, похоже, это обрабатывается правильно. Итоговые значения, которые определяются на основе партиалов, в большей степени соответствуют моим ожиданиям (по крайней мере, 0 и 1), но оптимизация не выполняется правильно.
К сожалению, я не могу поделиться полным кодом здесь. Я работаю над небольшим рабочим примером, который показал бы ту же проблему, но пока не нашел ее. Просто хотел поставить мой вопрос уже здесь, чтобы посмотреть, есть ли какие-либо советы по этому поводу.
Я ожидал, что модель будет работать одинаково с approx_totals()
или без него, поскольку все компоненты в модели будут определять партиалы с конечной разницей, или партиалы предоставляются аналитически (из которых я уверен, что они верны после проверка с check_partials()
). Поскольку входы различных компонентов не масштабируются, я попытался отрегулировать step_size
метода fd
, чтобы он соответствовал диапазону входа (поэтому для Gc.WE / D
вместо step_size=1E-6
это было изменено на step_size=10000*1E-6
, поскольку D
находится между 0 и 20000), но безрезультатно.
Есть ли у вас какие-либо советы по дальнейшей отладке этой проблемы? Как лучше всего объявить частичные значения для компонентов, где входные данные имеют совершенно разные диапазоны? Или может быть другая проблема, если оптимизация с approx_totals()
работает, но не без нее, кроме того, что что-то не так с партиалами?
Небольшой рабочий пример на основе первого ответа
import numpy as np
from openmdao.api import Problem, Group, ResponseSurface, IndepVarComp, MetaModelUnStructuredComp
x_train = np.arange(0., 10.)
y_train = np.arange(10., 20.)
z_train = x_train**2 + y_train**2
p = Problem()
p.model = m = Group()
params = IndepVarComp()
params.add_output('x', val=0.)
params.add_output('y', val=0.)
m.add_subsystem('params', params, promotes=['*'])
sm = MetaModelUnStructuredComp(default_surrogate=ResponseSurface())
sm.add_input('x', val=0.)
sm.add_input('y', val=0.)
sm.add_output('z', val=0.)
sm.options['train:x'] = x_train
sm.options['train:y'] = y_train
sm.options['train:z'] = z_train
# With or without the line below does not matter
# Only when method is set to fd, then RuntimeWarning disappears
sm.declare_partials('*', '*', method='exact')
m.add_subsystem('sm', sm, promotes=['*'])
m.add_design_var('x', lower=0., upper=10.)
m.add_design_var('y', lower=0., upper=10.)
m.add_objective('z')
p.setup()
p['x'] = 5.
p['y'] = 12.
p.run_model()
print('\nSM-value z: {}'.format(float(p['z'])))
print('theoretical z: {}'.format(float(p['x']**2 + p['y']**2)))
totals = p.compute_totals()
print('\nSM-value z wrt x: {}'.format(totals[('sm.z', 'params.x')][0][0]))
print('theoretical value z wrt x: {}'.format(2*p['x'][0]))
print('\nSM-value z wrt y: {}'.format(totals[('sm.z', 'params.y')][0][0]))
print('theoretical value z wrt y: {}'.format(2*p['y'][0]))
На основании этого примера я получаю следующий журнал:
/Users/imcovangent/Documents/PhD/Software/OpenMDAO/openmdao/components/meta_model_unstructured_comp.py:287: RuntimeWarning:Because the MetaModelUnStructuredComp 'sm' uses a surrogate which does not define a linearize method,
OpenMDAO will use finite differences to compute derivatives. Some of the derivatives will be computed
using default finite difference options because they were not explicitly declared.
The derivatives computed using the defaults are:
sm.z, sm.x
sm.z, sm.y
SM-value z: 169.213661944
theoretical z: 169.0
SM-value z wrt x: 10.0415292063
theoretical value z wrt x: 10.0
SM-value z wrt y: 23.9584707937
theoretical value z wrt y: 24.0
/usr/local/lib/python2.7/site-packages/scipy/linalg/basic.py:1018: RuntimeWarning: internal gelsd driver lwork query error, required iwork dimension not returned. This is likely the result of LAPACK bug 0038, fixed in LAPACK 3.2.2 (released July 21, 2010). Falling back to 'gelss' driver.
warnings.warn(mesg, RuntimeWarning)
Первое сообщение RunTimeWarning стало источником моего замешательства. Чтобы избавиться от этого, я объявил частичные значения с помощью method=fd
, но, глядя на это снова, похоже, просто выдает предупреждение, но на самом деле используется метод linearize
суррогатной модели. Следовательно, предупреждение является неправильным для ResponseSurface
суррогатных моделей.