Generating Texts without a Local GPU
NNsight can execute model traces through the National
Deep Inference Fabric (NDIF). The model weights remain on the remote service,
and only values marked for saving are returned. This makes it possible to
generate text and extract internal states without a local GPU.
NNsight and NDIF are third-party services, not gpi_pack components. Their
available models, quotas, API, and access policies can change, so check the
NNsight remote-execution guide before running a large
job.
Installing and Authenticating
Install NNsight and obtain an NDIF API key from the account page linked in the
official guide:
python -m pip install --upgrade nnsight
The preferred options are to set NDIF_API_KEY in your environment or save
the key through NNsight’s configuration interface:
import os
from nnsight import CONFIG
CONFIG.set_default_api_key(os.environ["NDIF_API_KEY"])
Large gated models can also require a Hugging Face token so NNsight can load
their tokenizer and configuration. Accept the checkpoint’s conditions and set
HF_TOKEN or authenticate with the Hugging Face CLI.
Choosing an Available Model
NDIF deployment status changes over time. Inspect the status before selecting
a checkpoint:
from nnsight import ndif
print(ndif.status())
The example below uses a Llama instruction checkpoint. Replace the identifier
with the exact deployed model key shown by NDIF when necessary. NNsight creates
a lightweight local model skeleton on the meta device; it does not download
the remote weights.
from nnsight import LanguageModel
checkpoint = "meta-llama/Llama-3.1-70B-Instruct"
model = LanguageModel(checkpoint)
tokenizer = model.tokenizer
Remote Generation and Hidden States
The following Llama-specific example uses the current NNsight generation API.
It processes each prompt independently and performs non-sampling generation
(do_sample=False), which is greedy with the selected checkpoint’s default
num_beams=1. It collects the last Llama decoder layer at every generation
step. Other architectures use different module paths; inspect the wrapped
model before replacing the checkpoint.
from pathlib import Path
import pandas as pd
import torch
prompts = [
"Create a biography of an American politician named Nathaniel C. Gilchrist",
"Create a biography of an American politician named John Doe",
"Create a biography of an American politician named Jane Smith",
]
instruction = (
"You are a text generator who always produces the text requested "
"by the user."
)
max_new_tokens = 256
pooling = "last" # or "mean"
save_hidden = Path("outputs/nnsight_hidden")
save_hidden.mkdir(parents=True, exist_ok=True)
generated_texts = []
for k, prompt in enumerate(prompts):
messages = [
{"role": "system", "content": instruction},
{"role": "user", "content": prompt},
]
input_ids = tokenizer.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_tensors="pt",
)
with model.generate(
input_ids,
max_new_tokens=max_new_tokens,
do_sample=False,
remote=True,
) as tracer:
hidden_steps = list().save()
# A bounded iterator allows the code after the loop to execute.
for _ in tracer.iter[:max_new_tokens]:
hidden_steps.append(
model.model.layers[-1].output[0][
:, -1, :
].detach().float().cpu()
)
output_ids = model.generator.output.save()
generated_ids = output_ids[0, input_ids.shape[-1]:]
generated_texts.append(
tokenizer.decode(generated_ids, skip_special_tokens=True)
)
if pooling == "last":
representation = hidden_steps[-1]
elif pooling == "mean":
generation_steps = hidden_steps[1:]
if not generation_steps:
raise RuntimeError(
"Mean pooling requires more than one generation step."
)
representation = torch.stack(generation_steps).mean(dim=0)
else:
raise ValueError("pooling must be 'last' or 'mean'")
torch.save(
representation.float().cpu(),
save_hidden / f"hidden_{k}.pt",
)
pd.DataFrame({"X": generated_texts, "P": prompts}).to_pickle(
"outputs/nnsight_generated.pkl"
)
At the first generation step, the model processes the full prompt; later steps
normally contain one new token position. Selecting [:, -1, :] produces one
vector per step. The "mean" rule excludes the first prompt-processing
entry, matching the rule used by the package’s local LLM workflow.
Only objects connected to .save() are downloaded from NDIF. This example
saves the full list of selected layer vectors because both pooling choices are
shown. For a large production run, reduce the values remotely before saving
when possible to lower transfer and storage costs.
Important Notes
extract_and_save_hidden_states expects a local Transformers model and
cannot be passed a remote NNsight wrapper. The manually saved .pt files
can still be loaded by load_hiddens.
Remote execution sends prompts and traced computations to NDIF. Review its
data-handling terms before submitting sensitive material.
Record the checkpoint revision, NNsight version, module path, pooling rule,
generation settings, and execution date. Model deployments and remote
environments can change independently of this package.