Repository navigation
Scope RunInference model_identifier annotation to BeamML_RunInference #40671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -1607,7 +1607,6 @@ def annotations(self): | |||
| 'model_handler_type': ( | ||||
| f'{self._model_handler.__class__.__module__}' | ||||
| f'.{self._model_handler.__class__.__qualname__}'), | ||||
| 'model_identifier': self._model_tag, | ||||
| **extra, | ||||
| **super().annotations() | ||||
| } | ||||
|
|
@@ -1715,47 +1714,54 @@ def expand( | |||
| ) if self._model_metadata_pcoll else None).with_resource_hints( | ||||
| **resource_hints) | ||||
|
|
||||
| if self._with_exception_handling: | ||||
| # On timeouts, report back to the central model metadata | ||||
| # that the model is invalid | ||||
| model_tag = self._model_tag | ||||
| share_across_processes = self._model_handler.share_model_across_processes( | ||||
| ) | ||||
| timeout = self._timeout | ||||
|
|
||||
| def failure_callback(exception: Exception, element: Any): | ||||
| if type(exception) is not TimeoutError: | ||||
| return | ||||
| model_metadata = load_model_status(model_tag, share_across_processes) | ||||
| model_metadata.try_mark_current_model_invalid(timeout) | ||||
| logging.warning( | ||||
| "Inference failed with a timeout, marking the current " + | ||||
| "model for garbage collection") | ||||
|
|
||||
| callback = None | ||||
| if (self._timeout is not None and | ||||
| self._model_handler.should_garbage_collect_on_timeout()): | ||||
| callback = failure_callback | ||||
| results, bad_inference = ( | ||||
| batched_elements_pcoll | ||||
| | 'BeamML_RunInference' >> | ||||
| run_inference_pardo.with_exception_handling( | ||||
| exc_class=self._exc_class, | ||||
| use_subprocess=self._use_subprocess, | ||||
| threshold=self._threshold, | ||||
| timeout = self._timeout, | ||||
| on_failure_callback=callback)) | ||||
| else: | ||||
| results = ( | ||||
| batched_elements_pcoll | ||||
| | 'BeamML_RunInference' >> run_inference_pardo) | ||||
| # Attach model_identifier only to the inference step so that runners can | ||||
| # associate it with the ParDo that actually loads and runs the model. | ||||
| # TODO(https://github.com/apache/beam/issues/40715): When | ||||
| # with_exception_handling(threshold<1) is used, the threshold-checking | ||||
| # transforms added by _ExceptionHandlingWrapper also inherit this | ||||
| # annotation. Refactor to annotate only the inner inference ParDo. | ||||
| with batched_elements_pcoll.pipeline.transform_annotations( | ||||
| model_identifier=self._model_tag): | ||||
| if self._with_exception_handling: | ||||
| # On timeouts, report back to the central model metadata | ||||
| # that the model is invalid | ||||
| model_tag = self._model_tag | ||||
| share_across_processes = ( | ||||
| self._model_handler.share_model_across_processes()) | ||||
| timeout = self._timeout | ||||
|
|
||||
| def failure_callback(exception: Exception, element: Any): | ||||
| if type(exception) is not TimeoutError: | ||||
| return | ||||
| model_metadata = load_model_status(model_tag, share_across_processes) | ||||
| model_metadata.try_mark_current_model_invalid(timeout) | ||||
| logging.warning( | ||||
| "Inference failed with a timeout, marking the current " + | ||||
| "model for garbage collection") | ||||
|
|
||||
| callback = None | ||||
| if (self._timeout is not None and | ||||
| self._model_handler.should_garbage_collect_on_timeout()): | ||||
| callback = failure_callback | ||||
| results, bad_inference = ( | ||||
| batched_elements_pcoll | ||||
| | 'BeamML_RunInference' >> | ||||
| run_inference_pardo.with_exception_handling( | ||||
| exc_class=self._exc_class, | ||||
| use_subprocess=self._use_subprocess, | ||||
| threshold=self._threshold, | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it appears that if threshold < 1, then we add a few more nodes in the pipeline graph that will unintentionally get this annotation, see: beam/sdks/python/apache_beam/transforms/core.py Line 2414 in 5b6aa70
I don't have an opinion yet how to best account for this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I agree we should probably refactor this. I will add a comment for now and make a feature request for the refactor and follow up to keep this change smaller.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #40715 here for tracking
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. possible direction to consider (note: this is a draft rn #40738) |
||||
| timeout = self._timeout, | ||||
| on_failure_callback=callback)) | ||||
| else: | ||||
| results = ( | ||||
| batched_elements_pcoll | ||||
| | 'BeamML_RunInference' >> run_inference_pardo) | ||||
|
|
||||
| if self._monitoring_transform is not None: | ||||
| with results.pipeline.transform_annotations(model_identifier=''): | ||||
| _ = ( | ||||
| results | ||||
| | 'BeamML_RunInference_MonitoringOutlet' >> | ||||
| self._monitoring_transform) | ||||
| _ = ( | ||||
| results | ||||
| | | ||||
| 'BeamML_RunInference_MonitoringOutlet' >> self._monitoring_transform) | ||||
|
|
||||
| results, bad_postprocessed = self._apply_fns( | ||||
| results, postprocess_fns, 'BeamML_RunInference_Postprocess') | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -542,8 +542,7 @@ def test_annotations_shadow_model_identifier(self): | |||
| bigquery_table=self.bq_table, | ||||
| ) | ||||
| annotations = transform.annotations() | ||||
| self.assertIn("model_identifier", annotations) | ||||
| self.assertEqual(annotations["model_identifier"], "") | ||||
| self.assertNotIn("model_identifier", annotations) | ||||
|
|
||||
| def test_run_inference_monitoring_outlet_shadows_model_identifier(self): | ||||
| class DummyMonitoring(beam.PTransform): | ||||
|
|
@@ -572,7 +571,7 @@ def load_model(self): | |||
| ] | ||||
| self.assertTrue(len(outlet_transforms) > 0) | ||||
| for t in outlet_transforms: | ||||
| self.assertEqual(t.annotations.get("model_identifier"), b"") | ||||
| self.assertFalse(t.annotations.get("model_identifier")) | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we remove
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes we should, that got lost in the split, will add it back. |
||||
|
|
||||
| @mock.patch( | ||||
| "apache_beam.ml.inference.vertex_ai_model_monitoring_v2.WriteToBigQuery") | ||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to add this annotation even when not using ModelManager, or should we downscope this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
based on offline discussion sounds like it is probably ok to keep as is.