Skip to content

Commit

Permalink
Merge branch 'main' into sharedmem
Browse files Browse the repository at this point in the history
  • Loading branch information
Vogull committed Apr 22, 2024
2 parents 87ac647 + e85094f commit 3c7d11c
Show file tree
Hide file tree
Showing 38 changed files with 630 additions and 34,634 deletions.
1 change: 1 addition & 0 deletions .github/workflows/client-R-cran-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-R-cran-package

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-R-git-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-R-git-package

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-c++-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-c++-example

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-c++.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-c++

on:
push:
pull_request:
branches:
- 'main'

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/client-matlab.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-matlab

on:
push:
pull_request:
branches:
- 'main'

Expand All @@ -11,7 +12,7 @@ jobs:

services:
model:
image: linusseelinger/benchmark-analytic-funnel:latest
image: linusseelinger/benchmark-analytic-gaussian-mixture:latest
ports:
- 4243:4243

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-emcee.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-emcee

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-example

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-pymc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-pymc

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-qmcpy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-qmcpy

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-raw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-raw

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python-tinyDA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python-tinyDA

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/client-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: client-python

on:
push:
pull_request:
branches:
- 'main'

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ __pycache__/
build/
.ipynb_checkpoints/
.vscode/
.idea/
kubernetes/setup/secret.txt
46 changes: 45 additions & 1 deletion clients/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ std::vector<std::vector<double>> inputs {{100.0, 18.0}};
The input vector can then be passed into the model.

```
std::vector<std::vector<double>> outputs = client.Evaluate(input);
std::vector<std::vector<double>> outputs = client.Evaluate(inputs);
```

The output of the model evaluation is a `std::vector<std::vector<double>>` containing the output defined by the model.
Expand Down Expand Up @@ -228,6 +228,7 @@ Note that `webwrite` handles all HTTP statuses internally, and is unable to filt
The Julia integration can be installed using Julia's builtin package manager Pkg

```
import Pkg
Pkg.add("UMBridge")
```

Expand Down Expand Up @@ -519,3 +520,46 @@ The remaining arguments are the stopping tolerance (`1e-5`) and a vectorization
We can notice the total number of model evaluations as `cum#evals=449` in the printout of `greedy2_cross`, and the Tensor-Train rank `max_rank=3`. A neat reduction compared to 1089 points in the full 2D grid!

