Updating https://tensorflow.rstudio.com/tutorials/quickstart/advanced to Keras3

In a previous topic, t.kalinowski invited me to ask "here" about problems I had with the keras tutorials at
https://tensorflow.rstudio.com/tutorials/quickstart/ after updating R package keras to keras3. I have been unable to get the specific tutorial "QuickStart/Advanced" to work. Specifically, it fails at the last section starting with "EPOCHS = 1". I made the following 4 changes to the code to get it working up to that point:

  1. Installed keras3 as per "Getting Started with Keras • keras3" with:
    keras3::install_keras(backend = "tensorflow")
  2. loaded MNIST editing "keras" to "keras3:
    "c(c(x_train, y_train), c(x_test, y_test)) %<-% keras3::dataset_mnist()
  3. adding "library(tfdatasets)", needed for "tensor_slices_dataset()", and perhaps for other functions,
  4. changing "tf_function" to "tensorflow::tf_function", evidently not included in the keras3 tensorflow install.
    With those changes, the code worked up to the last section starting with "EPOCHS = 1", where the code abended with the message and traceback as follows:

"Error in py_get_attr(x, name) :
AttributeError: 'Mean' object has no attribute 'reset_states'
Run reticulate::py_last_error() for details.

reticulate::py_last_error()

── Python Exception Message ──────────────────────────────────────────────────────────────
AttributeError: 'Mean' object has no attribute 'reset_states'

── R Traceback ───────────────────────────────────────────────────────────────────────────

  1. └─global reset_metrics()
  2. ├─metric$reset_states
  3. └─reticulate:::$.python.builtin.object(metric, "reset_states")
  4. └─reticulate:::py_get_attr_or_item(x, name, TRUE)
    
  5.   └─reticulate::py_get_attr(x, name)
    

See reticulate::py_last_error()$r_trace$full_call for more details.

reset_metrics()
Error in py_get_attr(x, name) :
AttributeError: 'Mean' object has no attribute 'reset_states'
Run reticulate::py_last_error() for details.
train(train_ds)
Error in py_call_impl(callable, call_args$unnamed, call_args$named) :
TypeError: enter() missing 1 required positional argument: 'self'
Run reticulate::py_last_error() for details.
test(test_ds)
Error in assert_all_dots_named(envir, call) :
RuntimeError: All arguments provided to ... must be named.
Call with unnamed arguments in dots:
test_loss(t_loss)
Run reticulate::py_last_error() for details."

I didn't understand these messages.

I would be very grateful if t.kalinowski or one of the keras3 team can update the code in this keras tutorial so that I can run it successfully with R package keras3. Thanks. Larry Hunsicker

Running R 4.4.1 and RStudio 2024.04.2 Build 764 on a 64 bit Windows 11 laptop.

Addendum: I also had to edit the line:

 with(tf$GradientTape() %as% tape, {

to:
"tape <- tf$GradientTape
train_step <- function(images, labels) {
with(tape, {"

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")
}

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.