Note
Click here to download the full example code
Export Algorithms to JSON#
This example demonstrates how to save algorithms including their configuration to json and load them again to ensure reproducibility.
The example will use StrideLevelParameter as example, but the same will
work with all other algorithms (and Pipelines).
Warning
This json export only stores the Parameters of an algorithm and not any potential results!
Warning
While calling an Algorithms with the same parameters should produce the same results, you also need to ensure that the same version of gaitmap (and all other dependencies) is used to ensure full reproducibility. This means you should save the exact library version together with the json version of the used algorithms.
from pprint import pprint
To JSON#
In the following we will create an algorithm instance that itself has other nested algorithm objects. In the from the json output
from scipy.spatial.transform import Rotation
from gaitmap.base import BaseAlgorithm
from gaitmap.trajectory_reconstruction import ForwardBackwardIntegration, MadgwickAHRS, StrideLevelTrajectory
# Setting an initial orientation here, is pointless as it will be overwritten by StrideLevelTrajectory
# It is used here to demonstrate the ability to serialize Rotation objects.
custom_ori_method = MadgwickAHRS(beta=0.5, initial_orientation=Rotation.from_quat([0, 3, 3, 0]))
custom_pos_method = ForwardBackwardIntegration(turning_point=0.8)
slt = StrideLevelTrajectory(ori_method=custom_ori_method, pos_method=custom_pos_method, align_window_width=10)
pprint(slt.get_params())
{'align_window_width': 10,
'ori_method': MadgwickAHRS(beta=0.5, initial_orientation=<scipy.spatial.transform._rotation.Rotation object at 0x7070f44afa80>, memory=None, use_magnetometer=False),
'ori_method__beta': 0.5,
'ori_method__initial_orientation': <scipy.spatial.transform._rotation.Rotation object at 0x7070f44afa80>,
'ori_method__memory': None,
'ori_method__use_magnetometer': False,
'pos_method': ForwardBackwardIntegration(gravity=array([0. , 0. , 9.81]), level_assumption=True, steepness=0.08, turning_point=0.8),
'pos_method__gravity': array([0. , 0. , 9.81]),
'pos_method__level_assumption': True,
'pos_method__steepness': 0.08,
'pos_method__turning_point': 0.8,
'trajectory_method': None}
json_str = slt.to_json()
print(json_str)
{
"_gaitmap_obj": "StrideLevelTrajectory",
"params": {
"align_window_width": 10,
"ori_method": {
"_gaitmap_obj": "MadgwickAHRS",
"params": {
"beta": 0.5,
"initial_orientation": {
"_obj_type": "Rotation",
"quat": [
0.0,
0.7071067811865476,
0.7071067811865476,
0.0
]
},
"memory": null,
"use_magnetometer": false
}
},
"pos_method": {
"_gaitmap_obj": "ForwardBackwardIntegration",
"params": {
"gravity": {
"_obj_type": "Array",
"array": [
0.0,
0.0,
9.81
]
},
"level_assumption": true,
"steepness": 0.08,
"turning_point": 0.8
}
},
"trajectory_method": null
}
}
This output could now be stored in a file to document the exact parameters that were used for a specific analysis.
From JSON#
All algorithms can be loaded from json as well using the from_json method.
This method can be called on any algorithm class and the Algorithm class specified in the json object is returned.
To avoid confusion it is advisable to use either the exact algorithm class that was stored or BaseAlgorithm.
{'align_window_width': 10,
'ori_method': MadgwickAHRS(beta=0.5, initial_orientation=<scipy.spatial.transform._rotation.Rotation object at 0x7070f7001030>, memory=None, use_magnetometer=False),
'ori_method__beta': 0.5,
'ori_method__initial_orientation': <scipy.spatial.transform._rotation.Rotation object at 0x7070f7001030>,
'ori_method__memory': None,
'ori_method__use_magnetometer': False,
'pos_method': ForwardBackwardIntegration(gravity=array([0. , 0. , 9.81]), level_assumption=True, steepness=0.08, turning_point=0.8),
'pos_method__gravity': array([0. , 0. , 9.81]),
'pos_method__level_assumption': True,
'pos_method__steepness': 0.08,
'pos_method__turning_point': 0.8,
'trajectory_method': None}
To show that you can call from_json from any Algorithm class we will perform the same import using the
StrideLevelTrajectory.
loaded_slt = StrideLevelTrajectory.from_json(json_str)
pprint(loaded_slt.get_params())
from joblib import Memory
{'align_window_width': 10,
'ori_method': MadgwickAHRS(beta=0.5, initial_orientation=<scipy.spatial.transform._rotation.Rotation object at 0x7070f51c9e40>, memory=None, use_magnetometer=False),
'ori_method__beta': 0.5,
'ori_method__initial_orientation': <scipy.spatial.transform._rotation.Rotation object at 0x7070f51c9e40>,
'ori_method__memory': None,
'ori_method__use_magnetometer': False,
'pos_method': ForwardBackwardIntegration(gravity=array([0. , 0. , 9.81]), level_assumption=True, steepness=0.08, turning_point=0.8),
'pos_method__gravity': array([0. , 0. , 9.81]),
'pos_method__level_assumption': True,
'pos_method__steepness': 0.08,
'pos_method__turning_point': 0.8,
'trajectory_method': None}
Caching Support#
Note that the json export does not cover joblib.memory objects that some algorithms use to cache results.
When you attempt to do this, you will get a warning with further information.
from gaitmap.stride_segmentation import BarthDtw
# Create a memory object. Usually you would pass the path to a cache dir.
mem = Memory()
instance = BarthDtw(memory=Memory())
pprint(instance.get_params())
{'conflict_resolution': True,
'find_matches_method': 'find_peaks',
'max_cost': 4.0,
'max_match_length_s': 3.0,
'max_signal_stretch_ms': None,
'max_template_stretch_ms': None,
'memory': Memory(location=None),
'min_match_length_s': 0.6,
'resample_template': True,
'snap_to_min_axis': 'gyr_ml',
'snap_to_min_win_ms': 300,
'template': BarthOriginalTemplate(scaling=FixedScaler(offset=0, scale=500.0), use_cols=None),
'template__scaling': FixedScaler(offset=0, scale=500.0),
'template__scaling__offset': 0,
'template__scaling__scale': 500.0,
'template__use_cols': None}
json_str_cached = instance.to_json()
print(json_str_cached)
/home/docs/checkouts/readthedocs.org/user_builds/gaitmap/checkouts/latest/gaitmap/base.py:83: UserWarning: Exporting `joblib.Memory` objects to json is not supported. The value will be replaced by `None` and caching needs to be reactivated after loading the object again. This can be using `instance.set_params(memory=Memory(...))`
warnings.warn(
{
"_gaitmap_obj": "BarthDtw",
"params": {
"conflict_resolution": true,
"find_matches_method": "find_peaks",
"max_cost": 4.0,
"max_match_length_s": 3.0,
"max_signal_stretch_ms": null,
"max_template_stretch_ms": null,
"memory": null,
"min_match_length_s": 0.6,
"resample_template": true,
"snap_to_min_axis": "gyr_ml",
"snap_to_min_win_ms": 300,
"template": {
"_gaitmap_obj": "BarthOriginalTemplate",
"params": {
"scaling": {
"_gaitmap_obj": "FixedScaler",
"params": {
"offset": 0,
"scale": 500.0
}
},
"use_cols": null
}
}
}
}
If we now load the object again, the memory argument is empty. We need to set it again. If we use the same memory object or recreate a new memory object that points to the same cache-location, the same cache will be used as before.
loaded_instance = BarthDtw.from_json(json_str_cached)
print(loaded_instance.memory)
None
We can simply reactivate the memory.
loaded_instance = loaded_instance.set_params(memory=mem)
pprint(loaded_instance.get_params())
{'conflict_resolution': True,
'find_matches_method': 'find_peaks',
'max_cost': 4.0,
'max_match_length_s': 3.0,
'max_signal_stretch_ms': None,
'max_template_stretch_ms': None,
'memory': Memory(location=None),
'min_match_length_s': 0.6,
'resample_template': True,
'snap_to_min_axis': 'gyr_ml',
'snap_to_min_win_ms': 300,
'template': BarthOriginalTemplate(scaling=FixedScaler(offset=0, scale=500.0), use_cols=None),
'template__scaling': FixedScaler(offset=0, scale=500.0),
'template__scaling__offset': 0,
'template__scaling__scale': 500.0,
'template__use_cols': None}
Total running time of the script: ( 0 minutes 4.254 seconds)
Estimated memory usage: 9 MB