Как определить партиалы для немасштабированных моделей (с компонентами ResponseSurface)? - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь запустить оптимизацию большой модели, содержащей 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 суррогатных моделей.

1 Ответ

0 голосов
/ 11 января 2019

Мое первое предложение состоит в том, чтобы создать группу вокруг вашего экземпляра MetaModelUnstructured, а затем установить метод приблизительно для этой группы, в частности. Это позволит вам выделить этот конкретный компонент. Если вы можете заставить его работать / не работать на основе этого, то его 100% подтвердили, что это метамодель, а не какой-то другой компонент с плохими частями. Ваш собственный тест с использованием метамодели с ручным кодированием и компонента OpenMDAO определенно может показаться, что проблема в том, что есть ... но было бы неплохо провести еще одну проверку работоспособности.

Некоторые суррогатные модели имеют аналитические производные, но некоторые нет, и тогда используется FD. Похоже, вы используете суррогат ResponseSurface , который предоставляет аналитические производные. Но, возможно, в этой реализации есть ошибка. Если есть ошибка, и вы не видите ничего, что появляется в check_partials при просмотре, тогда я предлагаю взять окончательный оптимизированный результат (или некоторую близкую к нему точку) и установить его в качестве начального условия, затем вызвать одиночный run_model() перед звонком check_partials(). Если приведенная выше проверка работоспособности доказывает, что проблема связана с вашей компиляцией MetaModel. FY Вы можете указать имя компонента метамодели конкретно

...