With the help of Perplexity, I was able to update this tutorial to run successfully with Keras3. Please note that a message appearing at the completion of each EPOCH of the final training loop is a harmless known not yet fixed issue with Keras3. My final code for this tutorial is as follows (Prepend each section header with "#" to run correctly):
mnist2.r: Keras subclassing API and custom training loop
library(tensorflow)
library(tfdatasets)
library(keras3)
install_keras(backend = "tensorflow")Test setup.
tf$constant("Hello TensorFlow!")
tf$config$list_physical_devices('GPU')Get and adjust MNIST data set.
c(c(x_train, y_train), c(x_test, y_test)) %<-% keras3::dataset_mnist()
x_train %<>% { . / 255 }
x_test %<>% { . / 255 }Batch and shuffle:
train_ds <- list(x_train, y_train) %>%
tensor_slices_dataset() %>%
dataset_shuffle(10000) %>%
dataset_batch(32)
test_ds <- list(x_test, y_test) %>%
tensor_slices_dataset() %>%
dataset_batch(32)
train_ds <- train_ds %>%
dataset_map(function(x, y) {
list(
tf$expand_dims(tf$cast(x, tf$float32), axis = as.integer(-1)),
y
)
})
test_ds <- test_ds %>%
dataset_map(function(x, y) {
list(
tf$expand_dims(tf$cast(x, tf$float32), axis = as.integer(-1)),
y
)
})Build a model using model subclassing:
my_model <- new_model_class(
classname = "MyModel",
initialize = function(...) {
super$initialize()
self$conv1 <- layer_conv_2d(filters = 32, kernel_size = 3,
activation = 'relu')
self$flatten <- layer_flatten()
self$d1 <- layer_dense(units = 128, activation = 'relu')
self$d2 <- layer_dense(units = 10)
},
call = function(inputs) {
inputs %>%
self$conv1() %>%
self$flatten() %>%
self$d1() %>%
self$d2()
}
)Create an instance of same:
model <- my_model()
Choose an optimizer and loss function:
loss_object <- loss_sparse_categorical_crossentropy(from_logits = TRUE)
optimizer <- optimizer_adam()Choose loss and accuracy metrics:
train_loss <- keras$metrics$Mean(name = "train_loss")
train_accuracy <- keras$metrics$SparseCategoricalAccuracy(name = "train_accuracy")
test_loss <- keras$metrics$Mean(name = "test_loss")
test_accuracy <- keras$metrics$SparseCategoricalAccuracy(name = "test_accuracy")Training step
train_step <- function(images, labels) {
with(tf$GradientTape() %as% tape, {
predictions <- model(images)
loss <- loss_object(labels, predictions)
})
gradients <- tape$gradient(loss, model$trainable_variables)
optimizer$apply_gradients(zip_lists(gradients, model$trainable_variables))
train_loss$update_state(loss)
train_accuracy$update_state(labels, predictions)
}Test step
test_step <- function(images, labels) {
predictions <- model(images)
t_loss <- loss_object(labels, predictions)
test_loss$update_state(t_loss)
test_accuracy$update_state(labels, predictions)
}Run model.
EPOCHS <- 2
for (epoch in seq_len(EPOCHS)) {
train_loss$reset_state()
train_accuracy$reset_state()
test_loss$reset_state()
test_accuracy$reset_state()Train the model
train_iter <- as_iterator(train_ds)
while (!is.null(batch <- iter_next(train_iter))) {
images <- batch[[1]]
labels <- batch[[2]]
train_step(images, labels)
}Test the model
test_iter <- as_iterator(test_ds)
while (!is.null(batch <- iter_next(test_iter))) {
images <- batch[[1]]
labels <- batch[[2]]
test_step(images, labels)
}
cat(sprintf('Epoch %d', epoch), "\n")
cat(sprintf('Loss: %f', train_loss$result()$numpy()), "\n")
cat(sprintf('Accuracy: %f', train_accuracy$result()$numpy() * 100), "\n")
cat(sprintf('Test Loss: %f', test_loss$result()$numpy()), "\n")
cat(sprintf('Test Accuracy: %f', test_accuracy$result()$numpy() * 100), "\n")
}