library(tensorflow)
# Uncomment to see where your variables get placed (see below)
# tf$debugging$set_log_device_placement(TRUE)
Introduction to Variables
A TensorFlow variable is the recommended way to represent shared, persistent state your program manipulates. This guide covers how to create, update, and manage instances of tf$Variable
in TensorFlow.
Variables are created and tracked via the tf$Variable
class. A tf$Variable
represents a tensor whose value can be changed by running ops on it. Specific ops allow you to read and modify the values of this tensor. Higher level libraries like tf$keras
use tf$Variable
to store model parameters.
Setup
This notebook discusses variable placement. If you want to see on what device your variables are placed, uncomment this line.
Create a variable
To create a variable, provide an initial value. The tf$Variable
will have the same dtype
as the initialization value.
<- as_tensor(1:4, "float32", shape = c(2, 2))
my_tensor <- tf$Variable(my_tensor)) (my_variable
<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[1., 2.],
[3., 4.]], dtype=float32)>
# Variables can be all kinds of types, just like tensors
<- tf$Variable(c(FALSE, FALSE, FALSE, TRUE))) (bool_variable
<tf.Variable 'Variable:0' shape=(4,) dtype=bool, numpy=array([False, False, False, True])>
<- tf$Variable(c(5 + 4i, 6 + 1i))) (complex_variable
<tf.Variable 'Variable:0' shape=(2,) dtype=complex128, numpy=array([5.+4.j, 6.+1.j])>
A variable looks and acts like a tensor, and, in fact, is a data structure backed by a tf$Tensor
. Like tensors, they have a dtype
and a shape, and can be exported to regular R arrays.
cat("Shape: "); my_variable$shape
Shape:
TensorShape([2, 2])
cat("DType: "); my_variable$dtype
DType:
tf.float32
cat("As R array: "); str(as.array(my_variable))
As R array:
num [1:2, 1:2] 1 3 2 4
Most tensor operations work on variables as expected, although variables cannot be reshaped.
message("A variable: ")
A variable:
my_variable
<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[1., 2.],
[3., 4.]], dtype=float32)>
message("Viewed as a tensor: ")
Viewed as a tensor:
as_tensor(my_variable)
tf.Tensor(
[[1. 2.]
[3. 4.]], shape=(2, 2), dtype=float32)
message("Index of highest value: ")
Index of highest value:
$math$argmax(my_variable) tf
tf.Tensor([1 1], shape=(2), dtype=int64)
# This creates a new tensor; it does not reshape the variable.
message("Copying and reshaping: ")
Copying and reshaping:
$reshape(my_variable, c(1L, 4L)) tf
tf.Tensor([[1. 2. 3. 4.]], shape=(1, 4), dtype=float32)
As noted above, variables are backed by tensors. You can reassign the tensor using tf$Variable$assign
. Calling assign
does not (usually) allocate a new tensor; instead, the existing tensor’s memory is reused.
<- tf$Variable(c(2, 3))
a
# assigning allowed, input is automatically
# cast to the dtype of the Variable, float32
$assign(as.integer(c(1, 2))) a
<tf.Variable 'UnreadVariable' shape=(2,) dtype=float32, numpy=array([1., 2.], dtype=float32)>
# resize the variable is not allowed
try(a$assign(c(1.0, 2.0, 3.0)))
Error in py_call_impl(callable, dots$args, dots$keywords) :
ValueError: Cannot assign value to variable ' Variable:0': Shape mismatch.The variable shape (2,), and the assigned value shape (3,) are incompatible.
If you use a variable like a tensor in operations, you will usually operate on the backing tensor.
Creating new variables from existing variables duplicates the backing tensors. Two variables will not share the same memory.
<- tf$Variable(c(2, 3))
a # Create b based on the value of a
<- tf$Variable(a)
b $assign(c(5, 6)) a
<tf.Variable 'UnreadVariable' shape=(2,) dtype=float32, numpy=array([5., 6.], dtype=float32)>
# a and b are different
as.array(a)
[1] 5 6
as.array(b)
[1] 2 3
# There are other versions of assign
as.array(a$assign_add(c(2,3))) # c(7, 9)
[1] 7 9
as.array(a$assign_sub(c(7,9))) # c(0, 0)
[1] 0 0
Lifecycles, naming, and watching
In TensorFlow, tf$Variable
instance have the same lifecycle as other R objects. When there are no references to a variable it is automatically deallocated (garbage-collected).
Variables can also be named which can help you track and debug them. You can give two variables the same name.
# Create a and b; they will have the same name but will be backed by
# different tensors.
<- tf$Variable(my_tensor, name = "Mark")
a # A new variable with the same name, but different value
# Note that the scalar add `+` is broadcast
<- tf$Variable(my_tensor + 1, name = "Mark")
b
# These are elementwise-unequal, despite having the same name
print(a == b)
tf.Tensor(
[[False False]
[False False]], shape=(2, 2), dtype=bool)
Variable names are preserved when saving and loading models. By default, variables in models will acquire unique variable names automatically, so you don’t need to assign them yourself unless you want to.
Although variables are important for differentiation, some variables will not need to be differentiated. You can turn off gradients for a variable by setting trainable
to false at creation. An example of a variable that would not need gradients is a training step counter.
<- tf$Variable(1L, trainable = FALSE)) (step_counter
<tf.Variable 'Variable:0' shape=() dtype=int32, numpy=1>
Placing variables and tensors
For better performance, TensorFlow will attempt to place tensors and variables on the fastest device compatible with its dtype
. This means most variables are placed on a GPU if one is available.
However, you can override this. In this snippet, place a float tensor and a variable on the CPU, even if a GPU is available. By turning on device placement logging (see above), you can see where the variable is placed.
Note: Although manual placement works, using distribution strategies can be a more convenient and scalable way to optimize your computation.
If you run this notebook on different backends with and without a GPU you will see different logging. Note that logging device placement must be turned on at the start of the session.
with(tf$device('CPU:0'), {
# Create some tensors
<- tf$Variable(array(1:6, c(2, 3)), dtype = "float32")
a <- as_tensor(array(1:6, c(3, 2)), dtype = "float32")
b <- tf$matmul(a, b)
c
})
c
tf.Tensor(
[[22. 49.]
[28. 64.]], shape=(2, 2), dtype=float32)
It’s possible to set the location of a variable or tensor on one device and do the computation on another device. This will introduce delay, as data needs to be copied between the devices.
You might do this, however, if you had multiple GPU workers but only want one copy of the variables.
with(tf$device('CPU:0'), {
<- tf$Variable(array(1:6, c(2, 3)), dtype = "float32")
a <- tf$Variable(array(1:3, c(1, 3)), dtype = "float32")
b
})
with(tf$device('GPU:0'), {
# Element-wise multiply
<- a * b
k
})
k
tf.Tensor(
[[ 1. 6. 15.]
[ 2. 8. 18.]], shape=(2, 3), dtype=float32)
Note: Because tf$config$set_soft_device_placement()
is turned on by default, even if you run this code on a device without a GPU, it will still run. The multiplication step will happen on the CPU.
For more on distributed training, refer to the guide.
Next steps
To understand how variables are typically used, see our guide on automatic differentiation.
Environment Details
::tf_config() tensorflow
TensorFlow v2.11.0 (~/.virtualenvs/r-tensorflow-website/lib/python3.10/site-packages/tensorflow)
Python v3.10 (~/.virtualenvs/r-tensorflow-website/bin/python)
sessionInfo()
R version 4.2.1 (2022-06-23)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.5 LTS
Matrix products: default
BLAS: /home/tomasz/opt/R-4.2.1/lib/R/lib/libRblas.so
LAPACK: /usr/lib/x86_64-linux-gnu/libmkl_intel_lp64.so
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] tensorflow_2.9.0.9000
loaded via a namespace (and not attached):
[1] Rcpp_1.0.9 whisker_0.4.1 knitr_1.41
[4] magrittr_2.0.3 here_1.0.1 lattice_0.20-45
[7] rlang_1.0.6 fastmap_1.1.0 fansi_1.0.3
[10] stringr_1.5.0 tools_4.2.1 grid_4.2.1
[13] xfun_0.35 png_0.1-8 utf8_1.2.2
[16] cli_3.4.1 tfruns_1.5.1 htmltools_0.5.4
[19] rprojroot_2.0.3 yaml_2.3.6 digest_0.6.31
[22] tibble_3.1.8 lifecycle_1.0.3 Matrix_1.5-3
[25] base64enc_0.1-3 htmlwidgets_1.5.4 vctrs_0.5.1
[28] glue_1.6.2 evaluate_0.18 rmarkdown_2.18
[31] stringi_1.7.8 compiler_4.2.1 pillar_1.8.1
[34] reticulate_1.26-9000 jsonlite_1.8.4 pkgconfig_2.0.3
system2(reticulate::py_exe(), c("-m pip freeze"), stdout = TRUE) |> writeLines()
absl-py==1.3.0
asttokens==2.2.1
astunparse==1.6.3
backcall==0.2.0
cachetools==5.2.0
certifi==2022.12.7
charset-normalizer==2.1.1
decorator==5.1.1
dill==0.3.6
etils==0.9.0
executing==1.2.0
flatbuffers==22.12.6
gast==0.4.0
google-auth==2.15.0
google-auth-oauthlib==0.4.6
google-pasta==0.2.0
googleapis-common-protos==1.57.0
grpcio==1.51.1
h5py==3.7.0
idna==3.4
importlib-resources==5.10.1
ipython==8.7.0
jedi==0.18.2
kaggle==1.5.12
keras==2.11.0
keras-tuner==1.1.3
kt-legacy==1.0.4
libclang==14.0.6
Markdown==3.4.1
MarkupSafe==2.1.1
matplotlib-inline==0.1.6
numpy==1.23.5
oauthlib==3.2.2
opt-einsum==3.3.0
packaging==22.0
pandas==1.5.2
parso==0.8.3
pexpect==4.8.0
pickleshare==0.7.5
Pillow==9.3.0
promise==2.3
prompt-toolkit==3.0.36
protobuf==3.19.6
ptyprocess==0.7.0
pure-eval==0.2.2
pyasn1==0.4.8
pyasn1-modules==0.2.8
pydot==1.4.2
Pygments==2.13.0
pyparsing==3.0.9
python-dateutil==2.8.2
python-slugify==7.0.0
pytz==2022.6
PyYAML==6.0
requests==2.28.1
requests-oauthlib==1.3.1
rsa==4.9
scipy==1.9.3
six==1.16.0
stack-data==0.6.2
tensorboard==2.11.0
tensorboard-data-server==0.6.1
tensorboard-plugin-wit==1.8.1
tensorflow==2.11.0
tensorflow-datasets==4.7.0
tensorflow-estimator==2.11.0
tensorflow-hub==0.12.0
tensorflow-io-gcs-filesystem==0.28.0
tensorflow-metadata==1.12.0
termcolor==2.1.1
text-unidecode==1.3
toml==0.10.2
tqdm==4.64.1
traitlets==5.7.1
typing_extensions==4.4.0
urllib3==1.26.13
wcwidth==0.2.5
Werkzeug==2.2.2
wrapt==1.14.1
zipp==3.11.0
TF Devices:
- PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU')
- PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')
CPU cores: 12
Date rendered: 2022-12-16
Page render time: 4 seconds