ObjectVision / GeoDMS

Source code for the GeoDMS software
https://www.geodms.nl/
Other
8 stars 1 forks source link

GeoDMS R Integration #659

Open BPJandree opened 9 months ago

BPJandree commented 9 months ago

Hi Maarten!

Ik sprak Chris en Eric eerder vandaag. Momenteel is het zo dat die suitability maps gegenereerd worden door tamelijk inflexibele parametrische formules van het type

suitability = logit(b1*hoogte + b2 * afstandTot)

Dit wordt direct in geoDMS ingeprogrammeerd en b1 en b2 worden dan hardcoded ingevoerd.

Het zou handig zijn als geoDMS bepaalde berekeningen in een R (of Python) environment kan laten doen en de uitkomsten dan terug kan halen naar de geoDMS environment. Dit maakt het volgende dan mogelijk:

suitability = Rmodel(data=X)

waar X een matrix is (hoogte, afstandTot) en Rmodel() een wrapper is om een R functie. In R zijn alle modellen (lineaire regressie, logit, Random Forest, Neural Networks, XGBoost etc etc) allemaal gestandardizeerd en kan je er het volgende mee:

schattingen = predict(model_obect, newdata=X)

model_obect kan daarmee van alles zijn.

kijk maar naar de volgende code:

> # random data
> df = data.frame(y=rnorm(100), x1=rnorm(100), x2=rnorm(100))
> 
> # modellen bouwen
> linear = lm(y~., df)
> 
> random_forest = randomForest(y~., df)
> 
> 
> 
> # toepassing gebruikt dezelfde interface
> linear_suitability = predict(linear, newdata = df)
> rf_suitability = predict(random_forest, newdata = df)
> 
> # output is zelfde format
> head(linear_suitability)
         1          2          3          4          5          6 
0.18118969 0.10888232 0.15146227 0.20488109 0.09091855 0.14044853 
> 
> head(rf_suitability)
         1          2          3          4          5          6 
-0.1088751 -0.1391017  0.7869346  0.3682675 -0.1115316  1.3629448 

bovendien kun je die R modellen op je disk opslaan. Er is daar een functie voor saveRDS(object) dat serialized het object en slaat dat op. Je kan dan de volgende code gebruiken in een lege R sessie:


model_object <- readRDS(model_locatie_op_hd)
predict(model_object, newdata=X)

Dit zou niet zo moeilijk moeten zijn. I k geloof dat jij ooit zei dat geoDMS in c++ is geschreven? Deze integratie is goed uitgewerkt: https://www.rcpp.org/

dit zou moeten werken:


#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector calculateMeanInR(NumericVector x) {
  Environment base("package:base");
  Function mean_r = base["mean"];
  return mean_r(x);
}

int main() {
  NumericVector data = {1.2, 2.3, 3.4, 4.5, 5.6};

  NumericVector mean = calculateMeanInR(data);

  Rcout << "Mean calculated in R: " << mean << std::endl;

  return 0;
}

Het enige wat dus nodig is, is een functie die een data matrix X en een bestandslocatie file in geoDMS naar een R functie stuurt die dan model<-readRDS(file) doet om een model te laden, en vervolgens predict(model, newdata=X) doet om de schattingen te genereren die terug naar geoDMS moeten.

Cheers

eoudejans commented 9 months ago

The OP given c++ example seems a valid starting point for using Rcpp.

Two routes have been explored to get the example to work from the geodms build environment:

  1. Using Rcpp as git submodule header only, with included header and lib files of R-4.3.3
  2. Using Rcpp binaries found on CRAN

From these two attempts it turns out that Rcpp requires the same build toolchain in which R is build. This is also stated by the author of Rcpp in paragraph 2.9: image

Furthermore, Rcpp requires c++ standard library version << 17 as the std::unary_function is removed from version 17 onwards, this can easily be circumvented however.

BPJandree commented 8 months ago

I'm not a full blown c++ expert but here's a thought from my end (and I may be wrong)

Using Rcpp as a Git Submodule (Header-Only, with Included Header and Lib Files of R-4.3.3)

Pros:

Cons:

Using Rcpp Binaries Found on CRAN

Pros:

Cons:

My advice

If you can make integration work without needing to fixate on a specific version of Rcpp or R, and custom modifications aren't required to interact with geoDMS, I suggest opting for Rcpp binaries from CRAN. The argument concerning overhead and maintenance takes probably weights strongly given the relatively small size of the geoDMS community. Also geoDMS is not really intended for light-weight real-time applications that you want to run with little dead-weight code as possible. The CRAN files should also simplifies the setup process and make the overall task easier. Finally, the continuous and rapid advancements in AI/ML are reflected by the frequent release of new R packages, a compelling reason for this integration is the opportunity to tap into these developments within the R community.

MaartenHilferink commented 8 months ago

We kunnen het linken aan Rcpp en het in geheugen door geven van de matrix X en vector y overslaan als we die ook door de GeoDms in een file opslaan en via ShellExecute of CMD R aanroepen met een script-naam waarbij filename worden doorgegeven:

Dit vereist enkel het kunnen starten van R via de bestaande Exec functie, en behoeft wat aandacht mb.t. synchronisatie (volgorde) van rekenvoorwerk, data schrijfwerk, Exec uitvoeren, en resultaten lezen en verder verwerken in GeoDms.

Deze route lijkt me veel makkelijker dan linken, want kan met huidige GeoDms en toolchain; installatie (van R) laten we dan aan gebruikers over; bestaande functionaliteit en de overhead van GeoDms-memory -> file-format -> R-memory is tegenwoordig beperkter dan in de tijd van disk-drives en gebrek aan memory-caches.

Aandachtspunten en beslispunten:

Het synchronisatie issue is zeker opgelost als eea vanuit een batch file (.bat of .cmd) in stappen wordt aangestuurd:

EstimateModel.cmd:

  1. bereken en schrijf [y:X0] met GeoDMS naar file0
  2. schat model in R met input file0 en output modelfile

ApplyModel.cmd:

  1. bereken en schrijf [X1] in GeoDMS naar file1
  2. 'predict' in R met input file1 en modelfile en output file_y
  3. bereken allocatie in GeoDMS met input file_y.