求助:在约束中使用om.slicer时SqliteRecorder崩溃问题
SqliteRecorder崩溃问题:使用
om.slicer约束时JSON序列化失败 问题描述
当在OpenMDAO中为约束配置使用om.slicer时,SqliteRecorder会在启动阶段直接崩溃,抛出TypeError: Object of type slice is not JSON serializable错误。根源在于slice对象无法被Python默认的JSON编码器处理,而SqliteRecorder在记录变量配置信息时,会尝试把包含om.slicer的约束设置转为JSON格式,最终触发序列化失败。
错误追踪栈
Traceback (most recent call last): File "test_slicer.py", line 38, in <module> p.run_model() File "/Users/frza/git/OpenMDAO/openmdao/core/problem.py", line 610, in run_model self.final_setup() File "/Users/frza/git/OpenMDAO/openmdao/core/problem.py", line 959, in final_setup self._setup_recording() File "/Users/frza/git/OpenMDAO/openmdao/core/problem.py", line 728, in _setup_recording self._rec_mgr.startup(self) File "/Users/frza/git/OpenMDAO/openmdao/recorders/recording_manager.py", line 91, in startup recorder.startup(recording_requester) File "/Users/frza/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py", line 394, in startup var_settings_json = json.dumps(var_settings) File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py", line 231, in dumps return _default_encoder.encode(obj) File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True) File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 257, in iterencode return _iterencode(o, 0) File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 179, in default raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type slice is not JSON serializable
复现代码
以下是可复现该问题的最小示例(取自openmdao/core/tests/test_group.py):
import numpy as np import openmdao.api as om from openmdao.api import SqliteRecorder arr_order_1x1 = np.array([1, 2, 3, 4]) class SlicerComp(om.ExplicitComponent): def setup(self): self.add_input('x', np.ones(4)) self.add_output('y', 1.0) def compute(self, inputs, outputs): outputs['y'] = np.sum(inputs['x'])**2.0 p = om.Problem() p.model.add_subsystem('indep', om.IndepVarComp('x', arr_order_1x1)) p.model.add_subsystem('C1', SlicerComp()) p.model.connect('indep.x', 'C1.x') p.model.add_constraint('indep.x', indices=om.slicer[2:]) p.model.add_objective('C1.y') p.setup() p.run_model() precorder = SqliteRecorder('poptimization.sqlite') p.recording_options['record_desvars'] = True p.recording_options['record_constraints'] = True p.recording_options['record_objectives'] = True p.add_recorder(precorder) p.setup() p.run_model() p.cleanup()
环境信息
- 操作系统:OS X 10.15.5、CentOS
- Python版本:3.6.1、3.8.5
- OpenMDAO版本:master分支
解决方案
永久修复(修改OpenMDAO源码)
需要给SqliteRecorder添加自定义JSON编码器来处理slice对象,具体操作:
- 在
openmdao/recorders/sqlite_recorder.py文件中,添加自定义编码器类:
import json class SliceEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, slice): return { '__type__': 'slice', 'start': obj.start, 'stop': obj.stop, 'step': obj.step } return super().default(obj)
- 修改文件中
startup方法里的json.dumps调用,指定使用自定义编码器:
var_settings_json = json.dumps(var_settings, cls=SliceEncoder)
临时 workaround(无需修改源码)
暂时替换om.slicer的用法,改用列表形式的索引。比如把indices=om.slicer[2:]改成indices=[2,3],这样就能绕过序列化问题,正常使用SqliteRecorder。
内容的提问来源于stack exchange,提问作者frza
相关产品推荐
相关产品推荐

