pub struct Value<'tape, E> { /* private fields */ }Expand description
A Copy proxy to a value recorded on a Tape: the operand of
recording.
A value stores its node position together with a borrow of the tape, so
it cannot outlive the construction phase — Tape::into_network
consumes the tape, and the borrow checker rejects a proxy that would
cross the seal; take Value::symbol first. Arithmetic and tensor
operations append computed nodes to the tape without consuming their
operands. Payload literals can be mixed directly into expressions, in
either operand order; every literal occurrence records a new leaf.
Operations validate tape identity and shape compatibility when they are recorded, so invalid expressions panic before a forward run begins.
The methods in this file are opcode mnemonics: each records exactly one
computed node, one per Op variant (payload literals additionally
record a leaf, which is data injection rather than computation). Methods
that expand to several computed nodes are composites and live in the
composition tier of composite.rs.
Value::shape returns the shape inferred when the node was recorded.
Value::payload clones the stored payload of a leaf, parameter, or
input; computed values are read from a Run, live
parameter payloads from Parameters — both by
Symbol.
Implementations§
Source§impl<'tape, E: Element> Value<'tape, E>
§Composites
Formulas that expand to several primitive nodes, paid by the
chain rule with no dedicated backward rule.
impl<'tape, E: Element> Value<'tape, E>
§Composites
Formulas that expand to several primitive nodes, paid by the chain rule with no dedicated backward rule.
Sourcepub fn abs(self) -> Self
pub fn abs(self) -> Self
Records the absolute value of this value as the composition
self.maximum(-self) and returns a proxy to it; the subgradient
at zero is one, by maximum’s left-biased tie rule.
Sourcepub fn relu(self) -> Self
pub fn relu(self) -> Self
Records the rectified linear unit of this value as the
composition self.maximum(zero), where the zero enters the
graph as a counted leaf of
this value’s shape — the same leaf a payload literal would
record; the subgradient at zero is one, by maximum’s
left-biased tie rule.
The once-dedicated opcode was retired when the leaf failed to show up in a consumer-scale training step: the extra cost is one activation-sized zero buffer per occurrence, and the fused form never measured past it.
Source§impl<'tape, E: Element> Value<'tape, E>
impl<'tape, E: Element> Value<'tape, E>
Sourcepub fn softplus(self) -> Self
pub fn softplus(self) -> Self
Records the softplus of this value, ln(1 + e^x), as the
stable split self.relu() + log1p(exp(-|x|)) and returns a
proxy to it.
The naive composition overflows to infinity for large positive
operands and answers zero long before the true value underflows
for large negative ones; the split is finite and accurate over
the whole line, riding the fused log1p — the
consumer that earned that opcode. The gradient is the chain
rule over the parts, which analytically is the logistic
sigmoid.
Sourcepub fn gelu(self) -> Self
pub fn gelu(self) -> Self
Records the exact Gaussian error linear unit of this value,
x * (1 + erf(x / sqrt(2))) / 2, and returns a proxy to it:
the consumer that earned the Erf opcode.
Every constant is formula-pure: the 1 and 2 enter as
counted leaves and sqrt(2) is
computed from the counted 2, so each element type rounds the
formula at its own precision and the spec stores no decimal.
The tanh approximation many models use instead is a caller
composition over tanh (the gpt2 example records it); this is
the exact form.
Sourcepub fn softmax(self, axis: usize) -> Self
pub fn softmax(self, axis: usize) -> Self
Records the softmax probabilities of this value along axis as
the composition self.log_softmax(axis).exp() and returns a proxy
to it.
Stability is inherited from the fused core: log-probabilities are at most zero, so the exponential cannot overflow — which is why softmax needs no fused form of its own.
§Panics
Panics if axis is out of rank.
Sourcepub fn mean_along(self, axis: usize) -> Self
pub fn mean_along(self, axis: usize) -> Self
Sourcepub fn broadcast_like(self, reference: Self) -> Self
pub fn broadcast_like(self, reference: Self) -> Self
Sourcepub fn broadcast_along_like(self, axis: usize, reference: Self) -> Self
pub fn broadcast_along_like(self, axis: usize, reference: Self) -> Self
Records this value repeated along axis to match reference’s
shape: broadcast_along reading the
reference for its extent alone, one node, no operand edge.
§Panics
Panics if axis is out of reference’s rank or this value’s
shape differs from reference’s with that axis removed.
Sourcepub fn transpose(self) -> Self
pub fn transpose(self) -> Self
Records the transposition of this value — its axes reversed — as
a permute of the reversed order, and returns a proxy to it.
The once-dedicated opcode was retired as a strict special case:
Permute { [1, 0] } is the same O(1) view with the same
self-inverse gradient rule.
§Panics
Panics if this value’s rank exceeds 2.
Sourcepub fn unsqueeze(self, axis: usize) -> Self
pub fn unsqueeze(self, axis: usize) -> Self
Records this value with a new extent-1 axis inserted at axis:
a reshape that leaves the elements unchanged.
§Panics
Panics if axis exceeds this value’s rank.
Sourcepub fn squeeze(self, axis: usize) -> Self
pub fn squeeze(self, axis: usize) -> Self
Records this value with the extent-1 axis at axis removed: a
reshape that leaves the elements unchanged.
§Panics
Panics if axis is out of rank or that axis is not extent 1.
Sourcepub fn broadcast_to(self, shape: impl Into<Shape>) -> Self
pub fn broadcast_to(self, shape: impl Into<Shape>) -> Self
Records this value broadcast to shape under the right-aligned
NumPy and TensorFlow rule, and returns a proxy to it.
The two shapes align from the trailing axis: the target’s rank must
be at least this value’s, and each source axis must either match its
aligned target axis or have extent one, in which case it is repeated
to the target extent. It composes the shape-changing primitives – a
right-aligning reshape that prepends the missing leading axes, then
one broadcast_along per repeated axis, or a single broadcast
when the source holds one element – so the gradient is the chain
rule over their adjoints: the incoming gradient summed back over
every repeated axis.
§Panics
Panics if shape’s rank is smaller than this value’s, or a source
axis neither matches its aligned target axis nor has extent one.
Source§impl<'tape, E: Element> Value<'tape, E>
impl<'tape, E: Element> Value<'tape, E>
Sourcepub fn tape(&self) -> &'tape Tape<E>
pub fn tape(&self) -> &'tape Tape<E>
Returns the tape this proxy records onto: the recording phase is this operand, which is what lets a module express itself from its input alone.
Sourcepub fn symbol(&self) -> Symbol
pub fn symbol(&self) -> Symbol
Returns the detached name of this value: the currency of every
phase after recording, and the documented bridge across
Tape::into_network.
Source§impl<'tape, E: Element> Value<'tape, E>
impl<'tape, E: Element> Value<'tape, E>
Sourcepub fn payload(&self) -> Option<Tensor<E>>
pub fn payload(&self) -> Option<Tensor<E>>
Returns a clone of this node’s stored payload, or None for a computed
value.
Leaves return their recorded payload, parameters their record-site
initial, and inputs their recorded default. Live parameter payloads
are read from Parameters::of, run results
from Run::of.
Source§impl<'tape, E: Element> Value<'tape, E>
§Elementary maps
One recorded node per call: the transcendentals and the order
pair. Arithmetic records through the standard operators.
impl<'tape, E: Element> Value<'tape, E>
§Elementary maps
One recorded node per call: the transcendentals and the order pair. Arithmetic records through the standard operators.
Sourcepub fn tanh(self) -> Self
pub fn tanh(self) -> Self
Records the hyperbolic tangent of this value on the same tape and returns a proxy to it.
Sourcepub fn exp(self) -> Self
pub fn exp(self) -> Self
Records the exponential of this value on the same tape and returns a proxy to it.
Sourcepub fn ln(self) -> Self
pub fn ln(self) -> Self
Records the natural logarithm of this value on the same tape and returns a proxy to it.
Sourcepub fn sqrt(self) -> Self
pub fn sqrt(self) -> Self
Records the square root of this value on the same tape and returns a proxy to it.
Sourcepub fn sin(self) -> Self
pub fn sin(self) -> Self
Records the sine of this value on the same tape and returns a proxy to it.
Sourcepub fn cos(self) -> Self
pub fn cos(self) -> Self
Records the cosine of this value on the same tape and returns a proxy to it.
Sourcepub fn log1p(self) -> Self
pub fn log1p(self) -> Self
Records the natural logarithm of one plus this value on the same tape and returns a proxy to it.
It is a distinct opcode, not sugar for (one + x).ln(): the
composed form rounds 1 + x first and destroys every
significant digit of an x near zero, while this one stays
accurate there. The two spellings are different specs with
different bits, and both remain valid.
Sourcepub fn expm1(self) -> Self
pub fn expm1(self) -> Self
Records e raised to this value, minus one, on the same tape
and returns a proxy to it.
Like log1p, it is a distinct opcode: the
composed x.exp() - one cancels catastrophically near zero,
and this one does not.
Sourcepub fn erf(self) -> Self
pub fn erf(self) -> Self
Records the error function of this value on the same tape and returns a proxy to it.
The computation delegates to the pure-Rust libm crate, like
every transcendental; its derivative rule speaks
erf_derivative, the closed pair that
keeps the constant 2/sqrt(pi) inside per-element kernels
rather than in any recorded graph.
Sourcepub fn erf_derivative(self) -> Self
pub fn erf_derivative(self) -> Self
Records the derivative of the error function of this value —
the scaled Gaussian (2/sqrt(pi)) * e^(-x^2) — on the same
tape and returns a proxy to it: what differentiate emits
where the engine’s rules call
Elementary::erf_derivative.
Its own derivative is -2x times itself, so the pair closes
under differentiation.
Sourcepub fn powf(self, exponent: Self) -> Self
pub fn powf(self, exponent: Self) -> Self
Records this value raised elementwise to the power of exponent
on the same tape and returns a proxy to it.
The exponent-side gradient involves the logarithm of this value, so it is a number only where this value is positive.
§Panics
Panics if the operands belong to different tapes or their shapes differ.
Sourcepub fn maximum(self, rhs: Self) -> Self
pub fn maximum(self, rhs: Self) -> Self
Records the elementwise maximum of this value and rhs on the
same network and returns a proxy to it; on a tie the gradient goes
to this value, not rhs.
§Panics
Panics if the operands belong to different tapes or their shapes differ.
Sourcepub fn step(self, threshold: Self) -> Self
pub fn step(self, threshold: Self) -> Self
Records the elementwise 0/1 indicator of self >= threshold on
the same network and returns a proxy to it: the Heaviside step,
ties answering one.
It is the derivative mask of the maximum family as a recorded
node — what differentiate emits where the engine’s rules call
Elementary::step — and it carries no
gradient of its own: the function is locally constant almost
everywhere, so both operands are data, not differentiable
dependencies.
§Panics
Panics if the values belong to different tapes or their shapes differ.
Source§impl<'tape, E: Element> Value<'tape, E>
§Tensor operations, views, windows, and index
One recorded node per call: products and reductions, the
explicit broadcasts, the view movers, the sliding-window pair,
the gather/scatter pair, and the two fused log-domain nodes.
Multi-node formulas are composites and live in composite.rs.
impl<'tape, E: Element> Value<'tape, E>
§Tensor operations, views, windows, and index
One recorded node per call: products and reductions, the
explicit broadcasts, the view movers, the sliding-window pair,
the gather/scatter pair, and the two fused log-domain nodes.
Multi-node formulas are composites and live in composite.rs.
Sourcepub fn matmul(self, rhs: Self) -> Self
pub fn matmul(self, rhs: Self) -> Self
Records the matrix product of this value and rhs on the same
network and returns a proxy to it.
§Panics
Panics if the operands belong to different tapes, either operand is not rank 2, or their inner dimensions differ.
Sourcepub fn sum(self) -> Self
pub fn sum(self) -> Self
Records the sum of every value in this payload on the same tape and returns a proxy to it.
Sourcepub fn sum_along(self, axis: usize) -> Self
pub fn sum_along(self, axis: usize) -> Self
Records the sum of this value along axis on the same tape
and returns a proxy to it.
§Panics
Panics if axis is out of rank.
Sourcepub fn broadcast(self, shape: impl Into<Shape>) -> Self
pub fn broadcast(self, shape: impl Into<Shape>) -> Self
Records the explicit broadcast of this single-value payload
across shape on the same tape and returns a proxy to it.
This is the narrowest expansion opcode: the operand must hold
exactly one element, and the target shape is a recorded
parameter, never an alignment rule. To read the shape off
another value, use broadcast_like; for
a source of any broadcastable shape, use the composite
broadcast_to, which applies the
right-aligned NumPy rule over this opcode and
broadcast_along.
§Panics
Panics if this value’s shape does not contain exactly one element.
Sourcepub fn broadcast_along(self, axis: usize, extent: usize) -> Self
pub fn broadcast_along(self, axis: usize, extent: usize) -> Self
Records the explicit repetition of this value along a new axis
of extent inserted at axis on the same tape and returns a
proxy to it.
This opcode widens exactly one named axis and never infers an
alignment. To read the extent off a reference value, use
broadcast_along_like; to widen
several axes at once, or to expand under the right-aligned
NumPy rule, use the composite
broadcast_to.
§Panics
Panics if axis exceeds this value’s rank or extent is zero.
Sourcepub fn reshape(self, shape: impl Into<Shape>) -> Self
pub fn reshape(self, shape: impl Into<Shape>) -> Self
Records a reshape of this value to shape on the same tape and
returns a proxy to it; the elements keep their logical row-major
order.
§Panics
Panics if shape’s volume differs from this value’s.
Sourcepub fn permute(self, order: impl IntoIterator<Item = usize>) -> Self
pub fn permute(self, order: impl IntoIterator<Item = usize>) -> Self
Records a permutation of this value’s axes by order on the same
network and returns a proxy to it; axis i of the result takes
axis order[i] of this value.
§Panics
Panics if order is not a permutation of 0..rank.
Sourcepub fn narrow(self, axis: usize, start: usize, len: usize) -> Self
pub fn narrow(self, axis: usize, start: usize, len: usize) -> Self
Records the window of len elements from start along axis on
the same network and returns a proxy to it; the forward is an O(1)
view and the gradient scatters back into the unselected positions
as zeros.
§Panics
Panics if axis is out of rank, len is zero (tensors cannot be
empty), or start + len overflows or exceeds the axis extent.
Sourcepub fn pad(self, axis: usize, start: usize, full_extent: usize) -> Self
pub fn pad(self, axis: usize, start: usize, full_extent: usize) -> Self
Records this value placed at start .. along axis inside zeros
whose axis has extent full_extent, on the same tape, and
returns a proxy to it: the adjoint of Value::narrow, with
narrow as its own gradient rule.
§Panics
Panics if axis is out of rank or the window overflows or
exceeds full_extent.
Sourcepub fn unfold(
self,
axis: usize,
size: usize,
step: usize,
dilation: usize,
) -> Self
pub fn unfold( self, axis: usize, size: usize, step: usize, dilation: usize, ) -> Self
Records the sliding windows of this value along axis on the
same network and returns a proxy to it: the axis becomes a
(count, size) pair where window w starts at w * step and
takes every dilation-th element. The forward is a strided view;
the gradient folds every window contribution back onto its
source position, so overlapping windows accumulate.
§Panics
Panics if axis is out of rank, size, step, or dilation is
zero, or the dilated window span dilation * (size - 1) + 1
overflows or exceeds the axis extent.
Sourcepub fn fold(
self,
axis: usize,
size: usize,
step: usize,
dilation: usize,
extent: usize,
) -> Self
pub fn fold( self, axis: usize, size: usize, step: usize, dilation: usize, extent: usize, ) -> Self
Records the (count, size) window pair at axis, axis + 1
folded back onto an axis of extent on the same tape and
returns a proxy to it: unfold’s adjoint, each
source position summing the window elements read from it,
accumulated output-centrically so the result is deterministic
under any evaluation strategy.
§Panics
Panics if the operand has no (count, size) pair at axis, a
parameter is zero, the dilated window span exceeds extent, or
the pair is not what unfolding an extent axis by these
parameters produces.
Sourcepub fn gather(self, selection: Self) -> Self
pub fn gather(self, selection: Self) -> Self
Records the row gather of this value (the table) by selection, a
one-hot [count, vocab] whose vocabulary matches the table’s first
axis: output[i] is the table row selection names for position
i. The gradient scatter-adds into the table only; the selection is
data and receives no gradient.
It is the embedding lookup: feed selection per run, so one graph
serves any batch of indices.
§Panics
Panics if the values belong to different tapes, selection is not
rank 2, or its vocabulary does not match this value’s first axis.
Sourcepub fn scatter(self, selection: Self) -> Self
pub fn scatter(self, selection: Self) -> Self
Records the rows of this value scatter-added into one row per
entry of selection’s vocabulary by its one-hot indices on the
same tape and returns a proxy to it: gather’s
adjoint, accumulating rows selected more than once. The
selection is data and receives no gradient.
§Panics
Panics if the values belong to different tapes, this value is
rank 0, or selection is not rank 2 with one row per leading
entry of this value.
Sourcepub fn log_softmax(self, axis: usize) -> Self
pub fn log_softmax(self, axis: usize) -> Self
Records the log-softmax of this value along axis on the same
network and returns a proxy to it: the logarithm of the softmax
probabilities, computed stably in one fused node.
Exponentiating the result recovers the probabilities themselves; the fused form exists because the stable computation shifts by the axis maximum, which no composition of recorded operations can express.
§Panics
Panics if axis is out of rank.
Sourcepub fn logsumexp(self, axis: usize) -> Self
pub fn logsumexp(self, axis: usize) -> Self
Records the log-sum-exp of this value along axis on the same
network and returns a proxy to it: the softmax family’s normalizer
and a smooth maximum; like sum_along, the reduced axis is
removed.
It is a fused node for the same reason as
log_softmax: the stable form shifts by the
axis maximum, so the result is finite for every finite operand —
where the former composition over log_softmax returned inf
once finite logits differed by more than the representable range.
The gradient is the softmax.
§Panics
Panics if axis is out of rank.
Source§impl<E: Element + Emittable> Value<'_, E>
impl<E: Element + Emittable> Value<'_, E>
Sourcepub fn to_html(&self, theme: Theme) -> String
pub fn to_html(&self, theme: Theme) -> String
Renders the proxy’s stored payload as a self-contained HTML card.
The payload shown is the recorded one: a leaf’s constant, a
parameter’s record-site initial, or an input’s default. Live
parameter payloads belong to the caller’s
Parameters and are read by Symbol.
Sourcepub fn evcxr_display(&self)
pub fn evcxr_display(&self)
Displays the value when it is the last expression in an Evcxr cell.
Trait Implementations§
impl<E> Copy for Value<'_, E>
Source§impl<E> Debug for Value<'_, E>
It prints only the node position to avoid dumping the whole network.
impl<E> Debug for Value<'_, E>
It prints only the node position to avoid dumping the whole network.
Source§impl<E: Element> From<Value<'_, E>> for Symbol
The conversion form of Value::symbol, for positions where a
list must be homogeneous in Symbol: [loss.into(), stored].
impl<E: Element> From<Value<'_, E>> for Symbol
The conversion form of Value::symbol, for positions where a
list must be homogeneous in Symbol: [loss.into(), stored].