collie-mlops 0.1.0b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of collie-mlops might be problematic. Click here for more details.

Files changed (45) hide show
  1. collie/__init__.py +69 -0
  2. collie/_common/__init__.py +0 -0
  3. collie/_common/decorator.py +53 -0
  4. collie/_common/exceptions.py +104 -0
  5. collie/_common/mlflow_model_io/__init__.py +0 -0
  6. collie/_common/mlflow_model_io/base_flavor_handler.py +26 -0
  7. collie/_common/mlflow_model_io/flavor_registry.py +72 -0
  8. collie/_common/mlflow_model_io/model_flavors.py +259 -0
  9. collie/_common/mlflow_model_io/model_io.py +65 -0
  10. collie/_common/utils.py +13 -0
  11. collie/contracts/__init__.py +0 -0
  12. collie/contracts/event.py +79 -0
  13. collie/contracts/mlflow.py +444 -0
  14. collie/contracts/orchestrator.py +79 -0
  15. collie/core/__init__.py +41 -0
  16. collie/core/enums/__init__.py +0 -0
  17. collie/core/enums/components.py +26 -0
  18. collie/core/enums/ml_models.py +20 -0
  19. collie/core/evaluator/__init__.py +0 -0
  20. collie/core/evaluator/evaluator.py +147 -0
  21. collie/core/models.py +125 -0
  22. collie/core/orchestrator/__init__.py +0 -0
  23. collie/core/orchestrator/orchestrator.py +47 -0
  24. collie/core/pusher/__init__.py +0 -0
  25. collie/core/pusher/pusher.py +98 -0
  26. collie/core/trainer/__init__.py +0 -0
  27. collie/core/trainer/trainer.py +78 -0
  28. collie/core/transform/__init__.py +0 -0
  29. collie/core/transform/transform.py +87 -0
  30. collie/core/tuner/__init__.py +0 -0
  31. collie/core/tuner/tuner.py +84 -0
  32. collie/helper/__init__.py +0 -0
  33. collie/helper/pytorch/__init__.py +0 -0
  34. collie/helper/pytorch/callback/__init__.py +0 -0
  35. collie/helper/pytorch/callback/callback.py +155 -0
  36. collie/helper/pytorch/callback/earlystop.py +54 -0
  37. collie/helper/pytorch/callback/model_checkpoint.py +100 -0
  38. collie/helper/pytorch/model/__init__.py +0 -0
  39. collie/helper/pytorch/model/loader.py +55 -0
  40. collie/helper/pytorch/trainer.py +304 -0
  41. collie_mlops-0.1.0b0.dist-info/METADATA +217 -0
  42. collie_mlops-0.1.0b0.dist-info/RECORD +45 -0
  43. collie_mlops-0.1.0b0.dist-info/WHEEL +5 -0
  44. collie_mlops-0.1.0b0.dist-info/licenses/LICENSE +21 -0
  45. collie_mlops-0.1.0b0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,147 @@
