The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
There are two ways another package can build on ggmlR:
Imports: ggmlR) and call the exported ggml_*
/ ag_* functions. This is the simplest path and is right
for packages that build, train or run models from R. See Part A
below.libggml.a) and C headers (LinkingTo: ggmlR)
to call ggml directly from your own C/C++ code. This is the path used by
llamaR (LLM inference) and sd2R (Stable
Diffusion). See Part B below.The two are independent — most packages need only one. You can also combine them (use the R API for orchestration and drop to C for a custom kernel).
In your DESCRIPTION:
Package: myPackage
...
Imports:
ggmlR
Then import the functions you use in NAMESPACE (via
roxygen @importFrom ggmlR ...), or call them fully
qualified as ggmlR::ggml_fit().
The whole high-level surface is exported and therefore usable from a
downstream package — the sequential, functional and autograd APIs,
optimizers, schedulers, the dataloader, data-parallel training, plus the
diagnostics/reproducibility helpers. For instance, the entire
titanic_classification.R example (Keras-like + functional +
autograd, ~30 ggmlR functions) runs unchanged from another package once
ggmlR is in Imports.
my_train <- function(x, y, epochs = 50L) {
model <- ggmlR::ggml_model_sequential() |>
ggmlR::ggml_layer_dense(64L, activation = "relu", input_shape = ncol(x)) |>
ggmlR::ggml_layer_dense(ncol(y), activation = "softmax") |>
ggmlR::ggml_compile(optimizer = "adam", loss = "categorical_crossentropy")
ggmlR::ggml_fit(model, x, y, epochs = epochs, verbose = 0L)
}A few things worth knowing:
ggml_compile(), ggml_fit() and
ggml_predict() are S3 generics with methods registered for
the sequential and functional model classes; the dispatch resolves
correctly when called from your package.model$forward(), opt$step(),
dl$epoch(), …). These are fields of objects returned by
exported functions, so they just work — there is nothing extra to
import.|> is base R (≥ 4.1); it
is not a ggmlR dependency.ggml_set_seed(), ggml_training_history() and
ggml_model_backend() let your package fix seeds and inspect
the loss curve / actual backend of a fitted model.ag_predict_colmajor(),
custom autograd layers). Those are not part of the ggmlR API —
copy them into your own package if you want them.ggmlR registers a parsnip "ggml" engine and
mlr3 learners (classif.ggml,
regr.ggml) in its .onLoad: if
mlr3 / parsnip are already loaded they are
registered immediately, otherwise a load hook registers them as soon as
those packages load. A downstream package that
Imports: ggmlR therefore gets these registrations with no
manual call — just make sure ggmlR’s namespace is loaded (any
ggmlR:: call or importFrom does that). See the
tidymodels and mlr3 vignettes for usage.
After installing ggmlR you will find:
$(R_HOME_DIR)/library/ggmlR/lib/libggml.a
$(R_HOME_DIR)/library/ggmlR/include/ggml.h
$(R_HOME_DIR)/library/ggmlR/include/ggml-backend.h
$(R_HOME_DIR)/library/ggmlR/include/ggml-alloc.h
$(R_HOME_DIR)/library/ggmlR/include/ggml-opt.h
$(R_HOME_DIR)/library/ggmlR/include/ggml-quants.h
$(R_HOME_DIR)/library/ggmlR/include/ggml-vulkan.h
$(R_HOME_DIR)/library/ggmlR/include/r_ggml_compat.h
... (full list in inst/include/)
r_ggml_compat.h redirects
printf/fprintf/abort to R-safe
equivalents (Rprintf, Rf_error). Always
include it (or use -include r_ggml_compat.h) in your C/C++
sources.
Add ggmlR to LinkingTo and Imports:
Package: myPackage
...
Imports: ggmlR
LinkingTo: ggmlR
LinkingTo makes R add ggmlR/include to the
compiler include path automatically.
src/MakevarsLink against the static library:
GGMLR_LIB = $(shell Rscript -e "cat(system.file('lib', package='ggmlR'))")
GGMLR_INC = $(shell Rscript -e "cat(system.file('include', package='ggmlR'))")
PKG_CPPFLAGS = -I$(GGMLR_INC) -include r_ggml_compat.h
PKG_LIBS = $(GGMLR_LIB)/libggml.aIf ggmlR was built with Vulkan you also need to link Vulkan:
# detect Vulkan (same logic as ggmlR's own configure)
VULKAN_LIBS = $(shell pkg-config --libs vulkan 2>/dev/null)
PKG_LIBS = $(GGMLR_LIB)/libggml.a $(VULKAN_LIBS)configure — detect ggmlR at build time#!/bin/sh
# configure
GGMLR_INC=$(Rscript -e "cat(system.file('include', package='ggmlR'))" 2>/dev/null)
GGMLR_LIB=$(Rscript -e "cat(system.file('lib', package='ggmlR'))" 2>/dev/null)
if [ -z "$GGMLR_INC" ] || [ ! -f "$GGMLR_LIB/libggml.a" ]; then
echo "ERROR: ggmlR not found. Install it first: install.packages('ggmlR')" >&2
exit 1
fi
sed -e "s|@GGMLR_INC@|$GGMLR_INC|g" \
-e "s|@GGMLR_LIB@|$GGMLR_LIB|g" \
src/Makevars.in > src/Makevarssrc/Makevars.in:
/* src/my_model.c */
#include "ggml.h"
#include "ggml-backend.h"
#include <R.h>
#include <Rinternals.h>
SEXP R_my_inference(SEXP r_input) {
struct ggml_init_params params = {
.mem_size = 256 * 1024 * 1024, /* 256 MB */
.mem_buffer = NULL,
.no_alloc = false,
};
struct ggml_context *ctx = ggml_init(params);
int n = length(r_input);
struct ggml_tensor *x = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n);
memcpy(x->data, REAL(r_input), n * sizeof(float));
/* ... build graph, compute ... */
ggml_free(ctx);
return R_NilValue;
}Register in the .Call table (R’s standard routine
registration):
/* src/init.c */
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
extern SEXP R_my_inference(SEXP);
static const R_CallMethodDef CallEntries[] = {
{"R_my_inference", (DL_FUNC) &R_my_inference, 1},
{NULL, NULL, 0}
};
void R_init_myPackage(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}ggmlR manages the CPU thread count via
ggmlR_get_n_threads() (exported from
r_interface.c). If your package calls
ggml_backend_cpu_init() directly, set the thread count to
match:
#include "ggml-backend.h"
/* ggmlR_get_n_threads() is exported by ggmlR — link against libggml.a */
extern int ggmlR_get_n_threads(void);
ggml_backend_t cpu = ggml_backend_cpu_init();
ggml_backend_cpu_set_n_threads(cpu, ggmlR_get_n_threads());This ensures your package respects the same thread limit as ggmlR (important for CRAN compliance — tests must not exceed 2 threads).
If your package needs Vulkan, the Vulkan backend is already compiled
into libggml.a when ggmlR was built with Vulkan support.
You only need to link -lvulkan:
VULKAN_LIBS = $(shell pkg-config --libs vulkan 2>/dev/null)
PKG_LIBS = @GGMLR_LIB@/libggml.a $(VULKAN_LIBS)Do not vendor ggml source again — link the pre-built
libggml.a from ggmlR to avoid symbol collisions.
llamaR — LLM inference (LLaMA, Mistral, …) using ggmlR
as backendsd2R — Stable Diffusion image generation using ggmlR as
backendBoth follow the pattern above: LinkingTo: ggmlR,
configure script to locate headers and
libggml.a, thin C wrappers, R .Call
interface.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.