-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(cloning): metadata, finalizer, and repeated cloning #1134
Conversation
Also, the Cpp code to clone tensors / buffers / parameters behaves differently, right? |
I also think it would be nice if |
There is also another discrepancy between the clonee and the cloned object: library(torch)
lin = nn_linear(1, 1)
lin$parameters$weight$requires_grad
#> [1] TRUE
lin$clone(deep = TRUE)$parameters$weight$requires_grad
#> [1] FALSE Created on 2024-02-08 with reprex v2.0.2 |
one more: library(torch)
nn_linear(1, 1)$train()$clone(deep = TRUE)
#> Error in FUN(X[[i]], ...): not an environment
nn_linear(1, 1)$eval()$clone(deep = TRUE)
#> Error in FUN(X[[i]], ...): not an environment Created on 2024-02-08 with reprex v2.0.2 |
Also, cloning repeatedly causes issues and builds up a structure of parent environments. Line 521 in 0e9fdd7
The patched version still has the original version as its enclosing environment so it should still work but will repeatedly call the clone() method of the enclosing environment (Line 549 in 0e9fdd7
library(torch)
n = nn_linear(1, 1)
head(attr(n, "module")$clone, n = 1)
#>
#> 1 function (deep = FALSE, ..., replace_values = TRUE)
head(attr(n, "module")$clone |> environment() |> with(clone), n = 1)
#>
#> 1 function (deep = FALSE)
n1 = n$clone(deep = TRUE)
head(attr(n1, "module")$clone, n = 1)
#>
#> 1 function (deep = FALSE, ..., replace_values = TRUE)
head(attr(n1, "module")$clone |> environment() |> with(clone), n = 1)
#>
#> 1 function (deep = FALSE, ..., replace_values = TRUE)
head(attr(n1, "module")$clone |> environment() |> with(clone) |> environment() |> with(clone), n = 1)
#>
#> 1 function (deep = FALSE)
identical(
attr(n1, "module")$clone |> environment(),
attr(n1, "module")$clone |> environment() |> with(clone) |> environment()
)
#> [1] FALSE
attr(n1, "module")$clone |> environment() |> names()
#> [1] "clone" "f" "instance"
attr(n1, "module")$clone |> environment() |> with(clone) |> environment() |> names()
#> [1] "clone" "f" "instance" Created on 2024-02-10 with reprex v2.0.2 |
Also, I included support for a private clone finalizer method. In mlr3torch we need something like this, because we have an |
I also just saw: r-lib/R6#273, which would make the post_clone hook officially supported by R6. |
So there is at least one more issue shown in the reprex below. When creating the Line 543 in 0e9fdd7
I think we need to recurse through the children and things should probably work. Setting library(torch)
nn_test = nn_module("test", initialize = function() {
self$l = nn_module_list(list(nn_linear(1, 1)))
},
forward = function(x) {
self$l[[1]](x)
}
)()
nn_test1 = nn_test$clone(deep = TRUE)
nn_test$clone(deep = TRUE)
#> An `nn_module` containing 2 parameters.
#>
#> ── Modules ─────────────────────────────────────────────────────────────────────
#> • l: <nn_module_list> #2 parameters
l1 = nn_test$l$modules[[2]]
l2 = nn_test1$l$modules[[2]]
identical(l1, l2)
#> [1] TRUE Created on 2024-02-10 with reprex v2.0.2 |
stills needs some cleanup but in principle it should be working
The current workaround for the clone method caused the cloned object to reference the original object. Line 523 in 0e9fdd7
This implied that the size of the cloned object was larger than the original object: library(torch)
pryr::object_size(nn_relu())
#> 484.47 kB
pryr::object_size(nn_relu()$clone(deep = TRUE))
#> 492.42 kB Created on 2024-02-12 with reprex v2.0.2 |
@dfalbel I am done here and would love to get your feedback whether you think these changes make sense :) |
Ok, now I think it is actually ready from my side |
the encapsulation of the patched clone method of the nn_module caused private functions like xptr_address to be inaccessible
@dfalbel we can also have a call where I can explain some of the changes if you have the time / you think this is useful or necessary. Otherwise I can also give more details here |
Edit: please see comment below, this no longer applies. @sebffischer I wonder if we instead of renaming
Thus renaming these methods will certainly cause problems in other codebases that rely on that behavior. For instance, it breaks some torch optimizers that do use Besides that, the PR looks great! Thank you very much for working on this. |
…to pr/sebffischer/1134
Ok, so renaming works fine, we just had to support the other arguments to |
@dfalbel Thanks for the feedback. Regarding the call to |
please don't merge yet I want to add one more refactor |
Done now |
Thanks @sebffischer ! Looks great! |
Addresses #1126, where you offered to take care of the renaming.
I.e. the
$clone2()
method should just be renamed to$clone()
, which currently has no effect, as thefind_method()
function (iirc) still finds thetorch_clone()
function that is auto-generated.