|
1 | | -# dpl |
| 1 | + |
| 2 | +# kerasnip |
| 3 | + |
| 4 | +<!-- badges: start --> |
| 5 | +[](https://lifecycle.r-lib.org/articles/stages.html#experimental) |
| 6 | +[](https://github.com/davidrsch/kerasnip/actions/workflows/R-CMD-check.yaml) |
| 7 | +<!-- badges: end --> |
| 8 | + |
| 9 | +The goal of `kerasnip` is to provide a seamless bridge between the `keras` and `tidymodels` ecosystems. It allows for the dynamic creation of `parsnip` model specifications for Keras models, making them fully compatible with `tidymodels` workflows. |
| 10 | + |
| 11 | +## Installation |
| 12 | + |
| 13 | +You can install the development version of `kerasnip` from GitHub with: |
| 14 | + |
| 15 | +```r |
| 16 | +# install.packages("pak") |
| 17 | +pak::pak("davidrsch/kerasnip") |
| 18 | +``` |
| 19 | + |
| 20 | +## Example |
| 21 | + |
| 22 | +### Example: Building a Sequential MLP from Layer Blocks |
| 23 | + |
| 24 | +This example shows the core `kerasnip` workflow for building a model from modular "layer blocks". We will: |
| 25 | +1. Define reusable blocks of Keras layers. |
| 26 | +2. Create a model specification from these blocks. |
| 27 | +3. Fit the model with a fixed architecture. |
| 28 | + |
| 29 | +```r |
| 30 | +library(kerasnip) |
| 31 | +library(tidymodels) |
| 32 | +library(keras3) |
| 33 | + |
| 34 | +# 1. Define Keras layer blocks |
| 35 | +# Each block is a function that takes a Keras model object and adds layers. |
| 36 | +# The first block in the sequence is responsible for initializing the model. |
| 37 | +mlp_input_block <- function(model, input_shape) { |
| 38 | + keras_model_sequential(input_shape = input_shape) |
| 39 | +} |
| 40 | + |
| 41 | +mlp_dense_block <- function(model, units = 32) { |
| 42 | + model |> |
| 43 | + layer_dense(units = units, activation = "relu") |
| 44 | +} |
| 45 | + |
| 46 | +mlp_output_block <- function(model) { |
| 47 | + model |> |
| 48 | + layer_dense(units = 1) |
| 49 | +} |
| 50 | + |
| 51 | +# 2. Create a spec from the layer blocks |
| 52 | +# This creates a new model function, `basic_mlp()`, in your environment. |
| 53 | +create_keras_spec( |
| 54 | + model_name = "basic_mlp", |
| 55 | + layer_blocks = list( |
| 56 | + input = mlp_input_block, |
| 57 | + dense = mlp_dense_block, |
| 58 | + output = mlp_output_block |
| 59 | + ), |
| 60 | + mode = "regression" |
| 61 | +) |
| 62 | + |
| 63 | +# 3. Use the generated spec to define and fit a model |
| 64 | +# We can set the number of dense layers (`num_dense`) and their parameters |
| 65 | +# (`dense_units`). |
| 66 | +spec <- basic_mlp( |
| 67 | + num_dense = 2, |
| 68 | + dense_units = 64, |
| 69 | + epochs = 50, |
| 70 | + learn_rate = 0.01 |
| 71 | +) |> |
| 72 | + set_engine("keras") |
| 73 | + |
| 74 | +# 4. Fit the model within a tidymodels workflow |
| 75 | +rec <- recipe(mpg ~ ., data = mtcars) |> |
| 76 | + step_normalize(all_numeric_predictors()) |
| 77 | + |
| 78 | +wf <- workflow() |> |
| 79 | + add_recipe(rec) |> |
| 80 | + add_model(spec) |
| 81 | + |
| 82 | +set.seed(123) |
| 83 | +fit_obj <- fit(wf, data = mtcars) |
| 84 | + |
| 85 | +# 5. Make predictions |
| 86 | +predictions <- predict(fit_obj, new_data = mtcars[1:5, ]) |
| 87 | +print(predictions) |
| 88 | +#> # A tibble: 5 × 1 |
| 89 | +#> .pred |
| 90 | +#> <dbl> |
| 91 | +#> 1 22.6 |
| 92 | +#> 2 20.9 |
| 93 | +#> 3 26.1 |
| 94 | +#> 4 19.7 |
| 95 | +#> 5 17.8 |
| 96 | +``` |
| 97 | + |
| 98 | +### Example: Tuning a Sequential MLP Architecture |
| 99 | + |
| 100 | +This example demonstrates how to tune the number of dense layers and the rate of a final dropout layer, showcasing how to tune both architecture and block hyperparameters simultaneously. |
| 101 | + |
| 102 | +```r |
| 103 | +library(kerasnip) |
| 104 | +library(tidymodels) |
| 105 | +library(keras3) |
| 106 | + |
| 107 | +# 1. Define Keras layer blocks for a tunable MLP |
| 108 | +mlp_input_block <- function(model, input_shape) { |
| 109 | + keras_model_sequential(input_shape = input_shape) |
| 110 | +} |
| 111 | + |
| 112 | +tunable_dense_block <- function(model, units = 32) { |
| 113 | + model |> layer_dense(units = units, activation = "relu") |
| 114 | +} |
| 115 | + |
| 116 | +tunable_dropout_block <- function(model, rate = 0.2) { |
| 117 | + model |> layer_dropout(rate = rate) |
| 118 | +} |
| 119 | + |
| 120 | +mlp_output_block <- function(model) { |
| 121 | + model |> layer_dense(units = 1) |
| 122 | +} |
| 123 | + |
| 124 | +# 2. Create a spec from the layer blocks |
| 125 | +create_keras_spec( |
| 126 | + model_name = "tunable_mlp", |
| 127 | + layer_blocks = list( |
| 128 | + input = mlp_input_block, |
| 129 | + dense = tunable_dense_block, |
| 130 | + dropout = tunable_dropout_block, |
| 131 | + output = mlp_output_block |
| 132 | + ), |
| 133 | + mode = "regression" |
| 134 | +) |
| 135 | + |
| 136 | +# 3. Define a tunable model specification |
| 137 | +tune_spec <- tunable_mlp( |
| 138 | + num_dense = tune(), |
| 139 | + dense_units = tune(), |
| 140 | + num_dropout = 1, |
| 141 | + dropout_rate = tune(), |
| 142 | + epochs = 20 |
| 143 | +) |> |
| 144 | + set_engine("keras") |
| 145 | + |
| 146 | +# 4. Set up a tuning workflow |
| 147 | +rec <- recipe(mpg ~ ., data = mtcars) |> |
| 148 | + step_normalize(all_numeric_predictors()) |
| 149 | + |
| 150 | +wf_tune <- workflow() |> |
| 151 | + add_recipe(rec) |> |
| 152 | + add_model(tune_spec) |
| 153 | + |
| 154 | +# Define the tuning grid. |
| 155 | +params <- extract_parameter_set_dials(wf_tune) |> |
| 156 | + update( |
| 157 | + num_dense = dials::num_terms(c(1, 3)), |
| 158 | + dense_units = dials::hidden_units(c(8, 64)), |
| 159 | + dropout_rate = dials::dropout(c(0.1, 0.5)) |
| 160 | + ) |
| 161 | +grid <- grid_regular(params, levels = 2) |
| 162 | + |
| 163 | +# 5. Run the tuning |
| 164 | +set.seed(456) |
| 165 | +folds <- vfold_cv(mtcars, v = 3) |
| 166 | + |
| 167 | +tune_res <- tune_grid( |
| 168 | + wf_tune, |
| 169 | + resamples = folds, |
| 170 | + grid = grid |
| 171 | +) |
| 172 | + |
| 173 | +# 6. Show the best architecture |
| 174 | +show_best(tune_res, metric = "rmse") |
| 175 | +#> # A tibble: 5 × 7 |
| 176 | +#> num_dense dense_units dropout_rate .metric .estimator .mean .config |
| 177 | +#> <int> <int> <dbl> <chr> <chr> <dbl> <chr> |
| 178 | +#> 1 1 64 0.1 rmse standard 2.92 Preprocessor1_Model02 |
| 179 | +#> 2 1 64 0.5 rmse standard 3.02 Preprocessor1_Model08 |
| 180 | +#> 3 3 64 0.1 rmse standard 3.15 Preprocessor1_Model04 |
| 181 | +#> 4 1 8 0.1 rmse standard 3.20 Preprocessor1_Model01 |
| 182 | +#> 5 3 8 0.1 rmse standard 3.22 Preprocessor1_Model03 |
| 183 | +``` |
0 commit comments