torch icon indicating copy to clipboard operation
torch copied to clipboard

Indexing model parameters doesn't agree with PyTorch semantics

Open alexpeys opened this issue 4 years ago • 10 comments

I'm trying to constrain my solution space to the positive orthant so I'm projecting negative parameters (from nn_embedding()) to 0 at each gradient step.

I use: model$lhs_emb$weight$data()[model$lhs_emb$weight$data()<0] <- 0

and get

Error in model$lhs_emb$weight$data()[model$lhs_emb$weight$data() < 0] <- 0 : invalid (NULL) left side of assignment

In PyTorch this is totally legal.

Is this an R limitation or fixable?

alexpeys avatar Oct 19 '20 21:10 alexpeys

This works in theory:

library(torch)
x <- torch_tensor(c(1,2,3))
x[x < 2] <- 0
x
#> torch_tensor
#>  0
#>  2
#>  3
#> [ CPUFloatType{3} ]

Created on 2020-10-19 by the reprex package (v0.3.0)

I wonder if model$lhs_emb$weight is really a tensor in your module. Can you provide a reproducible example?

dfalbel avatar Oct 19 '20 21:10 dfalbel

Actually it seems to be a bug with using the $data() method. Here's an equivalent implementation:

library(torch)
m <- nn_embedding(num_embeddings = 100, embedding_dim = 50)
with_no_grad({
  m$weight[m$weight < 0] <- 0  
})
m$weight$min()
#> torch_tensor
#> 0
#> [ CPUFloatType{} ]

Created on 2020-10-19 by the reprex package (v0.3.0)

Minimal reprex for the error:

library(torch)
m <- nn_embedding(num_embeddings = 100, embedding_dim = 50)
m$weight$data()[m$weight$data() < 0] <- 0  
#> Error in m$weight$data()[m$weight$data() < 0] <- 0: invalid (NULL) left side of assignment

Created on 2020-10-19 by the reprex package (v0.3.0)

dfalbel avatar Oct 19 '20 21:10 dfalbel

Here is the class:

require(torch)
embedder <- nn_module(
  clasname = "embedder",
  initialize = function(n_lhs, n_rhs, dim=10) {
    self$lhs_emb <- nn_embedding(n_lhs, dim)
    self$lhs_bias <- nn_embedding(n_lhs, 1)
    
    self$rhs_emb <- nn_embedding(n_rhs, dim)
    self$rhs_bias <- nn_embedding(n_rhs, 1)
    
  },
  forward = function(lhs_indexes, rhs_indexes) {
    scores <- torch_sum(self$lhs_emb(lhs_indexes) * self$rhs_emb(rhs_indexes), 2)
    scores <- scores + torch_reshape(self$lhs_bias(lhs_indexes), list(-1))
    scores <- scores + torch_reshape(self$rhs_bias(rhs_indexes), list(-1))
    return(scores)
  }
)

model <- embedder(n_lhs=3, n_rhs=3, dim=2)

Now running

model$lhs_emb$weight$data()

Yields

torch_tensor -0.9773 -0.5023 0.6282 -1.4819 -1.0336 1.5777 [ CPUFloatType{3,2} ]

Running

model$lhs_emb$weight$data()[model$lhs_emb$weight$data()<0] <- 0

Yields

Error in model$lhs_emb$weight$data()[model$lhs_emb$weight$data() < 0] <- 0 : invalid (NULL) left side of assignment

Running

alexpeys avatar Oct 19 '20 21:10 alexpeys

with_no_grad({
  m$weight[m$weight < 0] <- 0  
})

Works except bugs out if you try to use an empty slice, which is another thing PyTorch allows (precisely for ease of this kind of projection).

alexpeys avatar Oct 19 '20 21:10 alexpeys

Ok! This should be an easy fix, I'll do it as soon as possible.

dfalbel avatar Oct 19 '20 21:10 dfalbel

Thanks!

alexpeys avatar Oct 19 '20 21:10 alexpeys

Wait, that doesn't seem to error for me:


library(torch)
m <- nn_embedding(num_embeddings = 100, embedding_dim = 50)
m$weight$min()
#> torch_tensor
#> -3.66959
#> [ CPUFloatType{} ]
with_no_grad({
  m$weight[m$weight < -100] <- 0    
})
m$weight$min()
#> torch_tensor
#> -3.66959
#> [ CPUFloatType{} ]

Created on 2020-10-19 by the reprex package (v0.3.0)

Are you sure this is the cause? What exactly is an empty slice?

dfalbel avatar Oct 19 '20 22:10 dfalbel

Oops, had a typo, was a non-existent rather than empty slice.

alexpeys avatar Oct 19 '20 22:10 alexpeys

Ok, so IIUC the with_no_grad solution is working as expected?

dfalbel avatar Oct 19 '20 22:10 dfalbel

Ok, so IIUC the with_no_grad solution is working as expected?

Yes, though would be good to also have the data() method correct since this is copy-pasted PyTorch code and it would be great for that to just work after swapping . to $.

alexpeys avatar Oct 19 '20 22:10 alexpeys