-
Notifications
You must be signed in to change notification settings - Fork 92
Description
Describe the bug
in my code below: I am experiencing a strange "object 'nu' not found" coming from the traceback soon after the foreach function is run. The thing is, nu is defined within that foreach which is going directly into the %dofuture%!
Judging by the fact that I simply merged the structure of supplied code from both progressr and dofuture to fit my needs, I am really shocked that this didn't work, and that I'm unable to figure out precisely why.
This file is found on my partner's GitHub repository under Ass2.qmd. This should make this easier to see how the error actually came up.
I've now spent a couple of hours debugging this without coming to any reasonable conclusions about how the nu value is not available to the dofuture section
The line of code in question begins "Val_error<-" within the "with_progress" block
#| label: validation-analysis
# the lengthy-execution part
n_val <- 10
nu_seq <- exp(seq(-6,2,length= n_val))
#should give us a progress bar, while computing the validation error for this
#neural net, for the given nu values.
# instead, somehow the nu value—defined in foreach—is not found?
# it may have just been faster to process this sequentially, but i am (perhaps
# foolishly) committed to learning these.
# I feel so close to a breakthrough I SWEAR
with_progress({
p <- progressor(along=nu_seq)
Val_error <- foreach(nu = nu_seq,
.combine = rbind) %dofuture%{
#Validation analysis, per nu
res_opt = nlm(obj_pen,theta_rand,iterlim=max_iter)
res_val = af_net(valid_X,valid_Y,res_opt$estimate,m,0)
#we are done with the penalised values now
error = res_val$E1
p(sprintf("nu=%g",nu))
data.frame(nu=nu,
error=error,
pid=Sys.getpid() # curiosity may kill this cat
)
} %seed% FALSE #no random numbers are generated within this as far as i'm aware, but double-check for consistency
},handlers=handler_pbcol())
This is a chunk within a qmd file.
Reproduce example
If I paste in the other user defined sections that will get this to run, I get this:
library(tidyverse,attach.required = T)
library(future)
library(progressr)
library(doFuture)
library(parallelly)
options(parallelly.availableCores.omit = 1)
if(supportsMulticore()) # multicore = mac, linux, etc. (outside of RStudio)
plan(multicore) else plan(multisession) #multisession = windows and other
# to ensure that the workers are correctly shut down
on.exit(
plan(sequential)
)
#dummy data
dat <- data.frame(X1=runif(90,-4,4),X2=runif(90,-4,4),X3=sample(c(1,0),90,replace=T),Y1=c(rep(1,30),rep(0,60)),Y2=c(rep(0,30),rep(1,30),rep(0,30)),Y3=c(rep(0,60),rep(1,30))) |> as_tibble()
# ------------------------------- model data ----------------------------------
# matrices for use in the NN functions
m <- 4 #hidden layer size
p <- 3 #predictors
q <- 3 #responses
N <- dat |> nrow()
X <- dat |> select( 1:p) |> as.matrix(ncol=p, nrow=N)
Y <- dat |> select(p+1:q) |> as.matrix(ncol=q, nrow=N)
npars <- p*p +2*p*m +m*m +m*q +p+m+m+q
g <- function(Yhat, Y){
N <- nrow(Y)
C <- numeric(N)
for(i in 1:N){
C[i] <- -log(Yhat[i, which.max(Y[i,])])
}
return(sum(C))
}
# --- activation functions ----------------------------------------------------
# augmentation layer
sig1 <- function(z)
{
tanh(z)
}
# first m hidden layer
sig2 <- function(z)
{
tanh(z)
}
# second m hidden layer
sig3 <- function(z)
{
tanh(z)
}
# output layer
sig4 <- function(z)
{
ez <- exp(z)
ez/matrix(1,q,q)%*%ez
}
# --- neural network ----------------------------------------------------------
af_net <- function(X, Y, theta, m, nu)
{
N <- X |> nrow()
p <- X |> ncol()
q <- Y |> ncol()
# allocating theta to weight and biases
index <- 1:(p*p)
# to auto-feature layer
W1 <- matrix(theta[index],p,p) # p*p
index <- max(index)+1:(2*p*m)
# from auto-feature (as well as from regular input) layer
W2 <- matrix(theta[index],2*p,m) # 2p*m
index <- max(index)+1:(m*m)
W3 <- matrix(theta[index],m,m) # m*m
index <- max(index)+1:(m*q)
W4 <- matrix(theta[index],m,q) # m*q
index <- max(index)+1:p
b1 <- matrix(theta[index],p,1) # p*1
index <- max(index)+1:m
b2 <- matrix(theta[index],m,1) # m*1
index <- max(index)+1:m
b3 <- matrix(theta[index],m,1) # m*1
index <- max(index)+1:q
b4 <- matrix(theta[index],q,1) # q*1
# Forward Evaluation of network
ones <- matrix(1,1,N) # vector of 1s transposed 1*N
# auto-features inputs
A0 <- t(X) # p*N
# regular inputs, followed by auto-features
A1 <- sig1(t(W1)%*%A0 +b1%*%ones) # p*N
# from auto-feature and regular inputs
A1. <- rbind(t(X),A1) # 2p*N
A2 <- sig2(t(W2)%*%A1.+b2%*%ones) # m*N
A3 <- sig3(t(W3)%*%A2 +b3%*%ones) # m*N
A4 <- sig4(t(W4)%*%A3 +b4%*%ones) # q*N
Yhat <- t(A4) # N*q
# Calculating error
E1 <- g(Yhat,Y)
# Penalised error
E2 <- E1/N -nu/N*(sum(W1^2,W2^2,W3^2,W4^2)) #MSE_penalised
# returning predictions and error
return(list(Yhat = Yhat, E1 = E1, E2 = E2))
}
set.seed(2025)
valid_split <- 0.8
selected <- sample(1:N,valid_split*N,replace = F)
train_X <- X[ selected,,drop=F]
train_Y <- Y[ selected,,drop=F]
valid_X <- X[-selected,,drop=F]
valid_Y <- Y[-selected,,drop=F]
nu <- 0
obj_pen <- function(pars)
{
res_model <- af_net(train_X,train_Y,pars,m,nu)
return(res_model$E2)
}
max_iter <- 1000
theta_rand <- runif(npars,-1,1)
res_opt <- nlm(obj_pen,theta_rand,iterlim = max_iter)
res_fitted <- af_net(X,Y,res_opt$estimate,m,0)
# the lengthy-execution part
n_val <- 10
nu_seq <- exp(seq(-6,2,length= n_val))
#should give us a progress bar, while computing the validation error for this
#neural net, for the given nu values.
# instead, somehow the nu value—defined in foreach—is not found?
# it may have just been faster to process this sequentially, but i am (perhaps
# foolishly) committed to learning these.
# I feel so close to a breakthrough I SWEAR
with_progress({
p <- progressor(along=nu_seq)
Val_error <- foreach(nu = nu_seq,
.combine = rbind) %dofuture%{
#Validation analysis, per nu
res_opt = nlm(obj_pen,theta_rand,iterlim=max_iter)
res_val = af_net(valid_X,valid_Y,res_opt$estimate,m,0)
#we are done with the penalised values now
error = res_val$E1
p(sprintf("nu=%g",nu))
data.frame(nu=nu,
error=error,
pid=Sys.getpid() # curiosity may kill this cat
)
} %seed% FALSE #no random numbers are generated within this as far as i'm aware, but double-check for consistency
},handlers=handler_pbcol())
Expected behavior
The nu value should be one of the most accessible values to the parallelised function, so this error really does feel shocking.
Session information
R version 4.4.2 (2024-10-31)
Platform: aarch64-apple-darwin20
Running under: macOS Sequoia 15.3.1
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: Africa/Johannesburg
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] doFuture_1.0.2 future_1.40.0 foreach_1.5.2 progressr_0.15.1 plotly_4.10.4
[6] parallelly_1.43.0 futureverse_0.1.0 lubridate_1.9.4 forcats_1.0.0 stringr_1.5.1
[11] dplyr_1.1.4 purrr_1.0.4 readr_2.1.5 tidyr_1.3.1 tibble_3.2.1
[16] ggplot2_3.5.2 tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] generics_0.1.3 stringi_1.8.7 listenv_0.9.1 hms_1.1.3
[5] digest_0.6.37 magrittr_2.0.3 evaluate_1.0.3 grid_4.4.2
[9] timechange_0.3.0 RColorBrewer_1.1-3 iterators_1.0.14 fastmap_1.2.0
[13] jsonlite_2.0.0 httr_1.4.7 crosstalk_1.2.1 viridisLite_0.4.2
[17] scales_1.4.0 codetools_0.2-20 lazyeval_0.2.2 cli_3.6.5
[21] crayon_1.5.3 rlang_1.1.6 future.apply_1.11.3 yaml_2.3.10
[25] withr_3.0.2 tools_4.4.2 parallel_4.4.2 tzdb_0.5.0
[29] globals_0.17.0 vctrs_0.6.5 R6_2.6.1 lifecycle_1.0.4
[33] htmlwidgets_1.6.4 pkgconfig_2.0.3 pillar_1.10.2 gtable_0.3.6
[37] glue_1.8.0 data.table_1.17.0 highr_0.11 xfun_0.52
[41] tidyselect_1.2.1 rstudioapi_0.17.1 knitr_1.50 farver_2.1.2
[45] htmltools_0.5.8.1 labeling_0.4.3 compiler_4.4.2