| Title: | Local Large Language Models as Base-R Objects |
|---|---|
| Description: | Load and run local large language models (through a vendored, patched 'llama.cpp') from R and work with them as plain data frames and matrices in base-R idiom. Provides model loading and tokenization ('llm', 'llm_tokens'), text generation ('llm_generate'), next-token distributions ('llm_logits'), text embeddings ('llm_embed'), and mechanistic interpretability tools -- activation tracing ('llm_trace'), activation steering ('llm_steer'), and neuron ablation ('llm_ablate'). A checksum-verified downloader ('llm_download') fetches pinned models. |
| Authors: | Alessandro Vadala [aut, cre, cph] |
| Maintainer: | Alessandro Vadala <[email protected]> |
| License: | MIT + file LICENSE | Apache License (== 2.0) |
| Version: | 0.1.0 |
| Built: | 2026-07-09 14:23:32 UTC |
| Source: | https://github.com/Vadale/R-ebirth |
Pulls a single (layer, component) slice out of a llm_trace() result as a
base numeric matrix: one row per captured (prompt_id, token_pos) and one
column per neuron (hidden_size wide). Row names are "<prompt_id>.<token_pos>".
This is the bridge from the long-format trace to matrix tools such as
stats::prcomp().
## S3 method for class 'relm_trace' as.matrix(x, layer, component = "residual", ...)## S3 method for class 'relm_trace' as.matrix(x, layer, component = "residual", ...)
x |
A |
layer |
Required single 1-based layer index; it must be present in the trace. |
component |
Single component name (default |
... |
Ignored. |
A numeric matrix, rows = captured (prompt_id, token_pos) (row names
"<prompt_id>.<token_pos>"), columns = neurons.
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) tr <- llm_trace(m, "The cat sat.", layers = 1:2) as.matrix(tr, layer = 1, component = "residual") close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) tr <- llm_trace(m, "The cat sat.", layers = 1:2) as.matrix(tr, layer = 1, component = "residual") close(m)
Deterministically frees the native memory behind an llm handle. On a
memory-constrained machine this lets you release several gigabytes
immediately rather than waiting for garbage collection (the finalizer remains
the safety net). A double close is a no-op; any later use of the handle
raises relm_error_closed.
## S3 method for class 'llm' close(con, ...)## S3 method for class 'llm' close(con, ...)
con |
An |
... |
Ignored (present for compatibility with the |
invisible(NULL).
Loads a GGUF model file and returns an llm handle: an external pointer to
the native model plus its metadata. All arguments are validated in R before
the native boundary is crossed, so a bad request is reported as a classed
condition and never reaches the engine.
llm( path, context_length = 4096, gpu_layers = NULL, backend = c("auto", "metal", "cuda", "cpu"), mmap = TRUE ) ## S3 method for class 'llm' print(x, ...)llm( path, context_length = 4096, gpu_layers = NULL, backend = c("auto", "metal", "cuda", "cpu"), mmap = TRUE ) ## S3 method for class 'llm' print(x, ...)
path |
Single string: path to a GGUF model file. |
context_length |
Positive integer: the active context window in tokens
(llama.cpp: |
gpu_layers |
|
backend |
One of |
mmap |
Logical: memory-map the model file (default |
x |
An |
... |
Ignored. |
The handle owns native memory (potentially several gigabytes). Free it
deterministically with close() when done; a garbage-collection
finalizer frees it as a safety net otherwise (see close.llm()).
backend = "auto" resolves to the fastest backend this build supports
(Metal on Apple silicon, otherwise CPU). Requesting a backend the build was
not compiled with raises relm_error_backend.
No model ships inside the package yet, so the runnable example is guarded by
the RELM_TEST_MODEL_QWEN environment variable (point it at a local
Qwen2.5 GGUF to run it). A tiny in-repo model arrives in a later work
package.
An object of class llm (see the package's class documentation).
x, invisibly.
close.llm(), print.llm(), summary.llm()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) print(m) summary(m) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) print(m) summary(m) close(m)
Returns a new llm handle with the listed 1-based neurons of component
at layer forced to value during every subsequent forward pass
(llm_generate(), llm_logits()). The original handle is untouched: to remove
the ablation, use the original object (reversibility is exact, D-003).
llm_ablate(m, layer, neurons, value = 0, component = "residual")llm_ablate(m, layer, neurons, value = 0, component = "residual")
m |
An |
layer |
Single 1-based transformer block, in |
neurons |
A non-empty vector of 1-based neuron indices in
|
value |
Single finite number the neurons are forced to (default |
component |
Which sub-layer to ablate. Only |
Ablation forces x[neuron] := value at the residual choke point – a native
graph op (x * mask + add), reversible by construction. Unlike steering it
covers every layer, including layer 1.
Composition. Deriving from an already-steered or ablated handle carries its
full spec forward and adds the new one, then builds a single fresh context from
the original weights (contexts are never chained). Ablation is a union,
last-write-wins per (layer, neuron) – a later ablation of the same neuron
overrides its value. The semantics are derivation-order-independent:
m |> llm_ablate(...) |> llm_steer(...) produces the same forward pass as
m |> llm_steer(...) |> llm_ablate(...), and a steer never moves an ablated
neuron (the ablation runs after the steer at the graph, (x + steer) * mask + add, forcing the neuron to value, D-016).
Not free. Each llm_ablate()/llm_steer() call allocates a fresh context
on the shared weights – a sub-second pause and real memory (its own KV cache),
not a cheap copy.
Generation/logits only (for now). Interventions apply to llm_generate()
and llm_logits(). llm_embed() and llm_trace() on an intervened handle
raise relm_error_embed / relm_error_trace rather than silently
returning base vectors mislabeled as ablated.
Only component = "residual" ablation is supported in this release (the shared
choke point); "attn_out"/"mlp_out" raise relm_error_intervention.
Model support. Interventions work on any standard-residual decoder; before the
handle is returned, a runtime probe verifies on this model that the ablation
takes effect at each requested layer, raising relm_error_intervention rather
than silently doing nothing. llama and qwen2 are additionally behaviorally
validated (the valence / KL acceptance fixtures); other architectures are enabled
once they pass the probe.
A new llm handle with the ablation added to its accumulated
interventions; the source handle is returned unchanged. print() shows the
active intervention count and summary() lists them.
llm_steer(), llm(), llm_generate()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) ablated <- llm_ablate(m, layer = 5, neurons = c(10, 42, 128)) # Composition is order-independent: these two derivations behave identically. dir <- rep(0.05, m$hidden_size) a <- m |> llm_ablate(layer = 5, neurons = 10) |> llm_steer(layer = 6, direction = dir) b <- m |> llm_steer(layer = 6, direction = dir) |> llm_ablate(layer = 5, neurons = 10) summary(a) close(a) close(b) close(ablated) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) ablated <- llm_ablate(m, layer = 5, neurons = c(10, 42, 128)) # Composition is order-independent: these two derivations behave identically. dir <- rep(0.05, m$hidden_size) a <- m |> llm_ablate(layer = 5, neurons = 10) |> llm_steer(layer = 6, direction = dir) b <- m |> llm_steer(layer = 6, direction = dir) |> llm_ablate(layer = 5, neurons = 10) summary(a) close(a) close(b) close(ablated) close(m)
Fetches a GGUF model file over HTTPS into a local cache and returns its path.
model is either a pinned alias from the package's model registry (see the
Details section) or a full https:// URL. The download is
fail-closed: for a registry alias the file's SHA256 must match the pinned
value or the file is deleted and relm_error_download is raised. Nothing
downloaded is ever executed — the file is only written to disk and checksummed.
llm_download(model, dir = NULL, quiet = FALSE)llm_download(model, dir = NULL, quiet = FALSE)
model |
Single string: a registry alias (see Details) or a full
|
dir |
|
quiet |
Single logical. |
Registry aliases. The package ships a small registry (inst/models.csv)
of license-clean, checksum-pinned models. The current aliases are:
"qwen2.5-0.5b-instruct-q8_0" — Qwen2.5 0.5B Instruct, Q8_0 (Apache-2.0);
the small CI-integration model.
"qwen2.5-1.5b-instruct-q4_k_m" — Qwen2.5 1.5B Instruct, Q4_K_M
(Apache-2.0); the demo default.
Passing an unknown alias raises relm_error_download and lists the known
aliases. Larger Qwen quantizations (7B) ship as split multi-part GGUFs and are
not in the single-file registry yet; Gemma models are gated by the Gemma Terms
of Use (they require accepting terms and an access token on Hugging Face), so
they are supplied by local path rather than downloaded here.
Full URLs. A full https:// URL is downloaded as given. Only HTTPS is
accepted (http://, ftp://, file://, ... are rejected). A bare URL has no
pinned checksum, so the file cannot be verified; it is downloaded and its
computed SHA256 is reported so you can pin it — the function never presents an
unverifiable file as if it had been verified.
Caching. dir = NULL uses the per-user cache directory
tools::R_user_dir("relm", "cache"); the directory is created if missing.
The target file name is the URL's last path segment. If a registry model is
already present and its checksum matches, the download is skipped (idempotent,
offline-friendly); a present-but-mismatching file is treated as corrupt and
re-downloaded. A bare URL has no pinned checksum, so a same-named cached file
cannot be shown to have come from that URL and is never reused – a bare URL is
always re-fetched. Verification happens on a temporary file that is only moved
into place once it passes, so the final path never holds unverified bytes.
Downloads follow HTTPS redirects; for a registry alias the pinned checksum
still guards integrity end-to-end, so a redirect cannot substitute the bytes.
This is one of only two functions in the package that write outside a session
temporary directory (the other is llm_trace() spill); see the package's
side-effect contract.
The local file path, returned invisibly. Errors:
relm_error_argument (bad model/dir/quiet type),
relm_error_download (non-HTTPS URL, unknown alias, network failure,
checksum mismatch, or an unwritable directory).
# The default download directory (dir = NULL); no network access is performed: tools::R_user_dir("relm", "cache") ## Not run: # Fetch a pinned, checksum-verified model and load it: path <- llm_download("qwen2.5-0.5b-instruct-q8_0") m <- llm(path) ## End(Not run)# The default download directory (dir = NULL); no network access is performed: tools::R_user_dir("relm", "cache") ## Not run: # Fetch a pinned, checksum-verified model and load it: path <- llm_download("qwen2.5-0.5b-instruct-q8_0") m <- llm(path) ## End(Not run)
Encodes each string in x into a fixed-length numeric vector, returning a base
matrix with one row per input and one column per embedding dimension (so the
matrix is length(x) by the model's hidden_size).
llm_embed(m, x, pooling = c("mean", "last", "model"), normalize = TRUE)llm_embed(m, x, pooling = c("mean", "last", "model"), normalize = TRUE)
m |
An |
x |
A character vector of one or more non-empty strings to embed; |
pooling |
How to reduce each input's per-token vectors to one vector:
|
normalize |
Single logical. |
Each input is tokenized (with the model's begin/end-of-sequence markers) and run
through a forward pass in a dedicated embeddings-mode context; the per-token
hidden states are then pooled into one vector per input by pooling. "mean"
averages the token vectors, "last" takes the final token's vector, and
"model" uses the model's own pooling when the GGUF defines one (a purely
generative model such as Qwen2.5 defines none, so "model" raises
relm_error_embed asking for "mean" or "last").
With normalize = TRUE (the default) each row is L2-normalized to a unit
vector, so the dot product of two rows is their cosine similarity. A zero vector
is returned unchanged (never NaN). normalize is validated and its effect is
explicit — there is no silent normalization.
The model must carry a tokenizer; a no_vocab model raises
relm_error_tokenize. No model ships inside the package yet (the in-repo
synthetic model has no tokenizer), so the runnable example is guarded by the
RELM_TEST_MODEL_QWEN environment variable — point it at a local Qwen2.5
GGUF to run it.
Embedding an intervened handle (from llm_steer()/llm_ablate()) raises
relm_error_embed: interventions currently apply to generation and logits
only, and the embedding context does not inherit them, so returning base vectors
labeled as intervened would be silent mislabeling. Embed the original handle.
A numeric matrix, length(x) rows by the model's embedding size
(columns), with row names names(x) when set, else the input positions as
characters.
llm(), llm_tokens(), llm_generate()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) e <- llm_embed(m, c(a = "cats and dogs", b = "domestic pets")) dim(e) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) e <- llm_embed(m, c(a = "cats and dogs", b = "domestic pets")) dim(e) close(m)
Autoregressively continues each prompt. With chat = TRUE (the default) the
prompt is wrapped as a user turn using the model's own chat template, so the
formatting matches what the model was trained on; with chat = FALSE the
prompt is completed verbatim.
llm_generate( m, prompt, max_tokens = 256, temperature = 0.8, top_p = 0.95, seed = NULL, chat = TRUE, stop = NULL )llm_generate( m, prompt, max_tokens = 256, temperature = 0.8, top_p = 0.95, seed = NULL, chat = TRUE, stop = NULL )
m |
An |
prompt |
A character vector of prompts; the result has one element per
prompt and preserves |
max_tokens |
Single positive integer: the maximum number of tokens to generate per prompt. |
temperature |
Single non-negative number. |
top_p |
Single number in |
seed |
|
chat |
Single logical. |
stop |
|
Decoding is greedy when temperature = 0 — the exact, reproducible path — and
temperature + nucleus (top-p) sampling otherwise. Sampling is drawn on the CPU
from a seeded generator, so a run is fully reproducible: the same seed and
arguments produce the same text across runs and sessions. When seed = NULL
a seed is drawn (from R's RNG, so set.seed() makes even that reproducible)
and recorded — the seed actually used is always returned as
attr(result, "seed"), so any generation can be replayed.
Generation stops at max_tokens, at the model's end-of-generation token, or
as soon as one of the stop strings appears (the output is truncated just
before it). A prompt longer than the model's context window raises
relm_error_context_overflow, whose message states by how much.
A character vector the same length as prompt (names preserved), each
element the generated continuation. The seed used is attached as
attr(result, "seed").
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) llm_generate(m, "In one sentence, what is R?", max_tokens = 40, seed = 1) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) llm_generate(m, "In one sentence, what is R?", max_tokens = 40, seed = 1) close(m)
Runs a forward pass over each prompt and returns the model's distribution for
the single token that would come next: the top most likely candidates, ranked
from most to least probable. This is the raw material behind generation — the
first token llm_generate() would pick (greedily) is exactly this table's
rank-1 token.
llm_logits(m, prompt, top = 20)llm_logits(m, prompt, top = 20)
m |
An |
prompt |
A character vector of prompts; the result has |
top |
Single positive integer: how many top candidates to return per prompt (clamped to the vocabulary size). Default 20. |
Each prompt is treated as raw text (no chat template is applied — wrap it
yourself if you want the chat framing) and tokenized the way chat = FALSE
generation is. The distribution is read at the final position, so it answers
"what token does the model expect immediately after this text?". Probabilities
are the softmax over the whole vocabulary, computed before the top
candidates are selected, so each prob is the token's true share of the full
distribution: the returned probabilities are correct but (being only the head of
the distribution) sum to less than 1.
The result is one long-format data.frame with top rows per prompt, stacked
in prompt order. Within each prompt the rows are ordered by descending logit,
so rank == 1 is the most likely next token; logit and prob are therefore
non-increasing down the ranks. Token ids are 1-based (like every index in
relm, and like llm_tokens()), so token_id round-trips through
llm_tokens(m, token_id, decode = TRUE).
Active interventions on m (from llm_steer()/llm_ablate()) apply, so
llm_logits() is the direct way to read how a steer or an ablation reshapes the
next-token distribution.
The model must carry a tokenizer; a no_vocab model (such as the in-repo
synthetic model) raises relm_error_tokenize. No model ships inside the
package yet, so the runnable example is guarded by the RELM_TEST_MODEL_QWEN
environment variable — point it at a local Qwen2.5 GGUF to run it.
A base data.frame with top rows per prompt and columns
prompt_id (int, 1-based index into prompt), rank (int, 1 = most likely),
token_id (int, 1-based), token (chr, the token piece), logit (dbl), and
prob (dbl, softmax over the full vocabulary).
llm(), llm_generate(), llm_tokens()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) llm_logits(m, "The capital of France is", top = 5) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) llm_logits(m, "The capital of France is", top = 5) close(m)
Returns a new llm handle that adds coef * direction to the residual
stream at layer during every subsequent forward pass (llm_generate(),
llm_logits()). The original handle is untouched: to remove the steering, use
the original object (reversibility is exact, D-003). Interventions compose –
see Details.
llm_steer(m, layer, direction, coef = 1, positions = "all")llm_steer(m, layer, direction, coef = 1, positions = "all")
m |
An |
layer |
Single 1-based transformer block to steer, in |
direction |
Numeric vector of length |
coef |
Single finite number scaling |
positions |
Which token positions to steer. Only |
Steering is llama.cpp's native control-vector mechanism: a per-layer,
hidden_size-wide vector added to the residual at layer's output, for all
token positions (hence positions = "all" is the only supported value in this
release; a position subset raises relm_error_intervention).
Composition. Deriving from an already-steered or ablated handle carries its
full spec forward and adds the new one, then builds a single fresh context from
the original weights (contexts are never chained). Steering stacks by
summation – two steers on the same layer add – and the semantics are
derivation-order-independent: m |> llm_steer(...) |> llm_ablate(...)
produces the same forward pass as m |> llm_ablate(...) |> llm_steer(...). A
steer never moves an ablated neuron: at the graph the ablation runs after the
steer ((x + steer) * mask + add), so a jointly steered-and-ablated neuron is
forced to the ablation value (D-016).
Layer 1 is not steerable. The native control vector reserves engine index 0
and has no slot for the first transformer block, so layer = 1 raises
relm_error_intervention. Steer a later layer (2:m$layers), or ablate
layer 1 with llm_ablate() (ablation covers every layer).
Not free. Each llm_steer()/llm_ablate() call allocates a fresh context
on the shared weights – a sub-second pause and real memory (its own KV cache,
~hundreds of MB on the demo models), not a cheap copy. Hold a handful of
intervened handles, not hundreds.
Generation/logits only (for now). Interventions apply to llm_generate()
and llm_logits(). llm_embed() and llm_trace() build their own fresh
contexts that do not inherit the adapters, so calling them on an intervened
handle raises relm_error_embed / relm_error_trace rather than silently
returning base (un-intervened) vectors mislabeled as steered.
Model support. Interventions work on any standard-residual decoder. Before
the handle is returned, a runtime probe verifies on this model that steering
actually shifts the residual at each requested layer; if it would silently do
nothing (an architecture that does not route its residual through the choke point
the mechanism hooks), relm_error_intervention is raised instead of a no-op
handle. The llama and qwen2 architectures are additionally behaviorally
validated – they pass the valence-steering and KL-ablation acceptance fixtures;
any other architecture is enabled the moment it passes the probe.
A new llm handle with the steering added to its accumulated
interventions; the source handle is returned unchanged. print() shows the
active intervention count and summary() lists them.
llm_ablate(), llm(), llm_generate()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) # A steering direction is any hidden_size-wide vector (here a placeholder). dir <- rep(0.05, m$hidden_size) steered <- llm_steer(m, layer = 8, direction = dir, coef = 2) summary(steered) # lists the active intervention # The original handle is untouched -- generation reproduces the base output. identical( llm_generate(m, "Tell me about the sea.", max_tokens = 20, seed = 1), llm_generate(m, "Tell me about the sea.", max_tokens = 20, seed = 1) ) close(steered) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) # A steering direction is any hidden_size-wide vector (here a placeholder). dir <- rep(0.05, m$hidden_size) steered <- llm_steer(m, layer = 8, direction = dir, coef = 2) summary(steered) # lists the active intervention # The original handle is untouched -- generation reproduces the base output. identical( llm_generate(m, "Tell me about the sea.", max_tokens = 20, seed = 1), llm_generate(m, "Tell me about the sea.", max_tokens = 20, seed = 1) ) close(steered) close(m)
Converts between text and the model's tokens. With decode = FALSE (the
default) x is text and the result is the token ids; with decode = TRUE
x is token ids and the result is the reconstructed string.
llm_tokens(m, x, decode = FALSE)llm_tokens(m, x, decode = FALSE)
m |
An |
x |
For encoding, a character vector; for decoding, an integer vector of 1-based token ids. |
decode |
Single logical. |
Encoding (decode = FALSE). x is a character vector. Each element is
tokenized into a named integer vector: the values are the token ids and
the names are the token pieces (the text each id renders as). For a single
string a named integer vector is returned; for several strings a list of such
vectors is returned, preserving names(x). No beginning/end-of-sequence
markers are added (you get exactly the tokens of the text); chat formatting is
llm_generate's job, not this function's.
Decoding (decode = TRUE). x is an integer vector of token ids and the
result is a single string. Decoding is UTF-8 correct even when a multi-byte
character spans two tokens — always decode the whole id vector rather than
concatenating the piece names, which can split a character.
Token ids are 1-based in the R API (like every other index in relm);
subtract 1 to compare them with a raw vocabulary index (llama.cpp / Hugging
Face). Encoding and decoding are exact inverses:
llm_tokens(m, llm_tokens(m, txt), decode = TRUE) reproduces txt.
The model must carry a tokenizer; a no_vocab model raises
relm_error_tokenize.
Encoding: a named integer vector (single input) or a list of them (several inputs). Decoding: a single string.
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) ids <- llm_tokens(m, "The quick brown fox") ids llm_tokens(m, ids, decode = TRUE) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) ids <- llm_tokens(m, "The quick brown fox") ids llm_tokens(m, ids, decode = TRUE) close(m)
Runs a forward pass over each prompt's tokens (no sampling) and captures the
internal activations selected by the filters, returning a long-format
relm_trace data.frame with one row per
(prompt, token position, layer, component, neuron).
llm_trace( m, prompts, layers = NULL, positions = "last", components = "residual", spill = TRUE, spill_dir = NULL ) ## S3 method for class 'relm_trace' print(x, ...) ## S3 method for class 'relm_trace' summary(object, ...) ## S3 method for class 'summary.relm_trace' print(x, ...)llm_trace( m, prompts, layers = NULL, positions = "last", components = "residual", spill = TRUE, spill_dir = NULL ) ## S3 method for class 'relm_trace' print(x, ...) ## S3 method for class 'relm_trace' summary(object, ...) ## S3 method for class 'summary.relm_trace' print(x, ...)
m |
An |
prompts |
A character vector of one or more non-empty prompts; |
layers |
|
positions |
Which token positions to capture: |
components |
A subset of |
spill |
Single logical (default |
spill_dir |
|
x |
A |
... |
Ignored. |
object |
A |
llm_trace() is the anatomy lab's core tool: it observes the residual stream
and the attention/MLP sub-layer outputs as the model processes text, so those
activations can be analysed with ordinary R (PCA, per-layer probes, and so on).
The tap adds no overhead to normal generation — it runs on a dedicated, transient
context created only for the trace.
The captured columns are exactly (in order): prompt_id (1-based index into
prompts), token_pos (1-based position within that prompt), token (the token
piece), layer (1-based transformer block), component ("residual",
"attn_out", or "mlp_out"), neuron (1-based index within the component
vector), and value (the activation).
Memory (the 16 GB rule). A full trace can be large, so the defaults capture
little (positions = "last", components = "residual"); widen them deliberately.
Before running, the size of the data.frame you would receive is estimated from
the filters (the materialized-object cost, D-017). If it fits the budget
(min(2 GB, 20% of RAM), overridable with
options(relm.trace_budget = <bytes>)) it is held in memory. If it exceeds the
budget and spill = TRUE (the default), the capture is streamed to an Arrow-IPC
file under the session cache and the result is a spilled relm_trace that
loads lazily: print()/summary() never read the file, and
as.matrix.relm_trace() reads only the requested (layer, component) slice.
If it exceeds the budget and spill = FALSE, the call raises relm_error_oom
before any allocation, its estimate_bytes field stating the estimate. Spill
files are removed when the R session ends.
The model must carry a tokenizer; a no_vocab model raises
relm_error_tokenize. As with the other text entry points, the runnable
example is guarded by the RELM_TEST_MODEL_QWEN environment variable.
Tracing an intervened handle (from llm_steer()/llm_ablate()) raises
relm_error_trace: interventions currently apply to generation and logits
only, and the trace context does not inherit them, so tracing would capture the
base (un-intervened) forward pass while labeling it intervened. Trace the
original handle.
A relm_trace: a data.frame (class c("relm_trace", "data.frame")) with the seven columns above, carrying model, spilled,
spill_files, and prompts attributes. When spilled is TRUE the rows live
in spill_files (read on demand by as.matrix.relm_trace()) rather than in
the frame. See as.matrix.relm_trace() to extract one (layer, component)
slice as a numeric matrix.
print returns its argument invisibly.
summary returns a data.frame (class summary.relm_trace) with one
row per captured (layer, component) group: its n and mean |value|. For a
spilled trace, mean_abs is NA (reporting it would force a data load); use
as.matrix.relm_trace() to read a slice.
llm(), llm_embed(), as.matrix.relm_trace()
m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) tr <- llm_trace(m, c("The cat sat.", "Quarks bind."), layers = 1:4) tr summary(tr) x <- as.matrix(tr, layer = 1, component = "residual") dim(x) close(m)m <- llm(Sys.getenv("RELM_TEST_MODEL_QWEN")) tr <- llm_trace(m, c("The cat sat.", "Quarks bind."), layers = 1:4) tr summary(tr) x <- as.matrix(tr, layer = 1, component = "residual") dim(x) close(m)
Returns a classed list with the print-level metadata plus the model's memory
footprint, tokenizer (vocabulary) information, and the full list of active
interventions. Its own print method renders it.
## S3 method for class 'llm' summary(object, ...) ## S3 method for class 'summary.llm' print(x, ...)## S3 method for class 'llm' summary(object, ...) ## S3 method for class 'summary.llm' print(x, ...)
object |
An |
... |
Ignored. |
x |
A |
An object of class summary.llm.
x, invisibly.