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

docs/major update to docs, sphinx, and docs ci script #36

Merged
merged 30 commits into from
Nov 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b8dd5d1
Merge pull request #16 from madeline-scyphers/develop
madeline-scyphers Oct 3, 2022
9bd3e5c
Update install instructions to include pip from repo
madeline-scyphers Oct 13, 2022
76ae093
Fix formatting for install instructions and a couple small changes
jemissik Oct 13, 2022
a741ab9
Add instructions for x86 macs
madeline-scyphers Oct 17, 2022
fa7b225
Move env x86 yaml file to use torch nightly
madeline-scyphers Oct 17, 2022
5eacab4
Update docs/user_guide/getting_started.rst
jemissik Oct 19, 2022
9285ece
Merge pull request #32 from madeline-scyphers/docs/add-info-on-how-to…
jemissik Oct 19, 2022
98b1e90
Update ModularMetric to directly save metric_to_eval instead of using…
madeline-scyphers Oct 24, 2022
37f5016
Last commit missed a couple files, here they are
madeline-scyphers Oct 24, 2022
e8eb401
Readding example jupyter notebook
madeline-scyphers Oct 24, 2022
d17bcdb
reverting metric file changes for git history reasons
madeline-scyphers Oct 24, 2022
f8d2d0a
Splitting metrics.py to only the ready to go Metrics
madeline-scyphers Oct 24, 2022
2d1aa87
Splitting metrics.py to modular_metric.py
madeline-scyphers Oct 24, 2022
f87c244
Splitted metrics.py into metrics.py and modular_metrics.py
madeline-scyphers Oct 24, 2022
0cd4972
rearrange rst files and doc formatting
madeline-scyphers Oct 24, 2022
11ee4f3
Modify api template and add more module docstrings
madeline-scyphers Oct 26, 2022
8cdcef8
More docstring updates, fix broken rst links
madeline-scyphers Oct 26, 2022
ff5ebec
Doc string updates and refernce fixes
madeline-scyphers Oct 26, 2022
5f358a8
Merge main into ci/add-sphinx-ci-script
madeline-scyphers Oct 26, 2022
d74f7bd
Add examples, boa cli info, config info
madeline-scyphers Oct 27, 2022
622b6d3
Change to importing module boa for example code
madeline-scyphers Oct 27, 2022
2a4ef48
Add docstrings for Controller class
madeline-scyphers Oct 27, 2022
2e8d72b
Docstring typing streamlining
madeline-scyphers Oct 27, 2022
93444ad
Add example notebooks and add docs build to CI
madeline-scyphers Oct 29, 2022
5b7989b
Until we move to Jupytext, remove force notebook builds for docs
madeline-scyphers Oct 29, 2022
9bc1729
Doc updates:
jemissik Nov 5, 2022
38521fa
fix linting
jemissik Nov 5, 2022
3fe3d6b
fix setup.py for x86 mac pytorch
jemissik Nov 5, 2022
06ea29c
Update some docs in response to PR, fix macos build
madeline-scyphers Nov 5, 2022
5eec540
update x86 install insts for people to isntall BOA
madeline-scyphers Nov 5, 2022
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
9 changes: 5 additions & 4 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ jobs:
- name: Lint
shell: bash -l {0}
run: |
invoke lint
invoke black --checkonly
invoke isort --checkonly
invoke style --checkonly

- name: Run tests
shell: bash -l {0}
run: pytest -s
run: invoke tests --options '-s -v'

- name: Test docs build with no errors
shell: bash -l {0}
run: invoke docs -w
mac:

strategy:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ docs/_build
docs/api
docs/_autosummary
docs/jupyter_execute
docs/code_reference/api
*.log

# autogenerated version file from setuptools-scm
_version.py
Expand Down
8 changes: 6 additions & 2 deletions boa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
__version__ = "0.0.0"

from boa.ax_instantiation_utils import * # noqa
from boa.controller import * # noqa
from boa.instantiation_base import * # noqa
from boa.metrics.metric_funcs import * # noqa
from boa.metrics.metrics import * # noqa
from boa.metrics.modular_metric import * # noqa
from boa.metrics.synthetic_funcs import * # noqa
from boa.runner import * # noqa
from boa.storage import * # noqa
from boa.wrapper import * # noqa
from boa.wrapper_utils import * # noqa
from boa.wrappers.wrapper import * # noqa
from boa.wrappers.wrapper_utils import * # noqa
8 changes: 5 additions & 3 deletions boa/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import click

