library(keras)
library(tensorflow)
<- dataset_mnist()
mnist
$train$x <- (mnist$train$x/255) %>%
mnistarray_reshape(., dim = c(dim(.), 1))
$test$x <- (mnist$test$x/255) %>%
mnistarray_reshape(., dim = c(dim(.), 1))
Deploying a Shiny app with a TensorFlow model
In this tutorial you will learn how to deploy a TensorFlow model inside a Shiny app. We will build a model that can classify handwritten digits in images, then we will build a Shiny app that let’s you upload an image and get predictions from this model.
Building the model
The first thing we are going to do is to build our model. We will use the Keras API to build this model.
We will use the MNIST dataset to build our model.
Now, we are going to define our Keras model, it will be a simple convolutional neural network.
<- keras_model_sequential() %>%
model layer_conv_2d(filters = 16, kernel_size = c(3,3), activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_conv_2d(filters = 16, kernel_size = c(3,3), activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_flatten() %>%
layer_dense(units = 128, activation = "relu") %>%
layer_dense(units = 10, activation = "softmax")
%>%
model compile(
loss = "sparse_categorical_crossentropy",
optimizer = "adam",
metrics = "accuracy"
)
Next, we fit the model using the MNIST dataset:
%>%
model fit(
x = mnist$train$x, y = mnist$train$y,
batch_size = 32,
epochs = 5,
validation_sample = 0.2,
verbose = 2
)
Epoch 1/5
1875/1875 - 7s - loss: 0.1730 - accuracy: 0.9477 - 7s/epoch - 4ms/step
Epoch 2/5
1875/1875 - 5s - loss: 0.0558 - accuracy: 0.9829 - 5s/epoch - 3ms/step
Epoch 3/5
1875/1875 - 4s - loss: 0.0387 - accuracy: 0.9879 - 4s/epoch - 2ms/step
Epoch 4/5
1875/1875 - 4s - loss: 0.0300 - accuracy: 0.9905 - 4s/epoch - 2ms/step
Epoch 5/5
1875/1875 - 5s - loss: 0.0226 - accuracy: 0.9926 - 5s/epoch - 3ms/step
When we are happy with our model accuracy in the validation dataset we can evaluate
the results on the test dataset with:
%>% evaluate(x = mnist$test$x, y = mnist$test$y) model
313/313 - 0s - loss: 0.0315 - accuracy: 0.9890 - 449ms/epoch - 1ms/step
loss accuracy
0.03146039 0.98900002
OK, we have 99% accuracy on the test dataset and we want to deploy that model. First, let’s save the model in the SavedModel
format using:
save_model_tf(model, "cnn-mnist")
With the model built and saved we can now start building our plumber API file.
Shiny app
A simple shiny app can be define in an app.R
file with a few conventions. Here’s how we can structure our Shiny app.
library(shiny)
library(keras)
# Load the model
<- load_model_tf("cnn-mnist/")
model
# Define the UI
<- fluidPage(
ui # App title ----
titlePanel("Hello TensorFlow!"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: File upload
fileInput("image_path", label = "Input a JPEG image")
),# Main panel for displaying outputs ----
mainPanel(
# Output: Histogram ----
textOutput(outputId = "prediction"),
plotOutput(outputId = "image")
)
)
)
# Define server logic required to draw a histogram ----
<- function(input, output) {
server
<- reactive({
image req(input$image_path)
::readJPEG(input$image_path$datapath)
jpeg
})
$prediction <- renderText({
output
<- image() %>%
img array_reshape(., dim = c(1, dim(.), 1))
paste0("The predicted class number is ", predict_classes(model, img))
})
$image <- renderPlot({
outputplot(as.raster(image()))
})
}
shinyApp(ui, server)
This app can be used locally or deployed using any Shiny deployment option. If you are deploying to RStudio Connect or Shinnyapps.io, don’t forget to set the RETICULATE_PYTHON
environment variable so rsconnect
can detect what python packages are required to reproduce your local environment. See the F.A.Q. for more information.
You can see a live version of this app here. Note that to keep the code simple, it will only accept JPEG images with 28x28 pixels. You can download this file if you want to try the app.
More advanced models
When building more advanced models you may not be able to save the entire model using the save_model_tf
function. In this case you can use the save_model_weights_tf
function.
For example:
save_model_weights_tf(model, " cnn-model-weights")
Then, in the api.R
file whenn loading the model you will need to rebuild the model using the exact same code that you used when training and saving and then use load_model_weights_tf
to load the model weights.
<- keras_model_sequential() %>%
model layer_conv_2d(filters = 16, kernel_size = c(3,3), activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_conv_2d(filters = 16, kernel_size = c(3,3), activation = "relu") %>%
layer_max_pooling_2d(pool_size = c(2,2)) %>%
layer_flatten() %>%
layer_dense(units = 128, activation = "relu") %>%
layer_dense(units = 10, activation = "softmax")
load_model_weights_tf(model, "cnn-model-weights")
Hosting the shiny app
This Shiny app can be hosted in any server using the Shiny Server. If you are managing the complete infrastructure, make sure that you have Python and all required Python packages installed in the server.
If you are using Shinyapps.io or RStudio Connect the dependencies will be infered when deploying the app. In this case, don’t forget to set the RETICULATE_PYTHON
environment variable.
You can find more examples of using reticulate in RStudio products here and learn more about Python in RStudio Connect best practices here.