View this notebook on GitHub or run it yourself on Binder!
Distinguish Failed Experiments¶
Modeling runs can fail for a number of reasons. When logging with rubicon_ml, a failed run may result in an empty or incomplete experiment. In this example, we’ll walk through how to handle such experiments.
First lets simulate the problem. To do this we’ll create an estimator that will fail on it’s fit()
30% of the time. We will consider any pipeline that has a learned attribute self.state_
to have “succeeded,” and any that does not to have “failed.”
[1]:
from sklearn.base import BaseEstimator
import random
class BadEstimator(BaseEstimator):
def __init__(self):
super().__init__()
self.knn = KNeighborsClassifier(n_neighbors=2)
def fit(self, X, y):
self.knn.fit(X, y)
output=random.random()
if output>.3:
self.state_=output
def score(self, X):
knn_score = self.knn.score(X)
return knn_score
Next, lets create a rubicon_ml
project to log our experimenation to.
[2]:
from rubicon_ml.sklearn import make_pipeline
from sklearn.neighbors import KNeighborsClassifier
from sklearn.impute import SimpleImputer
from rubicon_ml import Rubicon
random.seed(17)
rubicon = Rubicon(
persistence="memory",
)
project = rubicon.get_or_create_project(name="Failed Experiments")
Now let’s create a rubicon_ml.sklearn
pipeline with this sporadically failing estimator and attempt to fit
the pipeline twenty times. Tag any experiment that doesn’t have a valid state_
attribute for failures with exp.add_tags(["failed"])
and passed experiments with exp.add_tags(["passed"])
.
[3]:
X = [[1], [1], [1], [1]]
y = [1, 1, 1, 1]
for _ in range(20):
pipe=make_pipeline(project, SimpleImputer(strategy="mean"),BadEstimator())
pipe.fit(X,y)
if not hasattr(pipe["badestimator"],"state_"):
pipe.experiment.add_tags(["failed"])
else:
pipe.experiment.add_tags(["passed"])
Finally, we can now retrieve all our failed experiments by passing the tags=["failed"]
to project.experiments()
.
[4]:
for exp in project.experiments(tags=["failed"]):
print(exp)
Experiment(project_name='Failed Experiments', id='375a55ec-9e50-4c59-86c8-e06be471d45e', name='RubiconPipeline experiment', description=None, model_name=None, branch_name=None, commit_hash=None, training_metadata=None, tags=['failed'], created_at=datetime.datetime(2022, 5, 10, 14, 50, 44, 669757))
Experiment(project_name='Failed Experiments', id='fce82fb6-58d8-42df-a40b-304bc83826b5', name='RubiconPipeline experiment', description=None, model_name=None, branch_name=None, commit_hash=None, training_metadata=None, tags=['failed'], created_at=datetime.datetime(2022, 5, 10, 14, 50, 44, 676902))
Experiment(project_name='Failed Experiments', id='912b9efe-db1f-4ff2-b7c3-51d23bc60acf', name='RubiconPipeline experiment', description=None, model_name=None, branch_name=None, commit_hash=None, training_metadata=None, tags=['failed'], created_at=datetime.datetime(2022, 5, 10, 14, 50, 44, 678565))
Experiment(project_name='Failed Experiments', id='75f4d429-b67e-4d16-a634-700b600224fc', name='RubiconPipeline experiment', description=None, model_name=None, branch_name=None, commit_hash=None, training_metadata=None, tags=['failed'], created_at=datetime.datetime(2022, 5, 10, 14, 50, 44, 683442))
Experiment(project_name='Failed Experiments', id='e0ca4d92-5c37-4118-bfc8-96253fe390c9', name='RubiconPipeline experiment', description=None, model_name=None, branch_name=None, commit_hash=None, training_metadata=None, tags=['failed'], created_at=datetime.datetime(2022, 5, 10, 14, 50, 44, 697318))
We can also see that the pipeline passed ~70% of the time and ~30% of the time.
[5]:
len(project.experiments(tags=["failed"]))
[5]:
5
[6]:
len(project.experiments(tags=["passed"]))
[6]:
15