[Full example sources here.](https://github.com/UM-Bridge/umbridge/blob/main/clients/matlab/ttClient.m)


## Sparse Grids Matlab Kit client

The Sparse Grids Matlab Kit (SGMK) provides a Matlab implementation of sparse grids, and can be used for approximating high-dimensional functions and, in particular, for surrogate-model-based uncertainty quantification; for more info, see the [SGMK website](https://sites.google.com/view/sparse-grids-kit).

The SGMK integrates in a very straightforward way with the Matlab UM-Bridge client (it literally takes 1 line!), see e.g. the script [sgmkClient.m](https://github.com/UM-Bridge/umbridge/blob/main/clients/matlab/sgmkClient.m) that can be found in the folder [clients/matlab](https://github.com/UM-Bridge/umbridge/blob/main/clients/matlab).

The script begins by checking whether the SGMK is already in our path, and if not downloads it from the Github repo [here](https://github.com/lorenzo-tamellini/sparse-grids-matlab-kit) and adds it to the path:
```matlab
check_sgmk()
```
The goal of this simple script is to use the SGMK as a high-dimensional quadrature tool to compute the integral of the posterior density function (pdf) defined in the benchmark **analytic-gaussian-mixture**. The pdf in the benchmark is actually not normalized so the integral should be around 3.

To this end, create a model as before:
```matlab
uri = 'http://localhost:4243';
model = HTTPModel(uri, 'posterior','webwrite');
```
then simply wrap `model.evaluate()` in an `@-function` and **you're done**!
```matlab
f = @(y) model.evaluate(y);
```
The script then goes on creating a sparse grid and evaluating `f` over the sparse grid points:
```matlab
N=2;
w=7;
domain = [-5.5 -5;
5 5.5];
knots = {@(n) knots_CC(n,domain(1,1),domain(2,1),'nonprob'), @(n) knots_CC(n,domain(1,2),domain(2,2),'nonprob')};
S = create_sparse_grid(N,w,knots,@lev2knots_doubling);
Sr = reduce_sparse_grid(S);
f_evals = evaluate_on_sparse_grid(f,Sr);
```
and finally, computing the integral given the values of `f` just obtained. Note that the values returned by the container and stored in `f_evals` are actually the log-posterior, so we need to take their exponent before computing the integral:
```matlab
Ev = quadrature_on_sparse_grid(exp(f_evals),Sr)
```
which indeed returns `Ev = 2.9948`, i.e., close to 3 as expected. The script then ends by plotting the sparse grids interpolant of `f` and of `exp(f)`.

[Full example sources here.](https://github.com/UM-Bridge/umbridge/blob/main/clients/matlab/sgmkClient.m)


48 changes: 48 additions & 0 deletions clients/matlab/check_sgmk.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
function check_sgmk()

% An aux function to check and download the sparse grids matlab kit

if exist('create_sparse_grid', 'file')==0
% the sgmk is not found in the current path, so either we don't have it or we are not in the right subfolder

if exist('sparse-grids-matlab-kit', 'dir')==0
% there is no subfolder -> we don't have sgmk. Need to download it (if we haven't yet) and unzip

if exist('sgmk.zip', 'file')==0
% zip not found, let's download it

try
disp('Sparse Grids Matlab Kit not found, downloading from github (https://github.com/lorenzo-tamellini/sparse-grids-matlab-kit/)...');
opts = weboptions;
opts.CertificateFilename=(''); % No idea why this is needed
opts.Timeout = 100; % a larger timeout (in ms, default 5), just in case internet is slow today
websave('sgmk.zip', 'https://github.com/lorenzo-tamellini/sparse-grids-matlab-kit/archive/refs/heads/main.zip', opts);
disp('... done');
catch ME
fprintf('\nAutomatic download from github failed. Try manual download, from either github or project website https://sites.google.com/view/sparse-grids-kit. Download the latest version in .zip and name it sgmk.zip \n\n')
error(ME.identifier,ME.message);
end
end

% now we have the zip, unzip
try
disp('unzipping ...');
unzip('sgmk.zip','sparse-grids-matlab-kit');
disp('done');
catch ME
error('%s. Automatic unzipping failed. Please extract sgmk.zip here', ME.message);
end
end

% ready to add to path. Mind the double folder
cd('sparse-grids-matlab-kit/sparse-grids-matlab-kit-main');
addpath(genpath(pwd))
disp('added Sparse Grids Matlab Kit to path')
cd('../..');

else
% the sgmk is found in the current path, we're good to go

disp('Sparse Grids Matlab Kit is already in Matlab''s path')
end

55 changes: 55 additions & 0 deletions clients/matlab/sgmkClient.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
clear

% Analytic-gaussian-mixture. Use the sparse grids matlab kit as a high-dimensional quadrature tool to compute the
% integral of the posterior density function (pdf) defined in the benchmark. The problem is a bit challenging so even a poor result is
% ok, this is just for testing the client. The pdfs in the benchmark is not normalized so the integral should be
% around 3

% add the Sparse Grids Matlab Kit to your path
check_sgmk()
% run these commands too if you haven't umbridge in your path
% currdir = pwd;
% cd ../../matlab/
% addpath(genpath(pwd))
% cd(currdir)

% also, start the Analytic-gaussian-mixture container
% sudo docker run -it -p 4243:4243 linusseelinger/benchmark-analytic-gaussian-mixture

% uri of the service running the server
uri = 'http://localhost:4243';

% HTTPModel is an object provided by the UM-Bridge Matlab client.
% model = HTTPModel(uri, 'posterior');
model = HTTPModel(uri, 'posterior','webwrite'); % let's use webwrite, it's much faster

% model.evaluate(y) sends a request to the server to evaluate the model at y. Wrap it in an @-function:
f = @(y) model.evaluate(y);

% define the sparse grid. Here we create it a basic one, but it can be as sophisticated as the user wants
N=2;
w=7;
% it is convenient to define the quadrature domain by a matrix D. IF the domain is [a b] x [c d], take each interval
% as a column, so that
% D = [a c ;
% b d ];
domain = [-5.5 -5;
5 5.5];
knots = {@(n) knots_CC(n,domain(1,1),domain(2,1),'nonprob'), @(n) knots_CC(n,domain(1,2),domain(2,2),'nonprob')};
S = create_sparse_grid(N,w,knots,@lev2knots_doubling);
Sr = reduce_sparse_grid(S);
f_evals = evaluate_on_sparse_grid(f,Sr);

% from here on, do whatever UQ analysis you want with the values contained in f_evals. Here we just check that
% the pdf integrates to 3 (the benchmark is not normalized). Note that the values returned by the container
% and stored in f_evals are actually the log-posterior, so we need to take their exponent before computing the integral

Ev = quadrature_on_sparse_grid(exp(f_evals),Sr)


% We also plot the sparse grids interpolant of the function in the benchmark
figure
plot_sparse_grids_interpolant(S,Sr,domain,exp(f_evals),'nb_plot_pts',80)
figure
plot_sparse_grids_interpolant(S,Sr,domain,f_evals,'with_f_values')

62 changes: 41 additions & 21 deletions hpc/LoadBalancer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,48 @@
#include <unistd.h>
#include <limits.h>

#include "lib/umbridge.h"
#include "../lib/umbridge.h"

void create_directory_if_not_existing(std::string directory) {
if (!std::filesystem::is_directory(directory) || !std::filesystem::exists(directory)) {
std::filesystem::create_directory(directory);
}
}

std::string get_hostname() {
char hostname[HOST_NAME_MAX];
gethostname(hostname, HOST_NAME_MAX);
return std::string(hostname);
void clear_url(std::string directory) {
for (auto& file : std::filesystem::directory_iterator(directory)) {
if (std::regex_match(file.path().filename().string(), std::regex("url-\\d+\\.txt"))) {
std::filesystem::remove(file);
}
}
}

void launch_hq_with_alloc_queue() {
std::system("hq server stop &> /dev/null");

std::system("hq server start &");
sleep(1); // Workaround: give the HQ server enough time to start.

// Create HQ allocation queue
std::system("hq_scripts/allocation_queue.sh");
}

const std::vector<std::string> get_model_names() {
// Don't start a client, always use the default job submission script.
HyperQueueJob hq_job("", false, true);

return umbridge::SupportedModels(hq_job.server_url);
}

std::atomic<int32_t> HyperQueueJob::job_count = 0;

int main(int argc, char *argv[])
{

create_directory_if_not_existing("urls");
create_directory_if_not_existing("sub-jobs");
clear_url("urls");

launch_hq_with_alloc_queue();

// Read environment variables for configuration
char const *port_cstr = std::getenv("PORT");
Expand All @@ -41,15 +64,15 @@ int main(int argc, char *argv[])
port = atoi(port_cstr);
}

// Start: Instaltialize multiple LB classes for multiple models on the regular server
char const *delay_cstr = std::getenv("HQ_SUBMIT_DELAY_MS");
if (delay_cstr != NULL)
{
hq_submit_delay_ms = atoi(delay_cstr);
}
std::cout << "HQ_SUBMIT_DELAY_MS set to " << hq_submit_delay_ms << std::endl;

// start a SLURM job for single request
const std::string job_id = submitJob("sbatch model.slurm");
const std::string server_url = readUrl("./urls/url-" + job_id + ".txt"); // read server url from txt file
// May use $SLURM_LOCALID in a .slurm file later
std::cout << "Hosting sub-server at : " << server_url << std::endl;
// List supported models
std::vector<std::string> model_names = umbridge::SupportedModels(server_url);
// Initialize load balancer for each available model on the model server.
const std::vector<std::string> model_names = get_model_names();

std::vector<LoadBalancer> LB_vector;
for (auto model_name : model_names)
Expand All @@ -58,14 +81,11 @@ int main(int argc, char *argv[])
LB_vector.emplace_back(LoadBalancer{model_name});
}

// End: Instaltialize multiple LB classes for multiple models on the regular server

// Create a new vector of pointers to LB_vector
// umbridge::serveModels currently only accepts raw pointers.
std::vector<umbridge::Model *> LB_ptr_vector(LB_vector.size());
std::transform(LB_vector.begin(), LB_vector.end(), LB_ptr_vector.begin(),
[](LoadBalancer& obj) { return &obj; });

std::cout << "Load balancer running on host " << get_hostname()
<< " and bound to 0.0.0.0:" << port << std::endl;
umbridge::serveModels(LB_ptr_vector, "0.0.0.0", port, false);
}
std::cout << "Load balancer running port" << port << std::endl;
umbridge::serveModels(LB_ptr_vector, "0.0.0.0", port, true, false);
}
Loading

0 comments on commit 3c7d11c

Please sign in to comment.