def log_batch(self, run_id, metrics=None, params=None, tags=None): """ Fetches the experiment by ID from the backend store. :param run_id: string containing run UUID (32 hex characters = a uuid4 stripped off of dashes) :param metrics: List of Mlflow Metric entities. :param params: List of Mlflow Param entities :param tags: List of Mlflow Tag entities. """ metrics = [] if metrics is None else metrics params = [] if params is None else params tags = [] if tags is None else tags try: self._client.log_run_data( self._project_id, UUID(run_id), params=[ mlflow_param_to_faculty_param(param) for param in params ], metrics=[ mlflow_metric_to_faculty_metric(metric) for metric in metrics ], tags=[mlflow_tag_to_faculty_tag(tag) for tag in tags], ) except ParamConflict as conflict: raise MlflowException( "Conflicting param keys: {}".format( conflict.conflicting_params ) ) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e)
def test_faculty_http_error_to_mlflow_exception(): dummy_response = Response() dummy_response.status_code = 418 faculty_http_error = HTTPError(dummy_response, "error", "error_code") assert isinstance( faculty_http_error_to_mlflow_exception(faculty_http_error), MlflowException, )
def restore_experiment(self, experiment_id): """ Restore deleted experiment unless it is permanently deleted. :param experiment_id: Integer id for the experiment """ try: self._client.restore(self._project_id, int(experiment_id)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e)
def delete_experiment(self, experiment_id): """ Deletes the experiment from the backend store. Deleted experiments can be restored until permanently deleted. :param experiment_id: Integer id for the experiment """ try: self._client.delete(self._project_id, int(experiment_id)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e)
def rename_experiment(self, experiment_id, new_name): """ Update an experiment's name. The new name must be unique. :param experiment_id: Integer id for the experiment """ try: self._client.update( self._project_id, int(experiment_id), name=new_name ) except faculty.clients.experiment.ExperimentNameConflict as e: raise MlflowException(str(e)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e)
def get_experiment(self, experiment_id): """ Fetches the experiment by ID from the backend store. :param experiment_id: Integer id for the experiment :return: A single :py:class:`mlflow.entities.Experiment` object if it exists, otherwise raises an exception. """ try: faculty_experiment = self._client.get(self._project_id, int(experiment_id)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: return faculty_experiment_to_mlflow_experiment(faculty_experiment)
def get_run(self, run_id): """ Fetches the run from backend store :param run_id: string containing run UUID (32 hex characters = a uuid4 stripped off of dashes) :return: A single :py:class:`mlflow.entities.Run` object if it exists, otherwise raises an exception """ try: faculty_run = self._client.get_run(self._project_id, UUID(run_id)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: mlflow_run = faculty_run_to_mlflow_run(faculty_run) return mlflow_run
def list_experiments(self, view_type=ViewType.ACTIVE_ONLY): """ :param view_type: Qualify requested type of experiments. :return: a list of Experiment objects stored in store for requested view. """ lifecycle_stage = mlflow_viewtype_to_faculty_lifecycle_stage(view_type) try: faculty_experiments = self._client.list(self._project_id, lifecycle_stage) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: return [ faculty_experiment_to_mlflow_experiment(faculty_experiment) for faculty_experiment in faculty_experiments ]
def create_run(self, experiment_id, user_id, start_time, tags): """ Creates a run under the specified experiment ID, setting the run's status to "RUNNING" and the start time to the current time. :param experiment_id: ID of the experiment for this run :param user_id: ID of the user launching this run :param start_time: Time the run started at in epoch milliseconds. :param tags: List of Mlflow Tag entities. :return: The created Run object """ tags = [] if tags is None else tags # For backward compatability, fall back to run name or parent run ID # set in tags tag_dict = {tag.key: tag.value for tag in tags} run_name = tag_dict.get(MLFLOW_RUN_NAME) or "" parent_run_id = tag_dict.get(MLFLOW_PARENT_RUN_ID) or None try: faculty_run = self._client.create_run( self._project_id, int(experiment_id), run_name, mlflow_timestamp_to_datetime(start_time), None if parent_run_id is None else UUID(parent_run_id), tags=[mlflow_tag_to_faculty_tag(tag) for tag in tags], ) except ExperimentDeleted as conflict: raise MlflowException( "Experiment {0} is deleted." " To create runs for this experiment," " first restore it with the shell command " "'mlflow experiments restore {0}'".format( conflict.experiment_id ) ) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: mlflow_run = faculty_run_to_mlflow_run(faculty_run) return mlflow_run
def get_metric_history(self, run_id, metric_key): """ Returns all logged value for a given metric. :param run_id: Unique identifier for run :param metric_key: Metric name within the run :return: A list of float values logged for the give metric if logged, else empty list """ try: metric_history = self._client.get_metric_history( self._project_id, UUID(run_id), metric_key) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: return [ faculty_metric_to_mlflow_metric(faculty_metric) for faculty_metric in metric_history ]
def restore_run(self, run_id): """ Restores a run. :param run_id: """ run_id = UUID(run_id) try: response = self._client.restore_runs(self._project_id, [run_id]) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) if run_id in response.restored_run_ids: return elif run_id in response.conflicted_run_ids: raise MlflowException( "Could not restore already-active run {}".format(run_id.hex)) else: raise MlflowException( "Could not restore non-existent run {}".format(run_id.hex))
def update_run_info(self, run_id, run_status, end_time): """ Updates the metadata of the specified run. :param run_id: string containing run UUID :param run_status: RunStatus to update the run to, optional :param end_time: timestamp to update the run ended_at to, optional :return: :py:class:`mlflow.entities.RunInfo` describing the updated run. """ try: faculty_run = self._client.update_run_info( self._project_id, UUID(run_id), mlflow_to_faculty_run_status(run_status), mlflow_timestamp_to_datetime(end_time), ) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: mlflow_run = faculty_run_to_mlflow_run(faculty_run) return mlflow_run.info
def create_experiment(self, name, artifact_location): """ Creates a new experiment. If an experiment with the given name already exists, throws exception. :param name: Desired name for an experiment :param artifact_location: Base location for artifacts in runs. May be None. :return: experiment_id (string) for the newly created experiment. """ if artifact_location == "": # Assume unspecified artifact location artifact_location = None try: faculty_experiment = self._client.create( self._project_id, name, artifact_location=artifact_location) except faculty.clients.experiment.ExperimentNameConflict as e: raise MlflowException(str(e)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) else: return str(faculty_experiment.id)
def _search_runs( self, experiment_ids, filter_string, run_view_type, max_results, order_by, page_token, ): """ Return runs that match the given list of search expressions within the experiments, as well as a pagination token (indicating where the next page should start). Subclasses of ``AbstractStore`` should implement this method to support pagination instead of ``search_runs``. See ``search_runs`` for parameter descriptions. :return: A tuple of ``runs`` and ``token`` where ``runs`` is a list of ``mlflow.entities.Run`` objects that satisfy the search expressions, and ``token`` is the pagination token for the next page of results. """ if order_by is not None and order_by != []: raise ValueError("order_by not currently supported") if page_token is not None: raise ValueError("page_token not currently supported") try: filter = build_search_runs_filter( experiment_ids, filter_string, run_view_type ) except mlflow_faculty.filter.MatchesNothing: return [], None except ValueError as e: raise MlflowException(str(e)) def _get_runs(): response = self._client.query_runs(self._project_id, filter) for run in response.runs: yield run next_page = response.pagination.next while next_page is not None: response = self._client.query_runs( self._project_id, filter, start=next_page.start, limit=next_page.limit, ) for run in response.runs: yield run next_page = response.pagination.next try: run_generator = _get_runs() faculty_runs = list(islice(run_generator, max_results)) except faculty.clients.base.HttpError as e: raise faculty_http_error_to_mlflow_exception(e) mlflow_runs = [faculty_run_to_mlflow_run(run) for run in faculty_runs] return mlflow_runs, None