Fitting models with neuralnetwork

neuralnetwork fits multilayer perceptrons for tabular regression and classification. The examples below use base R data sets and keep the training runs short enough for R CMD check, but the same calls work with your own data frames and matrices.

library(neuralnetwork)

Multiclass classification

Start with the formula interface. For small tabular data, hidden = "auto" and optimizer = "auto" are enough for a first fit.

fit_class <- nn_fit(
  Species ~ .,
  data = iris,
  hidden = "auto",
  optimizer = "auto",
  epochs = 10,
  validation_split = 0.2,
  seed = 1,
  verbose = FALSE
)

fit_class
#> neuralnetwork model
#>   Task:       classification
#>   Layers:     4 -> 4 -> 3
#>   Optimizer:  lbfgs | activation: tanh | backend: rcpp
#>   Loss:       cross_entropy
#>   Trained:    13 function evaluations
#>   Convergence: code 1 | message: NEW_X
#>   Final:      train loss 0.014447 | accuracy 0.99167
#>               validation loss 0.38622 | validation accuracy 0.9

The printed model reports the task, architecture, optimizer, loss, backend, training length, and final training or validation metrics.

Use predict() for classes or probabilities.

predict(fit_class, iris[1:5, ], type = "class")
#> [1] setosa setosa setosa setosa setosa
#> Levels: setosa versicolor virginica
round(predict(fit_class, iris[1:5, ], type = "prob"), 3)
#>      setosa versicolor virginica
#> [1,]      1          0         0
#> [2,]      1          0         0
#> [3,]      1          0         0
#> [4,]      1          0         0
#> [5,]      1          0         0

nn_evaluate() returns metrics for the fitted task. Multiclass classification includes accuracy, balanced accuracy, macro precision, macro recall, macro F1, and log loss.

ev_class <- nn_evaluate(fit_class, iris)
ev_class
#> neuralnetwork evaluation
#> Metrics:
#>             metric    value
#>           accuracy  0.97333
#>  balanced_accuracy  0.97333
#>    macro_precision  0.97359
#>       macro_recall  0.97333
#>           macro_f1   0.9734
#>           log_loss 0.088802
#> 
#> Confusion matrix:
#>             estimate
#> truth        setosa versicolor virginica
#>   setosa         49          1         0
#>   versicolor      0         48         2
#>   virginica       0          1        49

For imbalanced classification, balanced accuracy or F1 is usually more useful than raw accuracy. For probability forecasts, inspect log loss as well.

Binary classification and weights

Two-class outcomes use a one-output sigmoid model internally. The public prediction API still returns a two-column probability matrix.

iris_binary <- subset(iris, Species != "virginica")
row_weight <- ifelse(iris_binary$Species == "versicolor", 1.5, 1)

fit_binary <- nn_fit(
  Species ~ .,
  data = iris_binary,
  hidden = c(6, 3),
  optimizer = "adam",
  epochs = 8,
  batch_size = 16,
  learning_rate = 0.01,
  sample_weight = row_weight,
  class_weight = "balanced",
  gradient_clip = 5,
  validation_split = 0.2,
  seed = 2,
  verbose = FALSE
)

round(predict(fit_binary, iris_binary[1:5, ], type = "prob"), 3)
#>      setosa versicolor
#> [1,]  0.561      0.439
#> [2,]  0.605      0.395
#> [3,]  0.538      0.462
#> [4,]  0.569      0.431
#> [5,]  0.551      0.449
nn_evaluate(fit_binary, iris_binary)
#> neuralnetwork evaluation
#> Metrics:
#>             metric   value
#>           accuracy    0.95
#>  balanced_accuracy    0.95
#>    macro_precision 0.95018
#>       macro_recall    0.95
#>           macro_f1 0.94999
#>           log_loss 0.56381
#>        sensitivity    0.94
#>        specificity    0.96
#>          precision 0.95918
#>             recall    0.94
#>                 f1 0.94949
#> 
#> Confusion matrix:
#>             estimate
#> truth        setosa versicolor
#>   setosa         48          2
#>   versicolor      3         47

Regression

Regression follows the same shape. By default, regression targets are scaled for training and predictions are returned on the original scale.

fit_reg <- nn_fit(
  mpg ~ wt + hp + disp,
  data = mtcars,
  hidden = c(8, 4),
  optimizer = "adam",
  epochs = 25,
  batch_size = 8,
  learning_rate = 0.01,
  validation_split = 0.2,
  seed = 3,
  verbose = FALSE
)

fit_reg
#> neuralnetwork model
#>   Task:       regression
#>   Layers:     3 -> 8 -> 4 -> 1
#>   Optimizer:  adam | activation: sigmoid | backend: rcpp
#>   Loss:       squared_error
#>   Trained:    25 epochs | best epoch: 23
#>   Final:      train loss 0.11705 | rmse 3.0527
#>               validation loss 0.031615 | validation rmse 1.5865
round(predict(fit_reg, mtcars[1:5, ]), 2)
#> [1] 23.12 22.42 24.74 19.54 16.42
nn_evaluate(fit_reg, mtcars)
#> neuralnetwork evaluation
#> Metrics:
#>  metric   value
#>    rmse  3.0025
#>     mae   2.281
#>     rsq 0.74381

Robust regression

Squared error is the default regression loss. If a few observations may be unusually influential, use Huber loss.

mtcars_outlier <- mtcars
mtcars_outlier$mpg[1] <- mtcars_outlier$mpg[1] + 40

fit_huber <- nn_fit(
  mpg ~ wt + hp,
  data = mtcars_outlier,
  hidden = 4,
  optimizer = "adam",
  loss = "huber",
  huber_delta = 1,
  epochs = 20,
  batch_size = 8,
  learning_rate = 0.01,
  seed = 4,
  verbose = FALSE
)

