From 17a302058213f5925d4d2b083b9be6e9558a07df Mon Sep 17 00:00:00 2001 From: wenatuhs Date: Thu, 2 Jun 2022 22:41:00 +0000 Subject: [PATCH] Deploy website - based on 91f70bc84f637918f5269831b0490efd48d8a763 --- 404.html | 4 ++-- assets/js/54f44165.ab3747ea.js | 1 + assets/js/54f44165.bd72746d.js | 1 - assets/js/{c7e3ca8c.ce64d18e.js => c7e3ca8c.49355c15.js} | 2 +- .../{runtime~main.506f93c9.js => runtime~main.37ccbe77.js} | 2 +- blog.html | 4 ++-- blog/archive.html | 4 ++-- blog/tags.html | 4 ++-- blog/tags/badger.html | 4 ++-- blog/tags/hello.html | 4 ++-- blog/tags/slac.html | 4 ++-- blog/welcome.html | 4 ++-- docs/getting-started/installation.html | 6 +++--- docs/getting-started/tutorial.html | 4 ++-- docs/guides/api-usage.html | 4 ++-- docs/guides/cli-usage.html | 4 ++-- docs/guides/create-a-plugin.html | 6 +++--- docs/guides/gui-usage.html | 4 ++-- docs/guides/implement-an-extension.html | 4 ++-- docs/intro.html | 4 ++-- index.html | 4 ++-- 21 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 assets/js/54f44165.ab3747ea.js delete mode 100644 assets/js/54f44165.bd72746d.js rename assets/js/{c7e3ca8c.ce64d18e.js => c7e3ca8c.49355c15.js} (83%) rename assets/js/{runtime~main.506f93c9.js => runtime~main.37ccbe77.js} (97%) diff --git a/404.html b/404.html index 8febb78..77b1234 100644 --- a/404.html +++ b/404.html @@ -6,13 +6,13 @@ Page Not Found | Badger - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/54f44165.ab3747ea.js b/assets/js/54f44165.ab3747ea.js new file mode 100644 index 0000000..dc6586d --- /dev/null +++ b/assets/js/54f44165.ab3747ea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbadger_home=self.webpackChunkbadger_home||[]).push([[152],{681:function(e,t,a){a.r(t),a.d(t,{frontMatter:function(){return r},contentTitle:function(){return s},metadata:function(){return d},toc:function(){return p},default:function(){return c}});var n=a(7462),i=a(3366),l=(a(7294),a(3905)),o=["components"],r={sidebar_position:1},s="Installation",d={unversionedId:"getting-started/installation",id:"getting-started/installation",isDocsHomePage:!1,title:"Installation",description:"Badger is essentially a python package. It's recommended to install and test it in a separate python virtual environment before using it in a production env.",source:"@site/docs/getting-started/installation.md",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/Badger/docs/getting-started/installation",editUrl:"https://github.com/SLAC-ML/Badger-Home/edit/master/docs/getting-started/installation.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Introduction",permalink:"/Badger/docs/intro"},next:{title:"Tutorial",permalink:"/Badger/docs/getting-started/tutorial"}},p=[{value:"Requirements",id:"requirements",children:[],level:2},{value:"Install core package",id:"install-core-package",children:[],level:2},{value:"Install sample plugins",id:"install-sample-plugins",children:[],level:2},{value:"Set up Badger",id:"set-up-badger",children:[],level:2}],g={toc:p};function c(e){var t=e.components,a=(0,i.Z)(e,o);return(0,l.kt)("wrapper",(0,n.Z)({},g,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"installation"},"Installation"),(0,l.kt)("p",null,"Badger is essentially a python package. It's recommended to install and test it in a separate ",(0,l.kt)("a",{parentName:"p",href:"https://docs.python.org/3/library/venv.html"},"python virtual environment")," before using it in a production env."),(0,l.kt)("h2",{id:"requirements"},"Requirements"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Python version >= 3.6. Python 3.7+ is recommended")),(0,l.kt)("h2",{id:"install-core-package"},"Install core package"),(0,l.kt)("p",null,"Badger has a core package (",(0,l.kt)("inlineCode",{parentName:"p"},"badger-opt"),") that can be extended by a set of plugins. Badger core package is available on both ",(0,l.kt)("a",{parentName:"p",href:"https://pypi.org/project/badger-opt/"},"pip")," and ",(0,l.kt)("a",{parentName:"p",href:"https://anaconda.org/conda-forge/badger-opt"},"conda"),". So you could install Badger with:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"pip install badger-opt\n")),(0,l.kt)("p",null,"Or"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"conda install -c conda-forge badger-opt\n")),(0,l.kt)("div",{className:"admonition admonition-caution alert alert--warning"},(0,l.kt)("div",{parentName:"div",className:"admonition-heading"},(0,l.kt)("h5",{parentName:"div"},(0,l.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,l.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"},(0,l.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))),"caution")),(0,l.kt)("div",{parentName:"div",className:"admonition-content"},(0,l.kt)("p",{parentName:"div"},"If you go with the conda option and you are using macOS, the Badger GUI would need a specific version of Qt to work properly. Please run the following command in the conda env in which you installed ",(0,l.kt)("inlineCode",{parentName:"p"},"badger-opt"),":"),(0,l.kt)("pre",{parentName:"div"},(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"conda install qt=5.12.5\n")),(0,l.kt)("p",{parentName:"div"},"The potential GUI-not-launching issue should be gone now."))),(0,l.kt)("h2",{id:"install-sample-plugins"},"Install sample plugins"),(0,l.kt)("p",null,"Clone the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/SLAC-ML/Badger-Plugins"},"badger plugins repo")," to some directory on your computer:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"git clone https://github.com/SLAC-ML/Badger-Plugins.git\n")),(0,l.kt)("h2",{id:"set-up-badger"},"Set up Badger"),(0,l.kt)("p",null,"Once ",(0,l.kt)("inlineCode",{parentName:"p"},"badger-opt")," is installed and you have the badger plugins ready, run the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"badger\n")),(0,l.kt)("p",null,"Follow the instructions and configure several paths that are needed by Badger."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/54f44165.bd72746d.js b/assets/js/54f44165.bd72746d.js deleted file mode 100644 index fd5a595..0000000 --- a/assets/js/54f44165.bd72746d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbadger_home=self.webpackChunkbadger_home||[]).push([[152],{681:function(e,t,a){a.r(t),a.d(t,{frontMatter:function(){return o},contentTitle:function(){return s},metadata:function(){return d},toc:function(){return p},default:function(){return u}});var n=a(7462),r=a(3366),l=(a(7294),a(3905)),i=["components"],o={sidebar_position:1},s="Installation",d={unversionedId:"getting-started/installation",id:"getting-started/installation",isDocsHomePage:!1,title:"Installation",description:"Badger is essentially a python package. It's recommended to install and test it in a separate python virtual environment before using it in a production env.",source:"@site/docs/getting-started/installation.md",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/Badger/docs/getting-started/installation",editUrl:"https://github.com/SLAC-ML/Badger-Home/edit/master/docs/getting-started/installation.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Introduction",permalink:"/Badger/docs/intro"},next:{title:"Tutorial",permalink:"/Badger/docs/getting-started/tutorial"}},p=[{value:"Requirements",id:"requirements",children:[],level:2},{value:"Install core package",id:"install-core-package",children:[],level:2},{value:"Install sample plugins",id:"install-sample-plugins",children:[],level:2},{value:"Set up Badger",id:"set-up-badger",children:[],level:2}],g={toc:p};function u(e){var t=e.components,a=(0,r.Z)(e,i);return(0,l.kt)("wrapper",(0,n.Z)({},g,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"installation"},"Installation"),(0,l.kt)("p",null,"Badger is essentially a python package. It's recommended to install and test it in a separate ",(0,l.kt)("a",{parentName:"p",href:"https://docs.python.org/3/library/venv.html"},"python virtual environment")," before using it in a production env."),(0,l.kt)("h2",{id:"requirements"},"Requirements"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Python version >= 3.6. Python 3.7 is recommended")),(0,l.kt)("h2",{id:"install-core-package"},"Install core package"),(0,l.kt)("p",null,"Badger has a core package (",(0,l.kt)("inlineCode",{parentName:"p"},"badger-opt"),") that can be extended by a set of plugins. Badger core package is available on both ",(0,l.kt)("a",{parentName:"p",href:"https://pypi.org/project/badger-opt/"},"pip")," and ",(0,l.kt)("a",{parentName:"p",href:"https://anaconda.org/conda-forge/badger-opt"},"conda"),". So you could install Badger with:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"pip install badger-opt\n")),(0,l.kt)("p",null,"Or"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"conda install -c conda-forge badger-opt\n")),(0,l.kt)("h2",{id:"install-sample-plugins"},"Install sample plugins"),(0,l.kt)("p",null,"Clone the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/SLAC-ML/Badger-Plugins"},"badger plugins repo")," to some directory on your computer:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"git clone https://github.com/SLAC-ML/Badger-Plugins.git\n")),(0,l.kt)("h2",{id:"set-up-badger"},"Set up Badger"),(0,l.kt)("p",null,"Once ",(0,l.kt)("inlineCode",{parentName:"p"},"badger-opt")," is installed and you have the badger plugins ready, run the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"badger\n")),(0,l.kt)("p",null,"Follow the instructions and configure several paths that are needed by Badger."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c7e3ca8c.ce64d18e.js b/assets/js/c7e3ca8c.49355c15.js similarity index 83% rename from assets/js/c7e3ca8c.ce64d18e.js rename to assets/js/c7e3ca8c.49355c15.js index 32d901b..d8e0ee2 100644 --- a/assets/js/c7e3ca8c.ce64d18e.js +++ b/assets/js/c7e3ca8c.49355c15.js @@ -1 +1 @@ -"use strict";(self.webpackChunkbadger_home=self.webpackChunkbadger_home||[]).push([[978],{1874:function(e,n,t){t.r(n),t.d(n,{frontMatter:function(){return o},contentTitle:function(){return s},metadata:function(){return p},toc:function(){return m},default:function(){return u}});var a=t(7462),i=t(3366),r=(t(7294),t(3905)),l=["components"],o={sidebar_position:4},s="Create a plugin",p={unversionedId:"guides/create-a-plugin",id:"guides/create-a-plugin",isDocsHomePage:!1,title:"Create a plugin",description:"Plugins have three types:",source:"@site/docs/guides/create-a-plugin.md",sourceDirName:"guides",slug:"/guides/create-a-plugin",permalink:"/Badger/docs/guides/create-a-plugin",editUrl:"https://github.com/SLAC-ML/Badger-Home/edit/master/docs/guides/create-a-plugin.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"GUI Usage",permalink:"/Badger/docs/guides/gui-usage"},next:{title:"Implement an extension",permalink:"/Badger/docs/guides/implement-an-extension"}},m=[{value:"Create an algorithm plugin",id:"create-an-algorithm-plugin",children:[],level:2},{value:"Create an interface plugin",id:"create-an-interface-plugin",children:[],level:2},{value:"Create an environment plugin",id:"create-an-environment-plugin",children:[{value:"The basics",id:"the-basics",children:[],level:3},{value:"Advanced topics",id:"advanced-topics",children:[{value:"Specify variable range",id:"specify-variable-range",children:[],level:4},{value:"Incorperate hyper-parameters",id:"incorperate-hyper-parameters",children:[],level:4},{value:"Check variable readout",id:"check-variable-readout",children:[],level:4},{value:"Delayed observation",id:"delayed-observation",children:[],level:4}],level:3}],level:2}],d={toc:m};function u(e){var n=e.components,t=(0,i.Z)(e,l);return(0,r.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"create-a-plugin"},"Create a plugin"),(0,r.kt)("p",null,"Plugins have three types:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Algorithm: function"),(0,r.kt)("li",{parentName:"ul"},"Interface: class"),(0,r.kt)("li",{parentName:"ul"},"Environment: class")),(0,r.kt)("h2",{id:"create-an-algorithm-plugin"},"Create an algorithm plugin"),(0,r.kt)("h2",{id:"create-an-interface-plugin"},"Create an interface plugin"),(0,r.kt)("h2",{id:"create-an-environment-plugin"},"Create an environment plugin"),(0,r.kt)("p",null,'To let Badger deal with your own optimization problem, you\'ll need to turn the problem into a custom environment plugin first. An environment in Badger defines how Badger could interact with the "control system" upon which the optimization problem forms up. To be more specific, Badger wants to know:'),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"What variables can be tuned"),(0,r.kt)("li",{parentName:"ul"},"What are the ranges for the tunable variables"),(0,r.kt)("li",{parentName:"ul"},"What observations are available (objectives, constraints, anything you would like to monitor in the optimization)")),(0,r.kt)("p",null,"Plus (actually more importantly):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"How to tune one variable"),(0,r.kt)("li",{parentName:"ul"},"How to get one observation")),(0,r.kt)("p",null,"And you incorporate those knowledge into Badger by inheriting the ",(0,r.kt)("inlineCode",{parentName:"p"},"Environment")," base class provided by the Badger core, and implementing the corresponding methods."),(0,r.kt)("p",null,"Let's get a better idea about it by creating a simple custom environment plugin for Badger from the ground up."),(0,r.kt)("h3",{id:"the-basics"},"The basics"),(0,r.kt)("p",null,"First off, let's create a file structure like the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-shell",metastring:'title="Simplest environment plugin file structure"',title:'"Simplest',environment:!0,plugin:!0,file:!0,'structure"':!0},"|--myenv\n |--__init__.py\n |--configs.yaml\n")),(0,r.kt)("p",null,"Here we'll name our simple custom env as ",(0,r.kt)("inlineCode",{parentName:"p"},"myenv"),", as the folder name shows."),(0,r.kt)("p",null,"Then put the boilerplate code below into ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__.py"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/__init__.py"',title:'"myenv/__init__.py"'},"from badger import environment\nfrom badger.interface import Interface\n\n\nclass Environment(environment.Environment):\n\n name = 'myenv'\n\n def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n # Add other logic, try to not do time-consuming stuff here\n\n @staticmethod\n def list_vars():\n return []\n\n @staticmethod\n def list_obses():\n return []\n\n def _get_var(self, var):\n return 0\n\n def _set_var(self, var, x):\n pass\n\n def _get_obs(self, obs):\n return 0\n")),(0,r.kt)("p",null,"Several things to note regarding the boilerplate code:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"It should have a class variable called ",(0,r.kt)("inlineCode",{parentName:"li"},"name"),", and it should match the folder name of the plugin"),(0,r.kt)("li",{parentName:"ul"},"There are 5 methods that are required to be implemented to create a proper Badger env:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"list_vars"),": Get a list of all the supported variables"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"list_obses"),": Get a list of all the supported observations"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_get_var"),": Get the value of a specific variable"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_set_var"),": Set a specific variable to some value"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_get_obs"),": Get the value of a specific observation")))),(0,r.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,r.kt)("div",{parentName:"div",className:"admonition-heading"},(0,r.kt)("h5",{parentName:"div"},(0,r.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,r.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,r.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,r.kt)("div",{parentName:"div",className:"admonition-content"},(0,r.kt)("p",{parentName:"div"},"As the comment says, try to avoid doing time-consuming thing in ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__")," method. Badger would create an instance of the environment when users try to get the details of the plugin (say, when ",(0,r.kt)("inlineCode",{parentName:"p"},"badger env myenv")," is called in CLI mode), so just put some light-computing code there in the constructor would provide the users a smoother experience."))),(0,r.kt)("p",null,"Okay, now we can start to implement the methods. Assume that our sample environment has 3 variables: ",(0,r.kt)("inlineCode",{parentName:"p"},"x"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"y"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"z"),", it also has 2 observations: ",(0,r.kt)("inlineCode",{parentName:"p"},"norm"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"mean"),". Then the ",(0,r.kt)("inlineCode",{parentName:"p"},"list_vars")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"list_obses")," methods should look like:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," @staticmethod\n def list_vars():\n return ['x', 'y', 'z']\n\n @staticmethod\n def list_obses():\n return ['norm', 'mean']\n")),(0,r.kt)("p",null,"Our custom env is so simple that we don't really need an interface here. Let's implement the getter and setter for the variables:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n self.variables = {\n 'x': 0,\n 'y': 0,\n 'z': 0,\n }\n\n def _get_var(self, var):\n return self.variables[var]\n\n def _set_var(self, var, x):\n self.variables[var] = x\n")),(0,r.kt)("p",null,"Here we use a dictionary called ",(0,r.kt)("inlineCode",{parentName:"p"},"variables")," to hold the values for the variables."),(0,r.kt)("p",null,"Now let's add observation related logic:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," def _get_obs(self, obs):\n x = self.variables['x']\n y = self.variables['y']\n z = self.variables['z']\n\n if obs == 'norm':\n return (x ** 2 + y ** 2 + z ** 2) ** 0.5\n elif obs == 'mean':\n return (x + y + z) / 3\n")),(0,r.kt)("p",null,"At this point, the content of ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__.py")," should be:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/__init__.py"',title:'"myenv/__init__.py"'},"from badger import environment\nfrom badger.interface import Interface\n\n\nclass Environment(environment.Environment):\n\n name = 'myenv'\n\n def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n self.variables = {\n 'x': 0,\n 'y': 0,\n 'z': 0,\n }\n\n @staticmethod\n def list_vars():\n return ['x', 'y', 'z']\n\n @staticmethod\n def list_obses():\n return ['norm', 'mean']\n\n def _get_var(self, var):\n return self.variables[var]\n\n def _set_var(self, var, x):\n self.variables[var] = x\n\n def _get_obs(self, obs):\n x = self.variables['x']\n y = self.variables['y']\n z = self.variables['z']\n\n if obs == 'norm':\n return (x ** 2 + y ** 2 + z ** 2) ** 0.5\n elif obs == 'mean':\n return (x + y + z) / 3\n")),(0,r.kt)("p",null,"Alright! Our little env is almost done -- even though it doesn\u2019t do much, it already has everything that we need for a Badger environment! To make the plugin complete, we should also incorporate some meta data (such as version number) of our env into ",(0,r.kt)("inlineCode",{parentName:"p"},"configs.yaml"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/configs.yaml"',title:'"myenv/configs.yaml"'},'---\nname: myenv\nversion: "0.1"\ndependencies:\n - badger-opt\n')),(0,r.kt)("p",null,"Congrats! Our custom env plugin is ready to go! Let's put the whole folder under ",(0,r.kt)("inlineCode",{parentName:"p"},"BADGER_PLUGIN_ROOT/environments"),", then executing the following command in a terminal (in which the Badger package is available, of course):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-shell"},"badger env myenv\n")),(0,r.kt)("p",null,"The printouts should look like below. Yay!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-yaml"},"name: myenv\nversion: '0.1'\ndependencies:\n - badger-opt\nparams: null\nvariables:\n - x: 0 -> 1\n - y: 0 -> 1\n - z: 0 -> 1\nobservations:\n - norm\n - mean\n")),(0,r.kt)("p",null,"Now you can take ",(0,r.kt)("inlineCode",{parentName:"p"},"myenv")," for a spin -- just write some routine configs and run some algorithm (say, ",(0,r.kt)("inlineCode",{parentName:"p"},"silly")," the random sampler) on our newly created env, to see if everything works as expected."),(0,r.kt)("h3",{id:"advanced-topics"},"Advanced topics"),(0,r.kt)("h4",{id:"specify-variable-range"},"Specify variable range"),(0,r.kt)("h4",{id:"incorperate-hyper-parameters"},"Incorperate hyper-parameters"),(0,r.kt)("h4",{id:"check-variable-readout"},"Check variable readout"),(0,r.kt)("h4",{id:"delayed-observation"},"Delayed observation"))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkbadger_home=self.webpackChunkbadger_home||[]).push([[978],{1874:function(e,n,t){t.r(n),t.d(n,{frontMatter:function(){return o},contentTitle:function(){return s},metadata:function(){return p},toc:function(){return m},default:function(){return u}});var a=t(7462),i=t(3366),r=(t(7294),t(3905)),l=["components"],o={sidebar_position:4},s="Create a plugin",p={unversionedId:"guides/create-a-plugin",id:"guides/create-a-plugin",isDocsHomePage:!1,title:"Create a plugin",description:"Plugins have three types:",source:"@site/docs/guides/create-a-plugin.md",sourceDirName:"guides",slug:"/guides/create-a-plugin",permalink:"/Badger/docs/guides/create-a-plugin",editUrl:"https://github.com/SLAC-ML/Badger-Home/edit/master/docs/guides/create-a-plugin.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"GUI Usage",permalink:"/Badger/docs/guides/gui-usage"},next:{title:"Implement an extension",permalink:"/Badger/docs/guides/implement-an-extension"}},m=[{value:"Create an algorithm plugin",id:"create-an-algorithm-plugin",children:[],level:2},{value:"Create an interface plugin",id:"create-an-interface-plugin",children:[],level:2},{value:"Create an environment plugin",id:"create-an-environment-plugin",children:[{value:"The basics",id:"the-basics",children:[],level:3},{value:"Advanced topics",id:"advanced-topics",children:[{value:"Specify variable range",id:"specify-variable-range",children:[],level:4},{value:"Incorperate hyper-parameters",id:"incorperate-hyper-parameters",children:[],level:4},{value:"Check variable readout",id:"check-variable-readout",children:[],level:4},{value:"Delayed observation",id:"delayed-observation",children:[],level:4}],level:3}],level:2}],d={toc:m};function u(e){var n=e.components,t=(0,i.Z)(e,l);return(0,r.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"create-a-plugin"},"Create a plugin"),(0,r.kt)("p",null,"Plugins have three types:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Algorithm: function"),(0,r.kt)("li",{parentName:"ul"},"Interface: class"),(0,r.kt)("li",{parentName:"ul"},"Environment: class")),(0,r.kt)("h2",{id:"create-an-algorithm-plugin"},"Create an algorithm plugin"),(0,r.kt)("h2",{id:"create-an-interface-plugin"},"Create an interface plugin"),(0,r.kt)("h2",{id:"create-an-environment-plugin"},"Create an environment plugin"),(0,r.kt)("p",null,'To let Badger deal with your own optimization problem, you\'ll need to turn the problem into a custom environment plugin first. An environment in Badger defines how Badger could interact with the "control system" upon which the optimization problem forms up. To be more specific, Badger wants to know:'),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"What variables can be tuned"),(0,r.kt)("li",{parentName:"ul"},"What are the ranges for the tunable variables"),(0,r.kt)("li",{parentName:"ul"},"What observations are available (objectives, constraints, anything you would like to monitor in the optimization)")),(0,r.kt)("p",null,"Plus (actually more importantly):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"How to tune one variable"),(0,r.kt)("li",{parentName:"ul"},"How to get one observation")),(0,r.kt)("p",null,"And you incorporate those knowledge into Badger by inheriting the ",(0,r.kt)("inlineCode",{parentName:"p"},"Environment")," base class provided by the Badger core, and implementing the corresponding methods."),(0,r.kt)("p",null,"Let's get a better idea about it by creating a simple custom environment plugin for Badger from the ground up."),(0,r.kt)("h3",{id:"the-basics"},"The basics"),(0,r.kt)("p",null,"First off, let's create a file structure like the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-shell",metastring:'title="Simplest environment plugin file structure"',title:'"Simplest',environment:!0,plugin:!0,file:!0,'structure"':!0},"|--myenv\n |--__init__.py\n |--configs.yaml\n")),(0,r.kt)("p",null,"Here we'll name our simple custom env as ",(0,r.kt)("inlineCode",{parentName:"p"},"myenv"),", as the folder name shows."),(0,r.kt)("p",null,"Then put the boilerplate code below into ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__.py"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/__init__.py"',title:'"myenv/__init__.py"'},"from badger import environment\nfrom badger.interface import Interface\n\n\nclass Environment(environment.Environment):\n\n name = 'myenv'\n\n def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n # Add other logic, try to not do time-consuming stuff here\n\n @staticmethod\n def list_vars():\n return []\n\n @staticmethod\n def list_obses():\n return []\n\n def _get_var(self, var):\n return 0\n\n def _set_var(self, var, x):\n pass\n\n def _get_obs(self, obs):\n return 0\n")),(0,r.kt)("p",null,"Several things to note regarding the boilerplate code:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"It should have a class variable called ",(0,r.kt)("inlineCode",{parentName:"li"},"name"),", and it should match the folder name of the plugin"),(0,r.kt)("li",{parentName:"ul"},"There are 5 methods that are required to be implemented to create a proper Badger env:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"list_vars"),": Get a list of all the supported variables"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"list_obses"),": Get a list of all the supported observations"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_get_var"),": Get the value of a specific variable"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_set_var"),": Set a specific variable to some value"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"_get_obs"),": Get the value of a specific observation")))),(0,r.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,r.kt)("div",{parentName:"div",className:"admonition-heading"},(0,r.kt)("h5",{parentName:"div"},(0,r.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,r.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,r.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,r.kt)("div",{parentName:"div",className:"admonition-content"},(0,r.kt)("p",{parentName:"div"},"As the comment says, try to avoid doing time-consuming thing in ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__")," method. Badger would create an instance of the environment when users try to get the details of the plugin (say, when ",(0,r.kt)("inlineCode",{parentName:"p"},"badger env myenv")," is called in CLI mode), so just put some light-computing code there in the constructor would provide the users a smoother experience."))),(0,r.kt)("p",null,"Okay, now we can start to implement the methods. Assume that our sample environment has 3 variables: ",(0,r.kt)("inlineCode",{parentName:"p"},"x"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"y"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"z"),", it also has 2 observations: ",(0,r.kt)("inlineCode",{parentName:"p"},"norm"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"mean"),". Then the ",(0,r.kt)("inlineCode",{parentName:"p"},"list_vars")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"list_obses")," methods should look like:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," @staticmethod\n def list_vars():\n return ['x', 'y', 'z']\n\n @staticmethod\n def list_obses():\n return ['norm', 'mean']\n")),(0,r.kt)("p",null,"Our custom env is so simple that we don't really need an interface here. Let's implement the getter and setter for the variables:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n self.variables = {\n 'x': 0,\n 'y': 0,\n 'z': 0,\n }\n\n def _get_var(self, var):\n return self.variables[var]\n\n def _set_var(self, var, x):\n self.variables[var] = x\n")),(0,r.kt)("p",null,"Here we use a dictionary called ",(0,r.kt)("inlineCode",{parentName:"p"},"variables")," to hold the values for the variables."),(0,r.kt)("p",null,"Now let's add observation related logic:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"}," def _get_obs(self, obs):\n x = self.variables['x']\n y = self.variables['y']\n z = self.variables['z']\n\n if obs == 'norm':\n return (x ** 2 + y ** 2 + z ** 2) ** 0.5\n elif obs == 'mean':\n return (x + y + z) / 3\n")),(0,r.kt)("p",null,"At this point, the content of ",(0,r.kt)("inlineCode",{parentName:"p"},"__init__.py")," should be:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/__init__.py"',title:'"myenv/__init__.py"'},"from badger import environment\nfrom badger.interface import Interface\n\n\nclass Environment(environment.Environment):\n\n name = 'myenv'\n\n def __init__(self, interface: Interface, params):\n super().__init__(interface, params)\n self.variables = {\n 'x': 0,\n 'y': 0,\n 'z': 0,\n }\n\n @staticmethod\n def list_vars():\n return ['x', 'y', 'z']\n\n @staticmethod\n def list_obses():\n return ['norm', 'mean']\n\n def _get_var(self, var):\n return self.variables[var]\n\n def _set_var(self, var, x):\n self.variables[var] = x\n\n def _get_obs(self, obs):\n x = self.variables['x']\n y = self.variables['y']\n z = self.variables['z']\n\n if obs == 'norm':\n return (x ** 2 + y ** 2 + z ** 2) ** 0.5\n elif obs == 'mean':\n return (x + y + z) / 3\n")),(0,r.kt)("p",null,"Alright! Our little env is almost done -- even though it doesn\u2019t do much, it already has everything that we need for a Badger environment! To make the plugin complete, we should also incorporate some meta data (such as version number) of our env into ",(0,r.kt)("inlineCode",{parentName:"p"},"configs.yaml"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python",metastring:'title="myenv/configs.yaml"',title:'"myenv/configs.yaml"'},'---\nname: myenv\nversion: "0.1"\ndependencies:\n - badger-opt\n')),(0,r.kt)("p",null,"Congrats! Our custom env plugin is ready to go! Let's put the whole folder under ",(0,r.kt)("inlineCode",{parentName:"p"},"BADGER_PLUGIN_ROOT/environments"),", then executing the following command in a terminal (in which the Badger package is available, of course):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-shell"},"badger env myenv\n")),(0,r.kt)("p",null,"The printouts should look like below. Yay!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-yaml"},"name: myenv\nversion: '0.1'\ndependencies:\n - badger-opt\nparams: null\nvariables:\n - x: 0 -> 1\n - y: 0 -> 1\n - z: 0 -> 1\nobservations:\n - norm\n - mean\n")),(0,r.kt)("div",{className:"admonition admonition-caution alert alert--warning"},(0,r.kt)("div",{parentName:"div",className:"admonition-heading"},(0,r.kt)("h5",{parentName:"div"},(0,r.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,r.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"},(0,r.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))),"caution")),(0,r.kt)("div",{parentName:"div",className:"admonition-content"},(0,r.kt)("p",{parentName:"div"},"If you use an older version of Badger, you would encounter the following error when you do ",(0,r.kt)("inlineCode",{parentName:"p"},"badger env myenv"),":"),(0,r.kt)("pre",{parentName:"div"},(0,r.kt)("code",{parentName:"pre"},"Can't instantiate abstract class Environment with abstract method get_default_params\n")),(0,r.kt)("p",{parentName:"div"},"To get around this issue, simply put the following method inside the ",(0,r.kt)("inlineCode",{parentName:"p"},"myenv")," environment class definition:"),(0,r.kt)("pre",{parentName:"div"},(0,r.kt)("code",{parentName:"pre",className:"language-python"}," @staticmethod\n def get_default_params():\n return None\n")),(0,r.kt)("p",{parentName:"div"},"Then you should get the expected printouts. The usage of the ",(0,r.kt)("inlineCode",{parentName:"p"},"get_default_params")," method will be covered in ",(0,r.kt)("a",{parentName:"p",href:"#incorperate-hyper-parameters"},"future sections"),"."))),(0,r.kt)("p",null,"Now you can take ",(0,r.kt)("inlineCode",{parentName:"p"},"myenv")," for a spin -- just write some routine configs and run some algorithm (say, ",(0,r.kt)("inlineCode",{parentName:"p"},"silly")," the random sampler) on our newly created env, to see if everything works as expected."),(0,r.kt)("h3",{id:"advanced-topics"},"Advanced topics"),(0,r.kt)("h4",{id:"specify-variable-range"},"Specify variable range"),(0,r.kt)("h4",{id:"incorperate-hyper-parameters"},"Incorperate hyper-parameters"),(0,r.kt)("h4",{id:"check-variable-readout"},"Check variable readout"),(0,r.kt)("h4",{id:"delayed-observation"},"Delayed observation"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.506f93c9.js b/assets/js/runtime~main.37ccbe77.js similarity index 97% rename from assets/js/runtime~main.506f93c9.js rename to assets/js/runtime~main.37ccbe77.js index 1de1e39..b74a1b9 100644 --- a/assets/js/runtime~main.506f93c9.js +++ b/assets/js/runtime~main.37ccbe77.js @@ -1 +1 @@ -!function(){"use strict";var e,t,n,r,o,c={},a={};function f(e){var t=a[e];if(void 0!==t)return t.exports;var n=a[e]={id:e,loaded:!1,exports:{}};return c[e].call(n.exports,n,n.exports,f),n.loaded=!0,n.exports}f.m=c,f.c=a,e=[],f.O=function(t,n,r,o){if(!n){var c=1/0;for(d=0;d=o)&&Object.keys(f.O).every((function(e){return f.O[e](n[u])}))?n.splice(u--,1):(a=!1,o0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[n,r,o]},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,{a:t}),t},n=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},f.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);f.r(o);var c={};t=t||[null,n({}),n([]),n(n)];for(var a=2&r&&e;"object"==typeof a&&!~t.indexOf(a);a=n(a))Object.getOwnPropertyNames(a).forEach((function(t){c[t]=function(){return e[t]}}));return c.default=function(){return e},f.d(o,c),o},f.d=function(e,t){for(var n in t)f.o(t,n)&&!f.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},f.f={},f.e=function(e){return Promise.all(Object.keys(f.f).reduce((function(t,n){return f.f[n](e,t),t}),[]))},f.u=function(e){return"assets/js/"+({13:"01a85c17",53:"935f2afb",61:"5e2ad779",75:"6d4920cb",89:"a6aa9e1f",103:"ccc49370",104:"db84cbea",152:"54f44165",195:"c4f5d8e4",214:"7a8ea9cb",249:"13db8233",276:"e689722c",288:"a2b18811",489:"2a19b374",514:"1be78505",535:"814f3328",592:"common",608:"9e4087bc",610:"6875c492",618:"72b80372",653:"67b9383b",659:"e3ae7939",671:"0e384e19",769:"6eada910",918:"17896441",965:"b171606d",978:"c7e3ca8c"}[e]||e)+"."+{13:"0af78e0c",53:"d2fa5544",61:"5d0ffce7",75:"fcbe7e19",89:"37a21e01",103:"63b3eedb",104:"f3d00777",152:"bd72746d",195:"964462aa",214:"3a552fb0",249:"5a475061",276:"95133075",288:"5c11f824",489:"a7bdca31",514:"84f0b0c2",535:"4b1b2a12",592:"914f4003",608:"6ce78891",610:"73be0d48",618:"1d60fd4f",653:"69cb3bb8",659:"5669b728",671:"5cde339a",707:"5cb9c152",769:"fb2223d7",814:"b54f29fc",818:"8df777da",918:"3da4c305",965:"5fe2ce0e",978:"ce64d18e"}[e]+".js"},f.miniCssF=function(e){return"assets/css/styles.0b6aeb32.css"},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r={},o="badger-home:",f.l=function(e,t,n,c){if(r[e])r[e].push(t);else{var a,u;if(void 0!==n)for(var i=document.getElementsByTagName("script"),d=0;d=o)&&Object.keys(f.O).every((function(e){return f.O[e](n[u])}))?n.splice(u--,1):(a=!1,o0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[n,r,o]},f.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(t,{a:t}),t},n=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},f.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);f.r(o);var c={};t=t||[null,n({}),n([]),n(n)];for(var a=2&r&&e;"object"==typeof a&&!~t.indexOf(a);a=n(a))Object.getOwnPropertyNames(a).forEach((function(t){c[t]=function(){return e[t]}}));return c.default=function(){return e},f.d(o,c),o},f.d=function(e,t){for(var n in t)f.o(t,n)&&!f.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},f.f={},f.e=function(e){return Promise.all(Object.keys(f.f).reduce((function(t,n){return f.f[n](e,t),t}),[]))},f.u=function(e){return"assets/js/"+({13:"01a85c17",53:"935f2afb",61:"5e2ad779",75:"6d4920cb",89:"a6aa9e1f",103:"ccc49370",104:"db84cbea",152:"54f44165",195:"c4f5d8e4",214:"7a8ea9cb",249:"13db8233",276:"e689722c",288:"a2b18811",489:"2a19b374",514:"1be78505",535:"814f3328",592:"common",608:"9e4087bc",610:"6875c492",618:"72b80372",653:"67b9383b",659:"e3ae7939",671:"0e384e19",769:"6eada910",918:"17896441",965:"b171606d",978:"c7e3ca8c"}[e]||e)+"."+{13:"0af78e0c",53:"d2fa5544",61:"5d0ffce7",75:"fcbe7e19",89:"37a21e01",103:"63b3eedb",104:"f3d00777",152:"ab3747ea",195:"964462aa",214:"3a552fb0",249:"5a475061",276:"95133075",288:"5c11f824",489:"a7bdca31",514:"84f0b0c2",535:"4b1b2a12",592:"914f4003",608:"6ce78891",610:"73be0d48",618:"1d60fd4f",653:"69cb3bb8",659:"5669b728",671:"5cde339a",707:"5cb9c152",769:"fb2223d7",814:"b54f29fc",818:"8df777da",918:"3da4c305",965:"5fe2ce0e",978:"49355c15"}[e]+".js"},f.miniCssF=function(e){return"assets/css/styles.0b6aeb32.css"},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r={},o="badger-home:",f.l=function(e,t,n,c){if(r[e])r[e].push(t);else{var a,u;if(void 0!==n)for(var i=document.getElementsByTagName("script"),d=0;d Blog | Badger - +
- + \ No newline at end of file diff --git a/blog/archive.html b/blog/archive.html index a140b7d..fcedb1d 100644 --- a/blog/archive.html +++ b/blog/archive.html @@ -6,13 +6,13 @@ Archive | Badger - +

Archive

Archive

- + \ No newline at end of file diff --git a/blog/tags.html b/blog/tags.html index 0bd24fd..b4453a4 100644 --- a/blog/tags.html +++ b/blog/tags.html @@ -6,13 +6,13 @@ Tags | Badger - +

Tags

- + \ No newline at end of file diff --git a/blog/tags/badger.html b/blog/tags/badger.html index 4177cf4..9afd55d 100644 --- a/blog/tags/badger.html +++ b/blog/tags/badger.html @@ -6,13 +6,13 @@ One post tagged with "badger" | Badger - +

One post tagged with "badger"

View All Tags
- + \ No newline at end of file diff --git a/blog/tags/hello.html b/blog/tags/hello.html index 351295c..1863330 100644 --- a/blog/tags/hello.html +++ b/blog/tags/hello.html @@ -6,13 +6,13 @@ One post tagged with "hello" | Badger - +

One post tagged with "hello"

View All Tags
- + \ No newline at end of file diff --git a/blog/tags/slac.html b/blog/tags/slac.html index ddb0eea..bb78a76 100644 --- a/blog/tags/slac.html +++ b/blog/tags/slac.html @@ -6,13 +6,13 @@ One post tagged with "SLAC" | Badger - +

One post tagged with "SLAC"

View All Tags
- + \ No newline at end of file diff --git a/blog/welcome.html b/blog/welcome.html index edf6731..64def71 100644 --- a/blog/welcome.html +++ b/blog/welcome.html @@ -6,13 +6,13 @@ Welcome | Badger - +
- + \ No newline at end of file diff --git a/docs/getting-started/installation.html b/docs/getting-started/installation.html index 8251345..955b9d3 100644 --- a/docs/getting-started/installation.html +++ b/docs/getting-started/installation.html @@ -6,13 +6,13 @@ Installation | Badger - +
-

Installation

Badger is essentially a python package. It's recommended to install and test it in a separate python virtual environment before using it in a production env.

Requirements

  • Python version >= 3.6. Python 3.7 is recommended

Install core package

Badger has a core package (badger-opt) that can be extended by a set of plugins. Badger core package is available on both pip and conda. So you could install Badger with:

pip install badger-opt

Or

conda install -c conda-forge badger-opt

Install sample plugins

Clone the badger plugins repo to some directory on your computer:

git clone https://github.com/SLAC-ML/Badger-Plugins.git

Set up Badger

Once badger-opt is installed and you have the badger plugins ready, run the following command:

badger

Follow the instructions and configure several paths that are needed by Badger.

- +

Installation

Badger is essentially a python package. It's recommended to install and test it in a separate python virtual environment before using it in a production env.

Requirements

  • Python version >= 3.6. Python 3.7+ is recommended

Install core package

Badger has a core package (badger-opt) that can be extended by a set of plugins. Badger core package is available on both pip and conda. So you could install Badger with:

pip install badger-opt

Or

conda install -c conda-forge badger-opt
caution

If you go with the conda option and you are using macOS, the Badger GUI would need a specific version of Qt to work properly. Please run the following command in the conda env in which you installed badger-opt:

conda install qt=5.12.5

The potential GUI-not-launching issue should be gone now.

Install sample plugins

Clone the badger plugins repo to some directory on your computer:

git clone https://github.com/SLAC-ML/Badger-Plugins.git

Set up Badger

Once badger-opt is installed and you have the badger plugins ready, run the following command:

badger

Follow the instructions and configure several paths that are needed by Badger.

+ \ No newline at end of file diff --git a/docs/getting-started/tutorial.html b/docs/getting-started/tutorial.html index d9b5405..bf44088 100644 --- a/docs/getting-started/tutorial.html +++ b/docs/getting-started/tutorial.html @@ -6,7 +6,7 @@ Tutorial | Badger - + @@ -16,7 +16,7 @@ optimal means minimal c1) at the evaluation time are highlighted.

In the example above, we use the silly algorithm (which is just a random search algorithm) to optimize the TNK environment, as shown in the reviewed routine. Environment TNK has 2 variables and 5 observations:

TNK environment
name: TNK
version: '0.1'
dependencies:
- numpy
params: null
variables:
- x1: 0 -> 3.14159
- x2: 0 -> 3.14159
observations:
- y1
- y2
- c1
- c2
- some_array

We specify in the config.yaml that we would like to tune varaible x2, and minimize observation c1 of environment TNK as objective. The configuration that could reproduce the whole optimization setup is called a routine in Badger. A routine contains the information of the algorithm, the environment, and the config of the optimization (the variables, the objectives, and the constraints).

We just saved the routine of the run as helloworld. Now you could view the routine again by:

badger routine helloworld

Rerun an optimization

We can rerun a saved routine in Badger. Let's rerun the helloworld routine that we just saved:

badger routine helloworld -r

Badger would behave exactly the same way as the first time you run the routine.

View the historical optimization data

You can cd to the Badger archive root (the one you setup during the initial configurations) and view the historical optimization data. The file structure is a tree-like one, with year, year-month, year-month-day as the first 3 levels of branches, and the optimization runs as leaves:

Badger archive root file structure
|--2021
|--2021-11
|--2021-11-24
|--BadgerOpt-2021-11-24-133007.yaml
|--BadgerOpt-2021-11-24-113241.yaml
|--...
|--...
|--...
|--...

The yaml data file contains the routine information and the solutions evaluated during the run. The content would look like this:

BadgerOpt-2021-11-24-133007.yaml
routine:
name: helloworld
algo: silly
env: TNK
algo_params:
dimension: 1
max_iter: 10
env_params: null
config:
variables:
- x2:
- 0.0
- 3.1416
objectives:
- c1: MINIMIZE
constraints: null
data:
timestamp:
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:06
- 24-Nov-2021 13:30:07
- 24-Nov-2021 13:30:07
- 24-Nov-2021 13:30:07
c1:
- 2.093905436806936
- 2.6185501712620036
- -0.8170601778601619
- 7.869183841178197
- -1.0945113202011
- 0.514833333947652
- -1.0331173238615994
- 1.4523371516674013
- 1.3610274948700156
- -0.0042273815683477045
x2:
- 1.78715008793524
- 1.9283542649788197
- 0.5319208795862764
- 2.9948595695254556
- 0.07408562477903413
- 1.2707609271407632
- 0.2586168520000207
- 1.5976035652399507
- 1.5687662333407153
- 1.0467915830917118

Create a simple environment

Now let's create a simple Badger environment and run optimization on it.

WIP

- + \ No newline at end of file diff --git a/docs/guides/api-usage.html b/docs/guides/api-usage.html index d7f486a..2793c12 100644 --- a/docs/guides/api-usage.html +++ b/docs/guides/api-usage.html @@ -6,13 +6,13 @@ API Usage | Badger - +

API Usage

Badger can be imported as a regular python package, and you could use the plugins/utils that Badger offers in your own python script.

Heads-up

Make sure you have Badger installed and setup.

Use an algorithm

Badger has a get_algo API to get a specific algorithm.

The following code gets an algorithm named silly (which is a random search algorithm) from Badger.

import numpy as np
from badger.factory import get_algo

# Define a test evaluate function
def evaluate(X):
Y = np.linalg.norm(X, axis=1).reshape(-1, 1) # objectives
I = None # inequality constraints
E = None # equality constraints

# Show the progress
print(Y)

return Y, I, E

# Get the silly algorithm from Badger
optimize, configs = get_algo('silly')

# Optimize the test evaluate function
optimize(evaluate, configs['params'])

Use an interface

Badger has a get_intf API to get a specific interface.

The following code gets an interface named silly and constructs an instance of the interface.

from badger.factory import get_intf

# Get the silly interface from Badger
Interface, configs = get_intf('silly')
intf = Interface(configs['params'])

# Test get/set channels
intf.get_value('c1')
# Output: 0

intf.set_value('c1', 1.0)
intf.get_value('c1')
# Output: 1.0

Use an environment

Badger has a get_env API to get a specific environment.

The following code gets and instantiates an environment named silly from Badger. Note that it uses the silly interface instance intf from the last section.

from badger.factory import get_env

# Get the silly environment from Badger
Environment, configs = get_env('silly')
env = Environment(intf, configs['params'])

# Investigate the silly env
env.list_vars()
# Output: ['q1', 'q2', 'q3', 'q4']

env.list_obses()
# Output: ['l1', 'l2']

env.get_var('q1') # q1 in env maps to c1 in intf
# Output: 1.0

env.get_obs('l2') # l2 norm of (q1, q2, q3, q4)
# Output: 1.0

env.set_var('q2', 1)
env.get_obs('l2')
# Output: 1.4142135623730951

Now we can define an evaluate function based on the silly env, and use the silly algorithm from the use an algorithm section to optimize it.

# Define an evaluate function based on the env
def evaluate(X):
# Note that X is a 2D array
Y = []
for x in X:
env.set_vars(['q1', 'q2', 'q3', 'q4'][:len(x)], x)
y = env.get_obs('l2')
Y.append(y)
Y = np.array(Y).reshape(-1, 1)
I = None
E = None

# Show the progress
print(Y)

return Y, I, E

# Optimize the evaluate function with silly algorithm
optimize(evaluate, {'dimension': 4, 'max_iter': 42})
- + \ No newline at end of file diff --git a/docs/guides/cli-usage.html b/docs/guides/cli-usage.html index c2a5e70..84e5a31 100644 --- a/docs/guides/cli-usage.html +++ b/docs/guides/cli-usage.html @@ -6,13 +6,13 @@ CLI Usage | Badger - +

CLI Usage

For all the implemented and planned CLI usage, please refer to these slides. We'll highlight several common CLI use cases of Badger in the following sections.

Get help

badger -h

Or shoot me an email!

Show metadata of Badger

To show the version number and some other metadata such as plugin directory:

badger

Get information of the algorithms

List all the available algorithms:

badger algo

Get the configs of a specific algorithm:

badger algo ALGO_NAME

You'll get something like:

name: silly
version: '0.1'
dependencies:
- numpy
params:
dimension: 1
max_iter: 42

Note that in order to use this plugin, you'll need to install the dependencies listed in the command output. This dependency installation will be handled automatically if the plugin was installed through the badger install command, but that command is not available yet (it is coming soon).

The params part shows all the intrinsic parameters that can be tuned when doing optimization with this algorithm.

Get information of the environments

List all the available environments:

badger env

Get the configs of a specific environment:

badger env ENV_NAME

The command will print out something like:

name: dumb
version: '0.1'
dependencies:
- numpy
- badger-opt
interface:
- silly
environments:
- silly
- naive
params: null
variables:
- q1: 0 -> 1
- q2: 0 -> 1
- q3: 0 -> 1
- q4: 0 -> 1
- s1: 0 -> 1
- s2: 0 -> 1
observations:
- l2
- mean
- l2_x_mean

There are several important properties here:

  • variables: The tunable variables provided by this environment. You could choose a subset of the variables as the desicion variables for the optimization in the routine config. The allowed ranges (in this case, 0 to 1) are shown behind the corresponding variable names
  • observations: The measurements provided by this environment. You could choose some observations as the objectives, and some other observations as the constraints in the routine config

Run and save an optimization

badger run [-h] -a ALGO_NAME [-ap ALGO_PARAMS] -e ENV_NAME [-ep ENV_PARAMS] -c ROUTINE_CONFIG [-s [SAVE_NAME]] [-y] [-v [{0,1,2}]]

The -ap and -ep optional arguments, and the -c argument accept either a .yaml file path or a yaml string. The configs set to -ap and -ep optional arguments should be treated as "patch" on the default algorithm and environment parameters, respectively, which means that you only need to specify the paramters that you'd like to change on top of the default configs, rather than pass in a full config. The content of the ROUTINE_CONFIG (aka routine configs) should look like this:

variables:
- x1: [-1, 0.5]
- x2
objectives:
- c1
- y2: MINIMIZE
constraints:
- y1:
- GREATER_THAN
- 0
- c2:
- LESS_THAN
- 0.5

The variables and objectives properties are required, while the constraints property is optional. Just omit the constraints property if there are no constraints for your optimization problem. The names listed in variables should come from variables of the env specified by the -e argument, while the names listed in objectives and constraints should come from observations of that env.

All optimization runs will be archived in the $BADGER_ARCHIVE_ROOT folder that you initially set up when running badger the first time.

Several example routine configs can be found in the examples folder.

Below are some example badger run commands. They are assumed to run under the parent directory of the examples folder (you'll need to clone the examples folder from this repo to your computer first). You could run them from any directory, just remember to change the routine config path accordingly.

A simplest run command

badger run -a silly -e TNK -c examples/silly_tnk.yaml

Run without confirmation

Badger will let you confirm the routine before running it. You could skip the confirmation by adding the -y option:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -y

Change verbose level

By default, Badger will print out a table contains all the evaluated solutions along the optimization run (with the optimal ones highlighted), you could alter the default behavior by setting the -v option.

The default verbose level 2 will print out all the solutions:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -v 2

The table would look like:

|    iter    |     c1     |     x2     |
----------------------------------------
| 1 | 3.73 | 2.198 |
| 2 | -0.9861 | 0.3375 |
| 3 | 1.888 | 1.729 |
| 4 | 2.723 | 1.955 |
| 5 | -1.092 | 0.08923 |
| 6 | 1.357 | 1.568 |
| 7 | 4.559 | 2.379 |
| 8 | 8.757 | 3.14 |
| 9 | 2.957 | 2.014 |
| 10 | 0.1204 | 1.105 |
| 11 | 2.516 | 1.902 |
| 12 | -0.01194 | 1.043 |
| 13 | 7.953 | 3.009 |
| 14 | -1.095 | 0.07362 |
| 15 | -0.3229 | 0.8815 |
| 16 | -1.096 | 0.06666 |
| 17 | 2.662 | 1.94 |
| 18 | 6.987 | 2.844 |
| 19 | -0.9734 | 0.3558 |
| 20 | 3.694 | 2.19 |
| 21 | -1.032 | 0.2613 |
| 22 | 2.441 | 1.882 |
| 23 | 7.042 | 2.853 |
| 24 | 4.682 | 2.405 |
| 25 | 0.5964 | 1.302 |
| 26 | 0.3664 | 1.211 |
| 27 | 1.966 | 1.751 |
| 28 | 0.2181 | 1.148 |
| 29 | 7.954 | 3.009 |
| 30 | -0.8986 | 0.4488 |
| 31 | -0.7536 | 0.5885 |
| 32 | 3.602 | 2.168 |
| 33 | 0.5527 | 1.286 |
| 34 | -0.6969 | 0.6349 |
| 35 | -1.094 | 0.07974 |
| 36 | -0.8758 | 0.4735 |
| 37 | 5.995 | 2.664 |
| 38 | 3.638 | 2.177 |
| 39 | 2.489 | 1.895 |
| 40 | 0.8434 | 1.394 |
| 41 | 0.4919 | 1.262 |
| 42 | -0.4929 | 0.7792 |
========================================

Verbose level 1 only prints out the optimal solutions along the run:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -v 1

The table would look like:

|    iter    |     c1     |     x2     |
----------------------------------------
| 1 | 1.96 | 1.749 |
| 2 | -1.037 | 0.2518 |
| 18 | -1.1 | 0.01942 |
========================================

Verbose level 0 turns off the printing feature completely:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -v 0

The table would not be printed.

Configure algorithm/environment parameters

The following two commands show how to config parameters of the algorithm/environment.

badger run -a silly -ap "dimension: 4" -e dumb -c examples/silly_dumb.yaml
badger run -a silly -ap "{dimension: 4, max_iter: 10}" -e dumb -c examples/silly_dumb.yaml

Run with algorithms provided by extensions

In order to run the following command, you'll need to set up xopt on your computer (since the algorithms are provided by xopt).

badger run -a cnsga -ap "max_generations: 10" -e TNK -c examples/cnsga_tnk.yaml

Save a run

To save a routine to database in $BADGER_DB_ROOT, just add the -s [SAVE_NAME] option. This command will run and save the routine with a randomly generated two-word name:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -s

The following command will run the routine and save it as test_routine:

badger run -a silly -e TNK -c examples/silly_tnk.yaml -s test_routine

Rerun a saved optimization routine

Say we have the routine test_routine saved. List all the saved routines by:

badger routine

To get the details of some specific routine (say, test_routine):

badger routine test_routine

To rerun it, do:

badger routine test_routine -r

badger routine also supports the -y and -v options, as badger run does.

Configure Badger

If you would like to change some setting that you configured during the first time you run badger, you could do so with badger config.

List all the configurations:

badger config

To config a property:

badger config KEY

Where KEY is one of the keys in the configuration list.

Launch the Badger GUI

Badger supports a GUI mode. You can launch the GUI by:

badger -g
- + \ No newline at end of file diff --git a/docs/guides/create-a-plugin.html b/docs/guides/create-a-plugin.html index 0e367da..8a7cff5 100644 --- a/docs/guides/create-a-plugin.html +++ b/docs/guides/create-a-plugin.html @@ -6,13 +6,13 @@ Create a plugin | Badger - +
-

Create a plugin

Plugins have three types:

  • Algorithm: function
  • Interface: class
  • Environment: class

Create an algorithm plugin

Create an interface plugin

Create an environment plugin

To let Badger deal with your own optimization problem, you'll need to turn the problem into a custom environment plugin first. An environment in Badger defines how Badger could interact with the "control system" upon which the optimization problem forms up. To be more specific, Badger wants to know:

  • What variables can be tuned
  • What are the ranges for the tunable variables
  • What observations are available (objectives, constraints, anything you would like to monitor in the optimization)

Plus (actually more importantly):

  • How to tune one variable
  • How to get one observation

And you incorporate those knowledge into Badger by inheriting the Environment base class provided by the Badger core, and implementing the corresponding methods.

Let's get a better idea about it by creating a simple custom environment plugin for Badger from the ground up.

The basics

First off, let's create a file structure like the following:

Simplest environment plugin file structure
|--myenv
|--__init__.py
|--configs.yaml

Here we'll name our simple custom env as myenv, as the folder name shows.

Then put the boilerplate code below into __init__.py:

myenv/__init__.py
from badger import environment
from badger.interface import Interface


class Environment(environment.Environment):

name = 'myenv'

def __init__(self, interface: Interface, params):
super().__init__(interface, params)
# Add other logic, try to not do time-consuming stuff here

@staticmethod
def list_vars():
return []

@staticmethod
def list_obses():
return []

def _get_var(self, var):
return 0

def _set_var(self, var, x):
pass

def _get_obs(self, obs):
return 0

Several things to note regarding the boilerplate code:

  • It should have a class variable called name, and it should match the folder name of the plugin
  • There are 5 methods that are required to be implemented to create a proper Badger env:
    • list_vars: Get a list of all the supported variables
    • list_obses: Get a list of all the supported observations
    • _get_var: Get the value of a specific variable
    • _set_var: Set a specific variable to some value
    • _get_obs: Get the value of a specific observation
tip

As the comment says, try to avoid doing time-consuming thing in __init__ method. Badger would create an instance of the environment when users try to get the details of the plugin (say, when badger env myenv is called in CLI mode), so just put some light-computing code there in the constructor would provide the users a smoother experience.

Okay, now we can start to implement the methods. Assume that our sample environment has 3 variables: x, y, and z, it also has 2 observations: norm, and mean. Then the list_vars and list_obses methods should look like:

    @staticmethod
def list_vars():
return ['x', 'y', 'z']

@staticmethod
def list_obses():
return ['norm', 'mean']

Our custom env is so simple that we don't really need an interface here. Let's implement the getter and setter for the variables:

    def __init__(self, interface: Interface, params):
super().__init__(interface, params)
self.variables = {
'x': 0,
'y': 0,
'z': 0,
}

def _get_var(self, var):
return self.variables[var]

def _set_var(self, var, x):
self.variables[var] = x

Here we use a dictionary called variables to hold the values for the variables.

Now let's add observation related logic:

    def _get_obs(self, obs):
x = self.variables['x']
y = self.variables['y']
z = self.variables['z']

if obs == 'norm':
return (x ** 2 + y ** 2 + z ** 2) ** 0.5
elif obs == 'mean':
return (x + y + z) / 3

At this point, the content of __init__.py should be:

myenv/__init__.py
from badger import environment
from badger.interface import Interface


class Environment(environment.Environment):

name = 'myenv'

def __init__(self, interface: Interface, params):
super().__init__(interface, params)
self.variables = {
'x': 0,
'y': 0,
'z': 0,
}

@staticmethod
def list_vars():
return ['x', 'y', 'z']

@staticmethod
def list_obses():
return ['norm', 'mean']

def _get_var(self, var):
return self.variables[var]

def _set_var(self, var, x):
self.variables[var] = x

def _get_obs(self, obs):
x = self.variables['x']
y = self.variables['y']
z = self.variables['z']

if obs == 'norm':
return (x ** 2 + y ** 2 + z ** 2) ** 0.5
elif obs == 'mean':
return (x + y + z) / 3

Alright! Our little env is almost done -- even though it doesnโ€™t do much, it already has everything that we need for a Badger environment! To make the plugin complete, we should also incorporate some meta data (such as version number) of our env into configs.yaml:

myenv/configs.yaml
---
name: myenv
version: "0.1"
dependencies:
- badger-opt

Congrats! Our custom env plugin is ready to go! Let's put the whole folder under BADGER_PLUGIN_ROOT/environments, then executing the following command in a terminal (in which the Badger package is available, of course):

badger env myenv

The printouts should look like below. Yay!

name: myenv
version: '0.1'
dependencies:
- badger-opt
params: null
variables:
- x: 0 -> 1
- y: 0 -> 1
- z: 0 -> 1
observations:
- norm
- mean

Now you can take myenv for a spin -- just write some routine configs and run some algorithm (say, silly the random sampler) on our newly created env, to see if everything works as expected.

Advanced topics

Specify variable range

Incorperate hyper-parameters

Check variable readout

Delayed observation

- +

Create a plugin

Plugins have three types:

  • Algorithm: function
  • Interface: class
  • Environment: class

Create an algorithm plugin

Create an interface plugin

Create an environment plugin

To let Badger deal with your own optimization problem, you'll need to turn the problem into a custom environment plugin first. An environment in Badger defines how Badger could interact with the "control system" upon which the optimization problem forms up. To be more specific, Badger wants to know:

  • What variables can be tuned
  • What are the ranges for the tunable variables
  • What observations are available (objectives, constraints, anything you would like to monitor in the optimization)

Plus (actually more importantly):

  • How to tune one variable
  • How to get one observation

And you incorporate those knowledge into Badger by inheriting the Environment base class provided by the Badger core, and implementing the corresponding methods.

Let's get a better idea about it by creating a simple custom environment plugin for Badger from the ground up.

The basics

First off, let's create a file structure like the following:

Simplest environment plugin file structure
|--myenv
|--__init__.py
|--configs.yaml

Here we'll name our simple custom env as myenv, as the folder name shows.

Then put the boilerplate code below into __init__.py:

myenv/__init__.py
from badger import environment
from badger.interface import Interface


class Environment(environment.Environment):

name = 'myenv'

def __init__(self, interface: Interface, params):
super().__init__(interface, params)
# Add other logic, try to not do time-consuming stuff here

@staticmethod
def list_vars():
return []

@staticmethod
def list_obses():
return []

def _get_var(self, var):
return 0

def _set_var(self, var, x):
pass

def _get_obs(self, obs):
return 0

Several things to note regarding the boilerplate code:

  • It should have a class variable called name, and it should match the folder name of the plugin
  • There are 5 methods that are required to be implemented to create a proper Badger env:
    • list_vars: Get a list of all the supported variables
    • list_obses: Get a list of all the supported observations
    • _get_var: Get the value of a specific variable
    • _set_var: Set a specific variable to some value
    • _get_obs: Get the value of a specific observation
tip

As the comment says, try to avoid doing time-consuming thing in __init__ method. Badger would create an instance of the environment when users try to get the details of the plugin (say, when badger env myenv is called in CLI mode), so just put some light-computing code there in the constructor would provide the users a smoother experience.

Okay, now we can start to implement the methods. Assume that our sample environment has 3 variables: x, y, and z, it also has 2 observations: norm, and mean. Then the list_vars and list_obses methods should look like:

    @staticmethod
def list_vars():
return ['x', 'y', 'z']

@staticmethod
def list_obses():
return ['norm', 'mean']

Our custom env is so simple that we don't really need an interface here. Let's implement the getter and setter for the variables:

    def __init__(self, interface: Interface, params):
super().__init__(interface, params)
self.variables = {
'x': 0,
'y': 0,
'z': 0,
}

def _get_var(self, var):
return self.variables[var]

def _set_var(self, var, x):
self.variables[var] = x

Here we use a dictionary called variables to hold the values for the variables.

Now let's add observation related logic:

    def _get_obs(self, obs):
x = self.variables['x']
y = self.variables['y']
z = self.variables['z']

if obs == 'norm':
return (x ** 2 + y ** 2 + z ** 2) ** 0.5
elif obs == 'mean':
return (x + y + z) / 3

At this point, the content of __init__.py should be:

myenv/__init__.py
from badger import environment
from badger.interface import Interface


class Environment(environment.Environment):

name = 'myenv'

def __init__(self, interface: Interface, params):
super().__init__(interface, params)
self.variables = {
'x': 0,
'y': 0,
'z': 0,
}

@staticmethod
def list_vars():
return ['x', 'y', 'z']

@staticmethod
def list_obses():
return ['norm', 'mean']

def _get_var(self, var):
return self.variables[var]

def _set_var(self, var, x):
self.variables[var] = x

def _get_obs(self, obs):
x = self.variables['x']
y = self.variables['y']
z = self.variables['z']

if obs == 'norm':
return (x ** 2 + y ** 2 + z ** 2) ** 0.5
elif obs == 'mean':
return (x + y + z) / 3

Alright! Our little env is almost done -- even though it doesnโ€™t do much, it already has everything that we need for a Badger environment! To make the plugin complete, we should also incorporate some meta data (such as version number) of our env into configs.yaml:

myenv/configs.yaml
---
name: myenv
version: "0.1"
dependencies:
- badger-opt

Congrats! Our custom env plugin is ready to go! Let's put the whole folder under BADGER_PLUGIN_ROOT/environments, then executing the following command in a terminal (in which the Badger package is available, of course):

badger env myenv

The printouts should look like below. Yay!

name: myenv
version: '0.1'
dependencies:
- badger-opt
params: null
variables:
- x: 0 -> 1
- y: 0 -> 1
- z: 0 -> 1
observations:
- norm
- mean
caution

If you use an older version of Badger, you would encounter the following error when you do badger env myenv:

Can't instantiate abstract class Environment with abstract method get_default_params

To get around this issue, simply put the following method inside the myenv environment class definition:

    @staticmethod
def get_default_params():
return None

Then you should get the expected printouts. The usage of the get_default_params method will be covered in future sections.

Now you can take myenv for a spin -- just write some routine configs and run some algorithm (say, silly the random sampler) on our newly created env, to see if everything works as expected.

Advanced topics

Specify variable range

Incorperate hyper-parameters

Check variable readout

Delayed observation

+ \ No newline at end of file diff --git a/docs/guides/gui-usage.html b/docs/guides/gui-usage.html index 4d3a759..74f6586 100644 --- a/docs/guides/gui-usage.html +++ b/docs/guides/gui-usage.html @@ -6,13 +6,13 @@ GUI Usage | Badger - + - + \ No newline at end of file diff --git a/docs/guides/implement-an-extension.html b/docs/guides/implement-an-extension.html index 4cbe062..68b3118 100644 --- a/docs/guides/implement-an-extension.html +++ b/docs/guides/implement-an-extension.html @@ -6,13 +6,13 @@ Implement an extension | Badger - +
- + \ No newline at end of file diff --git a/docs/intro.html b/docs/intro.html index 7b5da11..1d7b3d2 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -6,13 +6,13 @@ Introduction | Badger - +

Introduction

Badger is an optimizer specifically designed for Accelerator Control Room (ACR). It's the spiritual successor of Ocelot optimizer.

Badger architecture

Badger abstracts an optimization run as an optimization algorithm interacts with an environment, by following some pre-defined rules. As visualized in the picture above, the environment is controlled by the algorithm and tunes/observes the control system/machine through an interface, while the users control/monitor the optimization flow through a graphical user interface (GUI) or a command line interface (CLI).

Algorithms, environments, and interfaces in Badger are all managed through a plugin system, and could be developed and maintained separately. The application interfaces (API) for creating the plugins are very straightforward and simple, yet abstractive enough to handle various situations.

Badger offers 3 modes to satisfy different user groups:

  • GUI mode, for ACR operators, enable them to perform regular optimization tasks with one click
  • CLI mode, for the command line lovers or the situation without a screen, configure and run the whole optimization in one line efficiently
  • API mode, for the algorithm developers, use the environments provided by Badger without the troubles to configure them

Important concepts

As shown in the Badger schematic plot above, there are several terms/concepts in Badger, and their meaning are a little different with regard to their general definitions. Let's briefly go through the terms/concepts in Badger in the following sections.

Routine

An optimization setup in Badger is called a routine. A routine contains all the information needed to perform the optimization:

  • The optimization algorithm and its hyperparameters
  • The environment on which the optimization would be performed
  • The configuration of the optimization, such as variables, objectives, and constraints

To run an optimization in Badger, the users need to define the routine. Badger provides several ways to easily compose the routine, so no worries, you'll not have to write it by hands:)

Interface

An interface in Badger is a piece of code that talks to the underlying control system/machine. It communicates to the control system to:

  • Set a process variable (PV) to some specific value
  • Get the value of a PV

An interface is also responsible to perform the configuration needed for communicating with the control system, and the configuration can be customized by passing a params dictionary to the interface.

The concept of interface was introduced to Badger for better code reuse. You don't have to copy-n-paste the same fundamental code again and again when coding your optimization problems for the same underlying control system. Now you could simply ask Badger to use the same interface, and focus more on the higher level logic of the problem.

tip

Interfaces are optional in Badger -- an interface is not needed if the optimization problem is simple enough (say, analytical function) that you can directly shape it into an environment.

Environment

An environment is Badger's way to (partially) abstract an optimization problem. A typical optimization problem usually consists of the variables to tune, and the objectives to optimize. A Badger environment defines all the interested variables and observations of a control system/machine. An optimization problem can be specified by stating which variables in the environment are the variables to tune, and which observations are the objectives to optimize. Furthermore, one can define the constraints for the optimization by picking up some observation from the environment and giving it a threshold.

Take the following case as an example. Assume that we have an accelerator control system and we'd like to tune the quadupoles QUAD:1, QUAD:2 and minimize the horizontal beam size on a screen BSIZE:X. We also want to keep the vertical beam size BSIZE:Y below a certain value. To do this in Badger, we could define an environment that has variables:

  • QUAD:1
  • QUAD:2

And observations:

  • BSIZE:X
  • BSIZE:Y

Then define a routine config to specify details of the optimization problem, as will be mentioned in the next section.

tip

One environment could support multiple relevant optimization problems -- just put all the variables and observations to the environment, and use routine config to select which variables/observations to use for the optimization.

Routine config

A routine config is the counterpart of optimization problem abstraction with regard to environment. An optimization problem can be fully defined by an environment with a routine config.

On top of the variables and observations provided by environment, routine config tells Badger which and how variables/observations are used as the tuning variables/objectives/constraints.

Use the example from the last section, the routine config for the problem could be:

Routine Config
variables:
- QUAD:1
- QUAD:2
objectives:
- BSIZE:X: MINIMIZE
constraints:
- BSIZE:Y:
- LESS_THAN
- 0.5

The reasons to divide the optimization problem definition into two parts (environment and routine config) are:

  • Better code reuse
  • Operations in ACR usually require slightly changing a routine frequently, so it's good to have an abstraction for the frequently changed configurations (routine config), to avoid messing with the optimization source code

Features

One of Badger's core features is the ability to extend easily. Badger offers two ways to extend its capibility: making a plugin, or implementing an extension.

Plugin system

Algorithms, interfaces, and environments are all plugins in Badger. A plugin in Badger is a set of python scripts, a YAML config file, and an optional README.md. A typical file structure of a plugin looks like:

Plugin File Structure
|--<PLUGIN_ID>
|--__init__.py
|--configs.yaml
|--README.md
|--...

The role/feature of each file will be discussed in details later in the create a plugin section.

tip

One unique feature of Badger plugins is that plugins can be nested -- you can use any available plugins inside your own plugin. Say, one could combine two environments and create a new one effortlessly, thanks to this nestable nature of Badger plugins. You could explore the infinity possibilities by nesting plugins together with your imagination!

Extension system

Extension system is another way to extend Badger's capabilities, and in a sense it's more powerful than the plugin system, since it could make a batch of existing algorithms available in Badger in a few lines of code!

Let's assume that we already have an optimization platform/framework that provides a dozen of algorithms, and we'd like to use these algorithms to optimize on our machine environment. One way to do that is porting all these algorthms to Badger through the plugin system, and use Badger to perform the optimization. Extension system was designed just for this situation, since porting the algorithms one by one is tedious and inefficient. Extension system provides the APIs that are required to be implemented in order to "port" all the algorithms of another optimization framework/platform in one go. More details about extension system can be found in the implement an extension section.

With the extension system, Badger could use any existing algorithms from another optimization package. Currently, Badger has the following extensions available:

And more extensions are on the way (for example, teeport extension for remote optimization)!

- + \ No newline at end of file diff --git a/index.html b/index.html index f3d4f83..6ef5e50 100644 --- a/index.html +++ b/index.html @@ -6,13 +6,13 @@ Badger the Optimizer | Badger - +

Badger

The Missing Optimizer in ACR

Easy to Use

Badger was specifically designed for operators. You could re-run an optimization routine with just one command/click.

Fast to Extend

Badger can be extended through its plugin system. Shape your algorithm/problem into a plugin in 5 minutes.

Multiple Mode

Badger can be used as a library, a command line tool, or a GUI application. Use Badger the way you want.

- + \ No newline at end of file