1
+ from typing import (
2
+ Dict,
3
+ Any,
4
+ List,
5
+ Optional
6
+ )
7
+
8
+ from collie.contracts.event import (
9
+ Event,
10
+ EventHandler,
11
+ EventType
12
+ )
13
+ from collie.contracts.mlflow import MLFlowComponentABC
14
+ from collie._common.decorator import type_checker
15
+ from collie.core.models import (
16
+ EvaluatorArtifact,
17
+ EvaluatorPayload
18
+ )
19
+ from collie._common.exceptions import EvaluatorError
20
+
21
+ class Evaluator(EventHandler, MLFlowComponentABC):
22
+
23
+ def __init__(
24
+ self,
25
+ description: Optional[str] = None,
26
+ tags: Optional[Dict[str, str]] = None
27
+ ) -> None:
28
+
29
+ """
30
+ Initializes the Evaluator.
31
+
32
+ Args:
33
+ description (Optional[str], optional): Description for the MLflow run. Defaults to None.
34
+ tags (Optional[Dict[str, str]], optional): Tags to associate with the MLflow run. Defaults to None.
35
+
36
+ """
37
+ super().__init__()
38
+ self._registered_model_name = None
39
+ self.description = description
40
+ self.tags = tags or {"component": "Evaluator"}
41
+
42
+ self.model_uri = None
43
+ self.metrics = None
44
+
45
+ @property
46
+ def registered_model_name(self) -> str:
47
+ if not self._registered_model_name:
48
+ raise EvaluatorError("Registered model name is not set.")
49
+ return self._registered_model_name
50
+
51
+ @registered_model_name.setter
52
+ def registered_model_name(self, name: str) -> None:
53
+ self._registered_model_name = name
54
+
55
+ def run(self, event: Event) -> Event:
56
+
57
+ with self.start_run(
58
+ tags=self.tags,
59
+ run_name="Evaluator",
60
+ log_system_metrics=True,
61
+ description=self.description,
62
+ nested=True,
63
+ ) as run:
64
+
65
+ try:
66
+ evaluator_event = self._handle(event)
67
+ payload = self._get_evaluator_payload(evaluator_event)
68
+
69
+ self.metrics: List[Dict[str, Any]] = payload.metrics
70
+ self.model_uri = event.context.get('model_uri')
71
+
72
+ self._log_metrics()
73
+ self._log_summary(payload)
74
+
75
+ event.context.set("evaluator_report_uri", self.artifact_uri(run))
76
+
77
+ if self.experiment_is_better(payload):
78
+ event.context.set("pass_evaluation", True)
79
+ self.mlflow.log_param("evaluation_result", "passed")
80
+ else:
81
+ event.context.set("pass_evaluation", False)
82
+ self.mlflow.log_param("evaluation_result", "failed")
83
+
84
+ except Exception as e:
85
+ raise EvaluatorError(f"Evaluator failed: {e}") from e
86
+
87
+ return Event(
88
+ type=EventType.EVALUATION_DONE,
89
+ payload=payload,
90
+ context=event.context,
91
+ )
92
+
93
+ @staticmethod
94
+ def experiment_is_better(
95
+ payload: EvaluatorPayload
96
+ ) -> bool:
97
+ """
98
+ Decide if experiment model is better based on score direction.
99
+ """
100
+ return payload.is_better_than_production
101
+
102
+ def _flatten_metrics(
103
+ self,
104
+ metrics: List[Dict[str, Any]]
105
+ ) -> Dict[str, Any]:
106
+ """
107
+ Flatten list of metric dictionaries into a single dictionary.
108
+ Useful for logging and analysis.
109
+ """
110
+ flattened = {}
111
+ for metric_dict in metrics:
112
+ flattened.update(metric_dict)
113
+ return flattened
114
+
115
+ def _log_summary(
116
+ self,
117
+ payload: EvaluatorPayload
118
+ ) -> None:
119
+ """
120
+ Generate summary statistics from metrics.
121
+ """
122
+ flattened = self._flatten_metrics(payload.metrics)
123
+
124
+ summary = {
125
+ "total_metrics": len(flattened),
126
+ "is_better": payload.is_better_than_production,
127
+ "metrics": flattened
128
+ }
129
+ self.mlflow.log_dict(
130
+ dictionary=summary,
131
+ artifact_file=f"{EvaluatorArtifact().report}"
132
+ )
133
+
134
+ def _log_metrics(self) -> None:
135
+ """
136
+ Log individual metrics to MLflow.
137
+ """
138
+ for metric_dict in self.metrics:
139
+ for metric_name, metric_value in metric_dict.items():
140
+ self.mlflow.log_metric(metric_name, metric_value)
141
+
142
+ @type_checker((EvaluatorPayload,), "EvaluatorPayload must be of type EvaluatorPayload.")
143
+ def _get_evaluator_payload(self, event: Event) -> EvaluatorPayload:
144
+ return event.payload
145
+
146
+ def artifact_uri(self, run) -> str:
147
+ return f"{run.info.artifact_uri}/{EvaluatorArtifact().report}"
collie/core/models.py ADDED
@@ -0,0 +1,125 @@
1
+ from typing import (
2
+ Dict,
3
+ Any,
4
+ Optional,
5
+ List,
6
+ )
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+ import pandas as pd
10
+
11
+
12
+ class BasePayload(BaseModel):
13
+ """Base class for all payload types with optional extra_data functionality."""
14
+
15
+ extra_data: Optional[Dict[str, Any]] = None
16
+
17
+ model_config = ConfigDict(arbitrary_types_allowed=True)
18
+
19
+ def set_extra(self, key: str, value: Any):
20
+ """
21
+ Set a value in extra_data and return self for chaining.
22
+
23
+ Args:
24
+ key: The key to set
25
+ value: The value to store
26
+
27
+ Returns:
28
+ Self for method chaining
29
+
30
+ Example:
31
+ >>> payload.set_extra("feature_names", ["age", "income"])
32
+ >>> payload.set_extra("n_classes", 3).set_extra("version", "1.0")
33
+ """
34
+ if self.extra_data is None:
35
+ self.extra_data = {}
36
+ self.extra_data[key] = value
37
+ return self
38
+
39
+ def get_extra(self, key: str, default: Any = None) -> Any:
40
+ """
41
+ Get a value from extra_data with optional default.
42
+
43
+ Args:
44
+ key: The key to retrieve
45
+ default: Default value if key doesn't exist
46
+
47
+ Returns:
48
+ The value or default
49
+
50
+ Example:
51
+ >>> features = payload.get_extra("feature_names", [])
52
+ """
53
+ if self.extra_data is None:
54
+ return default
55
+ return self.extra_data.get(key, default)
56
+
57
+ def has_extra(self, key: str) -> bool:
58
+ """
59
+ Check if a key exists in extra_data.
60
+
61
+ Args:
62
+ key: The key to check
63
+
64
+ Returns:
65
+ True if key exists, False otherwise
66
+
67
+ Example:
68
+ >>> if payload.has_extra("feature_names"):
69
+ ... features = payload.get_extra("feature_names")
70
+ """
71
+ if self.extra_data is None:
72
+ return False
73
+ return key in self.extra_data
74
+
75
+
76
+ class TransformerArtifact(BaseModel):
77
+ train_data: str = "train.csv"
78
+ validation_data: str = "validation.csv"
79
+ test_data: str = "test.csv"
80
+
81
+
82
+ class TunerArtifact(BaseModel):
83
+ hyperparameters: str = "hyperparameters.json"
84
+
85
+
86
+ class TrainerArtifact(BaseModel):
87
+ model: str = "model"
88
+
89
+
90
+ class EvaluatorArtifact(BaseModel):
91
+ report: str = "report.json"
92
+
93
+
94
+ class TransformerPayload(BasePayload):
95
+ train_data: Optional[pd.DataFrame] = None
96
+ validation_data: Optional[pd.DataFrame] = None
97
+ test_data: Optional[pd.DataFrame] = None
98
+
99
+ model_config = ConfigDict(arbitrary_types_allowed=True)
100
+
101
+
102
+ class TrainerPayload(BasePayload):
103
+ model: Any = None
104
+
105
+ model_config = ConfigDict(arbitrary_types_allowed=True)
106
+
107
+
108
+ class TunerPayload(BasePayload):
109
+ hyperparameters: Dict[str, Any]
110
+ train_data: Optional[pd.DataFrame] = None
111
+ validation_data: Optional[pd.DataFrame] = None
112
+ test_data: Optional[pd.DataFrame] = None
113
+
114
+ model_config = ConfigDict(arbitrary_types_allowed=True)
115
+
116
+
117
+ class EvaluatorPayload(BasePayload):
118
+ metrics: List[Dict[str, Any]]
119
+ is_better_than_production: bool
120
+
121
+
122
+ class PusherPayload(BasePayload):
123
+ model_uri: str
124
+ status: Optional[str] = None
125
+ model_version: Optional[str] = None
File without changes
@@ -0,0 +1,47 @@
1
+ from typing import (
2
+ Optional,
3
+ Dict,
4
+ )
5
+
6
+ from collie.contracts.orchestrator import OrchestratorBase
7
+ from collie.core.enums.components import CollieComponentType
8
+ from collie._common.utils import get_logger
9
+
10
+ logger = get_logger()
11
+
12
+
13
+ class Orchestrator(OrchestratorBase):
14
+
15
+ def __init__(
16
+ self,
17
+ components: CollieComponentType,
18
+ tracking_uri: str,
19
+ registered_model_name: str,
20
+ mlflow_tags: Optional[Dict[str, str]] = None,
21
+ experiment_name: Optional[str] = None,
22
+ description: Optional[str] = None,
23
+ ) -> None:
24
+ super().__init__(
25
+ components=components,
26
+ tracking_uri=tracking_uri,
27
+ mlflow_tags=mlflow_tags,
28
+ experiment_name=experiment_name,
29
+ description=description
30
+ )
31
+ self.registered_model_name = registered_model_name
32
+
33
+ def orchestrate_pipeline(self) -> None:
34
+ """Run the pipeline sequentially without Airflow."""
35
+
36
+ logger.info("Pipeline started.")
37
+ incoming_event = self.initialize_event()
38
+
39
+ for idx, component in enumerate(self.components):
40
+ logger.info(f"Running component {idx}: {type(component).__name__}")
41
+ component.mlflow_config = self.mlflow_config
42
+ if hasattr(component, "_registered_model_name"):
43
+ component.registered_model_name = self.registered_model_name
44
+
45
+ incoming_event = component.run(incoming_event)
46
+
47
+ logger.info(f"Component {idx} finished: {type(component).__name__}")
File without changes
@@ -0,0 +1,98 @@
1
+ from typing import Optional
2
+ from collie.contracts.event import (
3
+ Event,
4
+ EventHandler,
5
+ EventType
6
+ )
7
+ from collie.contracts.mlflow import MLFlowComponentABC
8
+ from collie.core.models import PusherPayload
9
+ from collie._common.decorator import type_checker
10
+ from collie._common.exceptions import PusherError
11
+ from collie.core.enums.ml_models import MLflowModelStage
12
+
13
+
14
+ class Pusher(EventHandler, MLFlowComponentABC):
15
+ def __init__(
16
+ self,
17
+ target_stage: MLflowModelStage = MLflowModelStage.PRODUCTION,
18
+ archive_existing_versions: bool = True,
19
+ description: Optional[str] = None,
20
+ tags: Optional[dict] = None
21
+ ) -> None:
22
+ """
23
+ Initializes the Pusher.
24
+
25
+ Args:
26
+ target_stage (Optional[MLflowModelStage], optional): The stage to transition the model to after evaluation. Defaults to None.
27
+ archive_existing_versions (bool, optional): Whether to archive existing versions at the target stage. Defaults to True.
28
+ description (Optional[str], optional): Description for the MLflow run. Defaults to None.
29
+ tags (Optional[dict], optional): Tags to associate with the MLflow run. Defaults to None.
30
+
31
+ """
32
+ super().__init__()
33
+ self._registered_model_name = None
34
+ self.target_stage = target_stage
35
+ self.archive_existing_versions = archive_existing_versions
36
+ self.description = description
37
+ self.tags = tags or {"component": "Pusher"}
38
+
39
+ @property
40
+ def registered_model_name(self) -> str:
41
+ if not self._registered_model_name:
42
+ raise PusherError("Registered model name is not set.")
43
+ return self._registered_model_name
44
+
45
+ @registered_model_name.setter
46
+ def registered_model_name(self, name: str) -> None:
47
+ self._registered_model_name = name
48
+
49
+ def run(self, event: Event) -> Event:
50
+ with self.start_run(
51
+ tags=self.tags,
52
+ run_name="Pusher",
53
+ log_system_metrics=False,
54
+ nested=True,
55
+ description=self.description
56
+ ):
57
+ try:
58
+ pusher_event = self._handle(event)
59
+ payload = self._get_pusher_payload(pusher_event)
60
+ pass_evaluation = event.context.get("pass_evaluation")
61
+
62
+ if pass_evaluation:
63
+ model_uri = event.context.get('model_uri')
64
+ if not model_uri:
65
+ raise PusherError("model_uri not found in event context")
66
+
67
+ version = self.register_model(
68
+ model_name=self.registered_model_name,
69
+ model_uri=model_uri
70
+ )
71
+ self.mlflow.log_param("model_registered", "true")
72
+ event.context.set("registered_version", str(version))
73
+ self.mlflow.log_param("model_version", version)
74
+
75
+ self.mlflow.log_param("target_stage", self.target_stage.value)
76
+ self.transition_model_version(
77
+ registered_model_name=self.registered_model_name,
78
+ version=str(version),
79
+ desired_stage=self.target_stage,
80
+ archive_existing_versions_at_stage=self.archive_existing_versions,
81
+ )
82
+
83
+ else:
84
+ self.mlflow.log_param("skip_reason", "evaluation_failed")
85
+ self.mlflow.log_param("model_registered", "false")
86
+
87
+ return Event(
88
+ type=EventType.PUSHER_DONE,
89
+ payload=payload,
90
+ context=event.context,
91
+ )
92
+
93
+ except Exception as e:
94
+ raise PusherError(f"Pusher failed with error: {e}")
95
+
96
+ @type_checker((PusherPayload,), "PusherPayload must be of type PusherPayload.")
97
+ def _get_pusher_payload(self, event: Event) -> PusherPayload:
98
+ return event.payload
File without changes
@@ -0,0 +1,78 @@
1
+ from typing import Optional
2
+ from collie.contracts.event import (
3
+ Event,
4
+ EventHandler,
5
+ EventType
6
+ )
7
+ from collie.contracts.mlflow import MLFlowComponentABC
8
+ from collie.core.models import (
9
+ TrainerPayload,
10
+ TrainerArtifact
11
+ )
12
+ from collie._common.decorator import type_checker
13
+ from collie._common.exceptions import TrainerError
14
+
15
+
16
+ class Trainer(EventHandler, MLFlowComponentABC):
17
+
18
+ def __init__(
19
+ self,
20
+ description: Optional[str] = None,
21
+ tags: Optional[dict] = None
22
+ ) -> None:
23
+ """
24
+ Initializes the Trainer component.
25
+
26
+ Args:
27
+ description (Optional[str], optional): Description for the MLflow run. Defaults to None.
28
+ tags (Optional[dict], optional): Tags to associate with the MLflow run. Defaults to None.
29
+ """
30
+ super().__init__()
31
+ self.description = description
32
+ self.tags = tags or {"component": "Trainer"}
33
+
34
+ def run(self, event: Event) -> Event:
35
+ """
36
+ Run the trainer component.
37
+
38
+ This method starts a new MLflow run, trains the model,
39
+ logs metrics, and sets the outputs.
40
+ """
41
+
42
+ with self.start_run(
43
+ run_name="Trainer",
44
+ tags=self.tags,
45
+ log_system_metrics=True,
46
+ nested=True,
47
+ description=self.description
48
+ ) as run:
49
+ try:
50
+ trainer_event = self._handle(event)
51
+
52
+ trainer_payload = self._trainer_payload(trainer_event)
53
+ event_type = EventType.TRAINING_DONE
54
+
55
+ model = trainer_payload.model
56
+ self.log_model(
57
+ model=model,
58
+ name=TrainerArtifact().model
59
+ )
60
+ event.context.set("model_uri", self.artifact_uri(run))
61
+
62
+ return Event(
63
+ type=event_type,
64
+ payload=trainer_payload,
65
+ context=event.context
66
+ )
67
+ except Exception as e:
68
+ raise TrainerError(f"Trainer failed with error: {e}") from e
69
+
70
+ @type_checker((TrainerPayload,) ,
71
+ "TrainerPayload must be of type TrainerPayload."
72
+ )
73
+ def _trainer_payload(self, event: Event) -> TrainerPayload:
74
+
75
+ return event.payload
76
+
77
+ def artifact_uri(self, run) -> str:
78
+ return f"runs:/{run.info.run_id}/{TrainerArtifact().model}"
File without changes
@@ -0,0 +1,87 @@
1
+ from typing import Optional
2
+ from collie.contracts.event import (
3
+ Event,
4
+ EventHandler,
5
+ EventType
6
+ )
7
+ from collie.contracts.mlflow import MLFlowComponentABC
8
+ from collie.core.models import (
9
+ TransformerPayload,
10
+ TransformerArtifact
11
+ )
12
+ from collie._common.decorator import type_checker
13
+ from collie._common.exceptions import TransformerError
14
+
15
+
16
+ class Transformer(EventHandler, MLFlowComponentABC):
17
+
18
+ def __init__(
19
+ self,
20
+ description: Optional[str] = None,
21
+ tags: Optional[dict] = None
22
+ ) -> None:
23
+ """
24
+ Initializes the Transformer component.
25
+
26
+ Args:
27
+ description (Optional[str], optional): Description for the MLflow run. Defaults to None.
28
+ tags (Optional[dict], optional): Tags to associate with the MLflow run. Defaults to None.
29
+ """
30
+ super().__init__()
31
+ self.description = description
32
+ self.tags = tags or {"component": "Transformer"}
33
+
34
+ def run(self, event: Event) -> Event:
35
+ """
36
+ Run the transformer component.
37
+
38
+ This method starts a new MLflow run, transforms the input data,
39
+ logs metrics, and sets the outputs.
40
+ """
41
+ with self.start_run(
42
+ tags=self.tags,
43
+ run_name="Transformer",
44
+ log_system_metrics=True,
45
+ nested=True,
46
+ description=self.description
47
+ ) as run:
48
+ try:
49
+ transformer_event = self._handle(event)
50
+
51
+ transformer_payload = self._transformer_payload(transformer_event)
52
+ event_type = EventType.DATA_READY
53
+
54
+ data = transformer_payload.model_dump()
55
+ for data_type, data in data.items():
56
+
57
+ if data is not None:
58
+ source = self.artifact_uri(run, data_type)
59
+ event.context.set(
60
+ f"{data_type}_uri",
61
+ source
62
+ )
63
+
64
+ self.log_pd_data(
65
+ data=data,
66
+ context=data_type,
67
+ source=source
68
+ )
69
+
70
+ return Event(
71
+ type=event_type,
72
+ payload=transformer_payload,
73
+ context=event.context
74
+ )
75
+
76
+ except Exception as e:
77
+ raise TransformerError(f"Transformer failed with error: {e}")
78
+
79
+ @type_checker((TransformerPayload,) ,
80
+ "TransformerPayload must be of type TransformerPayload."
81
+ )
82
+ def _transformer_payload(self, event: Event) -> TransformerPayload:
83
+
84
+ return event.payload
85
+
86
+ def artifact_uri(self, run, data_type) -> str:
87
+ return f"{run.info.artifact_uri}/{TransformerArtifact().model_dump()[data_type]}"
File without changes
@@ -0,0 +1,84 @@
1
+ from typing import Optional
2
+ from collie.contracts.event import (
3
+ Event,
4
+ EventHandler,
5
+ EventType
6
+ )
7
+ from collie.contracts.mlflow import MLFlowComponentABC
8
+ from collie._common.decorator import type_checker
9
+ from collie.core.models import (
10
+ TunerArtifact,
11
+ TunerPayload
12
+ )
13
+ from collie._common.exceptions import TunerError
14
+
15
+
16
+ class Tuner(EventHandler, MLFlowComponentABC):
17
+
18
+ def __init__(
19
+ self,
20
+ description: Optional[str] = None,
21
+ tags: Optional[dict] = None
22
+ ) -> None:
23
+ """
24
+ Initializes the Tuner component.
25
+
26
+ Args:
27
+ description (Optional[str], optional): Description for the MLflow run. Defaults to None.
28
+ tags (Optional[dict], optional): Tags to associate with the MLflow run. Defaults to None.
29
+ """
30
+ super().__init__()
31
+ self.description = description
32
+ self.tags = tags or {"component": "Tuner"}
33
+
34
+ def run(self, event: Event) -> None:
35
+ """
36
+ Run the hyperparameter tuner component.
37
+
38
+ This method starts a new MLflow run, tunes the hyperparameters,
39
+ logs metrics, and sets the outputs.
40
+ """
41
+
42
+ with self.start_run(
43
+ tags=self.tags,
44
+ run_name="Tuner",
45
+ log_system_metrics=True,
46
+ nested=True,
47
+ description=self.description
48
+ ) as run:
49
+ try:
50
+ tuner_event = self._handle(event)
51
+
52
+ tuner_payload = self._tuner_payload(tuner_event)
53
+ hyperparameters = tuner_payload.model_dump()
54
+
55
+ self.mlflow.log_dict(
56
+ dictionary=hyperparameters,
57
+ artifact_file=TunerArtifact().hyperparameters
58
+ )
59
+ event.context.set(
60
+ "hyperparameters_uri",
61
+ self.artifact_path(run)
62
+ )
63
+
64
+ event_type = EventType.TUNING_DONE
65
+
66
+ return Event(
67
+ type=event_type,
68
+ payload=tuner_payload,
69
+ context=event.context
70
+ )
71
+ except Exception as e:
72
+ raise TunerError(f"Tuner failed with error: {e}") from e
73
+
74
+ @type_checker((TunerPayload,) ,
75
+ "TunerPayload must be of type TunerPayload."
76
+ )
77
+ def _tuner_payload(self, event: Event) -> TunerPayload:
78
+
79
+ tuner_payload: TunerPayload = event.payload
80
+
81
+ return tuner_payload
82
+
83
+ def artifact_path(self, run) -> str:
84
+ return f"{run.info.artifact_uri}/{TunerArtifact().hyperparameters}"
File without changes
File without changes
File without changes