summary(fit_huber)
#> neuralnetwork summary
#>   Task:       regression
#>   Layers:     2 -> 4 -> 1
#>   Optimizer:  adam | activation: sigmoid | backend: rcpp
#>   Loss:       huber (delta=1)
#>   Epochs:     20 | best epoch: 20
#> 
#> Final training row:
#>  epoch train_loss validation_loss train_metric validation_metric gradient_norm
#>     20    0.18135              NA       7.6733                NA       0.41666
#>  learning_rate backtracked
#>           0.01       FALSE

Training controls

The training loop supports dropout, L2 regularization, gradient clipping, learning-rate decay, validation splits, early stopping, and callbacks. This example stops after two epochs so the callback behavior is visible without making the vignette slow.

epochs_seen <- 0L

fit_callback <- nn_fit(
  mpg ~ wt + hp,
  data = mtcars,
  hidden = 4,
  optimizer = "adam",
  epochs = 20,
  batch_size = 8,
  learning_rate = 0.01,
  l2 = 1e-4,
  dropout = 0.05,
  gradient_clip = 5,
  validation_split = 0.2,
  callbacks = function(state) {
    epochs_seen <<- state$epoch
    if (state$epoch >= 2) {
      return(list(stop = TRUE))
    }
    NULL
  },
  seed = 5,
  verbose = FALSE
)

fit_callback
#> neuralnetwork model
#>   Task:       regression
#>   Layers:     2 -> 4 -> 1
#>   Optimizer:  adam | activation: sigmoid | backend: rcpp
#>   Loss:       squared_error
#>   Trained:    2 epochs | best epoch: 2
#>   Final:      train loss 0.52135 | rmse 6.4176
#>               validation loss 0.13129 | validation rmse 3.2201
#>   Stopped:    callback

Training choices:

Tuning and cross-validation

Use nn_tune() for a grid search. Classification metrics include accuracy, balanced_accuracy, f1, and log_loss. Regression metrics include rmse, mae, and rsq.

tuned <- nn_tune(
  Species ~ .,
  data = iris,
  grid = list(
    hidden = list(4, c(6, 3)),
    learning_rate = c(0.01)
  ),
  metric = "balanced_accuracy",
  epochs = 4,
  validation_split = 0.2,
  seed = 6,
  verbose = FALSE
)

tuned
#> neuralnetwork tuning result
#>   Candidates: 2
#>   Objective:  balanced_accuracy (higher is better)
#>   Best score: 0.91534
#> 
#> Top candidates:
#>  hidden learning_rate success            metric   score error rank
#>       4          0.01    TRUE balanced_accuracy 0.91534  <NA>    1
#>    6, 3          0.01    TRUE balanced_accuracy 0.88889  <NA>    2
tuned$best_params
#>   hidden learning_rate
#> 1      4          0.01

When exploring a wider grid, error_action = "continue" keeps invalid candidate combinations in the result table and ranks the usable fits. The default remains strict, so a bad grid fails before it produces misleading results.

Use nn_cv() for fold-level estimates.

cv <- nn_cv(
  Species ~ .,
  data = iris,
  k = 3,
  metric = "f1",
  hidden = 4,
  epochs = 2,
  seed = 7,
  verbose = FALSE
)

cv
#> neuralnetwork cross-validation
#>   Folds:   3
#>   Repeats: 1
#> 
#>    metric    mean      sd
#>  macro_f1 0.86362 0.10213

Permutation importance

Permutation importance measures how much a metric changes when one feature is shuffled.

imp <- nn_permutation_importance(
  fit_reg,
  mtcars,
  metric = "mae",
  n_repeats = 2,
  seed = 8
)

imp
#> neuralnetwork permutation importance
#>   Metric:  mae
#>   Repeats: 2
#> 
#>  feature importance baseline permuted metric n_repeats
#>       wt    0.98792    2.281   3.2689    mae         2
#>     disp    0.57524    2.281   2.8562    mae         2
#>       hp    0.54879    2.281   2.8298    mae         2

Save, load, and inspect

Models are regular R objects. nn_save() and nn_load() add package-level checks around saveRDS() and readRDS().

model_path <- tempfile(fileext = ".rds")
nn_save(fit_reg, model_path)
fit_loaded <- nn_load(model_path)

all.equal(
  predict(fit_reg, mtcars[1:3, ]),
  predict(fit_loaded, mtcars[1:3, ])
)
#> [1] TRUE

The package includes compatibility helpers for common nnet and neuralnet tasks.

nn_class_ind(iris$Species[1:4])
#>      setosa versicolor virginica
#> [1,]      1          0         0
#> [2,]      1          0         0
#> [3,]      1          0         0
#> [4,]      1          0         0

computed <- nn_compute(fit_class, iris[1:2, ])
names(computed$neurons)
#> [1] "input"   "hidden1" "output"
round(computed$net.result, 3)
#>      setosa versicolor virginica
#> [1,]      1          0         0
#> [2,]      1          0         0

Function map

Function names:

Need Use
Fit a regression or classification network nn_fit()
Fit a no-hidden-layer multinomial model nn_multinom()
Get class probabilities or numeric predictions predict()
Score a fitted model nn_evaluate()
Tune a small grid nn_tune()
Run repeated k-fold validation nn_cv()
Estimate feature importance nn_permutation_importance()
Get compute-style hidden activations nn_compute()
Get generalized weights nn_generalized_weights()
Save and reload a model nn_save() and nn_load()

Start with nn_fit(), inspect nn_evaluate(), and add nn_tune() or nn_cv() when the first model is worth more computation.

Reference help: ?neuralnetwork, ?neuralnetwork-metrics, ?neuralnetwork-callbacks, and ?neuralnetwork-objects.