from boa.controller import Controller
from boa.wrapper_utils import cd_and_cd_back, load_jsonlike
from boa.wrappers.wrapper_utils import cd_and_cd_back, load_jsonlike


@click.command()
Expand Down Expand Up @@ -84,10 +84,12 @@ def _main(config_path, rel_to_here, experiment_dir=None):
# since we just loaded the module where the wrapper class is, we can now load it
WrapperCls = getattr(user_wrapper, wrapper_name)
else:
from boa.wrapper import BaseWrapper as WrapperCls
from boa.wrappers.wrapper import BaseWrapper as WrapperCls

controller = Controller(config_path=config_path, wrapper=WrapperCls)
scheduler = controller.run(append_timestamp=append_timestamp, experiment_dir=experiment_dir)

controller.setup(append_timestamp=append_timestamp, experiment_dir=experiment_dir)
scheduler = controller.run()
return scheduler


Expand Down
28 changes: 28 additions & 0 deletions boa/_doc_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import importlib
import pkgutil

import boa


def get_boa_submodules():
module_list = []
packages = []
for module_finder, modname, is_pkg in pkgutil.walk_packages(boa.__path__):
if is_pkg:
packages.append(modname)
if len(modname.split(".")) > 1:
module_list.append(modname)
return module_list


def import_boa_submod(submod_str):
return importlib.import_module(f"boa.{submod_str}")


def add_ref_to_all_submodules_inits():
module_list = get_boa_submodules()
for mod_str in module_list:
submod = import_boa_submod(mod_str)
info = f"""**Overview Information Here**: :mod:`{submod.__package__}`"""

submod.__doc__ = f"{submod.__doc__}\n\n{info}" if submod.__doc__ else info
11 changes: 10 additions & 1 deletion boa/ax_instantiation_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""
###################################
Ax Instantiation Utility Functions
###################################

Utility functions to instantiate Ax objects

"""

from __future__ import annotations

import copy
Expand Down Expand Up @@ -55,7 +64,7 @@ def get_scheduler(
generation_strategy: GenerationStrategy = None,
scheduler_options: SchedulerOptions = None,
config: dict = None,
):
) -> Scheduler:
scheduler_options = scheduler_options or SchedulerOptions(**config["optimization_options"]["scheduler"])
if generation_strategy is None:
if (
Expand Down
104 changes: 94 additions & 10 deletions boa/controller.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,95 @@
"""
###################################
Controller
###################################

The Controller class controls the optimization.

"""
from __future__ import annotations

import logging
import os
import time
from pathlib import Path
from typing import Type

from ax.service.scheduler import Scheduler

from boa.ax_instantiation_utils import get_experiment, get_scheduler
from boa.runner import WrappedJobRunner
from boa.storage import scheduler_to_json_file
from boa.utils import get_dictionary_from_callable
from boa.wrapper_utils import get_dt_now_as_str
from boa.wrappers.wrapper import BaseWrapper
from boa.wrappers.wrapper_utils import get_dt_now_as_str


class Controller:
def __init__(self, config_path, wrapper):
"""
Controls the instantiation of your :mod:`.wrapper` and the
necessary Ax objects to start your Experiment and control
the Ax scheduler. Once the Controller sets up your Experiment, it starts
the scheduler, which runs your trials. It then
saves the scheduler to a json file.

Parameters
----------
config_path
Path to configuration yaml or json file
wrapper
Your Wrapper subclass of BaseWrapper to be instantiated

See Also
--------
:ref:`Creating a configuration File`

"""

def __init__(self, config_path: os.PathLike | str, wrapper: Type[BaseWrapper]):
self.config_path = config_path
self.wrapper = wrapper

self.config = None

def run(self, append_timestamp, experiment_dir, **kwargs):
start = time.time()
self.scheduler = None

def setup(
self, append_timestamp: bool = None, experiment_dir: os.PathLike = None, **kwargs
) -> tuple[Scheduler, BaseWrapper]:
"""
Sets up all the classes and objects needed to create the Ax Scheduler

