Computational Efficiency: ttm vs rTensor
We compare the computational efficiency of the ttm
function from the tensory package with the equivalent
function in the rTensor package. This benchmark
demonstrates the performance benefits of using tensory for
tensor-times-matrix multiplication.
set.seed(123)
# Create a random 3-mode tensor and a matrix
X <- array(runif(30*40*50), dim = c(30, 40, 50))
mat <- matrix(runif(20*40), nrow = 20, ncol = 40)
library(bench)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Benchmark ttm in tensory vs rTensor
bm <- bench::mark(
tensory = tensory::ttm(X, mat, mode = 2)$data,
rTensor = rTensor::ttm(X_rTensor, mat, m = 2)@data,
min_iterations = 50,
check = FALSE
)
bm
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tensory 150us 264us 3859. 279.2KB 19.5
#> 2 rTensor 775us 920us 1030. 1.2MB 26.8
# Visualization
library(ggplot2)
library(dplyr)
library(tidyr)
autoplot(bm, type = "violin")
bm %>%
unnest(c(time, gc)) %>%
filter(gc == "none") %>%
mutate(expression = as.character(expression)) %>%
ggplot(aes(x = mem_alloc, y = time, color = expression)) +
geom_point() +
scale_color_bench_expr(scales::brewer_pal(type = "qual", palette = 3))
set.seed(123)
# Create a random 3-mode tensor and a matrix
X <- array(runif(10*100*50), dim = c(10, 100, 50))
mat <- matrix(runif(100*100), nrow = 100, ncol = 100)
library(bench)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Benchmark ttm in tensory vs rTensor
bm <- bench::mark(
tensory = tensory::ttm(X, mat, mode = 2)$data,
rTensor = rTensor::ttm(X_rTensor, mat, m = 2)@data,
iterations = 50,
check = FALSE
)
bm
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tensory 335us 543.92us 1901. 393.49KB 0
#> 2 rTensor 959us 1.06ms 817. 1.53MB 34.1
# Visualization
library(ggplot2)
autoplot(bm, type = "violin")
Multiple Matrix Multiplications Benchmark
Here we benchmark the performance of multiple matrix multiplications, which is a common operation in tensor decomposition algorithms and multilinear algebra.
set.seed(456)
# Create a 4-mode tensor and matrices for each mode
X3 <- array(runif(50*40*30*20), dim = c(50, 40, 30, 20))
matrices3 <- list(
matrix(runif(6*50), nrow = 6, ncol = 50), # mode 1
matrix(runif(4*40), nrow = 4, ncol = 40), # mode 2
matrix(runif(3*30), nrow = 3, ncol = 30), # mode 3
matrix(runif(2*20), nrow = 2, ncol = 20) # mode 4
)
library(bench)
# Prepare rTensor object
X3_rTensor <- rTensor::as.tensor(X3)
X3_tensor <- tensory::Tensor$new(X3)
# Define function for multiple rTensor ttm operations
multiple_ttm_rTensor <- function(tensor, mat_list) {
result <- tensor
for (i in seq_along(mat_list)) {
result <- rTensor::ttm(result, mat_list[[i]], m = i)
}
return(result)
}
# Benchmark multiple ttm operations
bm_multiple <- bench::mark(
tensory = tensory::ttm(X3_tensor, matrices3, mode = c(1, 2, 3, 4))$data,
rTensor = multiple_ttm_rTensor(X3_rTensor, matrices3)@data,
iterations = 50,
check = FALSE
)
bm_multiple
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tensory 514.81us 579.3us 1701. 1.09MB 70.9
#> 2 rTensor 6.82ms 7.84ms 118. 14.07MB 118.
# Visualization
library(ggplot2)
autoplot(bm_multiple, type = "violin")
set.seed(456)
# Create a 4-mode tensor and matrices for each mode
X <- array(runif(4^6), dim = rep(4,6))
a <- matrix(runif(4*4), nrow = 4, ncol = 4)
matrices <- lapply(1:6,function(xx) a)
library(bench)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Define function for multiple rTensor ttm operations
multiple_ttm_rTensor <- function(tensor, mat_list) {
result <- tensor
for (i in seq_along(mat_list)) {
result <- rTensor::ttm(result, mat_list[[i]], m = i)
}
return(result)
}
# Benchmark multiple ttm operations
bm_multiple <- bench::mark(
tensory = tensory::ttm(X, matrices, mode = 1:6)$data,
rTensor = multiple_ttm_rTensor(X_rTensor, matrices)@data,
iterations = 10,
check = FALSE
)
bm_multiple
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tensory 175.68us 203.68us 4373. 195KB 0
#> 2 rTensor 1.76ms 1.93ms 512. 792KB 0
# Visualization
library(ggplot2)
autoplot(bm_multiple, type = "violin")
Memory Efficiency Comparison
Let’s also compare memory usage during these operations:
set.seed(789)
# Create a tensor and matrix for memory comparison
X <- array(runif(30*25*20), dim = c(30, 25, 20))
mat <- matrix(runif(35*25), nrow = 35, ncol = 25)
library(bench)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Memory benchmark
bm_memory <- bench::mark(
tensory = tensory::ttm(X, mat, mode = 2)$data,
rTensor = rTensor::ttm(X_rTensor, mat, m = 2)@data,
iterations = 20,
check = FALSE
)
bm_memory
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tensory 130us 140us 6463. 167KB 0
#> 2 rTensor 417us 525us 1894. 610KB 99.7
# Visualization
library(ggplot2)
autoplot(bm_memory, type = "violin")
Scalability Analysis
Finally, let’s analyze how performance scales with tensor size:
set.seed(101112)
# Test different tensor sizes
sizes <- c(20, 60, 100, 140, 160)
scalability_results <- data.frame()
library(bench)
for (size in sizes) {
# Create tensor of varying size
X <- array(runif(size^3), dim = c(size, size, size))
mat <- matrix(runif((size) * size), nrow = size, ncol = size)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Benchmark
bm_scale <- bench::mark(
tensory = tensory::ttm(X, mat, mode = 2)$data,
rTensor = rTensor::ttm(X_rTensor, mat, m = 2)@data,
iterations = 20,
check = FALSE
)
# Store results
temp_results <- data.frame(
size = size,
package = as.character(bm_scale$expression),
median_time = as.numeric(bm_scale$median),
memory = as.numeric(bm_scale$mem_alloc)
)
scalability_results <- rbind(scalability_results, temp_results)
}
# Visualization
library(ggplot2)
ggplot(scalability_results, aes(x = size, y = median_time, color = package)) +
geom_line(size = 1.2) +
geom_point(size = 3) +
#scale_y_log10() +
labs(title = "Scalability Comparison",
subtitle = "Performance vs Tensor Size",
x = "Tensor Dimension Size",
y = "Median Time",
color = "Package") +
theme_minimal()
set.seed(101112)
# Test different tensor sizes
sizes <- c(20, 60, 100, 140, 160)
scalability_results <- data.frame()
library(bench)
for (size in sizes) {
# Create tensor of varying size
X <- array(runif(size*size*size), dim = c(size, size, size))
mat <- matrix(runif((size+10) * size), nrow = size+10, ncol = size)
# Prepare rTensor object
X_rTensor <- rTensor::as.tensor(X)
X <- tensory::Tensor$new(X)
# Benchmark
bm_scale <- bench::mark(
tensory = tensory::ttm(X, mat, mode = 3)$data,
rTensor = rTensor::ttm(X_rTensor, mat, m = 3)@data,
iterations = 10,
check = FALSE
)
# Store results
temp_results <- data.frame(
size = size,
package = as.character(bm_scale$expression),
median_time = as.numeric(bm_scale$median),
mean_time = as.numeric(bm_scale$total_time/bm_scale$n_itr),
memory = as.numeric(bm_scale$mem_alloc)
)
scalability_results <- rbind(scalability_results, temp_results)
}
# Visualization
library(ggplot2)
ggplot(scalability_results, aes(x = size, y = mean_time, color = package)) +
geom_line(size = 1.2) +
geom_point(size = 3) +
#scale_y_log10() +
labs(title = "Scalability Comparison",
subtitle = "Performance vs Tensor Size",
x = "Tensor Dimension Size",
y = "Median Time",
color = "Package") +
theme_minimal()