Skip to content

Commit e823f4e

Browse files
authored
Merge pull request #371 from Purg/dev/eval-2-logger-node
Eval 2 logger node
2 parents 10d0f5d + 7709b63 commit e823f4e

File tree

12 files changed

+726
-58
lines changed

12 files changed

+726
-58
lines changed

angel_system/data/config_structs.py

+160-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
Structures related to configuration files.
33
"""
44

5-
from dataclasses import dataclass, field
5+
from dataclasses import dataclass
66
from os import PathLike
7+
from pathlib import Path
78
from typing import cast
89
from typing import Dict
10+
from typing import Optional
911
from typing import Sequence
1012
from typing import Tuple
1113

@@ -34,7 +36,7 @@ class ObjectLabelSet:
3436

3537
def __post_init__(self):
3638
# coerce nested label objects into the ObjectLabel type.
37-
if self.labels and not isinstance(self.labels, ObjectLabel):
39+
if self.labels and not isinstance(self.labels[0], ObjectLabel):
3840
raw_labels = cast(Sequence[Dict], self.labels)
3941
self.labels = tuple(ObjectLabel(**rl) for rl in raw_labels)
4042

@@ -50,3 +52,159 @@ def load_object_label_set(filepath: PathLike) -> ObjectLabelSet:
5052
with open(filepath) as infile:
5153
data = yaml.safe_load(infile)
5254
return ObjectLabelSet(**data)
55+
56+
57+
@dataclass
58+
class ActivityLabel:
59+
"""
60+
One activity classification ID and paired label information.
61+
"""
62+
63+
# Identifier integer for this activity label
64+
id: int
65+
# Concise string label for this activity. Should not contain any spaces.
66+
label: str
67+
# Full sentence description of this activity.
68+
full_str: str
69+
# Optional integer representing how many times an activity should be
70+
# repeated to be considered "full"
71+
# TODO: This parameter has ambiguous and violated meaning (not used as
72+
# intended if at all).
73+
repeat: Optional[int] = None
74+
75+
76+
@dataclass
77+
class ActivityLabelSet:
78+
version: str
79+
title: str
80+
labels: Tuple[ActivityLabel]
81+
82+
def __post_init__(self):
83+
# coerce nested label objects into the ObjectLabel type.
84+
if self.labels and not isinstance(self.labels[0], ActivityLabel):
85+
raw_labels = cast(Sequence[Dict], self.labels)
86+
self.labels = tuple(ActivityLabel(**rl) for rl in raw_labels)
87+
88+
89+
def load_activity_label_set(filepath: PathLike) -> ActivityLabelSet:
90+
"""
91+
Load from YAML file an activity label set configuration.
92+
93+
:param filepath: Filepath to load from.
94+
95+
:return: Structure containing the loaded configuration.
96+
"""
97+
with open(filepath) as infile:
98+
data = yaml.safe_load(infile)
99+
return ActivityLabelSet(**data)
100+
101+
102+
@dataclass
103+
class TaskStep:
104+
"""
105+
A single task step with activity components.
106+
"""
107+
108+
id: int
109+
label: str
110+
full_str: str
111+
activity_ids: Tuple[int]
112+
113+
114+
@dataclass
115+
class LinearTask:
116+
"""
117+
A linear task with steps composed of activities.
118+
"""
119+
120+
version: str
121+
title: str
122+
labels: Tuple[TaskStep]
123+
124+
def __post_init__(self):
125+
# Coerce pathlike input (str) into a Path instance if not already.
126+
if self.labels and not isinstance(self.labels[0], TaskStep):
127+
raw = cast(Sequence[Dict], self.labels)
128+
self.labels = tuple(TaskStep(**r) for r in raw)
129+
130+
131+
def load_linear_task_config(filepath: PathLike) -> LinearTask:
132+
"""
133+
Load from YAML file a linear task configuration.
134+
135+
:param filepath: Filepath to load from.
136+
137+
:return: Structure containing the loaded configuration.
138+
"""
139+
with open(filepath) as infile:
140+
data = yaml.safe_load(infile)
141+
return LinearTask(**data)
142+
143+
144+
@dataclass
145+
class OneTaskConfig:
146+
"""
147+
Specification of where one task configuration is located.
148+
"""
149+
150+
id: int
151+
label: str
152+
config_file: Path
153+
active: bool
154+
155+
def __post_init__(self):
156+
# Coerce pathlike input (str) into a Path instance if not already.
157+
# Interpret relative paths now to absolute based on current working
158+
# directory.
159+
if not isinstance(self.config_file, Path):
160+
self.config_file = Path(self.config_file).absolute()
161+
162+
163+
@dataclass
164+
class MultiTaskConfig:
165+
"""
166+
A collection of linear task configurations.
167+
"""
168+
169+
version: str
170+
title: str
171+
tasks: Tuple[OneTaskConfig]
172+
173+
def __post_init__(self):
174+
# coerce nested task objects into OneTaskConfig types
175+
if self.tasks and not isinstance(self.tasks[0], OneTaskConfig):
176+
raw = cast(Sequence[Dict], self.tasks)
177+
self.tasks = tuple(OneTaskConfig(**r) for r in raw)
178+
179+
180+
def load_multi_task_config(filepath: PathLike):
181+
"""
182+
Relative file paths are currently interpreted relative to the current
183+
working directory and resolved to be absolute.
184+
185+
:param filepath: Filepath to load from.
186+
187+
:return: Structure containing the loaded configuration.
188+
"""
189+
with open(filepath) as infile:
190+
data = yaml.safe_load(infile)
191+
return MultiTaskConfig(**data)
192+
193+
194+
def load_active_task_configs(cfg: MultiTaskConfig) -> Dict[str, LinearTask]:
195+
"""
196+
Load task configurations that are enabled in the multitask configuration.
197+
198+
:param cfg: Multitask configuration to base loading on.
199+
200+
:raises FileNotFoundError: Configured task configuration file did not refer
201+
to an open-able file.
202+
203+
:return: Mapping of task label from the input configuration to the
204+
LinearTask instance loaded.
205+
"""
206+
return {
207+
ct.label: load_linear_task_config(ct.config_file)
208+
for ct in cfg.tasks
209+
if ct.active
210+
}

angel_system/global_step_prediction/global_step_predictor.py

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def __init__(
2828
GlobalStepPredctor: based on a TCN activity classifier's activity classification
2929
outputs + a set of recipes, track what step a user is on for multiple recipes.
3030
"""
31+
# TODO: make use of angel_system.data.config_structs instead of
32+
# manually loading and accessing by string keys.
3133
with open(activity_config_fpath, "r") as stream:
3234
self.activity_config = yaml.safe_load(stream)
3335
num_activity_classes = len(self.activity_config["labels"])
@@ -68,6 +70,8 @@ def __init__(
6870
self.activity_conf_history = np.empty((0, num_activity_classes))
6971

7072
self.recipe_types = recipe_types
73+
# TODO: Expect use of angel_system.data.config_structs instead of
74+
# a raw dictionary.
7175
self.recipe_configs = recipe_config_dict
7276

7377
# Array of tracker dicts
@@ -116,6 +120,8 @@ def get_activity_order_from_config(self, config_fn):
116120
Get the order of activity_ids (mapping to granular step
117121
number) based on a recipe config
118122
"""
123+
# TODO: make use of angel_system.data.config_structs instead of
124+
# manually loading and accessing by string keys.
119125
with open(config_fn, "r") as stream:
120126
config = yaml.safe_load(stream)
121127
broad_steps = config["labels"]
@@ -208,6 +214,8 @@ def initialize_new_recipe_tracker(self, recipe, config_fn=None):
208214
config_fn = self.recipe_configs[recipe]
209215

210216
# Read in task config
217+
# TODO: make use of angel_system.data.config_structs instead of
218+
# manually loading and accessing by string keys.
211219
with open(config_fn, "r") as stream:
212220
config = yaml.safe_load(stream)
213221
labels = [self.sanitize_str(l["full_str"]) for l in config["labels"]]
@@ -1025,6 +1033,8 @@ def get_gt_steps_from_gt_activities(self, video_dset, config_fn):
10251033
def sanitize_str(str_: str):
10261034
return str_.lower().strip(" .")
10271035

1036+
# TODO: make use of angel_system.data.config_structs instead of
1037+
# manually loading and accessing by string keys.
10281038
with open(config_fn, "r") as stream:
10291039
config = yaml.safe_load(stream)
10301040
labels = [sanitize_str(l["label"]) for l in config["labels"]]

config/tasks/multi-task-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ tasks:
1818
- id: 1
1919
label: "Tea"
2020
config_file: "./config/tasks/recipe_tea.yaml"
21-
active: false
21+
active: true
2222
- id: 2
2323
label: "Pinwheel"
2424
config_file: "./config/tasks/recipe_pinwheel.yaml"
25-
active: false
25+
active: true
2626
- id: 3
2727
label: "Oatmeal"
2828
config_file: "./config/tasks/recipe_oatmeal.yaml"
29-
active: false
29+
active: true
3030
- id: 4
3131
label: "Dessert Quesadilla"
3232
config_file: "./config/tasks/recipe_dessertquesadilla.yaml"

ros/angel_system_nodes/angel_system_nodes/eval/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)