mlr3torch icon indicating copy to clipboard operation
mlr3torch copied to clipboard

example of creating your own task?

Open tdhock opened this issue 9 months ago • 8 comments

Hi, I'm trying to implement a couple of torch learners on some custom data sets (tasks).

I'm reading https://mlr3torch.mlr-org.com/articles/pipeop_torch.html which how do implement a convolutional network for the tiny_imagenet pre-defined task. That page is definitely helpful for what I'm trying to do, but I wonder if you could please add another example which shows how to do it with a custom (not pre-defined) data set/task?

I would appreciate some more explanation about how po("torch_ingress_num") works, and when we need to use po("nn_reshape"), and can/should the user define tasks with lazy tensors, like the image feature/input in the example?

I seem to have got something to work using something similar to the code below, but I am not sure if this is an intended use of mlr3torch, because I do not see any such usage in the documentation.

N.pixels <- 10
N.classes <- 5
N.features <- 100
N.images <- 200
set.seed(1)
my.X.mat <- matrix(runif(N.features*N.images), N.images, N.features)
my.df <- data.frame(y=factor(1:N.classes), my.X.mat)
my.task <- mlr3::TaskClassif$new("MyTask", my.df, target="y")
library(mlr3pipelines)
library(mlr3torch)
graph <- po("select", selector = selector_type(c("numeric", "integer"))) %>>%
  po("torch_ingress_num") %>>%
  po("nn_reshape", shape=c(-1,1,N.pixels,N.pixels)) %>>%
  po("nn_conv2d_1", out_channels = 20, kernel_size = 3) %>>%
  po("nn_relu_1", inplace = TRUE) %>>%
  po("nn_max_pool2d_1", kernel_size = 2) %>>%
  po("nn_flatten") %>>%
  po("nn_linear", out_features = 100) %>>%
  po("torch_loss", t_loss("cross_entropy")) %>>%
  po("torch_optimizer", t_opt("sgd", lr=0.01)) %>>%
  po("torch_model_classif", batch_size = 32, epochs = 100L)
graph$train(my.task)
graph$predict(my.task)

In ths code above I have a custom classification task, with 100 features, X1 to X100, which is different from what I see in the example (1 feature called image).

Thanks for any help / clarification to the docs you can provide.

tdhock avatar Feb 17 '25 15:02 tdhock

Also in the example code above I provided, it appears to be missing a pipeop between nn_linear and torch_loss. Why isn't this an error?

I would expect some error like "please add nn_head before torch_loss"

tdhock avatar Feb 17 '25 16:02 tdhock

does this help: https://mlr3torch.mlr-org.com/articles/lazy_tensor.html? Then you just need to replace the torch_ingress_num with a torch_ingress_ltnsr

sebffischer avatar Feb 17 '25 16:02 sebffischer

i am on vacation right gut now, so won’t be able to address these suggestions for improvements immediately, but thanks a lot!

sebffischer avatar Feb 17 '25 16:02 sebffischer

Also in the example code above I provided, it appears to be missing a pipeop between nn_linear and torch_loss. Why isn't this an error?

I would expect some error like "please add nn_head before torch_loss"

nn_head is basically just a nn_linear that infers the output dimension from the task, but its equally valid to do create own nn_linear, so i don’t think this should be an error. users might for example create their own custom output head, so we also don’t want to throw an error in this case.

sebffischer avatar Feb 17 '25 16:02 sebffischer

Probably, the best resource for you would be: https://mlr-org.github.io/mlr3torch-course/notebooks/6-mlr3torch.html#working-with-non-tabular-data (I guess the main action point (that we want to tackle anyways) is to unify the documentation of mlr3torch, probably as part of the mlr3book, as it currently is a bit too spreaded).

sebffischer avatar Feb 17 '25 17:02 sebffischer

nn_head is basically just a nn_linear that infers the output dimension from the task, but its equally valid to do create own nn_linear, so i don’t think this should be an error. users might for example create their own custom output head, so we also don’t want to throw an error in this case.

This makes sense to me that nn_head can infer the output dimension for the task, that is very convenient.

It also makes sense to me that you could provide nn_linear with out_features=5 (the correct number of classes) and that should give the same result.

But I did not do that. My po code ends with:

  po("nn_linear", out_features = 100) %>>%
  po("torch_loss", t_loss("cross_entropy")) %>>%
  po("torch_optimizer", t_opt("sgd", lr=0.01)) %>>%
  po("torch_model_classif", batch_size = 32, epochs = 100L)

so there is no nn_head at the end. Is there one added automatically?

the last linear layer has out_features=100 which is not compatible with the number of classes (5), so I would expect an error like "output of neural network is dimension 100 but there are only 5 class labels, so please edit the output dimension to match the number of class labels, or add nn_head at the end"

tdhock avatar Mar 13 '25 18:03 tdhock

thanks for the links to the other docs about lazy tensors. I have not had a chance to review them yet, but they seem to be helpful.

tdhock avatar Mar 13 '25 18:03 tdhock

nn_head is basically just a nn_linear that infers the output dimension from the task, but its equally valid to do create own nn_linear, so i don’t think this should be an error. users might for example create their own custom output head, so we also don’t want to throw an error in this case.

This makes sense to me that nn_head can infer the output dimension for the task, that is very convenient.

It also makes sense to me that you could provide nn_linear with out_features=5 (the correct number of classes) and that should give the same result.

But I did not do that. My po code ends with:

po("nn_linear", out_features = 100) %>>% po("torch_loss", t_loss("cross_entropy")) %>>% po("torch_optimizer", t_opt("sgd", lr=0.01)) %>>% po("torch_model_classif", batch_size = 32, epochs = 100L)

so there is no nn_head at the end. Is there one added automatically?

No, it needs to be there explicitly.

the last linear layer has out_features=100 which is not compatible with the number of classes (5), so I would expect an error like "output of neural network is dimension 100 but there are only 5 class labels, so please edit the output dimension to match the number of class labels, or add nn_head at the end"

Yeah, improving the error message makes sense!

sebffischer avatar Mar 21 '25 08:03 sebffischer