Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sweeper PR #214

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions tango/sweeps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import itertools
import json
import subprocess
from collections import OrderedDict
from dataclasses import dataclass

from tango.common import Params, Registrable


class Sweeper(Registrable):
def __init__(
self,
main_config_path: str,
sweeps_config_path: str,
components: str,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Sweeper class needs to be aware of the Workspace being used in order to get the results of each target step, and to pass the workspace URL when it runs each experiment (with the -w option).

):
super(Registrable, self).__init__()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In recent versions of Python you can just do this:

Suggested change
super(Registrable, self).__init__()
super().__init__()

self.main_config_path = main_config_path
self.sweep_config = load_config(sweeps_config_path)
self.main_config_path = main_config_path
self.components = components

# returns all the combinations of hyperparameters in the form of a list of lists
def get_combinations(self) -> list:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For compat with older Python versions:

Suggested change
def get_combinations(self) -> list:
def get_combinations(self) -> List:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be better if this method was a generator function so that implementations could dynamically pick the next combination based on the history so far.

hyperparams = self.sweep_config.config["config"]["hyperparameters"]
hyperparams_lsts = []
for val in hyperparams.values():
hyperparams_lsts.append(val)
hyperparam_combos = list(itertools.product(*hyperparams_lsts))
return hyperparam_combos

# loops through all combinations of hyperparameters and creates a run for each
def run_experiments(self):
hyperparam_combos = self.get_combinations()
for combination in hyperparam_combos:
# main_config = self.override_hyperparameters(combination)
overrides = self.override_hyperparameters(combination)
# TODO: need to figure where & how to store results / way to track runs
# specify what workspace to use
subprocess.call(
[
"tango",
"run",
self.main_config_path,
"--include-package",
self.components,
"--overrides",
json.dumps(overrides),
]
)

# function to override all the hyperparameters in the current experiment_config
def override_hyperparameters(self, experiment_tuple: tuple) -> dict:
Comment on lines +52 to +53
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstrings should be written like this:

Suggested change
# function to override all the hyperparameters in the current experiment_config
def override_hyperparameters(self, experiment_tuple: tuple) -> dict:
def override_hyperparameters(self, experiment_tuple: tuple) -> dict:
"""
Generates a overrides dictionary for the current experiment config.
"""

overrides = {}
for (i, key) in enumerate(self.sweep_config.config["config"]["hyperparameters"].keys()):
overrides[key] = experiment_tuple[i]
return overrides


# function that loads the config from a specified yaml or jasonnet file
def load_config(sweeps_config_path: str):
return SweepConfig.from_file(sweeps_config_path)


# data class that loads the parameters
@dataclass(frozen=True)
class SweepConfig(Params):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class SweepConfig(Params):
class SweepConfig(FromParams):

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See

class TangoGlobalSettings(FromParams):
for example

config: OrderedDict
25 changes: 25 additions & 0 deletions test_fixtures/sweeps/basic_test/basic_arithmetic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from typing import Union

from tango import Step

IntOrFloat = Union[int, float]

@Step.register("addition")
class AdditionStep(Step):
def run(self, num1: int, num2: int) -> int:
return num1 + num2

@Step.register("scale_up")
class ScaleUp(Step):
def run(self, num1: int, factor: int) -> int:
return num1 * factor

@Step.register("scale_down")
class ScaleDown(Step):
def run(self, num1: int, factor: int) -> IntOrFloat:
return num1 / factor

@Step.register("print")
class Print(Step):
def run(self, num: IntOrFloat) -> None:
print(num)
28 changes: 28 additions & 0 deletions test_fixtures/sweeps/basic_test/config.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"steps": {
"add_numbers": {
"type": "addition",
"num1": 34,
"num2": 8
},
"multiply_result": {
"type": "scale_up",
"num1": {"type": "ref", "ref": "add_numbers"},
"factor": 10,
},
"divide_result": {
"type": "scale_down",
"num1": {"type": "ref", "ref": "multiply_result"},
"factor": 5,
},
"add_x": {
"type": "addition",
"num1": {"type": "ref", "ref": "divide_result"},
"num2": 1,
},
"print": {
"type": "print",
"num": {"type": "ref", "ref": "add_x"},
},
},
}
13 changes: 13 additions & 0 deletions test_fixtures/sweeps/basic_test/sweeps-config.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"config": {
"sweeper": "default",
"n_proc": 1,
"hyperparameters": {
"steps.add_numbers.num1": [8, 16],
"steps.add_numbers.num2": [2, 4],
"steps.multiply_result.factor": [1, 10],
"steps.divide_result.factor": [5, 10],
"steps.add_x.num2": [1, 2],
},
},
}
Empty file.
8 changes: 8 additions & 0 deletions test_fixtures/sweeps/cv_example_test/sweep-config.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
sweeper: "default",
n_proc: 1,
hyperparameters: {
batch_size: [16, 32, 64],
lr: [0.01, 0.001],
},
}
10 changes: 10 additions & 0 deletions test_fixtures/sweeps/cv_example_test/sweep-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
sweeper: "default"
n_proc: 1
hyperparameters:
batc_size:
- 16
- 32
- 64
lr:
- 0.001
- 0.0001