Getting Started with an Existing Codebase¶
Depending on your requirements, there are a few ways to make your existing code Scooch configurable. In most cases the scooch.configurize
will be a key piece of functionality.
Configurizing Classes that You Own¶
If you already have class definitions in your code that you want to make configurable, you can use the configurize
decorator:
from scooch import configurize
@configurize
class PreexistingClass(object):
def __init__(self, arg1, arg2=5)
...
Scooch will create a derived class that has arg1
and arg2
as configurable parameters, with a default value of 5
for arg2
. The derived class will take a Scooch Config
dictionary in the constructor argument, like any other Scooch Configurable
.
Note that Scooch will prefix Scooch
to the class name to differentiate it from the non-configurable version of the class. For example, in your Scooch config.yaml
file, the type of the configurized class above will be ScoochPreexistingClass
You can also add a class to an existing Scooch Configurable
hierarchy, by specifying a base_class
that is also a Configurable
.
@configurize(base_class=ScoochConfigurableBaseClass)
class PreexistingClass(object):
def __init__(self, arg1, arg2=5)
Configurizing Third-Party Classes¶
If the class you want to configure with Scooch belongs to a code base you are not a contributor for, you will have no access to modify the class definition. One way to make a third party class Scooch configurable is to use scooch.configurize
.
For example, if you are developing an ML training pipeline, you may want to use the classes in tensorflow.keras.losses
, and parameterize them in your Scooch config file. Making a single third party class configurable is as easy as:
from scooch import configurize
import tensorflow as tf
configurable_class = configurize(tf.keras.losses.BinaryCrossEntropy)
We can now write a ./config.yaml
for this new class:
ScoochBinaryCrossEntropy:
from_logits: True
label_smoothing: 0.5
The new configurable loss may be instantiated and used like any other keras loss function.
...
from scooch import Config
loss_func = configurable_class(Config('./config.yaml'))
...
This will create a single configurable class that is currently isolated to it’s own inheritance hierarchy. Perhaps you want to create a range of Loss
functions, some custom and some derived from a third party, that will be selectable in your config.yaml
like any other Scooch type. Scooch can do this through multiple inheritence, by adding a user defined Scooch base class to each congigurize
d third party class:
For example, to add all keras loss functions to our Scooch hierarchy we could do the following:
from scooch import Configurable
from scooch import configurize
import sys
import inspect
class Loss(Configurable):
"""
Base class for all Scooch Configurable loss functions.
"""
pass
clsmembers = inspect.getmembers(sys.modules[tf.keras.losses.__name__], inspect.isclass)
configurable_tf_losses = [configurize(mem[0], Loss) for mem in clsmembers if mem[0] != 'Loss']
With the above code, classes can now be defined with a Param
of type Loss
, which will now be able to use all keras loss functions in your config.yaml
file:
...
from scooch import Param
class Experiment(Configurable):
Param(Loss, doc="A Loss function to train a model with.")
...
Configurizing Code that is not Object Oriented¶
We are currently working on extending Scooch to configure functional code.
If you’re convinced by the arguments in Why Object Oriented Configs? section, you may want to start trying to structure your code using object oriented programming.
An easy start to transforming your code into an object oriented structure, can be to first place it in a run()
method of a Scooch Configurable
. For example,
from scooch import Configurable
from scooch import Config
class Experiment(Configurable):
"""
The class that encapsulates my ML task.
"""
def run():
# Your code here.
experiment = Experiment(Config('./config.yaml'))
experiment.run()
From here, you might want to start breaking out configurable parameters as scooch.Param
s, separate functionality into separate methods, and create classes used within the Experiment
class to modularize some of its processes.
If Scooch looks like something you want to use, but it does not meet your needs, you can file a feature request.