pub struct Gpt2 {
pub config: Gpt2Config,
/* private fields */
}Fields§
§config: Gpt2ConfigImplementations§
Source§impl Gpt2
impl Gpt2
Sourcepub fn from_safetensors(
path: impl AsRef<Path>,
config: Gpt2Config,
device: &Device,
) -> Result<Self>
pub fn from_safetensors( path: impl AsRef<Path>, config: Gpt2Config, device: &Device, ) -> Result<Self>
Load HF GPT-2 weights. path is the .safetensors file. Weight names
may or may not carry the “transformer.” prefix; both are accepted.
The LM head is tied to wte (the checkpoint has no separate tensor).
Sourcepub fn from_safetensors_bytes(
bytes: &[u8],
config: Gpt2Config,
device: &Device,
) -> Result<Self>
pub fn from_safetensors_bytes( bytes: &[u8], config: Gpt2Config, device: &Device, ) -> Result<Self>
Load HF GPT-2 weights from in-memory .safetensors bytes — the primary
form; on wasm the bytes arrive from an HTTP fetch. wte never touches
the device un-chunked: it is uploaded row-chunked straight from the
file buffer (roadmap v4, pitfall 2).
Sourcepub fn forward(&self, ids: &[u32]) -> Result<Tensor>
pub fn forward(&self, ids: &[u32]) -> Result<Tensor>
Full logits [t, vocab] — used by verification tests. The LM head is wte-tied: logits = h @ wte^T.
Sourcepub fn logits_last(&self, ids: &[u32]) -> Result<Vec<f32>>
pub fn logits_last(&self, ids: &[u32]) -> Result<Vec<f32>>
Logits for the last position only, recomputing the full context (no cache) — the reference decode path used by verification tests.
Sourcepub fn logits_step(&self, ids: &[u32], cache: &mut KvCache) -> Result<Vec<f32>>
pub fn logits_step(&self, ids: &[u32], cache: &mut KvCache) -> Result<Vec<f32>>
Last-position logits for ids continuing from cache (incremental
decode: pass the full prompt once, then one token at a time).
Sourcepub async fn logits_step_async(
&self,
ids: &[u32],
cache: &mut KvCache,
) -> Result<Vec<f32>>
pub async fn logits_step_async( &self, ids: &[u32], cache: &mut KvCache, ) -> Result<Vec<f32>>
Async form of Gpt2::logits_step — identical math; the readback is
awaited so it works on wasm32 (roadmap v4, pitfall 14).
Sourcepub async fn logits_step_attn_async(
&self,
ids: &[u32],
cache: &mut KvCache,
) -> Result<(Vec<f32>, Vec<AttnStep>)>
pub async fn logits_step_attn_async( &self, ids: &[u32], cache: &mut KvCache, ) -> Result<(Vec<f32>, Vec<AttnStep>)>
Gpt2::logits_step_async plus every block’s attention probabilities
for this step, in layer order.
The cheap probe: exactly Gpt2::logits_step_trace_async with no
detail layers and no top-n, so the two can never disagree about what
the model attended with.
Sourcepub async fn logits_step_trace_async(
&self,
ids: &[u32],
cache: &mut KvCache,
detail_layers: usize,
top_n: usize,
) -> Result<(Vec<f32>, StepTrace)>
pub async fn logits_step_trace_async( &self, ids: &[u32], cache: &mut KvCache, detail_layers: usize, top_n: usize, ) -> Result<(Vec<f32>, StepTrace)>
Gpt2::logits_step_async plus a full calculation trace for this step:
the embedding, every block’s attention, the whole forward pass through
the first detail_layers blocks (both LayerNorms, Q/K/V, pre-softmax
scores, the concatenated heads and their projection, both residual
adds, post-GELU MLP), the final LayerNorm, and the top_n most likely
next tokens with their probabilities.
The logits are identical to logits_step_async — the probe only reads
tensors the step computes anyway. The whole step is enqueued first, and
every captured tensor comes back in a single batched readback: one at
a time they cost ~2.7x the decode itself, since the price is the round
trip rather than the bytes.
detail_layers is the cost knob. At 0 this is the attention-only probe
and nothing but the post-softmax tensors is read. Each detail layer adds
q_len * (13 * n_embd + n_head * kv_len) floats, so a long prefill is
the only expensive call — a decode step is q_len == 1.
Sourcepub fn init_random(
config: Gpt2Config,
device: &Device,
seed: u64,
) -> Result<Gpt2>
pub fn init_random( config: Gpt2Config, device: &Device, seed: u64, ) -> Result<Gpt2>
Random initialization for training from scratch: N(0, 0.02) weights, residual projections scaled by 1/sqrt(2*n_layer), zero biases, identity LayerNorms.
Sourcepub fn param_specs(&self) -> Vec<(String, bool)>
pub fn param_specs(&self) -> Vec<(String, bool)>
Parameter names (safetensors keys) and weight-decay flags, in the
canonical order used by params, params_mut, and loss_grads.
Sourcepub fn params_mut(&mut self) -> Result<Vec<&mut Tensor>>
pub fn params_mut(&mut self) -> Result<Vec<&mut Tensor>>
Mutable parameters in param_specs order (for the optimizer).
Sourcepub fn save_safetensors(&self, path: impl AsRef<Path>) -> Result<()>
pub fn save_safetensors(&self, path: impl AsRef<Path>) -> Result<()>
Save a checkpoint loadable by from_safetensors. A chunked wte is
reassembled host-side first.
Sourcepub fn loss(&self, input: &[u32], targets: &[u32]) -> Result<f32>
pub fn loss(&self, input: &[u32], targets: &[u32]) -> Result<f32>
Mean cross-entropy of targets given input, forward only — no tape,
no gradients, no dropout. This is the evaluation path: a validation
split scored with Gpt2::loss_grads would build and discard a full
backward graph per window.
Sourcepub fn loss_grads(
&self,
input: &[u32],
targets: &[u32],
dropout_p: f32,
seed: u32,
) -> Result<(f32, Vec<Tensor>)>
pub fn loss_grads( &self, input: &[u32], targets: &[u32], dropout_p: f32, seed: u32, ) -> Result<(f32, Vec<Tensor>)>
One training forward + backward on a single sequence: mean
cross-entropy of targets given input, and gradients for every
parameter in param_specs order. Batching is achieved by
accumulating grads over calls (roadmap v4 batching policy).
Sourcepub fn generate(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
) -> Result<String>
pub fn generate( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, ) -> Result<String>
Autoregressive generation with KV-cache decode. Returns the full text (prompt + completion).
Sourcepub fn generate_streaming(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_token: impl FnMut(u32, &str),
) -> Result<String>
pub fn generate_streaming( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_token: impl FnMut(u32, &str), ) -> Result<String>
Sync streaming generation with KV-cache decode. on_token fires
exactly once per generated token (never for the prompt) with the
token id and the newly decodable text delta — which may be empty when
a multi-byte character spans several BPE tokens, since a partial UTF-8
sequence is held back until its trailing bytes arrive.
This is the accurate throughput hook: callback invocations map 1:1 to
tokens, unlike Gpt2::generate_async’s text-delta callback.
Sourcepub fn generate_streaming_ctl(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_token: impl FnMut(u32, &str) -> ControlFlow<()>,
) -> Result<String>
pub fn generate_streaming_ctl( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_token: impl FnMut(u32, &str) -> ControlFlow<()>, ) -> Result<String>
Gpt2::generate_streaming with an interruptible callback: returning
ControlFlow::Break stops after the current token and returns the
text generated so far. Long interactive runs need this — a callback
that cannot abort can only be “cancelled” once the whole run finishes.
Sourcepub async fn generate_async(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_text: impl FnMut(&str),
) -> Result<String>
pub async fn generate_async( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_text: impl FnMut(&str), ) -> Result<String>
Async autoregressive generation with KV-cache decode — the browser
form of Gpt2::generate. on_text receives each newly decoded text
fragment (the delta of the full decode, so multi-byte characters that
span BPE tokens are never split) so a page can stream output.
Sourcepub async fn generate_async_ctl(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_text: impl FnMut(&str) -> ControlFlow<()>,
) -> Result<String>
pub async fn generate_async_ctl( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_text: impl FnMut(&str) -> ControlFlow<()>, ) -> Result<String>
Gpt2::generate_async with an interruptible callback — the async
counterpart of Gpt2::generate_streaming_ctl. Returning
ControlFlow::Break stops after the current token, which is how a
page offers a working “stop” button.
Sourcepub async fn generate_async_probe(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_text: impl FnMut(&str) -> ControlFlow<()>,
on_attn: Option<impl FnMut(&[AttnStep])>,
) -> Result<String>
pub async fn generate_async_probe( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_text: impl FnMut(&str) -> ControlFlow<()>, on_attn: Option<impl FnMut(&[AttnStep])>, ) -> Result<String>
Gpt2::generate_async_ctl with an optional attention probe:
on_attn, when present, fires once per decode step with every block’s
attention probabilities — including the prompt prefill, whose q_len
is the prompt length rather than 1.
Opt-in because it costs one readback per block per token. Passing
None is exactly the non-probing path; the generated text is identical
either way, since the probe reads tensors the step already computed.
Sourcepub async fn generate_async_trace(
&self,
tokenizer: &impl Tokenizer,
prompt: &str,
max_new_tokens: usize,
sampling: Sampling,
on_text: impl FnMut(&str) -> ControlFlow<()>,
on_trace: Option<impl FnMut(&StepTrace)>,
detail_layers: usize,
top_n: usize,
) -> Result<String>
pub async fn generate_async_trace( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, on_text: impl FnMut(&str) -> ControlFlow<()>, on_trace: Option<impl FnMut(&StepTrace)>, detail_layers: usize, top_n: usize, ) -> Result<String>
Gpt2::generate_async_probe with the full calculation trace:
on_trace, when present, fires once per step — including the prompt
prefill, whose q_len is the prompt length rather than 1 — with
everything Gpt2::logits_step_trace_async captured.
None is byte-for-byte the non-probing path. With Some, the
generated text is still identical: the probe reads tensors the step
already computed and changes no arithmetic.
Auto Trait Implementations§
impl !RefUnwindSafe for Gpt2
impl !UnwindSafe for Gpt2
impl Freeze for Gpt2
impl Send for Gpt2
impl Sync for Gpt2
impl Unpin for Gpt2
impl UnsafeUnpin for Gpt2
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more