TensorFlow for R - Infrastructure and Deployment
Expert guidance for using TensorFlow in R through the tensorflow package, with emphasis on installation, keras3 integration, deployment, and when to choose TensorFlow vs other deep learning frameworks in R.
Overview
The tensorflow R package provides a complete interface to TensorFlow, enabling:
- Full TensorFlow API access through
reticulatebridge - Seamless keras3 integration for high-level modeling
- Production deployment with SavedModel format
- Graph optimization with
tf_function() - GPU acceleration and distributed training
- Integration with Python TensorFlow ecosystems
Key Distinction: TensorFlow for R serves as the infrastructure layer, while keras3 provides the high-level API. Most users interact primarily with keras3, accessing TensorFlow directly for deployment, custom operations, or advanced control.
When to Use TensorFlow in R
Choose TensorFlow When:
- Existing TensorFlow infrastructure: Integrating with existing TF pipelines
- Deployment requirements: Need TensorFlow Serving or SavedModel format
- Cross-platform models: Deploying to mobile (TFLite) or web (TF.js)
- Python interop: Working with Python TensorFlow code
- Graph optimization: Need
tf_function()compilation - Multi-backend flexibility: keras3 with TensorFlow backend
Choose torch When:
- Research and experimentation requiring flexibility
- Custom training loops and novel architectures
- State-of-the-art research implementations
- Need full control over training process
- PyTorch-based pretrained models
Choose keras3 Alone When:
- Standard architectures (ResNet, LSTM, transformers)
- Rapid prototyping with high-level API
- Backend-agnostic code (TensorFlow/JAX/torch)
- Production with built-in
fit()workflow
Study Path: Start with keras3 (gentle intro) → torch (low-level control) → TensorFlow (infrastructure/deployment)
For complete framework comparison, see references/framework-comparison.md
Installation and Setup
Basic Installation
# Step 1: Install R package
install.packages("tensorflow")
# Or development version
remotes::install_github("rstudio/tensorflow")
# Step 2: Install Python (if needed)
library(reticulate)
install_python()
# Step 3: Install TensorFlow in isolated environment
library(tensorflow)
install_tensorflow(envname = "r-tensorflow")
# Verification
tf$constant("Hello TensorFlow!")
Installation Variants
# GPU-capable (default)
install_tensorflow()
# Specific version
install_tensorflow(version = "2.10")
# CPU-only (smaller package)
install_tensorflow(version = "cpu")
# Nightly development build
install_tensorflow(version = "nightly")
# Custom environment name
install_tensorflow(envname = "my-tf-env")
# Virtual environment method
install_tensorflow(method = "virtualenv")
# Conda method (Windows recommended)
install_tensorflow(method = "conda")
# With additional packages
install_tensorflow(extra_packages = c("tensorflow-hub", "tensorflow-probability"))
# Specific Python version
install_tensorflow(python_version = "3.10")
# Linux GPU with automatic CUDA/cuDNN (v2.16.0+)
install_tensorflow() # Auto-detects GPU and installs CUDA
Configuration and Verification
# Check configuration
tf_config()
# Check version
tf_version()
# GPU availability
tf$config$list_physical_devices("GPU")
# Set visible GPUs
Sys.setenv(CUDA_VISIBLE_DEVICES = "0,1")
# Memory growth (prevent GPU memory preallocation)
gpus <- tf$config$list_physical_devices("GPU")
if (length(gpus) > 0) {
tf$config$experimental$set_memory_growth(gpus[[1]], TRUE)
}
Common Installation Issues
For comprehensive troubleshooting guide, see references/installation-troubleshooting.md
Quick fixes:
- Module not found: Reinstall with
install_tensorflow(force = TRUE) - Environment corruption: Remove and recreate with new envname
- GPU not detected (Linux): Update CUDA/cuDNN or use auto-install (v2.16.0+)
- WSL issues: Use latest tensorflow (v2.20.0+) with improved WSL support
- Mac M1: Use method="virtualenv" with ARM64-compatible builds
Core TensorFlow Concepts
Tensors and Operations
# Create tensors
x <- tf$constant(c(1, 2, 3, 4), shape = c(2, 2))
y <- tf$Variable(initial_value = 0.0, trainable = TRUE)
# Operations
z <- tf$add(x, 10)
product <- tf$matmul(x, x)
# Type conversion
as.array(x) # Convert to R array
as_tensor(matrix(1:4, 2, 2)) # R to tensor
Automatic Differentiation
# GradientTape for custom gradients
with(tf$GradientTape() %as% tape, {
loss <- model(x, training = TRUE)
})
gradients <- tape$gradient(loss, model$trainable_weights)
optimizer$apply_gradients(zip_lists(gradients, model$trainable_weights))
Graph Compilation with tf_function
# Compile R functions to TensorFlow graphs
train_step <- tf_function(function(x, y) {
with(tf$GradientTape() %as% tape, {
predictions <- model(x, training = TRUE)
loss <- loss_fn(y, predictions)
})
gradients <- tape$gradient(loss, model$trainable_weights)
optimizer$apply_gradients(zip_lists(gradients, model$trainable_weights))
return(loss)
})
# Significant performance improvement for loops
for (epoch in 1:num_epochs) {
loss <- train_step(x_batch, y_batch)
}
Keras3 Integration
TensorFlow for R primarily uses keras3 as the high-level API. The keras3 package supports multiple backends (TensorFlow, JAX, torch), with TensorFlow as the default.
Model Building Patterns
library(keras3)
# Sequential API
model <- keras_model_sequential(input_shape = c(784)) |>
layer_dense(128, activation = "relu") |>
layer_dropout(0.2) |>
layer_dense(10, activation = "softmax")
# Functional API (multi-input/output)
input_a <- keras_input(shape = c(100))
input_b <- keras_input(shape = c(50))
x <- layer_dense(input_a, 64, activation = "relu")
y <- layer_dense(input_b, 32, activation = "relu")
merged <- layer_concatenate(c(x, y))
output <- layer_dense(merged, 1, activation = "sigmoid")
model <- keras_model(
inputs = list(input_a, input_b),
outputs = output
)
# Model subclassing (custom models)
CustomModel <- new_keras_model(
"CustomModel",
initialize = function() {
super$initialize()
self$dense1 <- layer_dense(128, activation = "relu")
self$dense2 <- layer_dense(10, activation = "softmax")
},
call = function(inputs) {
x <- self$dense1(inputs)
self$dense2(x)
}
)
Training Workflow
# Compile model
model |> compile(
optimizer = optimizer_adam(learning_rate = 0.001),
loss = loss_sparse_categorical_crossentropy(),
metrics = c("accuracy")
)
# Train with callbacks
history <- model |> fit(
x_train, y_train,
epochs = 50,
batch_size = 128,
validation_split = 0.2,
callbacks = list(
callback_early_stopping(monitor = "val_loss", patience = 5),
callback_model_checkpoint("best_model.keras", save_best_only = TRUE),
callback_reduce_lr_on_plateau(monitor = "val_loss", factor = 0.5, patience = 3)
)
)
# Evaluate and predict
results <- model |> evaluate(x_test, y_test)
predictions <- model |> predict(x_test)
For complete Keras3 workflows and examples, see examples/keras-workflows.md
Model Deployment and Serialization
SavedModel Format (Recommended)
# Save complete model
save_model(model, "saved_model/my_model")
# Load model
loaded_model <- load_model("saved_model/my_model")
# Verify loaded model
loaded_model |> evaluate(x_test, y_test)
Keras Format (.keras)
# Save as .keras (zip archive)
save_model(model, "my_model.keras")
# Load
model <- load_model("my_model.keras")
Weights-Only Checkpoint
# Save weights during training
checkpoint <- callback_model_checkpoint(
filepath = "checkpoints/weights_epoch_{epoch:02d}.h5",
save_weights_only = TRUE,
save_best_only = TRUE,
monitor = "val_loss"
)
model |> fit(x, y, callbacks = list(checkpoint))
# Load weights into existing model
model |> load_model_weights_tf("checkpoints/weights_epoch_10.h5")
Export to ONNX (Cross-Platform)
# Requires onnx package
# Export for deployment to non-TensorFlow runtimes
# See references/deployment-strategies.md for details
TensorFlow Serving Integration
# Export SavedModel with serving signature
export_savedmodel(
model,
export_dir_base = "serving_models/",
versioned = TRUE # Creates timestamped versions
)
# View saved model
view_savedmodel("serving_models/1234567890")
For production deployment patterns, see references/deployment-strategies.md
Data Pipelines with tfdatasets
The tfdatasets package provides efficient data loading and preprocessing:
library(tfdatasets)
# Load from tensors
dataset <- tensor_slices_dataset(list(x_train, y_train))
# Transform pipeline
dataset <- dataset |>
dataset_shuffle(buffer_size = 10000) |>
dataset_batch(batch_size = 32) |>
dataset_map(function(x, y) {
list(x / 255, y) # Normalize
}) |>
dataset_prefetch(buffer_size = tf$data$AUTOTUNE) |>
dataset_cache() # Cache in memory
# Use in training
model |> fit(dataset, epochs = 10)
# Load from files
text_dataset <- text_line_dataset("data.txt") |>
dataset_map(preprocess_function) |>
dataset_batch(32)
# TFRecord format
tfrecord_dataset <- tfrecord_dataset("data.tfrecord") |>
dataset_map(parse_function)
GPU Configuration and Optimization
GPU Detection and Setup
# List available GPUs
gpus <- tf$config$list_physical_devices("GPU")
print(gpus)
# Set visible devices
tf$config$set_visible_devices(gpus[[1]], "GPU")
# Memory growth (prevent preallocation)
for (gpu in gpus) {
tf$config$experimental$set_memory_growth(gpu, TRUE)
}
# Set memory limit
tf$config$set_logical_device_configuration(
gpus[[1]],
list(tf$config$LogicalDeviceConfiguration(memory_limit = 4096))
)
Mixed Precision Training
# Enable mixed precision (FP16)
policy <- tf$keras$mixed_precision$Policy("mixed_float16")
tf$keras$mixed_precision$set_global_policy(policy)
# Build model (automatically uses mixed precision)
model <- keras_model_sequential() |>
layer_dense(128, activation = "relu") |>
layer_dense(10, activation = "softmax", dtype = "float32") # Keep output FP32
# ~2x speedup with minimal accuracy loss
Multi-GPU Training
# MirroredStrategy for single-machine multi-GPU
strategy <- tf$distribute$MirroredStrategy()
with(strategy$scope(), {
model <- keras_model_sequential() |>
layer_dense(128, activation = "relu") |>
layer_dense(10, activation = "softmax")
model |> compile(
optimizer = optimizer_adam(),
loss = loss_sparse_categorical_crossentropy(),
metrics = c("accuracy")
)
})
# Adjust batch size for all replicas
global_batch_size <- 32 * strategy$num_replicas_in_sync
model |> fit(dataset, epochs = 10)
For comprehensive GPU optimization strategies, see references/gpu-optimization.md
Custom Training Loops
When fit() is insufficient, use custom training loops:
# Setup
optimizer <- optimizer_adam()
loss_fn <- loss_sparse_categorical_crossentropy()
train_acc_metric <- metric_sparse_categorical_accuracy()
# Training loop
for (epoch in 1:num_epochs) {
cat("Epoch", epoch, "\n")
# Iterate over batches
for (batch in iterate(train_dataset)) {
with(tf$GradientTape() %as% tape, {
logits <- model(batch[[1]], training = TRUE)
loss_value <- loss_fn(batch[[2]], logits)
})
grads <- tape$gradient(loss_value, model$trainable_weights)
optimizer$apply_gradients(zip_lists(grads, model$trainable_weights))
# Update metrics
train_acc_metric$update_state(batch[[2]], logits)
}
# Display metrics
train_acc <- train_acc_metric$result()
cat("Training accuracy:", as.numeric(train_acc), "\n")
train_acc_metric$reset_state()
}
For advanced custom training patterns, see examples/custom-training-loops.md
Transfer Learning and Fine-Tuning
Basic Transfer Learning
# Load pretrained model
base_model <- application_resnet50(
weights = "imagenet",
include_top = FALSE,
input_shape = c(224, 224, 3)
)
# Freeze base model
base_model$trainable <- FALSE
# Add custom head
inputs <- keras_input(shape = c(224, 224, 3))
x <- base_model(inputs, training = FALSE) # Inference mode
x <- layer_global_average_pooling_2d()(x)
outputs <- layer_dense(x, units = 10, activation = "softmax")
model <- keras_model(inputs, outputs)
# Train only new layers
model |> compile(
optimizer = optimizer_adam(learning_rate = 0.001),
loss = loss_categorical_crossentropy(),
metrics = c("accuracy")
)
model |> fit(train_data, epochs = 10)
Fine-Tuning
# Unfreeze base model for fine-tuning
base_model$trainable <- TRUE
# Recompile with very low learning rate
model |> compile(
optimizer = optimizer_adam(learning_rate = 1e-5), # Very low LR
loss = loss_categorical_crossentropy(),
metrics = c("accuracy")
)
# Fine-tune
model |> fit(train_data, epochs = 5)
Important: Use training = FALSE when calling BatchNormalization layers during fine-tuning to keep them in inference mode.
TensorFlow Hub Integration
library(tfhub)
# Use pretrained embeddings
hub_layer <- layer_hub(
handle = "https://tfhub.dev/google/nnlm-en-dim50/2",
trainable = TRUE
)
model <- keras_model_sequential() |>
hub_layer |>
layer_dense(16, activation = "relu") |>
layer_dense(1, activation = "sigmoid")
# Train
model |> compile(
optimizer = optimizer_adam(),
loss = loss_binary_crossentropy(),
metrics = c("accuracy")
)
Preprocessing Layers
Keras3 preprocessing layers enable end-to-end models:
# Text preprocessing
text_vectorizer <- layer_text_vectorization(max_tokens = 10000)
# Adapt to vocabulary
text_vectorizer |> adapt(raw_text_data)
# Use in model
model <- keras_model_sequential() |>
text_vectorizer |>
layer_embedding(input_dim = 10000, output_dim = 128) |>
layer_lstm(64) |>
layer_dense(1, activation = "sigmoid")
# Image preprocessing
model <- keras_model_sequential(input_shape = c(NULL, NULL, 3)) |>
layer_rescaling(scale = 1/255) |>
layer_resizing(height = 224, width = 224) |>
layer_conv_2d(32, 3, activation = "relu") |>
# ... rest of model
Advantage: Preprocessing embedded in model ensures consistency between training and serving.
Experiment Tracking with tfruns
library(tfruns)
# Define training script with flags
# train.R:
FLAGS <- flags(
flag_numeric("learning_rate", 0.001),
flag_integer("epochs", 10),
flag_integer("batch_size", 32)
)
# Run training
training_run("train.R", flags = list(
learning_rate = 0.01,
epochs = 20
))
# Compare runs
compare_runs()
# List runs
ls_runs()
# View specific run
view_run("runs/2024-03-16T10-30-00Z")
Package Architecture and Integration
Lazy Loading Pattern
The tensorflow package uses lazy loading for fast startup:
# TensorFlow loads only when first accessed
library(tensorflow) # Fast
# First access triggers loading
tf$constant(1) # Loads TensorFlow
Reticulate Integration
TensorFlow for R bridges to Python via reticulate:
# Access Python TensorFlow API
tf$nn$relu(...)
tf$keras$layers$Dense(...)
# Type conversion
tensor <- as_tensor(r_array) # R to TF
r_array <- as.array(tensor) # TF to R
# Custom Python code
py_run_string("import tensorflow as tf")
S3 Methods for Tensors
# Tensors behave like R arrays
x <- tf$constant(c(1, 2, 3, 4), shape = c(2, 2))
as.array(x) # Convert to array
dim(x) # Get dimensions
length(x) # Get length
x[1, ] # Subset (converts to R)
Migration and Compatibility
TensorFlow 1.x to 2.x Migration
# Use compatibility mode for gradual migration
tf$compat$v1$enable_eager_execution() # TF 2.x behavior in TF 1.x code
# Or use compatibility API
use_compat("v1") # Run TF 1.x code in TF 2.x
use_compat("v2") # Run TF 2.x code explicitly
Breaking Changes (v2.7.0)
shape() behavior changed:
# Old behavior (< v2.7.0)
shape <- shape(tensor) # Returns R list
# New behavior (>= v2.7.0)
shape <- shape(tensor) # Returns tf.TensorShape object
# Migration
shape_list <- as.list(shape(tensor))
shape_int <- as.integer(shape(tensor))
Package Version History
- v2.20.0 (Aug 2024): NumPy 2.0 support, WSL GPU fixes
- v2.16.0 (Apr 2024): keras3 integration, auto CUDA/cuDNN (Linux)
- v2.14.0: Removed
install_tensorflow_extras() - v2.13.0: Default env changed to "r-tensorflow"
- v2.7.0: Breaking change in
shape()return type
Best Practices
Installation
- Use isolated environments (
envnameparameter) - Pin specific versions for reproducibility
- Test GPU detection immediately after install
- Use conda method on Windows for reliability
Model Development
- Start with keras3 high-level API
- Use
tf_function()for performance-critical loops - Implement callbacks for training control
- Save checkpoints frequently during long training
Deployment
- Use SavedModel format for production
- Test loaded models before deployment
- Version models with timestamps
- Include preprocessing in model for consistency
Performance
- Enable memory growth to prevent GPU memory issues
- Use
dataset_prefetch()anddataset_cache()for data loading - Apply mixed precision for 2x speedup on modern GPUs
- Profile with
tf$profilerfor bottleneck identification
Debugging
- Use
tf$debugging$assert_*functions for runtime checks - Enable eager execution during debugging
- Use
tf$print()insidetf_function()for debugging - Check tensor shapes frequently with
shape()
Common Gotchas
- Forgetting to recompile after changing
trainablestatus - BatchNorm in training mode during inference (use
training = FALSE) - Not adapting preprocessing layers before training
- Memory growth not enabled causing GPU OOM
- Using
training = TRUEin transfer learning base model - Hardcoding batch size in model architecture
- Not using
dataset_prefetch()causing training slowdowns - Shape mismatches between Python (0-indexed) and R (1-indexed)
For comprehensive troubleshooting, see references/common-gotchas.md
Complete Example
For a complete end-to-end example (CIFAR-10 image classification), see examples/cifar10-complete.md
Related Packages
- keras3: High-level neural networks API (primary interface)
- tfdatasets: Efficient data input pipelines
- tfhub: Access to pretrained models and embeddings
- tfruns: Experiment tracking and hyperparameter tuning
- tfautograph: Automatic graph compilation
- tfprobability: Probabilistic programming and statistical modeling
When to Use Low-Level TensorFlow API
Most users should use keras3 for model building. Access low-level TensorFlow API when:
- Custom operations not available in Keras
- Need
tf_function()graph compilation - Implementing research papers with TF-specific operations
- Deployment requiring SavedModel manipulation
- Integration with TensorFlow Serving or TFLite
- Advanced distributed training strategies
Resources
Documentation
- Official site: https://tensorflow.rstudio.com
- Keras3 docs: https://keras3.posit.co
- TensorFlow API: https://www.tensorflow.org/api_docs
Supporting Files
- Framework comparison: references/framework-comparison.md
- Installation troubleshooting: references/installation-troubleshooting.md
- GPU optimization: references/gpu-optimization.md
- Deployment strategies: references/deployment-strategies.md
- Keras workflows: examples/keras-workflows.md
- Custom training: examples/custom-training-loops.md
- Complete example: examples/cifar10-complete.md
Books
- Deep Learning with R (2nd edition) - Comprehensive coverage of keras3 and TensorFlow
Summary
TensorFlow for R provides robust infrastructure for deep learning in R, with keras3 serving as the primary high-level interface. Key strengths:
✅ Seamless keras3 integration for rapid development
✅ Production deployment with SavedModel and TensorFlow Serving
✅ GPU acceleration with automatic CUDA setup
✅ Multi-backend flexibility through keras3 (TensorFlow/JAX/torch)
✅ Python interoperability for TensorFlow ecosystem integration
✅ Graph optimization with tf_function() compilation
Recommended workflow: Build models with keras3, deploy with TensorFlow SavedModel format, optimize with tf_function() when needed.