Parameters
----------
append_timestamp
Whether to append the output experiment directory with a timestamp or not
(default True)
experiment_dir
Output experiment directory to which the experiment and trials will be saved
(defaults to experiment_dir specified in the config script options
or working_dir/experiment_name [if working_dir specified in config]
or current_dir/experiment_name [if working_dir and experiment_dir and
not specified])

Returns
-------
returns a tuple with the first element being the scheduler
and the second element being your wrapper (both initialized
and ready to go)
"""
kwargs["config_path"] = self.config_path
if experiment_dir:
kwargs["experiment_dir"] = experiment_dir
if append_timestamp is not None:
kwargs["append_timestamp"] = append_timestamp

load_config_kwargs = get_dictionary_from_callable(self.wrapper.load_config, kwargs)
wrapper = self.wrapper(**load_config_kwargs)
config = wrapper.config
load_config_kwargs = get_dictionary_from_callable(self.wrapper.__init__, kwargs)
self.wrapper = self.wrapper(**load_config_kwargs)
config = self.wrapper.config

log_format = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(
filename=Path(wrapper.experiment_dir) / "optimization.log",
filename=Path(self.wrapper.experiment_dir) / "optimization.log",
filemode="w",
format=log_format,
level=logging.DEBUG,
Expand All @@ -40,8 +98,34 @@ def run(self, append_timestamp, experiment_dir, **kwargs):
logger = logging.getLogger(__file__)
logger.info("Start time: %s", get_dt_now_as_str())

experiment = get_experiment(config, WrappedJobRunner(wrapper=wrapper), wrapper)
scheduler = get_scheduler(experiment, config=config)
experiment = get_experiment(config, WrappedJobRunner(wrapper=self.wrapper), self.wrapper)
self.scheduler = get_scheduler(experiment, config=config)
return self.scheduler, self.wrapper

def run(self, scheduler: Scheduler = None, wrapper: BaseWrapper = None) -> Scheduler:
"""
Run trials for scheduler

Parameters
----------
scheduler
initialed scheduler or None, if None, defaults to
``self.scheduler`` (the scheduler set up in :meth:`.Controller.setup`
wrapper
initialed wrapper or None, if None, defaults to
``self.wrapper`` (the wrapper set up in :meth:`.Controller.setup`

Returns
-------
The scheduler after all trials have been run or the
experiment has been stopped for another reason.
"""
start = time.time()

scheduler = scheduler or self.scheduler
wrapper = wrapper or self.wrapper
if not scheduler or not wrapper:
raise ValueError("Scheduler and wrapper must be defined, or setup in setup method!")

try:
scheduler.run_all_trials()
Expand Down
19 changes: 12 additions & 7 deletions boa/metaclasses.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
"""
########################
Meta Classes
########################

Meta class modify class behaviors. For example, the :class:`.WrapperRegister` ensures that all subclasses of
:class:`.BaseWrapper` will wrap functions in :func:`.cd_and_cd_back_dec`
to make sure that if users do any directory changes inside a wrapper function,
the original directory is returned to afterwards.

"""
import logging
import traceback
from abc import ABCMeta
Expand All @@ -7,7 +18,7 @@
from ax.storage.metric_registry import CORE_METRIC_REGISTRY
from ax.storage.runner_registry import CORE_RUNNER_REGISTRY

from boa.wrapper_utils import cd_and_cd_back_dec
from boa.wrappers.wrapper_utils import cd_and_cd_back_dec

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -53,9 +64,3 @@ def __init__(cls, *args, **kwargs):
CORE_DECODER_REGISTRY[cls.__name__] = cls
next_pk = max(CORE_METRIC_REGISTRY.values()) + 1
CORE_METRIC_REGISTRY[cls] = next_pk


class MetricToEvalRegister(type):
def __init__(cls, *args, **kwargs):
CORE_ENCODER_REGISTRY[cls] = cls.to_dict
CORE_DECODER_REGISTRY[cls.__name__] = cls
12 changes: 10 additions & 2 deletions boa/metrics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
"""
.. todo::
################################################
Metrics Overview & Advanced Usage
################################################

Coming soon!

Metrics are the objective functions we are optimizing over
or functions that are added as further constraints of our problem.

Metrics can be specified in your configuration file by passing in the name
of one of the predefined :mod:`Metrics <boa.metrics.metrics>` in BOA.

See :doc:`/user_guide/configuration` for details.
"""
Loading