configs.ipynb
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cookbook: Config\n",
"================\n",
"\n",
"Configuration files are used to control the behaviour model components in **PyAutoFit**, which perform the\n",
"following tasks:\n",
" \n",
" - Specify the default priors of model components, so that a user does not have to manually specify priors every time\n",
" they create a model.\n",
"\n",
" - Specify labels of every parameter, which are used for plotting and visualizing results.\n",
"\n",
"This cookbook illustrates how to create configuration files for your own model components, so that they can be used\n",
"with **PyAutoFit**.\n",
"\n",
"__Contents__\n",
"\n",
" - No Config Behaviour: An example of what happens when a model component does not have a config file.\n",
" - Template: A template config file for specifying default model component priors.\n",
" - Modules: Writing prior config files based on the Python module the model component Python class is contained in.\n",
" - Labels: Config files which specify the labels of model component parameters for visualization."
]
},
{
"cell_type": "code",
"metadata": {},
"source": [
"%matplotlib inline\n",
"from pyprojroot import here\n",
"workspace_path = str(here())\n",
"%cd $workspace_path\n",
"print(f\"Working Directory has been set to `{workspace_path}`\")\n",
"\n",
"import numpy as np\n",
"from os import path\n",
"\n",
"import autofit as af"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__No Config Behaviour__\n",
"\n",
"The examples seen so far have used `Gaussian` and `Exponential` model components, which have configuration files in\n",
"the `autofit_workspace/config/priors` folder which define their priors and labels.\n",
"\n",
"If a model component does not have a configuration file and we try to use it in a fit, **PyAutoFit** will raise an\n",
"error. \n",
"\n",
"Lets illustrate this by setting up the usual Gaussian object, but naming it `GaussianNoConfig` so that it does\n",
"not have a config file."
]
},
{
"cell_type": "code",
"metadata": {},
"source": [
"\n",
"\n",
"class GaussianNoConfig:\n",
" def __init__(\n",
" self,\n",
" centre=0.0, # <- PyAutoFit recognises these constructor arguments\n",
" normalization=0.1, # <- are the Gaussian`s model parameters.\n",
" sigma=0.01,\n",
" ):\n",
" \"\"\"\n",
" Represents a 1D `Gaussian` profile, which does not have a config file set up.\n",
" \"\"\"\n",
" self.centre = centre\n",
" self.normalization = normalization\n",
" self.sigma = sigma\n",
"\n",
" def model_data_1d_via_xvalues_from(self, xvalues: np.ndarray) -> np.ndarray:\n",
" \"\"\"\n",
" The usual method that returns the 1D data of the `Gaussian` profile.\n",
" \"\"\"\n",
" transformed_xvalues = xvalues - self.centre\n",
"\n",
" return np.multiply(\n",
" np.divide(self.normalization, self.sigma * np.sqrt(2.0 * np.pi)),\n",
" np.exp(-0.5 * np.square(np.divide(transformed_xvalues, self.sigma))),\n",
" )\n"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When we try make this a `Model` and fit it, **PyAutoFit** raises an error, as it does not know where the priors\n",
"of the `GaussianNoConfig` are located.\n",
"\n",
"I have commented the Python code out below so the script can run, but feel free to uncomment it and run it to see the \n",
"error."
]
},
{
"cell_type": "code",
"metadata": {},
"source": [
"model = af.Model(GaussianNoConfig)\n",
"\n",
"dataset_path = path.join(\"dataset\", \"example_1d\", \"gaussian_x1\")\n",
"data = af.util.numpy_array_from_json(file_path=path.join(dataset_path, \"data.json\"))\n",
"noise_map = af.util.numpy_array_from_json(\n",
" file_path=path.join(dataset_path, \"noise_map.json\")\n",
")\n",
"\n",
"analysis = af.ex.Analysis(data=data, noise_map=noise_map)\n",
"\n",
"search = af.DynestyStatic()\n",
"\n",
"# result = search.fit(model=model, analysis=analysis)"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In all other examples, the fits runs because the priors have been defined in one of two ways:\n",
"\n",
" - They were manually input in the example script.\n",
" - They were loaded via config files \"behind the scenes\".\n",
"\n",
"Checkout the folder `autofit_workspace/config/priors`, where .yaml files defining the priors of the `Gaussian` and\n",
"`Exponential` model components are located. These are the config files that **PyAutoFit** loads in the background\n",
"in order to setup the default priors of these model components.\n",
"\n",
"If we do not manually override priors, these are the priors that will be used by default when a model-fit is performed.\n",
"\n",
"__Templates__\n",
"\n",
"For your model-fitting task, you therefore should set up a config file for every model component you defining its\n",
"default priors.\n",
"\n",
"Next, inspect the `TemplateObject.yaml` priors configuration file in `autofit_workspace/config/priors`. \n",
"\n",
"You should see the following text:\n",
"\n",
" parameter0:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 1.0\n",
" parameter1:\n",
" type: Gaussian\n",
" mean: 0.0\n",
" sigma: 0.1\n",
" lower_limit: 0.0\n",
" upper_limit: inf\n",
" parameter2:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 10.0\n",
"\n",
"This specifies the default priors on two parameters, named `parameter0` and `parameter1`. \n",
"\n",
"The `type` is the type of prior assumed by **PyAutoFit** by default for its corresponding parameter, where in this\n",
"example:\n",
"\n",
"- `parameter0` is given a `UniformPrior` with limits between 0.0 and 1.0. \n",
"- `parameter1` a `GaussianPrior` with mean 0.0 and sigma 1.0.\n",
"- `parameter2` is given a `UniformPrior` with limits between 0.0 and 10.0. \n",
"\n",
"The `lower_limit` and `upper_limit` of a `GaussianPrior` define the boundaries of what parameter values are \n",
"physically allowed. If a model-component is given a value outside these limits during model-fitting the model is\n",
"instantly resampled and discarded.\n",
"\n",
"We can easily adapt this template for any model component, for example the `GaussianNoConfig`. \n",
"\n",
"First, copy and paste the `TemplateObject.yaml` file to create a new file called `GaussianNoConfig.yaml`. \n",
"\n",
"The name of the class is matched to the name of the configuration file, therefore it is a requirement that the \n",
"configuration file is named `GaussianNoConfig.yaml` so that **PyAutoFit** can associate it with the `GaussianNoConfig`\n",
"Python class.\n",
"\n",
"Now perform the follow changes to the `.yaml` file:\n",
"\n",
" - Rename `parameter0` to `centre` and updates its uniform prior to be from a `lower_limit` of 0.0 and \n",
" an `upper_limit` of 100.0.\n",
" - Rename `parameter1` to `normalization`. \n",
" - Rename `parameter2` to `sigma`.\n",
"\n",
"The `.yaml` file should read as follows:\n",
"\n",
" centre:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 100.0\n",
" normalization:\n",
" type: Gaussian\n",
" mean: 0.0\n",
" sigma: 0.1\n",
" lower_limit: 0.0\n",
" upper_limit: inf\n",
" sigma:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 10.0\n",
"\n",
"We should now be able to make a `Model` of the `GaussianNoConfig` class and fit it, without manually specifying\n",
"the priors.\n",
"\n",
"You may need to reset your Jupyter notebook's kernel for the changes to the `.yaml` file to take effect."
]
},
{
"cell_type": "code",
"metadata": {},
"source": [
"model = af.Model(GaussianNoConfig)\n",
"\n",
"dataset_path = path.join(\"dataset\", \"example_1d\", \"gaussian_x1\")\n",
"data = af.util.numpy_array_from_json(file_path=path.join(dataset_path, \"data.json\"))\n",
"noise_map = af.util.numpy_array_from_json(\n",
" file_path=path.join(dataset_path, \"noise_map.json\")\n",
")\n",
"\n",
"analysis = af.ex.Analysis(data=data, noise_map=noise_map)\n",
"\n",
"search = af.DynestyStatic()\n",
"\n",
"# result = search.fit(model=model, analysis=analysis)"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"__Modules__\n",
"\n",
"For larger projects, it may not be ideal to have to write a .yaml file for every Python class which acts as a model\n",
"component. \n",
"\n",
"We instead would prefer them to be in their own dedicated Python module.\n",
"\n",
"Suppose the `Gaussian` and `Exponential` model components were contained in a module named `profiles.py` in your\n",
"project's source code.\n",
"\n",
"You could then write a priors .yaml config file following the format given in the example config file\n",
"`autofit_workspace/config/priors/profiles.yaml`, noting that there is a paring between the module name\n",
"(`profiles.py`) and the name of the `.yaml` file (`profiles.yaml`).\n",
"\n",
"The file `autofit_workspace/config/priors/template_module.yaml` provides the tempolate for module based prior\n",
"configs and reads as follows:\n",
"\n",
"ModelComponent0:\n",
" parameter0:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 1.0\n",
" parameter1:\n",
" type: LogUniform\n",
" lower_limit: 1.0e-06\n",
" upper_limit: 1000000.0\n",
" parameter2:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 25.0\n",
"ModelComponent1:\n",
" parameter0:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 1.0\n",
" parameter1:\n",
" type: LogUniform\n",
" lower_limit: 1.0e-06\n",
" upper_limit: 1000000.0\n",
" parameter2:\n",
" type: Uniform\n",
" lower_limit: 0.0\n",
" upper_limit: 1.0\n",
"\n",
"This looks very similar to `TemplateObject`, the only differences are:\n",
"\n",
" - It now contains the model-component class name in the configuration file, e.g. `ModelComponent0`, `ModelComponent1`.\n",
" - It includes multiple model-components, whereas `TemplateObject.yaml` corresponded to only one model component.\n",
"\n",
"Labels\n",
"------\n",
"\n",
"There is an optional configs which associate model parameters with labels:\n",
"\n",
"`autofit_workspace/config/notation.yaml`\n",
"\n",
"It includes a `label` section which pairs every parameter with a label, which is used when visualizing results \n",
"(e.g. these labels are used when creating a corner plot).\n",
"\n",
"label:\n",
" label:\n",
" sigma: \\sigma\n",
" centre: x\n",
" normalization: norm\n",
" parameter0: a\n",
" parameter1: b\n",
" parameter2: c\n",
" rate: \\lambda\n",
"\n",
"It also contains a `superscript` section which pairs every model-component label with a superscript, so that\n",
"models with the same parameter names (e.g. `centre` can be distinguished).\n",
"\n",
"label:\n",
" superscript:\n",
" Exponential: e\n",
" Gaussian: g\n",
" ModelComponent0: M0\n",
" ModelComponent1: M1\n",
"\n",
"The `label_format` section sets Python formatting options for every parameter, controlling how they display in\n",
"the `model.results` file.\n",
"label_format:\n",
" format:\n",
" sigma: '{:.2f}'\n",
" centre: '{:.2f}'\n",
" normalization: '{:.2f}'\n",
" parameter0: '{:.2f}'\n",
" parameter1: '{:.2f}'\n",
" parameter2: '{:.2f}'\n",
" rate: '{:.2f}"
]
},
{
"cell_type": "code",
"metadata": {},
"source": [],
"outputs": [],
"execution_count": null
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.1"
}
},
"nbformat": 4,
"nbformat_minor": 4
}