From 2a3cdedc7fed7cfa1669066c26893d00f487c440 Mon Sep 17 00:00:00 2001 From: Kathryn Baker Date: Mon, 27 Mar 2023 15:15:13 -0700 Subject: [PATCH 1/4] checking in california example --- examples/pytorch/california_client.py | 89 +++++++++++++++++++++++++++ examples/pytorch/california_server.py | 42 +++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 examples/pytorch/california_client.py create mode 100644 examples/pytorch/california_server.py diff --git a/examples/pytorch/california_client.py b/examples/pytorch/california_client.py new file mode 100644 index 0000000..0b9a6f4 --- /dev/null +++ b/examples/pytorch/california_client.py @@ -0,0 +1,89 @@ +from bokeh.io import curdoc +from bokeh.layouts import column, row +from bokeh.models import Div, Button + +from lume_epics.client.controller import Controller +from lume_model.utils import variables_from_yaml +from lume_epics.utils import config_from_yaml + +from lume_epics.client.widgets.tables import ValueTable +from lume_epics.client.widgets.controls import build_sliders +from lume_epics.client.controller import Controller + +# load the model and the variables from LUME model +with open("examples/files/california_config.yml", "r") as f: + input_variables, output_variables = variables_from_yaml(f) + +# load the EPICS pv definitions +with open("examples/files/california_epics_config.yml", "r") as f: + epics_config = config_from_yaml(f) + +# create controller from epics config +controller = Controller(epics_config) + +# prepare as list for rendering +# define the variables that have range to make as sliders +sliding_variables = [ + input_var + for input_var in input_variables.values() + if input_var.value_range[0] != input_var.value_range[1] +] +input_variables = list(input_variables.values()) +output_variables = list(output_variables.values()) + +# define the plots we want to see - sliders for all input values +# and tables summarising the current state of the inputs and +# output values +sliders = build_sliders(sliding_variables, controller) +input_value_table = ValueTable(input_variables, controller) +output_value_table = ValueTable(output_variables, controller) + + +title_div = Div( + text=f"California Housing Prediction: Last update {controller.last_update}", + style={ + "font-size": "150%", + "color": "#3881e8", + "text-align": "center", + "width": "100%", + }, +) + + +def update_div_text(): + global controller + title_div.text = ( + f"California Housing Prediction: Last update {controller.last_update}" + ) + + +def reset_slider_values(): + for slider in sliders: + slider.reset() + + +slider_reset_button = Button(label="Reset") +slider_reset_button.on_click(reset_slider_values) + +# render +curdoc().title = "California Housing Prediction" +curdoc().add_root( + column( + row(column(title_div, width=600)), + row( + column( + [slider_reset_button] + [slider.bokeh_slider for slider in sliders], + width=350, + ), + column(input_value_table.table, output_value_table.table, width=350), + ), + ), +) + +# add refresh callbacks to ensure that the values are updated +# curdoc().add_periodic_callback(image_plot.update, 1000) +for slider in sliders: + curdoc().add_periodic_callback(slider.update, 1000) +curdoc().add_periodic_callback(update_div_text, 1000) +curdoc().add_periodic_callback(input_value_table.update, 1000) +curdoc().add_periodic_callback(output_value_table.update, 1000) diff --git a/examples/pytorch/california_server.py b/examples/pytorch/california_server.py new file mode 100644 index 0000000..31e994b --- /dev/null +++ b/examples/pytorch/california_server.py @@ -0,0 +1,42 @@ +from lume_epics.epics_server import Server +from lume_model.utils import model_from_yaml +from lume_epics.utils import config_from_yaml +from pathlib import Path +import json +from botorch.models.transforms.input import AffineInputTransform +import torch +from pprint import pprint + +if __name__ == "__main__": + # load the model and the variables from LUME model + with open("examples/files/california_config.yml", "r") as f: + model_class, model_kwargs = model_from_yaml(f, load_model=False) + + # load the EPICS pv definitions + with open("examples/files/california_epics_config.yml", "r") as f: + epics_config = config_from_yaml(f) + + # load the transformers required for the model + with open("examples/files/california_normalization.json", "r") as f: + normalizations = json.load(f) + + input_transformer = AffineInputTransform( + len(normalizations["x_mean"]), + coefficient=torch.tensor(normalizations["x_scale"]), + offset=torch.tensor(normalizations["x_mean"]), + ) + output_transformer = AffineInputTransform( + len(normalizations["y_mean"]), + coefficient=torch.tensor(normalizations["y_scale"]), + offset=torch.tensor(normalizations["y_mean"]), + ) + + # update the model kwargs with the transformers + model_kwargs["input_transformers"] = [input_transformer] + model_kwargs["output_transformers"] = [output_transformer] + + # start the EPICS server + server = Server(model_class, epics_config, model_kwargs=model_kwargs) + + # monitor = False does not loop in main thread + server.start(monitor=True) From 4103a4d43bcd64d3992d8122b1e3bc3638e4022c Mon Sep 17 00:00:00 2001 From: Kathryn Baker Date: Mon, 27 Mar 2023 15:38:46 -0700 Subject: [PATCH 2/4] fix for pva output variable not updating --- lume_epics/epics_pva_server.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lume_epics/epics_pva_server.py b/lume_epics/epics_pva_server.py index 27083c6..58c3284 100644 --- a/lume_epics/epics_pva_server.py +++ b/lume_epics/epics_pva_server.py @@ -117,14 +117,16 @@ def update_pv(self, pvname: str, value: Union[np.ndarray, float]) -> None: varname = self._pvname_to_varname_map[pvname] model_variable = self._input_variables[varname] + # check for already cached variable + model_variable = self._cached_values.get(varname, model_variable) + if model_variable.variable_type == "image": model_variable.x_min = value.attrib["x_min"] model_variable.x_max = value.attrib["x_max"] model_variable.y_min = value.attrib["y_min"] model_variable.y_max = value.attrib["y_max"] - - # check for already cached variable - model_variable = self._cached_values.get(varname, model_variable) + else: + model_variable.value = value self._cached_values[varname] = model_variable @@ -178,7 +180,6 @@ def setup_server(self) -> None: ].default else: - if self._context is None: self._context = Context("pva") @@ -198,7 +199,6 @@ def setup_server(self) -> None: self._initialize_model() model_outputs = None while not self.shutdown_event.is_set() and model_outputs is None: - try: model_outputs = self._out_queue.get(timeout=0.1) except Empty: @@ -224,14 +224,11 @@ def setup_server(self) -> None: self._structures = {} self._structure_specs = {} for variable_name, config in self._epics_config.items(): - if config["serve"]: - fields = config.get("fields") pvname = config.get("pvname") if fields is not None: - spec = [] structure = {} @@ -255,7 +252,6 @@ def setup_server(self) -> None: spec.append((field, "v")) table_rep = () for col in variable.columns: - # here we assume double type in tables... table_rep += (col, "ad") @@ -320,7 +316,6 @@ def setup_server(self) -> None: elif variable.variable_type == "table": table_rep = () for col in variable.columns: - # here we assume double type in tables... table_rep += (col, "ad") From 5ba127795728deba1102509ca03be2deef4cf44c Mon Sep 17 00:00:00 2001 From: Kathryn Baker Date: Mon, 27 Mar 2023 15:39:28 -0700 Subject: [PATCH 3/4] check in california regression model files --- examples/files/california_config.yml | 63 +++++++++++++++++++ examples/files/california_epics_config.yml | 38 +++++++++++ examples/files/california_model_info.json | 48 ++++++++++++++ examples/files/california_normalization.json | 28 +++++++++ examples/files/california_regression.pt | Bin 0 -> 6095 bytes 5 files changed, 177 insertions(+) create mode 100644 examples/files/california_config.yml create mode 100644 examples/files/california_epics_config.yml create mode 100644 examples/files/california_model_info.json create mode 100644 examples/files/california_normalization.json create mode 100644 examples/files/california_regression.pt diff --git a/examples/files/california_config.yml b/examples/files/california_config.yml new file mode 100644 index 0000000..15cdc15 --- /dev/null +++ b/examples/files/california_config.yml @@ -0,0 +1,63 @@ +model: + kwargs: + model_file: examples/files/california_regression.pt + model_class: lume_model.pytorch.PyTorchModel + model_info: examples/files/california_model_info.json + output_format: + type: variable + requirements: + torch: 1.12 + +input_variables: + MedInc: + default: 3.7857346534729004 + range: + - 0.4999000132083893 + - 15.000100135803223 + type: scalar + HouseAge: + default: 29.282135009765625 + range: + - 1.0 + - 52.0 + type: scalar + AveRooms: + default: 5.4074907302856445 + range: + - 0.8461538553237915 + - 141.90908813476562 + type: scalar + AveBedrms: + default: 1.1071722507476807 + range: + - 0.375 + - 34.06666564941406 + type: scalar + Population: + default: 1437.0687255859375 + range: + - 3.0 + - 28566.0 + type: scalar + AveOccup: + default: 3.035413980484009 + range: + - 0.692307710647583 + - 599.7142944335938 + type: scalar + Latitude: + default: 35.28323745727539 + range: + - 32.65999984741211 + - 41.95000076293945 + type: scalar + Longitude: + default: -119.11573028564453 + range: + - -124.3499984741211 + - -114.30999755859375 + type: scalar + +output_variables: + MedHouseVal: + type: scalar diff --git a/examples/files/california_epics_config.yml b/examples/files/california_epics_config.yml new file mode 100644 index 0000000..9ef05c2 --- /dev/null +++ b/examples/files/california_epics_config.yml @@ -0,0 +1,38 @@ +input_variables: + MedInc: + pvname: MedInc + protocol: pva + serve: true + HouseAge: + pvname: HouseAge + protocol: pva + serve: true + AveRooms: + pvname: AveRooms + protocol: pva + serve: true + AveBedrms: + pvname: AveBedrms + protocol: pva + serve: true + Population: + pvname: Population + protocol: pva + serve: true + AveOccup: + pvname: AveOccup + protocol: pva + serve: true + Latitude: + pvname: Latitude + protocol: pva + serve: true + Longitude: + pvname: Longitude + protocol: pva + serve: true +output_variables: + MedHouseVal: + pvname: MedHouseVal + protocol: pva + serve: true diff --git a/examples/files/california_model_info.json b/examples/files/california_model_info.json new file mode 100644 index 0000000..062e63f --- /dev/null +++ b/examples/files/california_model_info.json @@ -0,0 +1,48 @@ +{ + "train_input_mins": [ + 0.4999000132083893, + 1.0, + 0.8461538553237915, + 0.375, + 3.0, + 0.692307710647583, + 32.65999984741211, + -124.3499984741211 + ], + "train_input_maxs": [ + 15.000100135803223, + 52.0, + 141.90908813476562, + 34.06666564941406, + 28566.0, + 599.7142944335938, + 41.95000076293945, + -114.30999755859375 + ], + "model_in_list": [ + "MedInc", + "HouseAge", + "AveRooms", + "AveBedrms", + "Population", + "AveOccup", + "Latitude", + "Longitude" + ], + "model_out_list": [ + "MedHouseVal" + ], + "loc_in": { + "MedInc": 0, + "HouseAge": 1, + "AveRooms": 2, + "AveBedrms": 3, + "Population": 4, + "AveOccup": 5, + "Latitude": 6, + "Longitude": 7 + }, + "loc_out": { + "MedHouseVal": 0 + } +} \ No newline at end of file diff --git a/examples/files/california_normalization.json b/examples/files/california_normalization.json new file mode 100644 index 0000000..801156e --- /dev/null +++ b/examples/files/california_normalization.json @@ -0,0 +1,28 @@ +{ + "x_mean": [ + 3.7857348454995345, + 29.282134699245518, + 5.4074908062777505, + 1.1071723692329019, + 1437.0687339932165, + 3.0354138620008504, + 35.283234587868925, + -119.11572989538202 + ], + "x_scale": [ + 1.8973481323832475, + 12.395369585636528, + 2.8019995847982195, + 0.5464532026823882, + 1141.2672447074444, + 5.462164977692798, + 2.026003694993028, + 1.8325257865272555 + ], + "y_mean": [ + 1.985587451669133 + ], + "y_scale": [ + 1.1218406322612422 + ] +} \ No newline at end of file diff --git a/examples/files/california_regression.pt b/examples/files/california_regression.pt new file mode 100644 index 0000000000000000000000000000000000000000..c0814b5623cd80bd6c85d2ba48b443f647f0390f GIT binary patch literal 6095 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 X4bR-EZMejoJAM@i**|W)VeEech~P4y literal 0 HcmV?d00001 From 1464253432ec605a10ae2b3f138893497640c8e1 Mon Sep 17 00:00:00 2001 From: Kathryn Baker Date: Mon, 27 Mar 2023 15:39:41 -0700 Subject: [PATCH 4/4] reset button for slider --- lume_epics/client/widgets/controls.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lume_epics/client/widgets/controls.py b/lume_epics/client/widgets/controls.py index 984ed58..c069766 100644 --- a/lume_epics/client/widgets/controls.py +++ b/lume_epics/client/widgets/controls.py @@ -81,6 +81,9 @@ def update(self): """ self.bokeh_slider.value = self.controller.get_value(self.pvname) + + def reset(self): + self.bokeh_slider.value = self.variable.default def build_sliders(