Skip to content

Bug report: remove_keras_spec deletes multiple models if their names share a common prefix #30

@davidrsch

Description

@davidrsch

Description

The function remove_keras_spec has an issue where it removes more models than intended. When creating the to_kill vector, it deletes all objects whose names start with the name of the model to be deleted. This can cause problems if a user has defined two model specs, for example, my_mlp and my_mlp_2. When remove_keras_spec is called to delete my_mlp, it will also delete my_mlp_2 because its name also starts with "my_mlp".

A more specific approach is needed to create the to_kill vector. Instead of using a broad pattern, it should use a specific list of suffixes to identify the objects to be removed.

Reprex

# Load necessary libraries
library(kerasnip)
#> Warning: package 'kerasnip' was built under R version 4.5.1
library(parsnip)
#> 
#> Attaching package: 'parsnip'
#> The following object is masked from 'package:kerasnip':
#> 
#>     get_model_env
library(keras3)
#> Warning: package 'keras3' was built under R version 4.5.1

# Create first model spec
create_keras_sequential_spec(
  "my_mlp",
  list(
    input = \(model, input_shape) {
      keras_model_sequential(input_shape = input_shape)
    },
    dense = \(model, units = 16) model |> layer_dense(units = units)
  ),
  "regression"
)

# Create second model spec
create_keras_sequential_spec(
  "my_mlp_2",
  list(
    input = \(model, input_shape) {
      keras_model_sequential(input_shape = input_shape)
    },
    dense = \(model, units = 32) model |> layer_dense(units = units)
  ),
  "regression"
)

# Both models should exist
print(paste("my_mlp exists:", exists("my_mlp")))
#> [1] "my_mlp exists: TRUE"
print(paste("my_mlp_2 exists:", exists("my_mlp_2")))
#> [1] "my_mlp_2 exists: TRUE"

# Remove the first model
remove_keras_spec("my_mlp")
#> Removed from parsnip registry objects: my_mlp, my_mlp_2, my_mlp_2_args, my_mlp_2_encoding, my_mlp_2_fit, my_mlp_2_modes, my_mlp_2_pkgs, my_mlp_2_predict, my_mlp_args, my_mlp_encoding, my_mlp_fit, my_mlp_modes, my_mlp_pkgs, my_mlp_predict
#> Removed 'my_mlp' from parsnip:::get_model_env()$models

# Check if the second model still exists
print(paste("my_mlp exists after removal:", exists("my_mlp")))
#> [1] "my_mlp exists after removal: FALSE"
print(paste("my_mlp_2 exists after removal:", exists("my_mlp_2")))
#> [1] "my_mlp_2 exists after removal: TRUE"

# my_mlp_2 exist in the models list of the parsnip environment but the
# associated objects were deleted as informed by `remove_keras_spec`

Session Info

sessionInfo()
#> R version 4.5.0 (2025-04-11 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 10 x64 (build 19045)
#> 
#> Matrix products: default
#>   LAPACK version 3.12.1
#> 
#> locale:
#> [1] LC_COLLATE=English_United Kingdom.utf8 
#> [2] LC_CTYPE=English_United Kingdom.utf8   
#> [3] LC_MONETARY=English_United Kingdom.utf8
#> [4] LC_NUMERIC=C                           
#> [5] LC_TIME=English_United Kingdom.utf8    
#> 
#> time zone: Europe/Madrid
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] keras3_1.4.0       parsnip_1.3.1      kerasnip_0.0.2.900
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.6        xfun_0.52           ggplot2_3.5.2      
#>  [4] recipes_1.3.0       lattice_0.22-6      vctrs_0.6.5        
#>  [7] tools_4.5.0         tfruns_1.5.3        generics_0.1.3     
#> [10] parallel_4.5.0      tibble_3.2.1        pkgconfig_2.0.3    
#> [13] Matrix_1.7-3        data.table_1.17.0   lifecycle_1.0.4    
#> [16] compiler_4.5.0      munsell_0.5.1       codetools_0.2-20   
#> [19] htmltools_0.5.8.1   class_7.3-23        yaml_2.3.10        
#> [22] prodlim_2024.06.25  pillar_1.10.2       whisker_0.4.1      
#> [25] tidyr_1.3.1         MASS_7.3-65         gower_1.0.2        
#> [28] rpart_4.1.24        parallelly_1.43.0   lava_1.8.1         
#> [31] tidyselect_1.2.1    digest_0.6.37       future_1.40.0      
#> [34] dplyr_1.1.4         purrr_1.0.4         listenv_0.9.1      
#> [37] splines_4.5.0       fastmap_1.2.0       grid_4.5.0         
#> [40] colorspace_2.1-1    cli_3.6.4           magrittr_2.0.3     
#> [43] base64enc_0.1-3     survival_3.8-3      dotty_0.1.0        
#> [46] future.apply_1.11.3 withr_3.0.2         scales_1.3.0       
#> [49] lubridate_1.9.4     timechange_0.3.0    rmarkdown_2.29     
#> [52] globals_0.17.0      nnet_7.3-20         timeDate_4041.110  
#> [55] reticulate_1.42.0   png_0.1-8           evaluate_1.0.3     
#> [58] knitr_1.50          hardhat_1.4.1       rlang_1.1.6        
#> [61] Rcpp_1.0.14         zeallot_0.2.0       glue_1.8.0         
#> [64] ipred_0.9-15        reprex_2.1.1        jsonlite_2.0.0     
#> [67] R6_2.6.1            fs_1.6.6            tensorflow_2.16.0

Expected Behavior

When remove_keras_spec("my_mlp") is called, only the my_mlp model and its associated objects should be removed. The my_mlp_2 model and associated objects should remain untouched.

Actual Behavior

When remove_keras_spec("my_mlp") is called, objects from both my_mlp and my_mlp_2 models are removed from the parsnip registry. This is because the function uses a broad grep pattern that matches any model name starting with "my_mlp".

Additional Context

The issue is located in the remove_keras_spec.R file, specifically in the line where the to_kill vector is created: to_kill <- grep(paste0("^", model_name), all_regs, value = TRUE). This should be replaced with a more specific pattern to avoid unintended deletions.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions