计数函数评估
Counting function evaluations
我刚刚完成了有关 reader 和录音机的教程。我想知道是否有一种方法可以计算每个学科被调用的次数。下面我在 Sellar 问题中使用全局变量来计算这个。什么是更好的方法来做到这一点?另外,如果问题中没有求解器,建议的方法会改变吗?
import numpy as np
import time
import openmdao.api as om
tic = time.perf_counter()
dc1 = 0
dc2 = 0
class SellarDis1(om.ExplicitComponent):
def setup(self):
self.add_input('z', val=np.zeros(2))
self.add_input('x', val=0.)
self.add_input('y2', val=1.0)
self.add_output('y1', val=1.0)
self.declare_partials('*', '*', method='fd')
def compute(self, inputs, outputs):
global dc1
dc1+=1
z1 = inputs['z'][0]
z2 = inputs['z'][1]
x1 = inputs['x']
y2 = inputs['y2']
outputs['y1'] = z1**2 + z2 + x1 - 0.2*y2
class SellarDis2(om.ExplicitComponent):
def setup(self):
self.add_input('z', val=np.zeros(2))
self.add_input('y1', val=1.0)
self.add_output('y2', val=1.0)
self.declare_partials('*', '*',method='fd')
def compute(self, inputs, outputs):
global dc2
dc2 +=1
z1 = inputs['z'][0]
z2 = inputs['z'][1]
y1 = inputs['y1']
if y1.real < 0.0:
y1 *= -1
outputs['y2'] = y1**.5 + z1 + z2
class SellarMDF(om.Group):
def setup(self):
indeps = self.add_subsystem('indeps', om.IndepVarComp(), promotes=['*'])
indeps.add_output('x', 1.0)
indeps.add_output('z', np.array([5.0, 2.0]))
cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])
cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],
promotes_outputs=['y1'])
cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],
promotes_outputs=['y2'])
cycle.linear_solver = om.ScipyKrylov()
cycle.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',
z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0),
promotes=['x', 'z', 'y1', 'y2', 'obj'])
self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])
self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])
prob = om.Problem()
prob.model = SellarMDF()
driver = prob.driver = om.ScipyOptimizer()
prob.driver.options['optimizer'] = 'SLSQP'
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.run_driver()
print('minimum found at')
print(prob['x'][0])
print(prob['z'])
print('Coupling Variables')
print(prob['y1'][0])
print(prob['y2'][0])
print('minumum objective')
print(prob['obj'][0])
toc = time.perf_counter()
print(f"You waited {toc - tic:0.4f} seconds")
print("Function Calls")
print('SellarDis1 : ', dc1)
print('SellarDis2 : ', dc2)
编辑:更好的意思是“openmdao”方式,比如录音机之类的。
像 Coverage or PyTest-Cov 这样的覆盖工具可以在 python 解释器中使用钩子来收集有关代码在程序执行期间 运行 的数据,这通常包括“命中”的数量" 每个函数甚至单独的行。如果您只想要程序外的数字,这对您来说可能已经足够了。
如果您需要在脚本本身中使用数字,您可以自己使用一些底层 API。使用 sys.settrace you can register a function to be called on every function call in your program. The first argument to that function will be a frame object,其中包含您可以用来检查这是否是您感兴趣的函数的属性。
这是一个简短的例子:
import sys
class A:
def my_func(self, x):
return x + 1
my_func_calls = 0
def tracefunc(frame, event, arg):
global my_func_calls
if event == 'call' and frame.f_code.co_name == 'my_func':
my_func_calls += 1
sys.settrace(tracefunc)
if __name__ == '__main__':
a = A()
x = a.my_func(0)
x = a.my_func(x)
x = a.my_func(x)
print("my_func_calls:", my_func_calls)
因为我看不到任何方法来获取与之关联的实际函数对象(这会给你 class 使用 __self__.__class__
),你可能需要使用 frame.co_firstlineno
区分同名方法。
这个跟踪功能的细节有点棘手,您可以参考 coverage.py's implementation 以获取有关您的选择和可能出现的问题的灵感。
所有 OpenMDAO 系统(组件和组的总称)都具有 iter_count
属性。这是 documentation page for System
,所有组件和组都继承自它。 iter_count
是对每个 compute()
方法的调用总数,而 iter_count_without_approx
是对 compute()
方法的调用次数,不包括由于梯度近似引起的调用。此方法适用于任何求解器层次结构或驱动程序设置。
示例脚本的最后两行将是:
print('SellarDis1 : ', prob.model.cycle.d1.iter_count)
print('SellarDis2 : ', prob.model.cycle.d2.iter_count)
这并没有像您建议的那样使用录音机。如果您更喜欢使用记录器的解决方案,我们可以找到可行的方法。那里有很大的灵活性,要开始使用,您可以查看 this specific doc page on case reading,这可以帮助对案例进行后处理以获得呼叫总数。
如有不明之处请告诉我!
我刚刚完成了有关 reader 和录音机的教程。我想知道是否有一种方法可以计算每个学科被调用的次数。下面我在 Sellar 问题中使用全局变量来计算这个。什么是更好的方法来做到这一点?另外,如果问题中没有求解器,建议的方法会改变吗?
import numpy as np
import time
import openmdao.api as om
tic = time.perf_counter()
dc1 = 0
dc2 = 0
class SellarDis1(om.ExplicitComponent):
def setup(self):
self.add_input('z', val=np.zeros(2))
self.add_input('x', val=0.)
self.add_input('y2', val=1.0)
self.add_output('y1', val=1.0)
self.declare_partials('*', '*', method='fd')
def compute(self, inputs, outputs):
global dc1
dc1+=1
z1 = inputs['z'][0]
z2 = inputs['z'][1]
x1 = inputs['x']
y2 = inputs['y2']
outputs['y1'] = z1**2 + z2 + x1 - 0.2*y2
class SellarDis2(om.ExplicitComponent):
def setup(self):
self.add_input('z', val=np.zeros(2))
self.add_input('y1', val=1.0)
self.add_output('y2', val=1.0)
self.declare_partials('*', '*',method='fd')
def compute(self, inputs, outputs):
global dc2
dc2 +=1
z1 = inputs['z'][0]
z2 = inputs['z'][1]
y1 = inputs['y1']
if y1.real < 0.0:
y1 *= -1
outputs['y2'] = y1**.5 + z1 + z2
class SellarMDF(om.Group):
def setup(self):
indeps = self.add_subsystem('indeps', om.IndepVarComp(), promotes=['*'])
indeps.add_output('x', 1.0)
indeps.add_output('z', np.array([5.0, 2.0]))
cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])
cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],
promotes_outputs=['y1'])
cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],
promotes_outputs=['y2'])
cycle.linear_solver = om.ScipyKrylov()
cycle.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',
z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0),
promotes=['x', 'z', 'y1', 'y2', 'obj'])
self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])
self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])
prob = om.Problem()
prob.model = SellarMDF()
driver = prob.driver = om.ScipyOptimizer()
prob.driver.options['optimizer'] = 'SLSQP'
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.run_driver()
print('minimum found at')
print(prob['x'][0])
print(prob['z'])
print('Coupling Variables')
print(prob['y1'][0])
print(prob['y2'][0])
print('minumum objective')
print(prob['obj'][0])
toc = time.perf_counter()
print(f"You waited {toc - tic:0.4f} seconds")
print("Function Calls")
print('SellarDis1 : ', dc1)
print('SellarDis2 : ', dc2)
编辑:更好的意思是“openmdao”方式,比如录音机之类的。
像 Coverage or PyTest-Cov 这样的覆盖工具可以在 python 解释器中使用钩子来收集有关代码在程序执行期间 运行 的数据,这通常包括“命中”的数量" 每个函数甚至单独的行。如果您只想要程序外的数字,这对您来说可能已经足够了。
如果您需要在脚本本身中使用数字,您可以自己使用一些底层 API。使用 sys.settrace you can register a function to be called on every function call in your program. The first argument to that function will be a frame object,其中包含您可以用来检查这是否是您感兴趣的函数的属性。
这是一个简短的例子:
import sys
class A:
def my_func(self, x):
return x + 1
my_func_calls = 0
def tracefunc(frame, event, arg):
global my_func_calls
if event == 'call' and frame.f_code.co_name == 'my_func':
my_func_calls += 1
sys.settrace(tracefunc)
if __name__ == '__main__':
a = A()
x = a.my_func(0)
x = a.my_func(x)
x = a.my_func(x)
print("my_func_calls:", my_func_calls)
因为我看不到任何方法来获取与之关联的实际函数对象(这会给你 class 使用 __self__.__class__
),你可能需要使用 frame.co_firstlineno
区分同名方法。
这个跟踪功能的细节有点棘手,您可以参考 coverage.py's implementation 以获取有关您的选择和可能出现的问题的灵感。
所有 OpenMDAO 系统(组件和组的总称)都具有 iter_count
属性。这是 documentation page for System
,所有组件和组都继承自它。 iter_count
是对每个 compute()
方法的调用总数,而 iter_count_without_approx
是对 compute()
方法的调用次数,不包括由于梯度近似引起的调用。此方法适用于任何求解器层次结构或驱动程序设置。
示例脚本的最后两行将是:
print('SellarDis1 : ', prob.model.cycle.d1.iter_count)
print('SellarDis2 : ', prob.model.cycle.d2.iter_count)
这并没有像您建议的那样使用录音机。如果您更喜欢使用记录器的解决方案,我们可以找到可行的方法。那里有很大的灵活性,要开始使用,您可以查看 this specific doc page on case reading,这可以帮助对案例进行后处理以获得呼叫总数。
如有不明之处请告诉我!