{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "u4fiLarveGYu" }, "source": [ "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/google/vizier/blob/main/docs/guides/developer/designers.ipynb)\n", "\n", "\n", "# Designers\n", "This documentation will allow a developer to use the Designer API for typical algorithm design." ] }, { "cell_type": "markdown", "metadata": { "id": "QhwKY4FDB2El" }, "source": [ "## Installation and reference imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "b_QlZv03vj1u" }, "outputs": [], "source": [ "!pip install google-vizier[jax,algorithms]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "1f_E4bKleQfG" }, "outputs": [], "source": [ "from typing import Optional, Sequence\n", "import numpy as np\n", "\n", "from vizier import algorithms as vza\n", "from vizier import pythia\n", "from vizier import pyvizier as vz\n", "from vizier.algorithms import designers" ] }, { "cell_type": "markdown", "metadata": { "id": "aVv_fmTug1cn" }, "source": [ "## Designers\n", "The `Designer` API is an intuitive abstraction for writing and _designing_ algorithms. It only requires two basic methods, `update()` and `suggest()`, shown below.\n", "\n", "The source of truth for `Designer` can be found\n", "[here](https://github.com/google/vizier/blob/main/vizier/algorithms/__init__.py).\n", "\n", "```python\n", "class Designer(...):\n", " \"\"\"Suggestion algorithm for sequential usage.\"\"\"\n", "\n", " @abc.abstractmethod\n", " def update(self, completed: CompletedTrials, all_active: ActiveTrials) -\u003e None:\n", " \"\"\"Updates recently completed and ALL active trials into the designer's state.\"\"\"\n", "\n", " @abc.abstractmethod\n", " def suggest(self, count: Optional[int] = None) -\u003e Sequence[vz.TrialSuggestion]:\n", " \"\"\"Make new suggestions.\"\"\"\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "h43_ByEjgbb6" }, "source": [ "Every time `update()` is called, the `Designer` will get any newly `COMPLETED` trials since the last `update()` call, and will get all `ACTIVE` trials at the current moment in time.\n", "\n", "**Note:** Trials which may have been provided as `ACTIVE` in previous `update()` calls, can be provided as `COMPLETED` in subsequent `update()` calls." ] }, { "cell_type": "markdown", "metadata": { "id": "--eOH8TQDQnW" }, "source": [ "## GP-Bandit Designer Example\n", "The following example, using the default GP-Bandit algorithm, shows how to interact with Vizier designers." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "z1W_5eptI6IG" }, "outputs": [], "source": [ "# The problem statement (which parameters are being optimized)\n", "problem = vz.ProblemStatement()\n", "problem.search_space.root.add_float_param('x', 0.0, 1.0)\n", "problem.search_space.root.add_float_param('y', 0.0, 1.0)\n", "problem.metric_information.append(\n", " vz.MetricInformation(\n", " name='maximize_metric', goal=vz.ObjectiveMetricGoal.MAXIMIZE))\n", "\n", "# Create a new designer object\n", "designer = designers.VizierGPBandit(problem)\n", "# Ask the designer for 2 suggestions\n", "suggestions = designer.suggest(count=2)" ] }, { "cell_type": "markdown", "metadata": { "id": "Kfis8cWrJBK9" }, "source": [ "In this case, since the designer was not update with any `COMPLETED` or `ACTIVE` trials, it will produce suggestions which will look like:\n", "\n", "```python\n", "[TrialSuggestion(parameters=ParameterDict(_items={'x': 0.5, 'y': 0.5}), metadata=Metadata((namespace:, items: {'seeded': 'center'}), current_namespace=)),\n", " TrialSuggestion(parameters=ParameterDict(_items={'x': 0.10274669379450661, 'y': 0.10191725529767912}), metadata=Metadata((namespace:, items: {}), current_namespace=))]\n", " ```" ] }, { "cell_type": "markdown", "metadata": { "id": "YIK6bzIRJIwK" }, "source": [ "Note that the first suggestion is seeded at the center of the search space, and the second suggestion is random. If we call `designer.suggest()` again before calling `update()`, the designer will produce an identical first suggestion at the center of the search space, and a second random suggestion.\n", "\n", "Only when we call `update()`, will the designer update its internal state and generate different suggestions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PtwK0v9yJK9r" }, "outputs": [], "source": [ "completed_trials = []\n", "for suggestion in suggestions:\n", " metric_value = np.random.random() # Make up a fake metric value.\n", " suggestion.to_trial().complete(\n", " vz.Measurement(metrics={'maximize_metric': metric_value})\n", " )\n", "\n", "# Update the designer with the completed trials.\n", "designer.update(vza.CompletedTrials(completed_trials), vza.ActiveTrials())\n", "\n", "# Ask for more suggestions.\n", "new_suggestions = designer.suggest(count=2)" ] }, { "cell_type": "markdown", "metadata": { "id": "R93E7Fg9Jo6J" }, "source": [ "Thus `COMPLETED` trials should be incrementally updated, while all `ACTIVE` trials are passed to the designer in every `update()` call." ] }, { "cell_type": "markdown", "metadata": { "id": "5lE75RqHJwt4" }, "source": [ "A `Designer` can also be seeded with pre-existing data. Consider the following example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WR3t9bLNJ0oT" }, "outputs": [], "source": [ "# Make a fresh designer.\n", "designer = designers.VizierGPBandit(problem)\n", "\n", "# Create completed trials representing pre-existing training data.\n", "trials = [vz.Trial(parameters={'x': 0.5, 'y': 0.6}).complete(vz.Measurement(metrics={'maximize_metric': 0.3}))]\n", "designer.update(vza.CompletedTrials(trials), vza.ActiveTrials())\n", "\n", "# As the designer for suggestions.\n", "suggestions = designer.suggest(count=2)" ] }, { "cell_type": "markdown", "metadata": { "id": "si1a6RohKCuU" }, "source": [ "In this case, the designer will **not** return a first trial seeded at the center of the search space, since it has been updated with completed trials. The new suggestions will look something like:\n", "\n", "```python\n", "[TrialSuggestion(parameters=ParameterDict(_items={'x': 0.7199945005054509, 'y': 0.3800034493548722}), ...]\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "ZyyV8CfmHxUT" }, "source": [ "## Additional References\n", "* Our [designers folder](https://github.com/google/vizier/tree/main/vizier/_src/algorithms/designers) contains examples of designers.\n", "* Our [evolution folder](https://github.com/google/vizier/blob/main/vizier/_src/algorithms/evolution) contains examples of creating evolutionary designers, such as [NSGA2](https://ieeexplore.ieee.org/document/996017/).\n", "* Our [designer testing routine](https://github.com/google/vizier/blob/main/vizier/_src/algorithms/testing/test_runners.py) contains up-to-date examples on interacting with designers." ] } ], "metadata": { "colab": { "last_runtime": { "build_target": "", "kind": "local" }, "name": "Designers: Writing Algorithms.ipynb", "private_outputs": true, "provenance": [] }, "gpuClass": "standard", "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 0 }