library(keras)
library(here)
## here() starts at /home/auggy/dev/ibm/IBMCode/using-tensorflow-with-r
library(httr)
library(jsonlite)
library(tidyverse)
## ── Attaching packages ────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.0.0 ✔ purrr 0.2.5
## ✔ tibble 1.4.2 ✔ dplyr 0.7.6
## ✔ tidyr 0.8.1 ✔ stringr 1.3.1
## ✔ readr 1.1.1 ✔ forcats 0.3.0
## ── Conflicts ───────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ purrr::flatten() masks jsonlite::flatten()
## ✖ dplyr::lag() masks stats::lag()
# devtools::install_github("rstudio/tfdeploy")
library(tfdeploy)
Using tfdeploy to serialize your model after training provides transparency into how your model was created and lets others not only reproduce your work but potentially improve it.
In the previous example, hello-keras, we trained a model to recognize handwriting. We saved this model and its weights in hdf5 format.
model_dense <- load_model_hdf5("models/mnist_dense_hdf5.h5")
You can also read in model weights. Weights are loaded based on the model’s architecture, so it should be the same as when the weights were saved.
Note that layers that don’t have weights are not taken into account, so adding or removing layers is fine as long as they don’t have weights. Also note that if the by_name parameter is TRUE, weights are loaded into layers only if they share the same name. This is useful for fine-tuning or transfer-learning models where some of the layers have changed. We’ll talk about naming layers later.
load_model_weights_hdf5(model_dense, "models/mnist_dense_weights_hdf5.h5")
Let’s use a 2d convnent instead of dense layers.
mnist <- dataset_mnist()
train_images <- mnist$train$x
train_labels <- mnist$train$y
# TODO improve
# TODO show adding a layer from another model
The next step is to export the model as a TensorFlow SavedModel using the export_savedmodel() function:
export_savedmodel(model_dense, "models/savedmodel")
## Keras learning phase set to 0 for export (restart R session before doing additional training)
Note the message that is printed: exporting a Keras model requires setting the Keras “learning phase” to 0. In practice, this means that after calling export_savedmodel you can not continue to train models in the same R session.
It is important to assign reasonable names to the the first and last layers. For example, in the model code above we named the first layer “image” and the last layer “prediction”.
model %>%
layer_dense(units = 256, activation = 'relu', input_shape = c(784),
name = "image") %>%
layer_dense(units = 128, activation = 'relu') %>%
layer_dense(units = 10, activation = 'softmax',
name = "prediction")
The layer names are reflected in the structure of REST requests and responses to and from the deployed model.
You can view the graph of your model using TensorBoard with the view_savedmodel() function:
view_savedmodel("models/savedmodel")
## Started TensorBoard at http://127.0.0.1:3218
Tensorboard PNG Export
Use serve_savedmodel() to host the model locally. Once running, make an HTTP POST request:
Note this will take over your whole process, so you don’t want to do this here.
serve_savedmodel("models/savedmodel", daemonized=TRUE)
##
## Starting server under http://127.0.0.1:8089 with the following API entry points:
## http://127.0.0.1:8089/serving_default/predict/
## [1] "139696965423448"
# grab a random index from the "batch" index (the first axis)
digit_index <- sample.int(length(train_images[1,,]), 1)
digit <- train_images[digit_index,,] # <- one slice of tensor please :)
digit_raw <- base64enc::base64encode(digit)
plot(as.raster(digit, max=255))
This will use the same syntax as the CloudML Predict Request API
model_req_body <- paste('{"instances": [{"dense_3_input":{"', digit_raw, '"}]}')
model_req <- POST("http://127.0.0.1:8089/serving_default/predict/",
encode="json",
body=model_req_body)
Each instance of new data should be formatted as a json array, and each element in the array should be a named array corresponding to the feature columns. This structure is similar to a named list in R.
# parse json
model_json <- content(model_req, as = "text")
# rectangularize
model_df <- fromJSON(json, flatten=TRUE)
https://tensorflow.rstudio.com/tools/tfdeploy/articles/saved_models.html