Nothing
#!/usr/bin/env Rscript
# ---------------------------------------------------------------------------
# ggmlR Pipeline Parallelism (PP) demo — Stage E7.
#
# Splits a small 2-layer MLP BY LAYERS across devices: stage 1 (layer 1) on GPU 0,
# stage 2 (layer 2) on GPU 1. The activation tensor is handed from stage 1 to
# stage 2 exactly once (a single cross-device copy), the essence of pipeline
# parallelism — versus tensor parallelism's per-layer cross-device gather.
#
# Model: h = relu(W1 %*% x) on stage 1
# y = W2 %*% h on stage 2
# with x an [K x M] activation batch (ggml layout: ne = c(K, M)).
#
# Falls back to a single device (stages 0 and 0) when < 2 GPUs are present, which
# still exercises the full pipeline + handoff path (a loopback copy).
#
# Usage: Rscript inst/examples/pp_pipeline.R
# ---------------------------------------------------------------------------
suppressMessages(library(ggmlR))
if (!ggml_vulkan_available()) {
cat("Vulkan not available — nothing to demo.\n")
quit(save = "no", status = 0)
}
ndev <- ggml_vulkan_device_count()
cat(sprintf("Vulkan devices: %d\n", ndev))
# Two pipeline stages; use two GPUs if available, else both on device 0.
dev1 <- 0L
dev2 <- if (ndev >= 2) 1L else 0L
cat(sprintf("stage 1 (layer 1) -> GPU %d\nstage 2 (layer 2) -> GPU %d\n", dev1, dev2))
set.seed(1L)
K <- 64L; M <- 8L # K features, batch of M
W1 <- matrix(rnorm(K * K), nrow = K) # layer 1 weights [K x K]
W2 <- matrix(rnorm(K * K), nrow = K) # layer 2 weights [K x K]
X <- matrix(rnorm(K * M), nrow = K) # input, ggml ne = c(K, M): column m is sample m
# ggml_mul_mat(W, input): W is [K cols, K rows] (A), input is [K cols, M rows] (B),
# result is [K, M] = t(W) %*% input in R terms. Build each stage's sub-graph.
make_stage <- function(dev, Wt, relu) {
list(
device = dev,
in_shape = c(K, M),
build = function(ctx, input) {
w <- ggml_new_tensor_2d(ctx, GGML_TYPE_F32, K, K)
z <- ggml_mul_mat(ctx, w, input)
out <- if (relu) ggml_relu(ctx, z) else z
list(
output = out,
# Weights are set after allocation. Wt is [K x K]; ggml wants it column-
# major flattened, and mul_mat's A rows are Wt's rows -> pass as-is via
# as.numeric(Wt) since R matrices are already column-major (ne = c(K,K)).
set_weights = function() ggml_backend_tensor_set_data(w, as.numeric(Wt))
)
})
}
stages <- list(
make_stage(dev1, W1, relu = TRUE),
make_stage(dev2, W2, relu = FALSE)
)
t0 <- Sys.time()
y_ggml <- ggml_pp_forward(stages, x = as.numeric(X), out_shape = c(K, M))
dt <- as.numeric(Sys.time() - t0, units = "secs")
Y <- matrix(y_ggml, nrow = K, ncol = M)
# Reference: ggml_mul_mat(W, v) computes t(W) %*% v, so h = relu(t(W1) %*% X),
# y = t(W2) %*% h.
h_ref <- pmax(t(W1) %*% X, 0)
Y_ref <- t(W2) %*% h_ref
max_err <- max(abs(Y - Y_ref))
cat(sprintf("\nPipeline forward: y = %d x %d in %.3fs\n", nrow(Y), ncol(Y), dt))
cat(sprintf("max |Y - reference| = %.3e (%s)\n",
max_err, if (max_err < 5e-2) "OK" else "MISMATCH"))
# Tear down Vulkan and exit hard (_exit(0)) as the LAST statement, so the process
# skips the atexit/loader-static-destruction phase that otherwise flakily segfaults
# after results are printed. Results above are already final at this point.
ggml_vulkan_shutdown(hard = TRUE, status = 0L)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.