def _to_lib_selectors( dependencies: Set[Union[LibSelector, str, Tuple[str, str]]] ) -> Set[LibSelector]: selectors = set() for d in dependencies: selectors.add( LibSelector(name=d[0], constraint=d[1]) if isinstance( d, tuple) else LibSelector( name=d) if not isinstance(d, LibSelector) else d) return selectors
class MetricTorch(MetricILF): """ Function logging wrapped metrics of PyTroch """ supported_libraries = {LibSelector(name="torch", constraint="*", specificity=1)} _dependencies = {"torch"} def __init__(self,*args, **kwargs): super().__init__(*args, **kwargs) self.identity = MetricILF.__name__ def __post__(self, ctx, *args, _pypads_artifact_fallback=False, _pypads_env, _logger_call, _logger_output, _pypads_result, **kwargs): """ :param ctx: :param args: :param _pypads_artifact_fallback: Write to artifact if metric can not be logged as an double value into mlflow :param _pypads_result: :param kwargs: :return: """ result = _pypads_result if result is not None: from torch import Tensor if isinstance(result, Tensor): super().__post__(ctx, *args, _pypads_env=_pypads_env,_pypads_artifact_fallback=_pypads_artifact_fallback, _logger_call=_logger_call, _logger_output=_logger_output, _pypads_result=result.item(), **kwargs)
class DecisionsTorchILF(SingleInstanceILF): """ Function getting the prediction scores from torch models. Hook: Hook this logger to the inference function of your model, e.g, torch.modules.container.Sequential.forward. """ name = "PyTorch Decisions Logger" category = "TorchDecisionsLogger" supported_libraries = {LibSelector(name="torch", constraint="*", specificity=1)} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.identity = SingleInstanceILF.__name__ def __post__(self, ctx, *args, _logger_call, _pypads_pre_return, _pypads_result, _logger_output, _args, _kwargs, **kwargs): from pypads.app.pypads import get_current_pads pads = get_current_pads() if hasattr(ctx, "training") and ctx.training: pass else: pads.cache.run_add("probabilities", _pypads_result.data.numpy()) pads.cache.run_add("predictions", _pypads_result.argmax(dim=1).data.numpy()) return super().__post__(ctx, *args, _logger_call=_logger_call, _pypads_pre_return=_pypads_pre_return, _pypads_result=_pypads_result, _logger_output=_logger_output, _args=_args, _kwargs=_kwargs, **kwargs)
class DecisionsKerasILF(SingleInstanceILF): """ Function getting the prediction scores from keras models. Hook: Hook this logger to the inference function of your model, i.e. keras.engine.training.Model.predict_classes. """ name = "Keras Decisions Logger" category = "KerasDecisionsLogger" supported_libraries = {LibSelector(name="keras", constraint="*", specificity=1)} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.identity = SingleInstanceILF.__name__ def __pre__(self, ctx, *args, _logger_call, _logger_output, _args, _kwargs, **kwargs): """ :param ctx: :param args: :param kwargs: :return: """ from pypads.app.pypads import get_current_pads pads = get_current_pads() probabilities = None try: probabilities = ctx.predict(*_args, **_kwargs) except Exception as e: logger.warning("Couldn't compute probabilities because %s" % str(e)) pads.cache.run_add("probabilities", probabilities)
def get_relevant_mappings(self, package: Package): """ Function to find all relevant mappings. This produces a generator getting extended with found subclasses :return: """ if any([ package.path.segments[0] == s.name for s, _ in self.get_entries() ]): lib_version = find_package_version(str(package.path.segments[0])) mappings = set() # Take only mappings which are fitting for versions if we have a selector if lib_version: lib_selector = LibSelector(name=str(package.path.segments[0]), constraint=lib_version) for k, collection in [(s, c) for s, c in self.get_entries() if s.allows_any(lib_selector)]: for m in collection.find_mappings(package.path.segments): mappings.add(m) # Otherwise just use all name fitting mappings else: for k, collection in [(s, c) for s, c in self.get_entries() if s.name == package.path.segments[0]]: for m in collection.find_mappings(package.path.segments): mappings.add(m) return mappings return set()
class DecisionsSklearnILF(SingleInstanceILF): """ Function getting the prediction scores from sklearn estimators Hook: Hook this logger to the inference function of your model, i.e. sklearn.BaseEstimator.predict. """ name = "Sklearn Decisions Logger" type = "SklearnDecisionsLogger" supported_libraries = {LibSelector(name="sklearn", constraint="*", specificity=1)} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.identity = SingleInstanceILF.__name__ def __pre__(self, ctx, *args, _logger_call, _logger_output, _args, _kwargs, **kwargs): """ :param ctx: :param args: :param kwargs: :return: """ from pypads.app.pypads import get_current_pads pads = get_current_pads() # check if the estimator computes decision scores probabilities = None predict_proba = None if hasattr(ctx, "predict_proba"): # TODO find a cleaner way to invoke the original predict_proba in case it is wrapped predict_proba = ctx.predict_proba if _logger_call.original_call.call_id.context.has_original(predict_proba): predict_proba = _logger_call.original_call.call_id.context.original(predict_proba) elif hasattr(ctx, "_predict_proba"): predict_proba = ctx._predict_proba if _logger_call.original_call.call_id.context.has_original(predict_proba): _logger_call.original_call.call_id.context.original(predict_proba) if hasattr(predict_proba, "__wrapped__"): predict_proba = predict_proba.__wrapped__ try: probabilities = predict_proba(*_args, **_kwargs) except Exception as e: if isinstance(e, TypeError): try: predict_proba = predict_proba.__get__(ctx) probabilities = predict_proba(*_args, **_kwargs) except Exception as ee: logger.warning("Couldn't compute probabilities because %s" % str(ee)) else: logger.warning("Couldn't compute probabilities because %s" % str(e)) finally: pads.cache.run_add("probabilities", probabilities)
class ParameterSearchILF(InjectionLogger): """ Function logging the cv results of a parameter search """ name = "Parameter Search Logger" category = "ParameterSearchLogger" supported_libraries = { LibSelector(name="sklearn", constraint="*", specificity=1) } class ParameterSearchOutput(OutputModel): category: str = "ParameterSearchOutput" gridsearch_cv: str = None class Config: orm_mode = True @classmethod def output_schema_class(cls) -> Optional[Type[OutputModel]]: return cls.ParameterSearchOutput def __pre__(self, ctx, *args, _pypads_write_format=None, _logger_call: LoggerCall, _logger_output, _args, _kwargs, **kwargs): from pypads.app.pypads import get_current_pads pads = get_current_pads() pads.cache.run_add("parameter_search", True) def __post__(self, ctx, *args, _logger_call, _pypads_pre_return, _pypads_result, _logger_output, _args, _kwargs, **kwargs): from pypads.app.pypads import get_current_pads pads = get_current_pads() pads.cache.run_pop("parameter_search") from sklearn.model_selection._search import BaseSearchCV if isinstance(ctx, BaseSearchCV): gridsearch = ParameterSearchTO(parent=_logger_output) gridsearch.number_of_splits = ctx.n_splits_ # Track individual decisions for all splits pads.cache.add("tracking_mode", "multiple") gridsearch.best_candidate = ctx.best_index_ gridsearch.add_results(ctx.cv_results_) _logger_output.gridsearch_cv = gridsearch.store()
def __init__(self, key, version, library, author=None, **kwargs): """ Object holding a set of mappings related to a library :param key: Name / key of the collection :param version: Version of the collection :param library: Library information including library version constraint and name """ self._mappings = {} self._name = key self._author = author self._version = version self._lib = LibSelector.from_dict(library) self._hash = persistent_hash( (self._name, self._version, hash(self._lib))) self.uid = self._hash super().__init__()