Skip to content

Commit 7c8312b

Browse files
added example, deleted export of small functions
1 parent 2f1ff05 commit 7c8312b

23 files changed

+651
-121
lines changed

NAMESPACE

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
# Generated by roxygen2: do not edit by hand
22

33
export(BayesianOptimization)
4-
export(CheckBounds)
5-
export(MinMaxScale)
6-
export(RandParams)
7-
export(UnMMScale)
8-
export(applyCluster)
9-
export(applyNoise)
10-
export(assignKern)
11-
export(calcAcq)
12-
export(maxAcq)
13-
export(updateGP)
144
import(foreach)
155
importFrom(GauPro,Exponential)
166
importFrom(GauPro,GauPro_kernel_model)

R/BayesianOptimization.R

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -73,69 +73,87 @@
7373
#' \item{BestPars}{The best parameter set at each iteration}
7474
#' @references Jasper Snoek, Hugo Larochelle, Ryan P. Adams (2012) \emph{Practical Bayesian Optimization of Machine Learning Algorithms}
7575
#' @examples
76+
#' # Example 1 - Optimization of a Linear Function
77+
#' scoringFunction <- function(x) {
78+
#' a <- exp(-(2-x)^2)*1.5
79+
#' b <- exp(-(4-x)^2)*2
80+
#' c <- exp(-(6-x)^2)*1
81+
#' return(list(Score = a+b+c))
82+
#' }
83+
#'
84+
#' bounds <- list(x = c(0,8))
85+
#'
86+
#' Results <- BayesianOptimization(
87+
#' FUN = scoringFunction
88+
#' , bounds = bounds
89+
#' , initPoints = 5
90+
#' , nIters = 8
91+
#' , gsPoints = 10
92+
#' )
93+
#'
7694
#' \dontrun{
95+
#' # Example 2 - Hyperparameter Tuning in xgboost
7796
#' library("xgboost")
78-
#' library("ParBayesianOptimization")
7997
#'
8098
#' data(agaricus.train, package = "xgboost")
8199
#'
82-
#' Folds <- list( Fold1 = as.integer(seq(1,nrow(agaricus.train$data),by = 3))
83-
#' , Fold2 = as.integer(seq(2,nrow(agaricus.train$data),by = 3))
84-
#' , Fold3 = as.integer(seq(3,nrow(agaricus.train$data),by = 3)))
100+
#' Folds <- list( Fold1 = as.integer(seq(1,nrow(agaricus.train$data),by = 3))
101+
#' , Fold2 = as.integer(seq(2,nrow(agaricus.train$data),by = 3))
102+
#' , Fold3 = as.integer(seq(3,nrow(agaricus.train$data),by = 3)))
85103
#'
86104
#' scoringFunction <- function(max_depth, min_child_weight, subsample) {
87105
#'
88106
#' dtrain <- xgb.DMatrix(agaricus.train$data,label = agaricus.train$label)
89107
#'
90108
#' Pars <- list( booster = "gbtree"
91-
#' , eta = 0.01
92-
#' , max_depth = max_depth
93-
#' , min_child_weight = min_child_weight
94-
#' , subsample = subsample
95-
#' , objective = "binary:logistic"
96-
#' , eval_metric = "auc")
109+
#' , eta = 0.01
110+
#' , max_depth = max_depth
111+
#' , min_child_weight = min_child_weight
112+
#' , subsample = subsample
113+
#' , objective = "binary:logistic"
114+
#' , eval_metric = "auc")
97115
#'
98-
#' xgbcv <- xgb.cv(params = Pars,
99-
#' data = dtrain
100-
#' , nround = 100
101-
#' , folds = Folds
102-
#' , prediction = TRUE
103-
#' , showsd = TRUE
104-
#' , early_stopping_rounds = 5
105-
#' , maximize = TRUE
106-
#' , verbose = 0)
116+
#' xgbcv <- xgb.cv( params = Pars
117+
#' , data = dtrain
118+
#' , nround = 100
119+
#' , folds = Folds
120+
#' , prediction = TRUE
121+
#' , showsd = TRUE
122+
#' , early_stopping_rounds = 5
123+
#' , maximize = TRUE
124+
#' , verbose = 0)
107125
#'
108-
#' return(list(Score = max(xgbcv$evaluation_log$test_auc_mean)
109-
#' , nrounds = xgbcv$best_iteration
126+
#' return(list( Score = max(xgbcv$evaluation_log$test_auc_mean)
127+
#' , nrounds = xgbcv$best_iteration
110128
#' )
111129
#' )
112130
#' }
113131
#'
114-
#'
115-
#' bounds <- list( max_depth = c(2L, 10L)
116-
#' , min_child_weight = c(1, 100)
117-
#' , subsample = c(0.25, 1))
132+
#' bounds <- list(max_depth = c(2L, 10L)
133+
#' , min_child_weight = c(1, 100)
134+
#' , subsample = c(0.25, 1))
118135
#'
119136
#' kern <- "Matern52"
120137
#'
121138
#' acq <- "ei"
122139
#'
123-
#' ScoreResult <- BayesianOptimization(FUN = scoringFunction
124-
#' , bounds = bounds
125-
#' , initPoints = 10
126-
#' , bulkNew = 1
127-
#' , nIters = 12
128-
#' , kern = kern
129-
#' , acq = acq
130-
#' , kappa = 2.576
131-
#' , verbose = 1
132-
#' , parallel = FALSE)
140+
#' ScoreResult <- BayesianOptimization(
141+
#' FUN = scoringFunction
142+
#' , bounds = bounds
143+
#' , initPoints = 10
144+
#' , bulkNew = 1
145+
#' , nIters = 12
146+
#' , kern = kern
147+
#' , acq = acq
148+
#' , kappa = 2.576
149+
#' , verbose = 1
150+
#' , parallel = FALSE
151+
#' , gsPoints = 50)
133152
#' }
134153
#' @importFrom data.table data.table setDT setcolorder := as.data.table copy .I
135154
#' @importFrom utils head
136155
#' @importFrom GauPro GauPro_kernel_model Matern52 Matern32 Exponential Gaussian
137156
#' @export
138-
139157
BayesianOptimization <- function(
140158
FUN
141159
, bounds

R/SmallFuncs.R

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#' @param bounds the bounds list
1515
#' @importFrom data.table between
1616
#' @return the number of values that are outside the bounds/
17-
#' @export
1817
CheckBounds <- function(x, Table, bounds) sum(!between(Table[[x]], lower = bounds[[x]][[1]], upper = bounds[[x]][[2]]))
1918

2019

@@ -29,7 +28,6 @@ CheckBounds <- function(x, Table, bounds) sum(!between(Table[[x]], lower = bound
2928
#' @importFrom stats runif
3029
#' @return a data.table of random parameters
3130
#' @keywords internal
32-
#' @export
3331
RandParams <- function(x, Rpoints, boundsDT) {
3432

3533
B <- boundsDT[get("N") == x,]
@@ -55,7 +53,6 @@ RandParams <- function(x, Rpoints, boundsDT) {
5553
#' @param bounds the original bounds list
5654
#' @return a data.table the same length as \code{table} with scaled parameters
5755
#' @keywords internal
58-
#' @export
5956
MinMaxScale <- function(x, table, boundsDT) {
6057
B <- boundsDT[get("N") == x,]
6158
(table[[x]]-B$L) / (B$U-B$L)
@@ -72,7 +69,6 @@ MinMaxScale <- function(x, table, boundsDT) {
7269
#' @param bounds the original bounds list
7370
#' @return a data.table the same length as \code{table} with un-scaled parameters
7471
#' @keywords internal
75-
#' @export
7672
UnMMScale <- function(x, table, boundsDT) {
7773
B <- boundsDT[get("N") == x,]
7874

@@ -91,7 +87,6 @@ UnMMScale <- function(x, table, boundsDT) {
9187
#' @param beta the log10(theta) the lengthscale parameter
9288
#' @return an GauPro_kernel_beta R6 class
9389
#' @keywords internal
94-
#' @export
9590
assignKern <- function(kern,beta) {
9691

9792
if(kern == "Matern32"){kern <- Matern32$new(beta)

R/applyCluster.R

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#' @importFrom dbscan dbscan
88
#' @importFrom data.table fintersect
99
#' @return the number of values that are outside the bounds/
10-
#' @export
1110

1211
applyCluster <- function(e = parent.frame()) {
1312

@@ -21,7 +20,7 @@ applyCluster <- function(e = parent.frame()) {
2120

2221
} else{
2322

24-
Clust <- dbscan(Lo2,eps = length(Lo2)*sqrt(2)/e$convThresh, minPts = 1)
23+
Clust <- dbscan(Lo2,eps = length(Lo2)*sqrt(2)/1e3, minPts = 1)
2524

2625
Lo2[,"Cluster" := Clust$cluster]
2726
clusterPoints <- copy(Lo2[Lo2[,.I[which.max(get("GP_Utility"))], by = get("Cluster")]$V1])

R/applyNoise.R

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#' @importFrom stats rbeta
1111
#' @return a data.table with the same number of rows as \code{table} with noise added
1212
#' @keywords internal
13-
#' @export
1413
#'
1514
applyNoise <- function( x
1615
, table
@@ -36,4 +35,3 @@ applyNoise <- function( x
3635
return(Vec)
3736

3837
}
39-

R/calcAcq.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#' @importFrom stats dnorm pnorm
1313
#' @return The acquisition function value.
1414
#' @keywords internal
15-
#' @export
1615

1716
calcAcq <- function(Params, GP, acq, y_max, kappa, eps) {
1817
# Utility Function Type

R/maxAcq.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#' @importFrom data.table as.data.table
1717
#' @import foreach
1818
#' @keywords internal
19-
#' @export
2019

2120
maxAcq <- function(GP, TryOver, acq = "ucb", y_max, kappa, eps, parallel, ParMethod, convThresh) {
2221

R/updateGP.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#' @param scaleList list of scaling parameters for the responses
1111
#' @return A data table of local optimums.
1212
#' @keywords internal
13-
#' @export
1413

1514
updateGP <- function(GP, kern, X, Z, acq, scaleList, parallel) {
1615

README.md

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,37 @@ Idealy, we would use the information from prior model evaluations to guide us in
2828
4. New parameter-score pairs are found
2929
5. Repeat steps 2-4 until some stopping criteria is met
3030

31+
Graphical Intuition
32+
-------------------
33+
34+
As an example, let's say we are only tuning 1 hyperparameter in an xgboost model, min\_child weight in (0,1). We have initialized the process by randomly sampling the scoring function 6 times, and get the following results:
35+
36+
| min\_child\_weight| Score|
37+
|-------------------:|----------:|
38+
| 0.6280082| 0.7133457|
39+
| 0.3276477| 0.8655448|
40+
| 0.7486012| 0.6814730|
41+
| 0.2425469| 1.0000000|
42+
| 0.0724098| 0.1308284|
43+
| 0.1579683| 0.5733343|
44+
45+
How do we go about determining the best min\_child\_weight to try next? As it turns out, Gaussian processes can give us a very good definition for our prior distribution. Fitting a Gaussian process to the data above (indexed by min\_child\_weight), we can see the expected value accross our parameter bounds, as well as the uncertainty at different points:
46+
47+
![](vignettes/GPpredictions.png)
48+
49+
Before we can select our next candidate parameter to run the scoring function on, we need to determine how we define a "good" parameter inside this prior distribution. This is done by maximizing different functions within the Gaussian process. There are several functions to choose from:
50+
51+
- Upper Confidence Bound (ucb)
52+
- Probability Of Improvement (poi)
53+
- Expected Improvement (ei)
54+
- Expected Improvement Per Second (eips)
55+
56+
Continuing the example, we select to find the min\_child\_weight which maximizes the expected improvement according to the Gaussian process. As you can see, there are several good candidates:
57+
58+
![](vignettes/expectedImprovement.png)
59+
60+
An advanced feature of ParBayesianOptimization, which you can read about in the vignette advancedFeatures, describes how to use the `minClusterUtility` parameter to search over the different local maximums shown above. If not specified, only the global maximum would be sampled.
61+
3162
Practical Example
3263
-----------------
3364

@@ -110,12 +141,12 @@ ScoreResult <- BayesianOptimization(FUN = scoringFunction
110141
#>
111142
#> Starting round number 1
112143
#> 1) Fitting Gaussian process...
113-
#> 2) Running global optimum search...
144+
#> 2) Running local optimum search...
114145
#> 3) Running scoring function 1 times in 1 thread(s)...
115146
#>
116147
#> Starting round number 2
117148
#> 1) Fitting Gaussian process...
118-
#> 2) Running global optimum search...
149+
#> 2) Running local optimum search...
119150
#> 3) Running scoring function 1 times in 1 thread(s)...
120151
```
121152

@@ -124,24 +155,24 @@ The console informs us that the process initialized by running `scoringFunction`
124155
``` r
125156
ScoreResult$ScoreDT
126157
#> Iteration max_depth min_child_weight subsample Elapsed Score nrounds
127-
#> 1: 0 8 96 0.5935750 0.70 0.9797757 32
128-
#> 2: 0 4 87 0.7504342 0.16 0.9779723 1
129-
#> 3: 0 2 76 0.9639782 0.12 0.9779723 1
130-
#> 4: 0 8 48 0.8497707 0.22 0.9889367 3
131-
#> 5: 0 6 17 0.3089911 0.58 0.9951817 19
132-
#> 6: 0 9 24 0.7529264 0.67 0.9974167 23
133-
#> 7: 0 7 1 0.3099921 0.31 0.9986540 5
134-
#> 8: 0 4 49 0.8077531 0.33 0.9901100 8
135-
#> 9: 0 3 35 0.9579958 0.16 0.9900173 2
136-
#> 10: 0 3 22 0.8018554 0.36 0.9953687 15
137-
#> 11: 1 10 1 0.8609687 0.24 0.9984757 1
138-
#> 12: 2 8 1 0.6257481 0.42 0.9986603 8
158+
#> 1: 0 3 21 0.4527621 0.37 0.9947540 10
159+
#> 2: 0 4 63 0.6965777 0.21 0.9782343 1
160+
#> 3: 0 3 45 0.9528065 0.27 0.9874717 3
161+
#> 4: 0 2 54 0.8177109 0.30 0.9869460 8
162+
#> 5: 0 10 20 0.7861882 2.53 0.9991937 97
163+
#> 6: 0 10 12 0.2594141 0.72 0.9962943 16
164+
#> 7: 0 10 6 0.4839067 0.57 0.9991430 9
165+
#> 8: 0 7 58 0.5443817 0.18 0.9779723 1
166+
#> 9: 0 10 22 0.5056945 1.79 0.9970410 52
167+
#> 10: 0 10 27 0.6718752 0.39 0.9943417 6
168+
#> 11: 1 10 1 0.9089677 0.28 0.9984757 1
169+
#> 12: 2 10 1 0.6652759 0.43 0.9986620 5
139170
```
140171

141172
``` r
142173
ScoreResult$BestPars
143174
#> Iteration max_depth min_child_weight subsample Score nrounds elapsedSecs
144-
#> 1: 0 7 1 0.3099921 0.9986540 5 5 secs
145-
#> 2: 1 7 1 0.3099921 0.9986540 5 13 secs
146-
#> 3: 2 8 1 0.6257481 0.9986603 8 20 secs
175+
#> 1: 0 10 20 0.7861882 0.9991937 97 8 secs
176+
#> 2: 1 10 20 0.7861882 0.9991937 97 18 secs
177+
#> 3: 2 10 20 0.7861882 0.9991937 97 28 secs
147178
```

0 commit comments

Comments
 (0)