Closed njtierney closed 2 weeks ago
This is most likely related, using simulate
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
source("tests/testthat/helpers.R")
# fix variable
a <- normal(0, 1)
y <- normal(a, 1)
m <- model(y)
# the samples should be the same if the seed is the same
one <- simulate(m, seed = 12345)
two <- simulate(m, seed = 12345)
expect_identical(one, two)
#> Error: `one` (`actual`) not identical to `two` (`expected`).
#>
#> actual$a vs expected$a
#> [,1]
#> - actual$a[1, ] -0.3433419
#> + expected$a[1, ] -0.5080503
#>
#> actual$y vs expected$y
#> [,1]
#> - actual$y[1, ] -0.3244506
#> + expected$y[1, ] -0.7500944
Created on 2022-10-05 by the reprex package (v2.0.1)
does this work if the seed is set externally? Ie.:
set.seed(12345)
one <- calculate(y, nsim = 1)
set.seed(12345)
two <- calculate(y, nsim = 1)
Alas, no
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
source("tests/testthat/helpers.R")
a <- normal(0, 1)
y <- normal(a, 1)
set.seed(12345)
one <- calculate(y, nsim = 1)
set.seed(12345)
two <- calculate(y, nsim = 1)
one
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -0.3244506
two
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -0.7500944
Created on 2022-10-10 by the reprex package (v2.0.1)
And is the global seed respected by mcmc()
etc?
The interface to providing the seed to TF might well have changed. it was always fiddly (especially in TFP)
It does not appear to be the case :(
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
a <- normal(0, 1)
y <- normal(a, 1)
m <- model(y)
set.seed(12345)
one <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 18s warmup ==== 100/1000 | eta: 10s warmup ====== 150/1000 | eta: 7s warmup ======== 200/1000 | eta: 6s warmup ========== 250/1000 | eta: 5s warmup =========== 300/1000 | eta: 4s warmup ============= 350/1000 | eta: 4s warmup =============== 400/1000 | eta: 3s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 2s warmup ===================== 550/1000 | eta: 2s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 1s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
set.seed(12345)
two <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 17s warmup ==== 100/1000 | eta: 10s warmup ====== 150/1000 | eta: 7s warmup ======== 200/1000 | eta: 6s warmup ========== 250/1000 | eta: 5s warmup =========== 300/1000 | eta: 4s warmup ============= 350/1000 | eta: 3s warmup =============== 400/1000 | eta: 3s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 2s warmup ===================== 550/1000 | eta: 2s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 1s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
as.numeric(one)
#> [1] -0.5020496
as.numeric(two)
#> [1] 0.9642478
Created on 2022-10-10 by the reprex package (v2.0.1)
The current parts that operate on the seed are
https://github.com/njtierney/greta/blob/tf2-poke-tf-fun/R/calculate.R#L206-L216
However it seems that this isn't getting input later, or something? My only main thought on this is that we need to do the setting of the seed part a bit later, perhaps inside the TF function part, perhaps here?
values <- calculate_target_tensor_list(
dag,
fixed_greta_arrays,
values,
stochastic,
target,
nsim
)
That function, calculate_target_tensor_list
probably also needs to be wrapped in tf_function
It does seem that the random number generation aspect of TF has changed
https://www.tensorflow.org/guide/random_numbers#stateless_rngs
But this seems a bit wild to me in that you need to create a special function for controlling random number generation, rather than just having some way to manage the state outside like using seed =
or set.seed
?
Might need to investigate if rstudio/tensorflow do anything to manage random seeds
Ok, good news.
tensorflow::set_random_seed
Seems to be what we want for setting the global random seed (helpfile: https://tensorflow.rstudio.com/reference/tensorflow/set_random_seed.html)
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
a <- normal(0, 1)
y <- normal(a, 1)
tensorflow::set_random_seed(12345)
one <- calculate(y, nsim = 1)
tensorflow::set_random_seed(12345)
two <- calculate(y, nsim = 1)
one
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -1.84305
two
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -1.84305
Created on 2022-10-10 by the reprex package (v2.0.1)
and
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
a <- normal(0, 1)
y <- normal(a, 1)
m <- model(y)
tensorflow::set_random_seed(12345)
one <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 18s warmup ==== 100/1000 | eta: 10s warmup ====== 150/1000 | eta: 7s warmup ======== 200/1000 | eta: 6s warmup ========== 250/1000 | eta: 5s warmup =========== 300/1000 | eta: 4s warmup ============= 350/1000 | eta: 4s warmup =============== 400/1000 | eta: 3s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 2s warmup ===================== 550/1000 | eta: 2s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 1s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
tensorflow::set_random_seed(12345)
two <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 17s warmup ==== 100/1000 | eta: 10s warmup ====== 150/1000 | eta: 7s warmup ======== 200/1000 | eta: 6s warmup ========== 250/1000 | eta: 5s warmup =========== 300/1000 | eta: 4s warmup ============= 350/1000 | eta: 4s warmup =============== 400/1000 | eta: 3s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 2s warmup ===================== 550/1000 | eta: 2s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 1s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
as.numeric(one)
#> [1] 2.685009
as.numeric(two)
#> [1] 2.685009
Created on 2022-10-10 by the reprex package (v2.0.1)
I guess we replace instances of set.seed
with tensorflow::set_random_seed
?
I'm not quite sure how this would interact with code like this
# if an RNG seed was provided use it and reset the RNG on exiting
if (!is.null(seed)) {
if (!exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) {
runif(1)
}
r_seed <- get(".Random.seed", envir = .GlobalEnv)
on.exit(assign(".Random.seed", r_seed, envir = .GlobalEnv))
set.seed(seed)
}
or
# get the next seed as a L'Ecuyer
future_seed <- function() {
okind <- RNGkind()[1]
on.exit(RNGkind(okind), add = TRUE)
RNGkind("L'Ecuyer-CMRG")
.GlobalEnv$.Random.seed
}
So replacing set.seed
in calculate
here: https://github.com/njtierney/greta/blob/tf2-poke-tf-fun/R/calculate.R#L214
with tensorflow::set_random_seed(seed)
now means this succeeds all tests in test_calculate
It also passes the check above:
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
source("tests/testthat/helpers.R")
# fix variable
a <- normal(0, 1)
y <- normal(a, 1, dim = c(1, 3))
# the samples should be the same if the seed is the same
one <- calculate(y, nsim = 1, seed = 12345)
two <- calculate(y, nsim = 1, seed = 12345)
one
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -1.84305
#>
#> , , 2
#>
#> [,1]
#> [1,] -2.3286
#>
#> , , 3
#>
#> [,1]
#> [1,] -3.653452
two
#> $y
#> , , 1
#>
#> [,1]
#> [1,] -1.84305
#>
#> , , 2
#>
#> [,1]
#> [1,] -2.3286
#>
#> , , 3
#>
#> [,1]
#> [1,] -3.653452
expect_identical(one, two)
Created on 2022-10-10 by the reprex package (v2.0.1)
So perhaps that is all we needed to do? I'm not sure what the boilerplate code about extracting RNG seed from the global environment does so I'm a bit unsure about that part is all
OK cool! I think you want both, actually. Set the R seed (to make sure it updates) and set the TF seed to the same thing.
But rather than setting the TF seed there, we probably want to set the R seed there, and then set the TF seed (to whatever the R seed is) just before execution of the TF code. that way it works either if the user passes a seed to the function, or sets the global R seed.
[update from offline convo - tensorflow::set_random_seed(seed)
sets the R seed as well as the TF one, so this should work]
Ack, actually I'm not sure if this is resolved now, based on this behaviour - which is, I would expect in all of these scenarios for setting the seed to work when it is set outside with set.seed
or with the seed
argument.
Instead
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
a <- normal(0, 1)
y <- normal(a, 1)
m <- model(y)
set.seed(12345)
c_one <- calculate(y, nsim = 1)
set.seed(12345)
c_two <- calculate(y, nsim = 1)
as.numeric(c_one)
#> [1] -0.3244506
as.numeric(c_two)
#> [1] -0.7500944
c_one <- calculate(y, nsim = 1, seed = 12345)
c_two <- calculate(y, nsim = 1, seed = 12345)
as.numeric(c_one)
#> [1] -1.84305
as.numeric(c_two)
#> [1] -1.84305
set.seed(12345)
one <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 19s warmup ==== 100/1000 | eta: 12s warmup ====== 150/1000 | eta: 9s warmup ======== 200/1000 | eta: 7s warmup ========== 250/1000 | eta: 6s warmup =========== 300/1000 | eta: 5s warmup ============= 350/1000 | eta: 4s warmup =============== 400/1000 | eta: 4s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 3s warmup ===================== 550/1000 | eta: 3s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 2s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
set.seed(12345)
two <- mcmc(m, n_samples = 1, chains = 1)
#> warmup 0/1000 | eta: ?s warmup == 50/1000 | eta: 17s warmup ==== 100/1000 | eta: 10s warmup ====== 150/1000 | eta: 7s warmup ======== 200/1000 | eta: 6s warmup ========== 250/1000 | eta: 5s warmup =========== 300/1000 | eta: 4s warmup ============= 350/1000 | eta: 4s warmup =============== 400/1000 | eta: 3s warmup ================= 450/1000 | eta: 3s warmup =================== 500/1000 | eta: 2s warmup ===================== 550/1000 | eta: 2s warmup ======================= 600/1000 | eta: 2s warmup ========================= 650/1000 | eta: 2s warmup =========================== 700/1000 | eta: 1s warmup ============================ 750/1000 | eta: 1s warmup ============================== 800/1000 | eta: 1s warmup ================================ 850/1000 | eta: 1s warmup ================================== 900/1000 | eta: 0s warmup ==================================== 950/1000 | eta: 0s warmup ====================================== 1000/1000 | eta: 0s
#> sampling 0/1 | eta: ?s
as.numeric(one)
#> [1] 2.685009
as.numeric(two)
#> [1] 2.685009
Created on 2022-10-11 by the reprex package (v2.0.1)
Simulate results are the same now, which is good!
devtools::load_all(".")
#> ℹ Loading greta
#> ℹ Initialising python and checking dependencies, this may take a moment.
#>
#> ✔ Initialising python and checking dependencies ... done!
#> Loaded Tensorflow version 2.9.2
source("tests/testthat/helpers.R")
# fix variable
a <- normal(0, 1)
y <- normal(a, 1)
m <- model(y)
# the samples should be the same if the seed is the same
one <- simulate(m, seed = 12345)
two <- simulate(m, seed = 12345)
expect_identical(one, two)
Created on 2022-10-12 by the reprex package (v2.0.1)
NOTE: This is in the Tensorflow 2 development branch (https://github.com/greta-dev/greta/pull/534)
Created on 2022-10-05 by the reprex package (v2.0.1)
Session info
``` r sessioninfo::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.2.0 (2022-04-22) #> os macOS Monterey 12.3.1 #> system aarch64, darwin20 #> ui X11 #> language (EN) #> collate en_AU.UTF-8 #> ctype en_AU.UTF-8 #> tz Australia/Brisbane #> date 2022-10-05 #> pandoc 2.19.2 @ /Applications/RStudio.app/Contents/MacOS/quarto/bin/tools/ (via rmarkdown) #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> ! package * version date (UTC) lib source #> abind 1.4-5 2016-07-21 [1] CRAN (R 4.2.0) #> backports 1.4.1 2021-12-13 [1] CRAN (R 4.2.0) #> base64enc 0.1-3 2015-07-28 [1] CRAN (R 4.2.0) #> brio 1.1.3 2021-11-30 [1] CRAN (R 4.2.0) #> cachem 1.0.6 2021-08-19 [1] CRAN (R 4.2.0) #> callr 3.7.2 2022-08-22 [1] CRAN (R 4.2.0) #> cli 3.3.0.9000 2022-06-15 [1] Github (r-lib/cli@31a5db5) #> coda 0.19-4 2020-09-30 [1] CRAN (R 4.2.0) #> codetools 0.2-18 2020-11-04 [1] CRAN (R 4.2.0) #> crayon 1.5.1 2022-03-26 [1] CRAN (R 4.2.0) #> desc 1.4.2 2022-09-08 [1] CRAN (R 4.2.0) #> devtools 2.4.4 2022-07-20 [1] CRAN (R 4.2.0) #> diffobj 0.3.5 2021-10-05 [1] CRAN (R 4.2.0) #> digest 0.6.29 2021-12-01 [1] CRAN (R 4.2.0) #> ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.2.0) #> evaluate 0.16 2022-08-09 [1] CRAN (R 4.2.0) #> fansi 1.0.3 2022-03-24 [1] CRAN (R 4.2.0) #> fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.2.0) #> fs 1.5.2 2021-12-08 [1] CRAN (R 4.2.0) #> future 1.27.0 2022-07-22 [1] CRAN (R 4.2.0) #> globals 0.16.0 2022-08-05 [1] CRAN (R 4.2.0) #> glue 1.6.2 2022-02-24 [1] CRAN (R 4.2.0) #> P greta * 0.4.2.9000 2022-09-19 [?] load_all() #> here 1.0.1 2020-12-13 [1] CRAN (R 4.2.0) #> highr 0.9 2021-04-16 [1] CRAN (R 4.2.0) #> hms 1.1.1 2021-09-26 [1] CRAN (R 4.2.0) #> htmltools 0.5.3 2022-07-18 [1] CRAN (R 4.2.0) #> htmlwidgets 1.5.4 2021-09-08 [1] CRAN (R 4.2.0) #> httpuv 1.6.5 2022-01-05 [1] CRAN (R 4.2.0) #> jsonlite 1.8.0 2022-02-22 [1] CRAN (R 4.2.0) #> knitr 1.40 2022-08-24 [1] CRAN (R 4.2.0) #> later 1.3.0 2021-08-18 [1] CRAN (R 4.2.0) #> lattice 0.20-45 2021-09-22 [1] CRAN (R 4.2.0) #> lifecycle 1.0.2 2022-09-09 [1] CRAN (R 4.2.0) #> listenv 0.8.0 2019-12-05 [1] CRAN (R 4.2.0) #> magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.2.0) #> Matrix 1.4-1 2022-03-23 [1] CRAN (R 4.2.0) #> memoise 2.0.1 2021-11-26 [1] CRAN (R 4.2.0) #> mime 0.12 2021-09-28 [1] CRAN (R 4.2.0) #> miniUI 0.1.1.1 2018-05-18 [1] CRAN (R 4.2.0) #> parallelly 1.32.1 2022-07-21 [1] CRAN (R 4.2.0) #> pillar 1.8.1 2022-08-19 [1] CRAN (R 4.2.0) #> pkgbuild 1.3.1 2021-12-20 [1] CRAN (R 4.2.0) #> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.2.0) #> pkgload 1.3.0 2022-06-27 [1] CRAN (R 4.2.0) #> png 0.1-7 2013-12-03 [1] CRAN (R 4.2.0) #> prettyunits 1.1.1 2020-01-24 [1] CRAN (R 4.2.0) #> processx 3.7.0 2022-07-07 [1] CRAN (R 4.2.0) #> profvis 0.3.7 2020-11-02 [1] CRAN (R 4.2.0) #> progress 1.2.2 2019-05-16 [1] CRAN (R 4.2.0) #> promises 1.2.0.1 2021-02-11 [1] CRAN (R 4.2.0) #> ps 1.7.1 2022-06-18 [1] CRAN (R 4.2.0) #> purrr 0.3.4 2020-04-17 [1] CRAN (R 4.2.0) #> R.cache 0.16.0 2022-07-21 [1] CRAN (R 4.2.0) #> R.methodsS3 1.8.2 2022-06-13 [1] CRAN (R 4.2.0) #> R.oo 1.25.0 2022-06-12 [1] CRAN (R 4.2.0) #> R.utils 2.12.0 2022-06-28 [1] CRAN (R 4.2.0) #> R6 2.5.1 2021-08-19 [1] CRAN (R 4.2.0) #> Rcpp 1.0.9 2022-07-08 [1] CRAN (R 4.2.0) #> rematch2 2.1.2 2020-05-01 [1] CRAN (R 4.2.0) #> remotes 2.4.2 2021-11-30 [1] CRAN (R 4.2.0) #> reprex 2.0.1 2021-08-05 [1] CRAN (R 4.2.0) #> reticulate 1.25 2022-05-11 [1] CRAN (R 4.2.0) #> rlang 1.0.5 2022-08-31 [1] CRAN (R 4.2.0) #> rmarkdown 2.16 2022-08-24 [1] CRAN (R 4.2.0) #> rprojroot 2.0.3 2022-04-02 [1] CRAN (R 4.2.0) #> rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.2.0) #> sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.2.0) #> shiny 1.7.2 2022-07-19 [1] CRAN (R 4.2.0) #> stringi 1.7.8 2022-07-11 [1] CRAN (R 4.2.0) #> stringr 1.4.1 2022-08-20 [1] CRAN (R 4.2.0) #> styler 1.7.0 2022-03-13 [1] CRAN (R 4.2.0) #> tensorflow 2.9.0 2022-05-21 [1] CRAN (R 4.2.0) #> testthat * 3.1.4 2022-04-26 [1] CRAN (R 4.2.0) #> tfautograph 0.3.2 2021-09-17 [1] CRAN (R 4.2.0) #> tfruns 1.5.0 2021-02-26 [1] CRAN (R 4.2.0) #> tibble 3.1.8 2022-07-22 [1] CRAN (R 4.2.0) #> urlchecker 1.0.1 2021-11-30 [1] CRAN (R 4.2.0) #> usethis 2.1.6 2022-05-25 [1] CRAN (R 4.2.0) #> utf8 1.2.2 2021-07-24 [1] CRAN (R 4.2.0) #> vctrs 0.4.1 2022-04-13 [1] CRAN (R 4.2.0) #> waldo 0.4.0 2022-03-16 [1] CRAN (R 4.2.0) #> whisker 0.4 2019-08-28 [1] CRAN (R 4.2.0) #> withr 2.5.0 2022-03-03 [1] CRAN (R 4.2.0) #> xfun 0.33 2022-09-12 [1] CRAN (R 4.2.0) #> xtable 1.8-4 2019-04-21 [1] CRAN (R 4.2.0) #> yaml 2.3.5 2022-02-21 [1] CRAN (R 4.2.0) #> yesno 0.1.2 2020-07-10 [1] CRAN (R 4.2.0) #> #> [1] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library #> #> P ── Loaded and on-disk path mismatch. #> #> ─ Python configuration ─────────────────────────────────────────────────────── #> python: /Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2/bin/python #> libpython: /Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2/lib/libpython3.8.dylib #> pythonhome: /Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2:/Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2 #> version: 3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:05:16) [Clang 12.0.1 ] #> numpy: /Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2/lib/python3.8/site-packages/numpy #> numpy_version: 1.22.4 #> tensorflow: /Users/nick/Library/r-miniconda-arm64/envs/greta-env-tf2/lib/python3.8/site-packages/tensorflow #> #> NOTE: Python version was forced by use_python function #> #> ────────────────────────────────────────────────────────────────────────────── ```