library(ggplot2)
<- function(net, dataloader) {
predict_network local_no_grad()
<- list(x = numeric(), y = numeric(), pred = numeric())
xs <- 1
i $eval()
net::loop(for (batch in dataloader) {
coro$x <- c(xs$x, as.numeric(batch$x))
xs$y <- c(xs$y, as.numeric(batch$y))
xs$pred <- c(xs$pred, as.numeric(net(batch$x)))
xs
})as.data.frame(xs)
}<- function(net, dataloader, epochs, lr) {
train_network <- optim_ignite_adamw(net$parameters, lr = lr)
optimizer $train()
netfor (i in seq_len(epochs)) {
::loop(for (batch in dataloader) {
coro$zero_grad()
optimizer<- net(batch$x)
Y_pred <- nnf_mse_loss(Y_pred, batch$y)
loss $backward()
loss$step()
optimizer
})
}predict_network(net, dataloader)
}<- function(df) {
plot_results ggplot(data = df, aes(x = x)) +
geom_point(aes(y = y, color = "true")) +
geom_point(aes(y = pred, color = "pred")) +
theme_minimal()
}<- function(net, dataloader, epochs = 10, lr = 0.01) {
train_and_plot <- train_network(net, dataloader, epochs = epochs, lr = lr)
result plot_results(result)
}
It’s a Sin(us)
Question 1: Create a torch::dataset
class that takes in arguments n
, min
, and max
during initialization where:
n
is the total number of samplesmin
is the lower bound of the datamax
is the upper bound of the data
In the initialize
method, generate and store:
- a tensor
x
of shape(n, 1)
that containsn
values drawn from a uniform distribution betweenmin
andmax
- a tensor
y
of shape(n, 1)
that is defined as \(\sin(x) + \epsilon\) where \(\epsilon\) is drawn from a normal distribution with mean 0 and standard deviation 0.1
Hint
Usetorch_randn()
to draw from a standard normal distribution and multiply it with 0.1^2
to get the desired standard deviation.
Implement the $.getbatch()
method to return a named list with values x
and y
. Then, create an instance of the dataset with n = 1000
, min = 0
, and max = 10
.
Make sure that the dataset is working by calling the $.getbatch()
method. Also, check that the shapes of both tensors returned by the dataset are (n_batch, 1)
.
Question 2: Create a torch::dataloader
that takes in the dataset and returns batches of size 10. Then, iterate over the batches of the dataloader and create one tensor X
and one tensor Y
that contains the concatenated batches of x
and y
.
Hint
The functionscoro::loop()
and torch_cat()
might be helpful.
Question 3: Create a custom torch module that allows modeling the sinus data we have created. To test it, apply it to the tensor X
we have created above and calculate its mean squared error with the tensor Y
.
Hint
You can either usenn_module
to create a custom module generically, or you can use nn_sequential()
to create a custom module that is a sequence of layers.
Question 4: Train the model on the task for different hyperparameters (lr
or epochs
) and visualize the results. Play around with the hyperparameters until you get a good fit. You can use the following code for that:
Beware of the reference semantics and make sure that you create a new instance of the network for each run.
Question 5: Create a new instance from the sinus dataset class created earlier. Now, set the min
and max
values to 10
and 20
respectively and visualize the results. What do you observe? Can you explain why this is happening and can you fix the network architecture to make it work?