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

chore: add guides on supporting custom models and objectives. #153

Merged
merged 2 commits into from
Oct 21, 2023
Merged
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ To invoke only with the configurations defined in `config.json`, use `-i` flag
parrotfish <function_name> -i
```

## Using custom models and objectives
To explore the effects of other objectives and models, you need to modify the `src/objective/objective.py` and
`src/objective/parametric_function.py` files.
If you need to change the sampling process, e.g. the initial samples, you need to modify the `src/sampling/sampler.py`
file.

## Acknowledgments

This work was supported by the Natural Sciences and Engineering Research Council of Canada (NSERC), Mitacs, and The University of British Columbia (UBC).
Expand Down
4 changes: 2 additions & 2 deletions src/objective/objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ def __init__(
def termination_value(self) -> float:
"""computes a value that indicates that we are confident"""
knowledge_values = self.get_knowledge(self.memory_space)
y = self.param_function(self.memory_space)
y = self.param_function(self.memory_space) * self.memory_space
return knowledge_values[np.argmin(y)]

def get_values(self, memories: np.ndarray) -> np.ndarray:
"""Computes the objective values of the memories in input."""
real_cost = self.param_function(memories)
real_cost = self.param_function(memories) * memories
knowledge = self.get_knowledge(memories)
return real_cost * knowledge

Expand Down
18 changes: 9 additions & 9 deletions src/objective/parametric_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class ParametricFunction:
bounds (tuple): Lower and upper bounds on parameters.
"""

function: callable
bounds: tuple
function: callable = lambda x, a0, a1, a2: a0 + a1 * np.exp(-x / a2)
bounds: tuple = ([-np.inf, -np.inf, -np.inf], [np.inf, np.inf, np.inf])
params: any = None

def __call__(self, x: int or np.ndarray):
Expand All @@ -41,14 +41,14 @@ def fit(self, sample: Sample) -> None:
self.params = curve_fit(
f=self.function,
xdata=sample.memories,
ydata=sample.costs,
ydata=sample.durations,
maxfev=int(1e8),
p0=self.params,
bounds=self.bounds,
)[0]

def minimize(
self, memory_space: np.ndarray, execution_time_threshold: int = None
self, memory_space: np.ndarray, execution_time_threshold: int = None
) -> int:
"""Minimizes the cost function and returns the corresponding memory configuration.
Expand All @@ -59,7 +59,7 @@ def minimize(
Returns:
int: Memory configuration that minimizes the cost function.
"""
costs = self.__call__(memory_space)
costs = self.__call__(memory_space) * memory_space

# Handling execution threshold constraint
if execution_time_threshold:
Expand All @@ -73,11 +73,11 @@ def minimize(
min_index = np.argmin(costs)
return memory_space[min_index]

@staticmethod
def _filter_execution_time_constraint(
self,
memory_space: np.ndarray,
costs: np.ndarray,
execution_time_threshold: int = None,
memory_space: np.ndarray,
costs: np.ndarray,
execution_time_threshold: int = None,
) -> tuple:
filtered_memories = np.array([])
filtered_costs = np.array([])
Expand Down
5 changes: 1 addition & 4 deletions src/parrotfish.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ def __init__(self, config: any):
credentials=credentials,
)

self.param_function = ParametricFunction(
function=lambda x, a0, a1, a2: a0 * x + a1 * np.exp(-x / a2) * x,
bounds=([0, 0, 0], [np.inf, np.inf, np.inf]),
)
self.param_function = ParametricFunction()

self.objective = Objective(
param_function=self.param_function,
Expand Down
2 changes: 1 addition & 1 deletion src/sampling/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def update_sample(self, memory_mb: int) -> None:
self.sample.update(subsample)

logger.info(
f"Finished sampling {memory_mb} with billed duration results: {subsample_durations} is ms."
f"Finished sampling {memory_mb} with billed duration results: {subsample_durations} in ms."
)

def _explore_dynamically(self, durations: list) -> list:
Expand Down
5 changes: 1 addition & 4 deletions tests/recommendation/test_parametric_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

@pytest.fixture
def param_function():
bounds = ([0, 0, 0], [np.inf, np.inf, np.inf])
return ParametricFunction(
function=lambda x, a, b, c: a * x + b * np.exp(-x / c) * x, bounds=bounds
)
return ParametricFunction()


class TestFittingFunction:
Expand Down