about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning')
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/__init__.py5
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_finetuning_job.py242
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_hyperparameters.py125
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/custom_model_finetuning_job.py258
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_job.py224
-rw-r--r--.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_vertical.py202
6 files changed, 1056 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/__init__.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/__init__.py
new file mode 100644
index 00000000..fdf8caba
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/__init__.py
@@ -0,0 +1,5 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_finetuning_job.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_finetuning_job.py
new file mode 100644
index 00000000..e659c634
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_finetuning_job.py
@@ -0,0 +1,242 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+# pylint: disable=protected-access
+
+from typing import Any, Dict
+
+from azure.ai.ml._restclient.v2024_01_01_preview.models import (
+    ModelProvider as RestModelProvider,
+    AzureOpenAiFineTuning as RestAzureOpenAIFineTuning,
+    FineTuningJob as RestFineTuningJob,
+    JobBase as RestJobBase,
+)
+from azure.ai.ml.constants._common import BASE_PATH_CONTEXT_KEY
+from azure.ai.ml.entities._job._input_output_helpers import from_rest_data_outputs, to_rest_data_outputs
+
+from azure.ai.ml.entities._job.finetuning.finetuning_vertical import FineTuningVertical
+from azure.ai.ml.entities._job.finetuning.azure_openai_hyperparameters import AzureOpenAIHyperparameters
+from azure.ai.ml.entities._util import load_from_dict
+from azure.ai.ml.exceptions import ErrorCategory, ErrorTarget, ValidationException
+from azure.ai.ml._utils._experimental import experimental
+
+
+@experimental
+class AzureOpenAIFineTuningJob(FineTuningVertical):
+    def __init__(
+        self,
+        **kwargs: Any,
+    ) -> None:
+        # Extract any task specific settings
+        model = kwargs.pop("model", None)
+        task = kwargs.pop("task", None)
+        # Convert task to lowercase first letter, this is when we create
+        # object from the schema, using dict object from the REST api response.
+        # TextCompletion => textCompletion
+        if task:
+            task = task[0].lower() + task[1:]
+        training_data = kwargs.pop("training_data", None)
+        validation_data = kwargs.pop("validation_data", None)
+        hyperparameters = kwargs.pop("hyperparameters", None)
+        if hyperparameters and not isinstance(hyperparameters, AzureOpenAIHyperparameters):
+            raise ValidationException(
+                category=ErrorCategory.USER_ERROR,
+                target=ErrorTarget.JOB,
+                message="Hyperparameters if provided should of type AzureOpenAIHyperparameters",
+                no_personal_data_message="Hyperparameters if provided should of type AzureOpenAIHyperparameters",
+            )
+
+        self._hyperparameters = hyperparameters
+
+        super().__init__(
+            task=task,
+            model=model,
+            model_provider=RestModelProvider.AZURE_OPEN_AI,
+            training_data=training_data,
+            validation_data=validation_data,
+            **kwargs,
+        )
+
+    @property
+    def hyperparameters(self) -> AzureOpenAIHyperparameters:
+        """Get hyperparameters.
+
+        :return: Hyperparameters for finetuning the model.
+        :rtype: AzureOpenAIHyperparameters
+        """
+        return self._hyperparameters
+
+    @hyperparameters.setter
+    def hyperparameters(self, hyperparameters: AzureOpenAIHyperparameters) -> None:
+        """Set hyperparameters.
+
+        :param hyperparameters: Hyperparameters for finetuning the model.
+        :type hyperparameters: AzureOpenAiHyperParameters
+        """
+        self._hyperparameters = hyperparameters
+
+    def _to_rest_object(self) -> "RestFineTuningJob":
+        """Convert CustomFineTuningVertical object to a RestFineTuningJob object.
+
+        :return: REST object representation of this object.
+        :rtype: JobBase
+        """
+        aoai_finetuning_vertical = RestAzureOpenAIFineTuning(
+            task_type=self._task,
+            model=self._model,
+            model_provider=self._model_provider,
+            training_data=self._training_data,
+            validation_data=self._validation_data,
+            hyper_parameters=self.hyperparameters._to_rest_object() if self.hyperparameters else None,
+        )
+
+        self._resolve_inputs(aoai_finetuning_vertical)
+
+        finetuning_job = RestFineTuningJob(
+            display_name=self.display_name,
+            description=self.description,
+            experiment_name=self.experiment_name,
+            tags=self.tags,
+            properties=self.properties,
+            fine_tuning_details=aoai_finetuning_vertical,
+            outputs=to_rest_data_outputs(self.outputs),
+        )
+
+        result = RestJobBase(properties=finetuning_job)
+        result.name = self.name
+
+        return result
+
+    def _to_dict(self) -> Dict:
+        """Convert the object to a dictionary.
+
+        :return: dictionary representation of the object.
+        :rtype: typing.Dict
+        """
+        from azure.ai.ml._schema._finetuning.azure_openai_finetuning import AzureOpenAIFineTuningSchema
+
+        schema_dict: dict = {}
+        # TODO: Combeback to this later for FineTuningJob in Pipelines
+        # if inside_pipeline:
+        #    schema_dict = AutoMLClassificationNodeSchema(context={BASE_PATH_CONTEXT_KEY: "./"}).dump(self)
+        # else:
+        schema_dict = AzureOpenAIFineTuningSchema(context={BASE_PATH_CONTEXT_KEY: "./"}).dump(self)
+
+        return schema_dict
+
+    def __eq__(self, other: object) -> bool:
+        """Returns True if both instances have the same values.
+
+        This method check instances equality and returns True if both of
+            the instances have the same attributes with the same values.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        if not isinstance(other, AzureOpenAIFineTuningJob):
+            return NotImplemented
+
+        return super().__eq__(other) and self.hyperparameters == other.hyperparameters
+
+    def __ne__(self, other: object) -> bool:
+        """Check inequality between two AzureOpenAIFineTuningJob objects.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        return not self.__eq__(other)
+
+    @classmethod
+    def _from_rest_object(cls, obj: RestJobBase) -> "AzureOpenAIFineTuningJob":
+        """Convert a REST object to AzureOpenAIFineTuningJob object.
+
+        :param obj: AzureOpenAIFineTuningJob in Rest format.
+        :type obj: JobBase
+        :return: AzureOpenAIFineTuningJob objects.
+        :rtype: AzureOpenAIFineTuningJob
+        """
+
+        properties: RestFineTuningJob = obj.properties
+        finetuning_details: RestAzureOpenAIFineTuning = properties.fine_tuning_details
+
+        job_args_dict = {
+            "id": obj.id,
+            "name": obj.name,
+            "description": properties.description,
+            "tags": properties.tags,
+            "properties": properties.properties,
+            "experiment_name": properties.experiment_name,
+            "status": properties.status,
+            "creation_context": obj.system_data,
+            "display_name": properties.display_name,
+            "outputs": from_rest_data_outputs(properties.outputs),
+        }
+
+        aoai_finetuning_job = cls(
+            task=finetuning_details.task_type,
+            model=finetuning_details.model,
+            training_data=finetuning_details.training_data,
+            validation_data=finetuning_details.validation_data,
+            hyperparameters=AzureOpenAIHyperparameters._from_rest_object(finetuning_details.hyper_parameters),
+            **job_args_dict,
+        )
+
+        aoai_finetuning_job._restore_inputs()
+
+        return aoai_finetuning_job
+
+    @classmethod
+    def _load_from_dict(
+        cls,
+        data: Dict,
+        context: Dict,
+        additional_message: str,
+        **kwargs: Any,
+    ) -> "AzureOpenAIFineTuningJob":
+        """Load from a dictionary.
+
+        :param data: dictionary representation of the object.
+        :type data: typing.Dict
+        :param context: dictionary containing the context.
+        :type context: typing.Dict
+        :param additional_message: additional message to be added to the error message.
+        :type additional_message: str
+        :return: AzureOpenAIFineTuningJob object.
+        :rtype: AzureOpenAIFineTuningJob
+        """
+        from azure.ai.ml._schema._finetuning.azure_openai_finetuning import AzureOpenAIFineTuningSchema
+
+        # TODO: Combeback to this later - Pipeline part.
+        # from azure.ai.ml._schema.pipeline.automl_node import AutoMLClassificationNodeSchema
+
+        # if kwargs.pop("inside_pipeline", False):
+        #    loaded_data = load_from_dict(
+        #        AutoMLClassificationNodeSchema,
+        #        data,
+        #        context,
+        #        additional_message,
+        #        **kwargs,
+        #    )
+        # else:
+        loaded_data = load_from_dict(AzureOpenAIFineTuningSchema, data, context, additional_message, **kwargs)
+
+        job_instance = cls._create_instance_from_schema_dict(loaded_data)
+        return job_instance
+
+    @classmethod
+    def _create_instance_from_schema_dict(cls, loaded_data: Dict) -> "AzureOpenAIFineTuningJob":
+        """Create an instance from a schema dictionary.
+
+        :param loaded_data: dictionary containing the data.
+        :type loaded_data: typing.Dict
+        :return: AzureOpenAIFineTuningJob object.
+        :rtype: AzureOpenAIFineTuningJob
+        """
+
+        job = AzureOpenAIFineTuningJob(**loaded_data)
+        return job
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_hyperparameters.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_hyperparameters.py
new file mode 100644
index 00000000..2b420a46
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/azure_openai_hyperparameters.py
@@ -0,0 +1,125 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+from typing import Optional
+from azure.ai.ml.entities._mixins import RestTranslatableMixin
+from azure.ai.ml._restclient.v2024_01_01_preview.models import (
+    AzureOpenAiHyperParameters as RestAzureOpenAiHyperParameters,
+)
+from azure.ai.ml._utils._experimental import experimental
+
+
+@experimental
+class AzureOpenAIHyperparameters(RestTranslatableMixin):
+    """Hyperparameters for Azure OpenAI model finetuning."""
+
+    def __init__(
+        self,
+        *,
+        batch_size: Optional[int] = None,
+        learning_rate_multiplier: Optional[float] = None,
+        n_epochs: Optional[int] = None,
+    ):
+        """Initialize AzureOpenAIHyperparameters.
+
+        param batch_size: Number of examples in each batch.
+                          A larger batch size means that model parameters are updated less
+                          frequently, but with lower variance. Defaults to None.
+        type batch_size: int
+        param learning_rate_multiplier: Scaling factor for the learning rate.
+                                        A smaller learning rate may be useful to avoid overfitting.
+        type learning_rate_multiplier: float
+        param n_epochs: The number of epochs to train the model for.
+                        An epoch refers to one full cycle through the training dataset.
+        type n_epochs: int
+        """
+        self._batch_size = batch_size
+        self._learning_rate_multiplier = learning_rate_multiplier
+        self._n_epochs = n_epochs
+        # Not exposed in the public API, so need to check how to handle this
+        # self._additional_properties = kwargs
+
+    @property
+    def batch_size(self) -> Optional[int]:
+        """Get the batch size for training."""
+        return self._batch_size
+
+    @batch_size.setter
+    def batch_size(self, value: Optional[int]) -> None:
+        """Set the batch size for training.
+        :param value: The batch size for training.
+        :type value: int
+        """
+        self._batch_size = value
+
+    @property
+    def learning_rate_multiplier(self) -> Optional[float]:
+        """Get the learning rate multiplier.
+        :return: The learning rate multiplier.
+        :rtype: float
+        """
+        return self._learning_rate_multiplier
+
+    @learning_rate_multiplier.setter
+    def learning_rate_multiplier(self, value: Optional[float]) -> None:
+        """Set the learning rate multiplier.
+        :param value: The learning rate multiplier.
+        :type value: float
+        """
+        self._learning_rate_multiplier = value
+
+    @property
+    def n_epochs(self) -> Optional[int]:
+        """Get the number of epochs.
+        :return: The number of epochs.
+        :rtype: int
+        """
+        return self._n_epochs
+
+    @n_epochs.setter
+    def n_epochs(self, value: Optional[int]) -> None:
+        """Set the number of epochs.
+        :param value: The number of epochs.
+        :type value: int
+        """
+        self._n_epochs = value
+
+    # Not exposed in the public API, so need to check how to handle this
+    # @property
+    # def additional_properties(self) -> dict:
+    #    """Get additional properties."""
+    #    return self._additional_properties
+
+    # @additional_properties.setter
+    # def additional_properties(self, value: dict) -> None:
+    #    """Set additional properties."""
+    #    self._additional_properties = value
+
+    def _to_rest_object(self) -> RestAzureOpenAiHyperParameters:
+        return RestAzureOpenAiHyperParameters(
+            batch_size=self._batch_size,
+            learning_rate_multiplier=self._learning_rate_multiplier,
+            n_epochs=self._n_epochs,
+        )
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, AzureOpenAIHyperparameters):
+            return NotImplemented
+        return (
+            self._batch_size == other._batch_size
+            and self._learning_rate_multiplier == other._learning_rate_multiplier
+            and self._n_epochs == other._n_epochs
+        )
+
+    def __ne__(self, other: object) -> bool:
+        return not self.__eq__(other)
+
+    @classmethod
+    def _from_rest_object(cls, obj: RestAzureOpenAiHyperParameters) -> "AzureOpenAIHyperparameters":
+        aoai_hyperparameters = cls(
+            batch_size=obj.batch_size,
+            learning_rate_multiplier=obj.learning_rate_multiplier,
+            n_epochs=obj.n_epochs,
+        )
+        return aoai_hyperparameters
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/custom_model_finetuning_job.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/custom_model_finetuning_job.py
new file mode 100644
index 00000000..e6ddd86d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/custom_model_finetuning_job.py
@@ -0,0 +1,258 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+# pylint: disable=protected-access
+
+from typing import Any, Dict
+
+from azure.ai.ml._restclient.v2024_10_01_preview.models import (
+    ModelProvider as RestModelProvider,
+    CustomModelFineTuning as RestCustomModelFineTuningVertical,
+    FineTuningJob as RestFineTuningJob,
+    JobBase as RestJobBase,
+)
+from azure.ai.ml.entities._job._input_output_helpers import (
+    from_rest_data_outputs,
+    to_rest_data_outputs,
+)
+from azure.ai.ml.entities._job.job_resources import JobResources
+from azure.ai.ml.entities._job.queue_settings import QueueSettings
+from azure.ai.ml.entities._inputs_outputs import Input
+from azure.ai.ml.constants._common import BASE_PATH_CONTEXT_KEY
+from azure.ai.ml.entities._job.finetuning.finetuning_vertical import FineTuningVertical
+from azure.ai.ml.entities._util import load_from_dict
+from azure.ai.ml._utils._experimental import experimental
+
+
+@experimental
+class CustomModelFineTuningJob(FineTuningVertical):
+    def __init__(
+        self,
+        **kwargs: Any,
+    ) -> None:
+        # Extract any task specific settings
+        model = kwargs.pop("model", None)
+        task = kwargs.pop("task", None)
+        # Convert task to lowercase first letter, this is when we create
+        # object from the schema, using dict object from the REST api response.
+        # TextCompletion => textCompletion
+        if task:
+            task = task[0].lower() + task[1:]
+        training_data = kwargs.pop("training_data", None)
+        validation_data = kwargs.pop("validation_data", None)
+        self._hyperparameters = kwargs.pop("hyperparameters", None)
+        super().__init__(
+            task=task,
+            model=model,
+            model_provider=RestModelProvider.CUSTOM,
+            training_data=training_data,
+            validation_data=validation_data,
+            **kwargs,
+        )
+
+    @property
+    def hyperparameters(self) -> Dict[str, str]:
+        """Get hyperparameters.
+
+        :return:
+        :rtype: hyperparameters: Dict[str,str]
+        """
+        return self._hyperparameters
+
+    @hyperparameters.setter
+    def hyperparameters(self, hyperparameters: Dict[str, str]) -> None:
+        """Set hyperparameters.
+
+        :param hyperparameters: Hyperparameters for finetuning the model
+        :type hyperparameters: Dict[str,str]
+        """
+        self._hyperparameters = hyperparameters
+
+    def _to_rest_object(self) -> "RestFineTuningJob":
+        """Convert CustomFineTuningVertical object to a RestFineTuningJob object.
+
+        :return: REST object representation of this object.
+        :rtype: JobBase
+        """
+        custom_finetuning_vertical = RestCustomModelFineTuningVertical(
+            task_type=self._task,
+            model=self._model,
+            model_provider=self._model_provider,
+            training_data=self._training_data,
+            validation_data=self._validation_data,
+            hyper_parameters=self._hyperparameters,
+        )
+        self._resolve_inputs(custom_finetuning_vertical)
+
+        finetuning_job = RestFineTuningJob(
+            display_name=self.display_name,
+            description=self.description,
+            experiment_name=self.experiment_name,
+            services=self.services,
+            tags=self.tags,
+            properties=self.properties,
+            compute_id=self.compute,
+            fine_tuning_details=custom_finetuning_vertical,
+            outputs=to_rest_data_outputs(self.outputs),
+        )
+        if self.resources:
+            finetuning_job.resources = self.resources._to_rest_object()
+        if self.queue_settings:
+            finetuning_job.queue_settings = self.queue_settings._to_rest_object()
+
+        result = RestJobBase(properties=finetuning_job)
+        result.name = self.name
+
+        return result
+
+    def _to_dict(self) -> Dict:
+        """Convert the object to a dictionary.
+
+        :return: dictionary representation of the object.
+        :rtype: typing.Dict
+        """
+        from azure.ai.ml._schema._finetuning.custom_model_finetuning import (
+            CustomModelFineTuningSchema,
+        )
+
+        schema_dict: dict = {}
+        # TODO: Combeback to this later for FineTuningJob in pipeline
+        # if inside_pipeline:
+        #    schema_dict = AutoMLClassificationNodeSchema(context={BASE_PATH_CONTEXT_KEY: "./"}).dump(self)
+        # else:
+        schema_dict = CustomModelFineTuningSchema(context={BASE_PATH_CONTEXT_KEY: "./"}).dump(self)
+
+        return schema_dict
+
+    def __eq__(self, other: object) -> bool:
+        """Returns True if both instances have the same values.
+
+        This method check instances equality and returns True if both of
+            the instances have the same attributes with the same values.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        if not isinstance(other, CustomModelFineTuningJob):
+            return NotImplemented
+
+        return super().__eq__(other) and self.hyperparameters == other.hyperparameters
+
+    def __ne__(self, other: object) -> bool:
+        """Check inequality between two CustomModelFineTuningJob objects.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        return not self.__eq__(other)
+
+    @classmethod
+    def _from_rest_object(cls, obj: RestJobBase) -> "CustomModelFineTuningJob":
+        """Convert a REST object to CustomModelFineTuningJob object.
+
+        :param obj: CustomModelFineTuningJob in Rest format.
+        :type obj: JobBase
+        :return: CustomModelFineTuningJob objects.
+        :rtype: CustomModelFineTuningJob
+        """
+
+        properties: RestFineTuningJob = obj.properties
+        finetuning_details: RestCustomModelFineTuningVertical = properties.fine_tuning_details
+
+        job_args_dict = {
+            "id": obj.id,
+            "name": obj.name,
+            "description": properties.description,
+            "tags": properties.tags,
+            "properties": properties.properties,
+            "services": properties.services,
+            "experiment_name": properties.experiment_name,
+            "status": properties.status,
+            "creation_context": obj.system_data,
+            "display_name": properties.display_name,
+            "compute": properties.compute_id,
+            "outputs": from_rest_data_outputs(properties.outputs),
+        }
+
+        if properties.resources:
+            job_args_dict["resources"] = JobResources._from_rest_object(properties.resources)
+        if properties.queue_settings:
+            job_args_dict["queue_settings"] = QueueSettings._from_rest_object(properties.queue_settings)
+
+        custom_model_finetuning_job = cls(
+            task=finetuning_details.task_type,
+            model=finetuning_details.model,
+            training_data=finetuning_details.training_data,
+            validation_data=finetuning_details.validation_data,
+            hyperparameters=finetuning_details.hyper_parameters,
+            **job_args_dict,
+        )
+
+        custom_model_finetuning_job._restore_inputs()
+
+        return custom_model_finetuning_job
+
+    @classmethod
+    def _load_from_dict(
+        cls,
+        data: Dict,
+        context: Dict,
+        additional_message: str,
+        **kwargs: Any,
+    ) -> "CustomModelFineTuningJob":
+        """Load from a dictionary.
+
+        :param data: dictionary representation of the object.
+        :type data: typing.Dict
+        :param context: dictionary containing the context.
+        :type context: typing.Dict
+        :param additional_message: additional message to be added to the error message.
+        :type additional_message: str
+        :return: CustomModelFineTuningJob object.
+        :rtype: CustomModelFineTuningJob
+        """
+        from azure.ai.ml._schema._finetuning.custom_model_finetuning import (
+            CustomModelFineTuningSchema,
+        )
+
+        # TODO: Combeback to this later - Pipeline part.
+        # from azure.ai.ml._schema.pipeline.automl_node import AutoMLClassificationNodeSchema
+
+        # if kwargs.pop("inside_pipeline", False):
+        #    loaded_data = load_from_dict(
+        #        AutoMLClassificationNodeSchema,
+        #        data,
+        #        context,
+        #        additional_message,
+        #        **kwargs,
+        #    )
+        # else:
+        loaded_data = load_from_dict(CustomModelFineTuningSchema, data, context, additional_message, **kwargs)
+
+        training_data = loaded_data.get("training_data", None)
+        if isinstance(training_data, str):
+            loaded_data["training_data"] = Input(type="uri_file", path=training_data)
+
+        validation_data = loaded_data.get("validation_data", None)
+        if isinstance(validation_data, str):
+            loaded_data["validation_data"] = Input(type="uri_file", path=validation_data)
+
+        job_instance = cls._create_instance_from_schema_dict(loaded_data)
+        return job_instance
+
+    @classmethod
+    def _create_instance_from_schema_dict(cls, loaded_data: Dict) -> "CustomModelFineTuningJob":
+        """Create an instance from a schema dictionary.
+
+        :param loaded_data: dictionary containing the data.
+        :type loaded_data: typing.Dict
+        :return: CustomModelFineTuningJob object.
+        :rtype: CustomModelFineTuningJob
+        """
+        job = CustomModelFineTuningJob(**loaded_data)
+        return job
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_job.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_job.py
new file mode 100644
index 00000000..ec8d9d5d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_job.py
@@ -0,0 +1,224 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+# pylint: disable=protected-access
+
+from typing import Any, Dict, Optional
+
+from azure.ai.ml.entities._job.job import Job
+from azure.ai.ml.entities._job.job_io_mixin import JobIOMixin
+from azure.ai.ml._restclient.v2024_10_01_preview.models import (
+    ModelProvider as RestModelProvider,
+    JobBase as RestJobBase,
+)
+from azure.ai.ml.constants import JobType
+from azure.ai.ml.constants._common import TYPE
+from azure.ai.ml._utils.utils import camel_to_snake
+from azure.ai.ml.entities._job.job_resources import JobResources
+from azure.ai.ml.entities._job.queue_settings import QueueSettings
+from azure.ai.ml.exceptions import ErrorCategory, ErrorTarget, ValidationException
+from azure.ai.ml.constants._job.finetuning import FineTuningConstants
+from azure.ai.ml._utils._experimental import experimental
+
+
+@experimental
+class FineTuningJob(Job, JobIOMixin):
+    def __init__(
+        self,
+        **kwargs: Any,
+    ) -> None:
+        kwargs[TYPE] = JobType.FINE_TUNING
+        self.resources = kwargs.pop("resources", None)
+        self.queue_settings = kwargs.pop("queue_settings", None)
+        self.outputs = kwargs.pop("outputs", None)
+        super().__init__(**kwargs)
+
+    @property
+    def resources(self) -> Optional[JobResources]:
+        """Job resources to use during job execution.
+        :return: Job Resources object.
+        :rtype: JobResources
+        """
+        return self._resources if hasattr(self, "_resources") else None
+
+    @resources.setter
+    def resources(self, value: JobResources) -> None:
+        """Set JobResources.
+
+        :param value: JobResources object.
+        :type value: JobResources
+        :raises ValidationException: Expected a JobResources object.
+        """
+        if isinstance(value, JobResources):
+            self._resources = value
+        elif value:
+            msg = "Expected an instance of JobResources."
+            raise ValidationException(
+                message=msg,
+                no_personal_data_message=msg,
+                target=ErrorTarget.FINETUNING,
+                error_category=ErrorCategory.USER_ERROR,
+            )
+
+    @property
+    def queue_settings(self) -> Optional[QueueSettings]:
+        """Queue settings for job execution.
+        :return: QueueSettings object.
+        :rtype: QueueSettings
+        """
+        return self._queue_settings if hasattr(self, "_queue_settings") else None
+
+    @queue_settings.setter
+    def queue_settings(self, value: QueueSettings) -> None:
+        """Set queue settings for job execution.
+
+        :param value: QueueSettings object.
+        :type value: QueueSettings
+        :raises ValidationException: Expected a QueueSettings object.
+        """
+        if isinstance(value, QueueSettings):
+            self._queue_settings = value
+        elif value:
+            msg = "Expected an instance of QueueSettings."
+            raise ValidationException(
+                message=msg,
+                no_personal_data_message=msg,
+                target=ErrorTarget.FINETUNING,
+                error_category=ErrorCategory.USER_ERROR,
+            )
+
+    def __eq__(self, other: object) -> bool:
+        """Returns True if both instances have the same values.
+
+        This method check instances equality and returns True if both of
+            the instances have the same attributes with the same values.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        if not isinstance(other, FineTuningJob):
+            return NotImplemented
+
+        queue_settings_match = (not self.queue_settings and not other.queue_settings) or (
+            self.queue_settings is not None
+            and other.queue_settings is not None
+            and self.queue_settings.job_tier is not None
+            and other.queue_settings.job_tier is not None
+            and self.queue_settings.job_tier.lower() == other.queue_settings.job_tier.lower()
+        )
+
+        outputs_match = not self.outputs and not other.outputs
+        if self.outputs and other.outputs:
+            outputs_match = (
+                self.outputs["registered_model"].name == other.outputs["registered_model"].name
+                and self.outputs["registered_model"].type == other.outputs["registered_model"].type
+            )
+
+        return (
+            outputs_match
+            and self.resources == other.resources
+            and queue_settings_match
+            # add properties from base class
+            and self.name == other.name
+            and self.description == other.description
+            and self.tags == other.tags
+            and self.properties == other.properties
+            and self.compute == other.compute
+            and self.id == other.id
+            and self.experiment_name == other.experiment_name
+            and self.status == other.status
+        )
+
+    def __ne__(self, other: object) -> bool:
+        """Check inequality between two FineTuningJob objects.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        return not self.__eq__(other)
+
+    @classmethod
+    def _get_model_provider_mapping(cls) -> Dict:
+        """Create a mapping of task type to job class.
+
+        :return: An FineTuningVertical object containing the model provider type to job class mapping.
+        :rtype: FineTuningJob
+        """
+        from .custom_model_finetuning_job import CustomModelFineTuningJob
+        from .azure_openai_finetuning_job import AzureOpenAIFineTuningJob
+
+        return {
+            camel_to_snake(RestModelProvider.CUSTOM): CustomModelFineTuningJob,
+            camel_to_snake(RestModelProvider.AZURE_OPEN_AI): AzureOpenAIFineTuningJob,
+        }
+
+    @classmethod
+    def _load_from_rest(cls, obj: RestJobBase) -> "FineTuningJob":
+        """Loads the rest object to a dict containing items to init the AutoMLJob objects.
+
+        :param obj: Azure Resource Manager resource envelope.
+        :type obj: JobBase
+        :raises ValidationException: task type validation error
+        :return: A FineTuningJob
+        :rtype: FineTuningJob
+        """
+        model_provider = (
+            camel_to_snake(obj.properties.fine_tuning_details.model_provider)
+            if obj.properties.fine_tuning_details.model_provider
+            else None
+        )
+        class_type = cls._get_model_provider_mapping().get(model_provider, None)
+        if class_type:
+            res: FineTuningJob = class_type._from_rest_object(obj)
+            return res
+        msg = f"Unsupported model provider type: {obj.properties.fine_tuning_details.model_provider}"
+        raise ValidationException(
+            message=msg,
+            no_personal_data_message=msg,
+            target=ErrorTarget.FINETUNING,
+            error_category=ErrorCategory.SYSTEM_ERROR,
+        )
+
+    @classmethod
+    def _load_from_dict(
+        cls,
+        data: Dict,
+        context: Dict,
+        additional_message: str,
+        **kwargs: Any,
+    ) -> "FineTuningJob":
+        """Loads the dictionary objects to an FineTuningJob object.
+
+        :param data: A data dictionary.
+        :type data: typing.Dict
+        :param context: A context dictionary.
+        :type context: typing.Dict
+        :param additional_message: An additional message to be logged in the ValidationException.
+        :type additional_message: str
+
+        :raises ValidationException: task type validation error
+        :return: An FineTuningJob
+        :rtype: FineTuningJob
+        """
+        model_provider = data.get(FineTuningConstants.ModelProvider)
+        class_type = cls._get_model_provider_mapping().get(model_provider, None)
+        if class_type:
+            res: FineTuningJob = class_type._load_from_dict(
+                data,
+                context,
+                additional_message,
+                **kwargs,
+            )
+            return res
+        msg = f"Unsupported model provider type: {model_provider}"
+        raise ValidationException(
+            message=msg,
+            no_personal_data_message=msg,
+            target=ErrorTarget.AUTOML,
+            error_category=ErrorCategory.USER_ERROR,
+        )
diff --git a/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_vertical.py b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_vertical.py
new file mode 100644
index 00000000..c9a5fe41
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/ai/ml/entities/_job/finetuning/finetuning_vertical.py
@@ -0,0 +1,202 @@
+# ---------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# ---------------------------------------------------------
+
+from typing import Any, Optional, cast
+
+from azure.ai.ml.exceptions import ErrorCategory, ErrorTarget, ValidationException
+from azure.ai.ml._restclient.v2024_10_01_preview.models import (
+    ModelProvider as RestModelProvider,
+    FineTuningVertical as RestFineTuningVertical,
+    UriFileJobInput,
+    MLFlowModelJobInput,
+)
+from azure.ai.ml.constants._common import AssetTypes
+from azure.ai.ml._utils.utils import camel_to_snake
+from azure.ai.ml.entities._inputs_outputs import Input
+from azure.ai.ml.entities._job.finetuning.finetuning_job import FineTuningJob
+
+from azure.ai.ml._utils._experimental import experimental
+
+
+@experimental
+class FineTuningVertical(FineTuningJob):
+    def __init__(
+        self,
+        *,
+        task: str,
+        model: Input,
+        model_provider: Optional[str],
+        training_data: Input,
+        validation_data: Optional[Input] = None,
+        **kwargs: Any,
+    ) -> None:
+        self._task = task
+        self._model = model
+        self._model_provider = model_provider
+        self._training_data = training_data
+        self._validation_data = validation_data
+        super().__init__(**kwargs)
+
+    @property
+    def task(self) -> str:
+        """Get finetuning task.
+
+        :return: The type of task to run. Possible values include: "ChatCompletion"
+                 "TextCompletion", "TextClassification", "QuestionAnswering","TextSummarization",
+                 "TokenClassification", "TextTranslation", "ImageClassification", "ImageInstanceSegmentation",
+                 "ImageObjectDetection","VideoMultiObjectTracking".
+
+        :rtype: str
+        """
+        return self._task
+
+    @task.setter
+    def task(self, task: str) -> None:
+        """Set finetuning task.
+
+        :param task: The type of task to run. Possible values include: "ChatCompletion"
+                 "TextCompletion", "TextClassification", "QuestionAnswering","TextSummarization",
+                 "TokenClassification", "TextTranslation", "ImageClassification", "ImageInstanceSegmentation",
+                 "ImageObjectDetection","VideoMultiObjectTracking",.
+        :type task: str
+
+        :return: None
+        """
+        self._task = task
+
+    @property
+    def model(self) -> Optional[Input]:
+        """The model to be fine-tuned.
+        :return: Input object representing the mlflow model to be fine-tuned.
+        :rtype: Input
+        """
+        return self._model
+
+    @model.setter
+    def model(self, value: Input) -> None:
+        """Set the model to be fine-tuned.
+
+        :param value: Input object representing the mlflow model to be fine-tuned.
+        :type value: Input
+        :raises ValidationException: Expected a mlflow model input.
+        """
+        if isinstance(value, Input) and (cast(Input, value).type in ("mlflow_model", "custom_model")):
+            self._model = value
+        else:
+            msg = "Expected a mlflow model input or custom model input."
+            raise ValidationException(
+                message=msg,
+                no_personal_data_message=msg,
+                target=ErrorTarget.FINETUNING,
+                error_category=ErrorCategory.USER_ERROR,
+            )
+
+    @property
+    def model_provider(self) -> Optional[str]:
+        """The model provider.
+        :return: The model provider.
+        :rtype: str
+        """
+        return self._model_provider
+
+    @model_provider.setter
+    def model_provider(self, value: str) -> None:
+        """Set the model provider.
+
+        :param value: The model provider.
+        :type value: str
+        """
+        self._model_provider = RestModelProvider[camel_to_snake(value).upper()] if value else None
+
+    @property
+    def training_data(self) -> Input:
+        """Get training data.
+
+        :return: Training data input
+        :rtype: Input
+        """
+        return self._training_data
+
+    @training_data.setter
+    def training_data(self, training_data: Input) -> None:
+        """Set training data.
+
+        :param training_data: Training data input
+        :type training_data: Input
+        """
+        self._training_data = training_data
+
+    @property
+    def validation_data(self) -> Optional[Input]:
+        """Get validation data.
+
+        :return: Validation data input
+        :rtype: Input
+        """
+        return self._validation_data
+
+    @validation_data.setter
+    def validation_data(self, validation_data: Input) -> None:
+        """Set validation data.
+
+        :param validation_data: Validation data input
+        :type validation_data: Input
+        """
+        self._validation_data = validation_data
+
+    def _resolve_inputs(self, rest_job: RestFineTuningVertical) -> None:
+        """Resolve JobInputs to UriFileJobInput within data_settings.
+
+        :param rest_job: The rest job object.
+        :type rest_job: RestFineTuningVertical
+        """
+        if isinstance(rest_job.training_data, Input):
+            rest_job.training_data = UriFileJobInput(uri=rest_job.training_data.path)
+        if isinstance(rest_job.validation_data, Input):
+            rest_job.validation_data = UriFileJobInput(uri=rest_job.validation_data.path)
+        if isinstance(rest_job.model, Input):
+            rest_job.model = MLFlowModelJobInput(uri=rest_job.model.path)
+
+    def _restore_inputs(self) -> None:
+        """Restore UriFileJobInputs to JobInputs within data_settings."""
+        if isinstance(self.training_data, UriFileJobInput):
+            self.training_data = Input(type=AssetTypes.URI_FILE, path=self.training_data.uri)
+        if isinstance(self.validation_data, UriFileJobInput):
+            self.validation_data = Input(type=AssetTypes.URI_FILE, path=self.validation_data.uri)
+        if isinstance(self.model, MLFlowModelJobInput):
+            self.model = Input(type=AssetTypes.MLFLOW_MODEL, path=self.model.uri)
+
+    def __eq__(self, other: object) -> bool:
+        """Returns True if both instances have the same values.
+
+        This method check instances equality and returns True if both of
+            the instances have the same attributes with the same values.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        if not isinstance(other, FineTuningVertical):
+            return NotImplemented
+
+        return (
+            # TODO: Equality from base class does not work, no current precedence for this
+            super().__eq__(other)
+            and self.task == other.task
+            and self.model == other.model
+            and self.model_provider == other.model_provider
+            and self.training_data == other.training_data
+            and self.validation_data == other.validation_data
+        )
+
+    def __ne__(self, other: object) -> bool:
+        """Check inequality between two FineTuningJob objects.
+
+        :param other: Any object
+        :type other: object
+        :return: True or False
+        :rtype: bool
+        """
+        return not self.__eq__(other)