
Note: This package is under active development. The API may change in future versions.
{kindling} bridges the gap between
{torch} and {tidymodels}, offering a
streamlined interface for building, training, and tuning deep learning
models within the familiar tidymodels ecosystem.
Whether you’re prototyping neural architectures or deploying
production models, {kindling} minimizes boilerplate code
while preserving the flexibility of {torch}. It works
seamlessly with {parsnip}, {recipes}, and
{workflows} to bring deep learning into your existing
modeling pipeline.
parsnip through
set_engine("kindling"){tidymodels} workflows and
pipelines{torch} tensors{torch}
implementationsYou can install {kindling} on CRAN:
install.packages('kindling')Or install the development version from GitHub:
# install.packages("pak")
pak::pak("joshuamarie/kindling"){kindling} leverages R’s metaprogramming capabilities
through code generation. Generated
torch::nn_module expressions power the training functions,
which in turn serve as engines for {tidymodels}
integration. This architecture gives you flexibility to work at whatever
abstraction level suits your task.
library(kindling)
#>
#> Attaching package: 'kindling'
#> The following object is masked from 'package:base':
#>
#> argstorch::nn_moduleAt the lowest level, you can generate raw
torch::nn_module code for maximum customization. Functions
ending with _generator return unevaluated expressions you
can inspect, modify, or execute.
Here’s how to generate a feedforward network specification:
ffnn_generator(
nn_name = "MyFFNN",
hd_neurons = c(64, 32, 16),
no_x = 10,
no_y = 1,
activations = 'relu'
)
#> torch::nn_module("MyFFNN", initialize = function ()
#> {
#> self$fc1 = torch::nn_linear(10, 64, bias = TRUE)
#> self$fc2 = torch::nn_linear(64, 32, bias = TRUE)
#> self$fc3 = torch::nn_linear(32, 16, bias = TRUE)
#> self$out = torch::nn_linear(16, 1, bias = TRUE)
#> }, forward = function (x)
#> {
#> x = self$fc1(x)
#> x = torch::nnf_relu(x)
#> x = self$fc2(x)
#> x = torch::nnf_relu(x)
#> x = self$fc3(x)
#> x = torch::nnf_relu(x)
#> x = self$out(x)
#> x
#> })This creates a three-hidden-layer network (64 - 32 - 16 neurons) that takes 10 inputs and produces 1 output. Each hidden layer uses ReLU activation, while the output layer remains “untransformed”.
Skip the code generation and train models directly with your data.
This approach handles all the {torch} boilerplate
internally.
Let’s classify iris species:
model = ffnn(
Species ~ .,
data = iris,
hidden_neurons = c(10, 15, 7),
activations = act_funs(relu, softshrink = args(lambd = 0.5), elu),
loss = "cross_entropy",
epochs = 100
)
model======================= Feedforward Neural Networks (MLP) ======================
-- FFNN Model Summary ----------------------------------------------------------
----------------------------------------------------------------------
NN Model Type : FFNN n_predictors : 4
Number of Epochs : 100 n_response : 3
Hidden Layer Units : 10, 15, 7 Device : cpu
Number of Hidden Layers : 3 :
Pred. Type : classification :
----------------------------------------------------------------------
-- Activation function ---------------------------------------------------------
-------------------------------------------------
1st Layer {10} : relu
2nd Layer {15} : softshrink(lambd = 0.5)
3rd Layer {7} : elu
Output Activation : No act function applied
-------------------------------------------------
The predict() method offers flexible prediction behavior
through its newdata argument:
Without new data — predictions default to the training set:
predict(model) |>
(\(x) table(actual = iris$Species, predicted = x))()
#> predicted
#> actual setosa versicolor virginica
#> setosa 50 0 0
#> versicolor 0 47 3
#> virginica 0 1 49With new data — simply pass a data frame:
sample_iris = dplyr::slice_sample(iris, n = 10, by = Species)
predict(model, newdata = sample_iris) |>
(\(x) table(actual = sample_iris$Species, predicted = x))()
#> predicted
#> actual setosa versicolor virginica
#> setosa 10 0 0
#> versicolor 0 9 1
#> virginica 0 1 9Work with neural networks just like any other {parsnip}
model. This unlocks the entire {tidymodels} toolkit for
preprocessing, cross-validation, and model evaluation.
# library(kindling)
# library(parsnip)
# library(yardstick)
box::use(
kindling[mlp_kindling, rnn_kindling, act_funs, args],
parsnip[fit, augment],
yardstick[metrics],
mlbench[Ionosphere] # data(Ionosphere, package = "mlbench")
)
ionosphere_data = Ionosphere[, -2]
# Train a feedforward network with parsnip
mlp_kindling(
mode = "classification",
hidden_neurons = c(128, 64),
activations = act_funs(relu, softshrink = args(lambd = 0.5)),
epochs = 100
) |>
fit(Class ~ ., data = ionosphere_data) |>
augment(new_data = ionosphere_data) |>
metrics(truth = Class, estimate = .pred_class)
#> # A tibble: 2 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 accuracy binary 0.989
#> 2 kap binary 0.975
# Or try a recurrent architecture (demonstrative example with tabular data)
rnn_kindling(
mode = "classification",
hidden_neurons = c(128, 64),
activations = act_funs(relu, elu),
epochs = 100,
rnn_type = "gru"
) |>
fit(Class ~ ., data = ionosphere_data) |>
augment(new_data = ionosphere_data) |>
metrics(truth = Class, estimate = .pred_class)
#> # A tibble: 2 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 accuracy binary 0.641
#> 2 kap binary 0This functionality is available, but still not fully optimized.
The roadmap includes full support for hyperparameter tuning via
{tune} with searchable parameters:
Here’s an example:
box::use(
kindling[
mlp_kindling, hidden_neurons, activations, output_activation, grid_depth
],
parsnip[fit, augment],
recipes[recipe],
workflows[workflow, add_recipe, add_model],
rsample[vfold_cv],
tune[tune_grid, tune, select_best, finalize_workflow],
dials[grid_random],
yardstick[accuracy, roc_auc, metric_set, metrics]
)
mlp_tune_spec = mlp_kindling(
mode = "classification",
hidden_neurons = tune(),
activations = tune(),
output_activation = tune()
)
iris_folds = vfold_cv(iris, v = 3)
nn_wf = workflow() |>
add_recipe(recipe(Species ~ ., data = iris)) |>
add_model(mlp_tune_spec)
nn_grid = grid_random(
hidden_neurons(c(32L, 128L)),
activations(c("relu", "elu")),
output_activation(c("sigmoid", "linear")),
size = 10
)
nn_grid_depth = grid_depth(
hidden_neurons(c(32L, 128L)),
activations(c("relu", "elu")),
output_activation(c("sigmoid", "linear")),
n_hlayer = 2,
size = 10,
type = "latin_hypercube"
)
nn_tunes = tune::tune_grid(
nn_wf,
iris_folds,
grid = nn_grid_depth
# metrics = metric_set(accuracy, roc_auc)
)
best_nn = select_best(nn_tunes)
final_nn = finalize_workflow(nn_wf, best_nn)
# Last run: 4 - 91 (relu) - 3 (sigmoid) units
final_nn_model = fit(final_nn, data = iris)
final_nn_model |>
augment(new_data = iris) |>
metrics(truth = Species, estimate = .pred_class)
#> # A tibble: 2 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 accuracy multiclass 0.667
#> 2 kap multiclass 0.5Resampling strategies from {rsample} will enable robust
cross-validation workflows, orchestrated through the {tune}
and {dials} APIs.
{kindling} integrates with established variable
importance methods from {NeuralNetTools} and
{vip} to interpret trained neural networks. Two primary
algorithms are available:
Garson’s Algorithm
garson(model, bar_plot = FALSE)
#> x_names y_names rel_imp
#> 1 Petal.Width Species 30.38174
#> 2 Petal.Length Species 25.83497
#> 3 Sepal.Length Species 22.78038
#> 4 Sepal.Width Species 21.00291Olden’s Algorithm
olden(model, bar_plot = FALSE)
#> x_names y_names rel_imp
#> 1 Petal.Width Species 0.575948477
#> 2 Sepal.Width Species -0.286548868
#> 3 Sepal.Length Species -0.204277142
#> 4 Petal.Length Species 0.006615014For users working within the {tidymodels} ecosystem,
{kindling} models work seamlessly with the
{vip} package:
box::use(
vip[vi, vip]
)
vi(model) |>
vip()
Note: Weight caching increases memory usage proportional to network size. Only enable it when you plan to compute variable importance multiple times on the same model.
Falbel D, Luraschi J (2023). torch: Tensors and Neural Networks with ‘GPU’ Acceleration. R package version 0.13.0, https://torch.mlverse.org, https://github.com/mlverse/torch.
Wickham H (2019). Advanced R, 2nd edition. Chapman and Hall/CRC. ISBN 978-0815384571, https://adv-r.hadley.nz/.
Goodfellow I, Bengio Y, Courville A (2016). Deep Learning. MIT Press. https://www.deeplearningbook.org/.
MIT + file LICENSE
Please note that the kindling project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.