Commit 4bca31f5 authored by Daniel Williams's avatar Daniel Williams 🤖

Merge branch 'new-api' into 'master'

Implement a new extensible API

See merge request !6
parents bba2025b 67f31e03
Pipeline #67917 passed with stage
in 2 minutes and 5 seconds
===============================
heron
Heron
===============================
The ``heron`` package is a python library for using Gaussian Process
Regression to generate and train Gaussian Process regression models
for surrogate modelling.
The ``heron`` package is a python library for using Gaussian Process Regression (GPR) to emulate functions which are expensive to
It was originally built for producing a surrogate model for numerical
relativity waveforms from binary black hole coalesences, but the code
......@@ -17,12 +15,13 @@ python package to generate the underlying Gaussian Process, which can
handle very large models thanks to its use of a hierarchical matrix
inverter.
..
Features
--------
Features
--------
* Single-valued function surrogate production from multivalued inputs
* Handling very large datasets.
* Single-valued function surrogate production from multivalued inputs
* Handling very large datasets.
.. _george: http://dan.iel.fm/george/
.. _emcee: http://dan.iel.fm/emcee/
/*
* bootstrap-sphinx.css
* ~~~~~~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- Bootstrap theme.
*/
.navbar-inverse .brand {
color: #FFF;
}
/*
* Reset navbar styles from overrides in:
* https://bitbucket.org/birkenfeld/sphinx/commits/78d8ebf76b630ab4073a7328af9d91e8123b8d96
*/
.navbar .container {
padding-top: 0;
}
.page-top {
top: 0px;
}
{% if theme_navbar_fixed_top|tobool %}
{% if theme_bootstrap_version == "2" %}
@media (min-width: 980px) {
{% endif %}
{% if theme_bootstrap_version == "2" %}
}
{% endif %}
.navbar-inner {
padding-left: 12px !important;
padding-right: 12px !important;
}
{% else %}
{% if theme_bootstrap_version == "2" %}
@media (min-width: 980px) {
.navbar .container {
width: 940px;
}
}
{% endif %}
{% endif %}
table {
border: 0;
}
.highlighttable .code pre {
font-size: 12px;
}
.highlighttable .linenos pre {
word-break: normal;
font-size: 12px;
}
div.highlight {
background: none;
}
a.footnote-reference {
vertical-align: super;
font-size: 75%;
}
table.footnote td.label {
font-size: 100%;
display: block;
line-height: normal;
background: inherit;
}
table.footnote {
width: auto;
margin-bottom: 0px;
}
table.field-list {
width: auto;
}
.footer {
width: 100%;
border-top: 1px solid #ccc;
padding-top: 10px;
}
.bs-sidenav form, .bs-sidenav #sourcelink {
padding: 5px 20px;
}
{% if theme_bootstrap_version == "3" %}
/* The code below is based on the bootstrap website sidebar */
.bs-sidenav.affix {
position: static;
}
/* First level of nav */
.bs-sidenav {
margin-top: 30px;
margin-bottom: 30px;
padding-top: 10px;
padding-bottom: 10px;
text-shadow: 0 1px 0 #fff;
background-color: #f7f5fa;
border-radius: 5px;
}
/* All levels of nav */
.bs-sidenav .nav > li > a {
display: block;
color: #716b7a;
padding: 5px 20px;
}
.bs-sidenav .nav > li > a:hover,
.bs-sidenav .nav > li > a:focus {
text-decoration: none;
background-color: #e5e3e9;
border-right: 1px solid #dbd8e0;
}
.bs-sidenav .nav > .active > a,
.bs-sidenav .nav > .active:hover > a,
.bs-sidenav .nav > .active:focus > a {
font-weight: bold;
color: #563d7c;
background-color: transparent;
border-right: 1px solid #563d7c;
}
.bs-sidenav .nav .nav > li > a {
padding-top: 3px;
padding-bottom: 3px;
padding-left: 30px;
font-size: 90%;
}
.bs-sidenav .nav .nav .nav > li > a {
padding-top: 3px;
padding-bottom: 3px;
padding-left: 40px;
font-size: 90%;
}
.bs-sidenav .nav .nav .nav .nav > li > a {
padding-top: 3px;
padding-bottom: 3px;
padding-left: 50px;
font-size: 90%;
}
/* Show and affix the side nav when space allows it */
@media screen and (min-width: 992px) {
.bs-sidenav .nav > .active > ul {
display: block;
}
/* Widen the fixed sidenav */
.bs-sidenav.affix,
.bs-sidenav.affix-bottom {
width: 213px;
}
.bs-sidenav.affix {
position: fixed; /* Undo the static from mobile first approach */
}
.bs-sidenav.affix-bottom {
position: absolute; /* Undo the static from mobile first approach */
}
.bs-sidenav.affix-bottom .bs-sidenav,
.bs-sidenav.affix .bs-sidenav {
margin-top: 0;
margin-bottom: 0;
}
}
@media screen and (min-width: 1200px) {
/* Widen the fixed sidenav again */
.bs-sidenav.affix-bottom,
.bs-sidenav.affix {
width: 263px;
}
}
{% else %}
.bs-sidenav {
width: 228px;
margin: 30px 0 0;
padding: 10px 0 0 5px;
}
.bs-sidenav ul{
list-style-type: none;
padding-left: 25px;
margin-left: 0; /* bootstrap 2 compatability. */
}
@media (min-width: 1200px) {
.bs-sidenav {
width: 258px;
}
}
/* Desktop
------------------------- */
@media (max-width: 980px) {
.bs-sidenav {
width: 218px;
margin-top: 30px;
margin-right: 0;
}
}
/* Tablet to desktop
------------------------- */
@media (min-width: 768px) and (max-width: 979px) {
.bs-sidenav {
width: 166px;
margin-top: 20px;
}
}
/* Tablet
------------------------- */
@media (max-width: 767px) {
.navbar-version {
padding-left: 5px;
}
.bs-sidenav {
width: auto;
margin-bottom: 20px;
}
.bs-sidenav.affix {
position: static;
top: 0;
}
}
{% endif %}
h1 {
font-family: "Open Sans", sans-serif; }
a {
color: #FF327A; }
a.sidebar {
color: white; }
.jumbotron {
background-color: #FF327A;
background: linear-gradient(to bottom right, #FF327A, #cb0047);
color: white;
font-weight: 400; }
.panel-default > .panel-heading {
background-color: #FF327A;
background: linear-gradient(to bottom right, #FF327A, #cb0047);
color: white; }
.hexagon {
color: white;
position: relative;
width: 300px;
height: 173.21px;
background-color: #FF327A;
margin: 86.60px 0;
padding: 25px;
margin-top: 150px; }
.hexagon:before,
.hexagon:after {
content: "";
position: absolute;
width: 0;
border-left: 150px solid transparent;
border-right: 150px solid transparent;
padding: -10px; }
.hexagon:before {
bottom: 100%;
border-bottom: 86.6px solid #FF327A;
margin-left: -25px;
margin-top: 20px; }
.hexagon:after {
top: 100%;
width: 0;
margin-left: -120px;
border-top: 86.6px solid #FF327A; }
.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover {
background-color: #FF327A;
color: white;
border: 1px solid #FF327A; }
.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover a {
color: white; }
body {
padding-top: 0; }
......@@ -34,7 +34,7 @@ sys.path.insert(0, project_root)
import heron
# Load the bootstrap theme
import sphinx_bootstrap_theme
import sphinx_daniel_theme
# -- General configuration ---------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
......@@ -114,8 +114,8 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'bootstrap'
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
html_theme = 'daniel'
html_theme_path = sphinx_daniel_theme.get_html_theme_path()
# Theme options are theme-specific and customize the look and feel of a
# theme further. For a list of options available for each theme, see the
......
......@@ -3,67 +3,33 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to heron's documentation!
======================================
Heron : The Waveform Emulator
=============================
`Heron` is a Python package for producing surrogate models for
computationally intensive functions, such as numerical relativity
`Heron` is a Python package for producing surrogate models for computationally intensive functions, such as numerical relativity
waveforms.
Tutorials
=========
This version of heron is implemented slightly differently to older versions,
and should allow for a greater degree of flexibility for using different GP libraries for the modelling,
and to fit into analysis pipelines better than the earlier development versions.
.. toctree::
:maxdepth: 2
:caption: Basics
readme
api
usage
API documentation
=================
This is the low-level documentation for how each of the functions and
classes in the package actually work. If you're looking to get started
using `heron` you might be better-off looking at some of the
tutorials.
Surrogate Modelling
-------------------
.. autosummary::
:toctree: _autosummary
heron.data
heron.priors
heron.kernels
heron.regression
heron.training
..
Tutorials
=========
Matched Filtering
-----------------
.. autosummary::
:toctree: _autosummary
.. toctree::
:maxdepth: 2
:caption: Tutorials
heron.filtering
Bayesian optimisation
---------------------
.. autosummary::
:toctree: _autosummary
heron.acquisition
The Heron Code repository
=========================
.. toctree::
:maxdepth: 2
readme
usage
usage
Indices and tables
......
......@@ -5,3 +5,4 @@ heron
:maxdepth: 4
heron
heron.models
This diff is collapsed.
import numpy as np
class Model(object):
"""
This is the factory class for statistical models used for waveform generation.
A model class must expose the following methods:
- `distribution` : produce a distribution of waveforms at a given point in the parameter space
- `mean` : produce a mean waveform at a given point in the parameter space
- `train` : provide an interface for training the model
"""
def _process_inputs(self, times, p):
"""
Apply regularisations and normalisations to any input point dictionary.
Parameters
----------
times: list, array-like
An array of time stamps.
p : dict
A dictionary of the input locations
"""
# The default implementation of this method just passes the data straight through.
return times, p
def _generate_eval_matrix(self, p, times):
"""
Create the matrix of parameter points at which to evaluate the model.
"""
times, p = self._process_inputs(times, p)
nt = len(times)
points = np.ones((nt, self.x_dimensions))
points[:,self.c_ind['time']] = times
for column, value in p.items():
points[:, self.c_ind[column]] *= value
return points
pass
This diff is collapsed.
"""
Models utilising the `george` GPR library in Python and C++.
"""
from . import Model
from .gw import BBHSurrogate, BBHNonSpinSurrogate, HofTSurrogate
import numpy as np
import george
from george import HODLRSolver
import elk
from elk.waveform import Timeseries
from elk.catalogue import Catalogue
import scipy.optimize as op
<<<<<<< HEAD
import pkg_resources
DATA_PATH = pkg_resources.resource_filename('heron', 'models/data/')
def train(model):
=======
def train(model, batch_size=100, algorithm="adam", max_iter=1000):
>>>>>>> 5028adc92de28896a3e38139aab8616ba2dc60b9
"""
Train a george-based Gaussian process model.
"""
def callback(p):
print '{}\t{}'.format(np.exp(p), model.log_evidence(p, n=batch_size)[0])
def nll(k):
ll = model.log_evidence(k, n=batch_size)[0]
return -ll if np.isfinite(ll) else 1e25
def grad_nll(k):
return - model.log_evidence(k, n=batch_size)[1]
def grad_ll(k):
return model.log_evidence(k, n=batch_size)[1]
# Get the default value of the hyperparameters as the initial point for the optimisation
p0 = model.gp.get_parameter_vector()
model.train()
if not batch_size == None:
if algorithm == "adam":
"""
Optimise using the adam algorithm.
"""
import climin
opt = climin.Adam(p0, grad_nll)
for info in opt:
if info['n_iter']%10 == 0:
k = model.gp.get_parameter_vector()
print("{} - {} - {}".format(info['n_iter'],
model.log_evidence(k, n=batch_size)[0],
np.exp(k)
))
if info['n_iter'] > max_iter: break
results = model.gp.get_parameter_vector()
else:
results = op.minimize(nll, p0, jac=grad_nll, method="L-BFGS-B", callback=callback)
model.gp.set_parameter_vector(results.x)
model.eval()
return results
class HodlrGPR(Model):
"""
A GPR model using the hierarchical matrix approximation.
"""
training = False
evaluate = True
time_factor = 100
def eval(self):
"""
Prepare the model to be evaluated.
"""
self.training = False
self.gp.white_noise.set_parameter_vector(0.0)
self.training = False
self.gp.compute(self.training_data[:,:self.x_dimensions], self.yerr)
self.evaluate = True
def train(self):
"""
Prepare the model to be trained.
"""
# Put the model into training mode,
model.training = True
model.evaluate = False
# and set the white noise to a slightly higher level to improve stability
model.gp.white_noise.set_parameter_vector(0.1)
def _process_inputs(self, times, p):
"""
Apply regularisations and normalisations to any input point dictionary.
Parameters
----------
p : dict
A dictionary of the input locations
"""
times *= self.time_factor
p['mass ratio'] = np.log(p['mass ratio'])
return times, p
def build(self, mean=0.0, white_noise=0, tol=1e-6):
"""
Construct the GP object