An image needs context, but a scan introduces order
A patch of an image is easier to interpret when the model can use the rest of the scene. A convolution collects information from a local neighborhood. Full self-attention compares every token with every other token. VMamba takes another route: carry a compact running state across the image, then combine several traversal orders so information can arrive from different directions.
Start with a small feature map. The numbers below identify positions, not colors, feature values, or classes. Each position will eventually hold a vector of learned channels.
Reading this grid row by row creates the sequence 0, 1, 2, 3, 4, …, 11. A causal scan at position 5 has already seen position 1, directly above it, but has not seen position 9, directly below it. The scan also jumps from 3 to 4, although those positions lie at opposite ends of adjacent rows. Turning an image into a sequence introduces both an order and a spatial bias.
VMamba does not try to eliminate order. It uses four complementary orders, processes each with an input-dependent state update, and restores the results to their original positions. To understand why that works, first look at what one scan carries.
A state is a running summary
Imagine passing a small notebook from one position to the next. At each step, you retain part of the previous note, add something from the current input, and read an output from the updated note. The notebook is the state. It has a fixed number of coordinates even when the sequence gets longer.
The next diagram makes that update numerical. Scrub through the inputs and compare the retained state with the new input contribution. The values illustrate the recurrence; they are not activations from a trained image model.
Interactive mechanics
Watch the state retain and update
A scalar teaching example: one channel, one state coordinate. The same spatial grid is scanned with zero initial state in each direction.
Spatial token IDs · current input u = 1
Positive update time scale
Δ = softplus(0.8u + bias)
0.598
Retention exp(−0.7Δ) = 0.658
h = exp(ΔA) × previous h + ΔBu
Retained state
0.000
0.658 × 0.000
Input contribution
0.598
0.598 × 1 × 1
New state
0.598
retained + input
Read out the state, then add the separate D input skip:
y = 1 × 0.598 + 0.2 × 1 = 0.798
ID 0
1
ID 1
2
ID 2
0
ID 3
3
ID 4
1
ID 5
-1
ID 6
2
ID 7
0
ID 8
1
ID 9
3
ID 10
-2
ID 11
1
For one scalar state, let u_t be the current input, h_{t-1} the previous state, a_t the retention factor, and b_t the input coefficient. The next state and its output are:
Here c_t reads the state, while d supplies a direct input-to-output path. For example, with previous state 2, retention 0.5, input 3, and input coefficient 0.2, the next state is 0.5\times2+0.2\times3=1.6. It preserves some history while incorporating something new.
That fixed-size summary is also a constraint. The state does not keep a separate record of every preceding token. Different histories can be compressed into the same state. The important question becomes: which information should this input preserve, write, and read?
Selectivity changes the update at each position
VMamba learns the update from the current feature vector. Its projections produce three input-dependent quantities: Δ, the update time scale; B, the input-to-state coefficients; and C, the state-to-output coefficients. The learned A controls state decay, and D controls the direct skip. A and D do not change with the input token.
A larger Δ makes a negative-A state retain less history, but also changes how much new input is written. Δ is positive through a softplus transformation; it is not a sigmoid probability gate. B and C can be signed and are not attention probabilities either. Moving the diagram’s update controls changes the actual recurrence, rather than selecting a hand-drawn “important” patch.
Now give the running summary a state coordinate n and a channel j. For one direction and one example, the pinned reference implements:
Each direction starts from a zero state. B and C are specific to the direction and position but shared across channels within that direction’s group in the reference. Δ, A, D, and the state are per channel. The released Tiny model uses state dimension 1 per channel per direction, not one scalar for the entire image.
The exponential connects this discrete update to continuous-time state-space models: A describes decay, and Δ sets the interval over which decay acts. The input term in the official selective_scan_torch reference is explicitly \Delta B u. For constant scalar A, B, and u, exact zero-order-hold integration would instead use \frac{e^{\Delta A}-1}{A}Bu. These agree to first order for a small interval; they are not the same expression. Paper v4, §3 and Appendix A
We now have an operator for one ordered sequence. An image still needs information from positions that lie later in that sequence.
Four orders give each position several views of the image
SS2D means 2D Selective Scan. Its cross-scan operation builds four sequences from the same feature map: row-major, column-major, the complete reversed row-major sequence, and the complete reversed column-major sequence. Select a direction below and watch the token IDs. Notice the wrap jumps at the end of each row or column.
Interactive mechanics
One grid, four complete sequences
A token is a spatial location. Change the direction and watch the same 12 locations become a different causal sequence.
Original positions stay fixed: 3 rows × 4 columns
Row forward
Start
0
Current
0
End
11
Begin with zero state at the first token.
Sequence order · numbers are spatial token IDs
Row →
Column ↓
Row ←
Column ↑
For our 3×4 grid, the four orders are:
Row forward: 0 1 2 3 4 5 6 7 8 9 10 11 Column forward: 0 4 8 1 5 9 2 6 10 3 7 11 Row reverse: 11 10 9 8 7 6 5 4 3 2 1 0 Column reverse: 11 7 3 10 6 2 9 5 1 8 4 0
These are four full-image scans. The state continues across row and column boundaries. They are not independent scans of each row, and they do not follow a serpentine path. The column sequence comes from transposing the spatial axes before flattening; each reverse sequence flips the entire corresponding forward sequence. Pinned cross_scan_fwd
A forward path lets a position receive information from its prefix. Its reverse lets it receive information from the other side. Even the row-forward/reverse pair structurally connects every pair of positions; the column pair provides a second ordering with different spatial distances. Four paths reduce reliance on one ordering without making all routes equivalent.
The highlighted prefixes show possible information paths. They do not show learned importance, saliency, or how strongly a trained model uses a distant pixel. That strength depends on repeated retention factors, B and C, and the learned features. Before these directional outputs can form an image again, their positions must agree.
Cross-merge restores positions before adding
Position 5 appears at different sequence indices in different directions. Adding the four outputs at sequence index 5 would combine different image positions. Cross-merge first undoes each permutation, then sums the outputs associated with the same original pixel.
Interactive mechanics
Different sequence slots, the same pixel
Choose a spatial pixel. Find its output in all four sequences, restore its position, then add the four aligned values.
Choose a pixel in the original grid
Pixel 6: row 1, column 2. Sequence slots below are zero-based.
Row forward
slot 6 → 6
7 tokens can reach this output through the causal prefix.
Column forward
slot 7 → 6
8 tokens can reach this output through the causal prefix.
Row reverse
slot 5 → 6
6 tokens can reach this output through the causal prefix.
Column reverse
slot 4 → 6
5 tokens can reach this output through the causal prefix.
Undo order → restore pixel 6 → sum
Row →
6
slot 6 → pixel 6
Column ↓
6
slot 7 → pixel 6
Row ←
6
slot 5 → pixel 6
Column ↑
6
slot 4 → pixel 6
Forward and reverse row prefixes together cover every location; so do the column prefixes. This shows structural reachability, not how strongly a trained model uses a pixel.
Let p_k(t) map sequence index t in direction k to an original flat pixel index, and let y^{(k)}_t be that direction’s output vector. The merged vector for original position p is:
The inverse reverses the two backward sequences and restores the transposed column layout. On a rectangle, that column stream must be reshaped as width × height, then transposed back to height × width. Square-only examples can conceal a wrong inverse. The reference adds the aligned outputs; it does not average or concatenate them. Replacing every scan with the identity therefore gives four times the input after merge. Pinned cross_merge_fwd
The original paper now reads as a compact description of the mechanism we have traced: permute, update four running states, restore positions, combine.
Original Figure 2, arXiv 2401.10166v4, PDF page 4. The printed grid uses IDs 1–9; our rectangular walkthrough uses 0–11.
Open the source at full size.
SS2D supplies global spatial mixing. A useful network block must also transform channels, preserve an easy residual path, and prepare the next layer’s features.
Inside the final VSS block
A Visual State Space block wraps SS2D in two residual updates. First normalize the incoming feature map, run the SS2D branch, and add it back to the input. Then normalize again, apply a channel MLP, and add that result to the intermediate features.
Interactive mechanics
Local mixing, global routes, two residuals
Inspect the final VMamba-T s1l8 VSS block (v05_noz). The feature grid keeps its spatial shape throughout the block.
Residual 1 · input x travels around SS2D
x → +
1 · At each position
Normalize & project
LN → pointwise projection
2 · Nearby positions
Local convolution
3×3 depthwise conv → SiLU
3 · Whole-image routes
Four selective scans
cross-scan → project Δ, B, C → scan
4 · Back to the grid
Align & project
cross-merge → LN → output projection
5 · Add the original x
+x₁Residual 2 · x₁ travels around the MLP
LN → pointwise MLP
C → 4C → GELU → C
Add x₁
Second residual
LN → pointwise projection
Channel normalization and the input projection act at each spatial position. This final Tiny block has no separate z gate.
Inside the SS2D branch, a pointwise projection mixes channels. A 3×3 depthwise convolution and SiLU gather local spatial information before scanning. Direction-specific projections derive Δ, B, and C; the scans carry global context; cross-merge restores the grid. Channel normalization and an output projection complete the branch. The MLP expands channels by a factor of four, applies GELU, and projects back to the block width.
For input feature map X, write this as:
This expression shows the inference path; training also applies stochastic depth to residual branch outputs. LN normalizes channels at each spatial position. The direct D·u term lives inside each selective scan. The two additions above carry complete feature maps around entire branches. They are three different skip mechanisms.
The architecture shown here is the final no-z VSS block. The earlier “Vanilla VMamba” design multiplied its scan output by a separate z branch. The final design removes that branch and introduces the MLP residual. Selectivity remains through Δ, B, and C. Mixing the historical branch into the final Tiny configuration would describe a different model. Paper v4, §4.1, pinned v05_noz implementation
Once that block preserves its spatial shape, stacking it is straightforward. The backbone changes resolution between groups of blocks.
From an image to a four-stage backbone
The released VMamba-T s1l8 starts with two padded 3×3 stride-two convolutions: RGB becomes 48 channels at 112×112, then 96 channels at 56×56. Each convolution is followed by channel normalization, with GELU between the two. This is the code’s actual convolutional stem, rather than a single non-overlapping patch projection.
Interactive mechanics
A shrinking grid, a growing channel width
Follow the released VMamba-T s1l8 backbone on a 224×224 RGB input. Select a stage to inspect its real tensor shape and repeated VSS blocks.
224 × 224 × 3 → two-convolution stem
3×3 stride 2 → LN → GELU → 3×3 stride 2 → LN
112 × 112 × 48 → 56 × 56 × 96
Stage 1 · VSS × 2
56 × 56 × 96
Each scan visits 3,136 spatial tokens.
Next: downsample v3
A padded 3×3 stride-two convolution halves the spatial resolution and doubles channel width, followed by channel normalization.
For detection and segmentation, the backbone can provide feature grids from multiple stages to a task-specific head instead of pooling them into one classifier vector.
For a 224×224 image, the four stage outputs are 56×56×96, 28×28×192, 14×14×384, and 7×7×768. Their VSS block counts are [2, 2, 8, 2]. Between stages, a padded 3×3 stride-two convolution reduces resolution and doubles the channel width. Each scan runs over the current stage’s entire feature map, not repeatedly over the original RGB pixels.
In the name s1l8, s1 means SSM expansion ratio 1, and l8 means eight blocks in stage 3. The state dimension is 1, while the Δ projection rank is the stage width divided by 16, rounded up. The classifier normalizes the last feature map, globally averages its spatial positions, and maps the resulting 768 features to 1,000 ImageNet logits. A logit is a score; softmax converts those scores into class probabilities. Pinned vmamba_tiny_s1l8 and backbone builders, Tiny factory
A detection or segmentation system keeps these spatial stage features and attaches a task-specific head instead of the ImageNet classifier. The four-stage hierarchy is therefore useful beyond classification: early maps retain spatial detail, while later maps combine that detail at coarser resolution.
Original Figure 3(a)–(d), arXiv 2401.10166v4, PDF page 5; performance panel (e) is outside this crop. Read panel (d) for the final block. Panel (c) records the historical multiplicative branch.
Open the complete source figure.
We can now connect each part of the diagrams to a tensor operation, rather than treating the backbone as an opaque collection of blocks.
Implementation: paper, math, and Python
Read the seven rows in order: cross-scan, selectivity, recurrence, cross-merge, SS2D, the VSS block, and the backbone. Each row places the original paper reference beside the equation, tensor shapes, and highlighted Python extracted from the runnable example. The code uses the same rectangular order and positional alignment as the diagrams.
Follow the same operations in a runnable CPU PyTorch reference. Its readable scan loop explains the state updates; it does not reproduce the throughput of the authors’ CUDA and Triton kernels.
Download the Python reference · Pinned requirements · Pinned official source
python vmamba.py --smoke --backward
The smoke run uses random weights and checks a forward and backward pass. Its outputs are mechanics checks, not pretrained predictions.
1. Unfold the image into four complete sequences
Original paper
SS2D starts by traversing every spatial position in four complementary orders. Row-major and column-major flattening each supply a forward path and a full reversed path.
Math and tensor shapes
Flatten the original grid, then flatten its spatial transpose. Flip each complete sequence to produce the backward paths. The state continues across row and column boundaries: a new row does not reset it. The batch dimension b is distinct from the input-dependent state parameter B.
3 × 4 grid → 4 sequences of length 12
Python implementation
def cross_scan(x):
"""Map [batch, channels, H, W] to four [batch, 4, channels, H*W] routes."""
if x.ndim != 4 or min(x.shape) <= 0:
raise ValueError("Expected a nonempty NCHW feature map")
row = x.flatten(2)
column = x.transpose(2, 3).flatten(2)
forward = torch.stack((row, column), dim=1)
return torch.cat((forward, forward.flip(-1)), dim=1)2. Let the current input choose how the state updates
Original paper
Selective state-space models replace fixed input and output mappings with mappings derived from the current input. A learned positive time scale controls the update.
Math and tensor shapes
Project each token to B, C and a low-rank time-scale representation, then expand that representation to the channel width. Softplus makes the time scale positive. The negative diagonal A makes exp(ΔA) a decaying retention factor. Δ is a time scale, not a probability gate: changing it affects both retained state and the input contribution.
Per direction: Bₜ and Cₜ describe state coordinates; Δₜ varies by channel
Python implementation
def selective_parameters(self, routes):
"""Each direction projects input into its delta, B and C sequences."""
projected = torch.einsum("bkdl,kpd->bkpl", routes, self.x_proj)
low_rank_delta, b, c = projected.split(
(self.rank, self.state_size, self.state_size), dim=2
)
raw_delta = torch.einsum("bkrl,kdr->bkdl", low_rank_delta, self.dt_proj)
a = (
-self.a_log.exp()
) # Learned stable negative rates, not input-derived.
return raw_delta.flatten(1, 2), a, b, c3. Retain previous state, write new information, read an output
Original paper
The discrete update carries information along each sequence. The reference implements the input contribution as ΔBu, while the transition is exp(ΔA).
Math and tensor shapes
Start a separate zero state for every direction and channel. The first term keeps part of the previous summary; the second writes the current input. C reads the state into one output per channel, and D adds a direct input path. This readable loop matches the reference recurrence; fast kernels reorganize its computation. ΔBu is the reference discretization, not the exact zero-order-hold input integral.
States: [b, 4C, N]; output sequences: [b, 4C, L]
Python implementation
def selective_scan(
u, delta, a, b, c, d=None, delta_bias=None, delta_softplus=True
):
"""Scan grouped B/C, using the official delta*B*u input discretization.
u/delta: [batch, channels, length]; a: [channels, state].
b/c: [batch, groups, state, length], shared within each channel group.
d/delta_bias: [channels]. States start at zero for each channel/route.
Computation is float32, matching the upstream torch reference.
"""
_validate_scan(u, delta, a, b, c)
if delta_bias is not None:
delta = delta + delta_bias[None, :, None]
if delta_softplus:
delta = F.softplus(delta)
u, delta, a, b, c = (v.float() for v in (u, delta, a, b, c))
batch, channels, length = u.shape
channels_per_group = channels // b.shape[1]
b = b.repeat_interleave(channels_per_group, dim=1)
c = c.repeat_interleave(channels_per_group, dim=1)
state = u.new_zeros(batch, channels, a.shape[-1])
outputs = []
for t in range(length):
step = delta[:, :, t, None]
retention = torch.exp(step * a)
injection = step * b[:, :, :, t] * u[:, :, t, None]
state = retention * state + injection
outputs.append((c[:, :, :, t] * state).sum(-1))
y = torch.stack(outputs, dim=-1)
return y if d is None else y + d[None, :, None] * u4. Restore pixel positions before adding the directions
Original paper
After selective scanning, every directional output is restored to the original spatial layout. Corresponding pixels can then combine their contextual information.
Math and tensor shapes
Undo each backward reversal. Reshape the column-order sequences as W × H and transpose them back to H × W. Only then add the four outputs. Summation preserves all four contributions; it does not divide by four. Rectangular examples make a wrong reshape immediately visible.
4 aligned [b, C, H, W] tensors → one [b, C, H, W] tensor
Python implementation
def cross_merge(routes, height, width):
"""Undo reversals and column transpose, then SUM aligned outputs."""
if (
routes.ndim != 4
or routes.shape[1] != 4
or height <= 0
or width <= 0
or routes.shape[-1] != height * width
):
raise ValueError("Expected four routes with length height * width")
aligned = routes[:, :2] + routes[:, 2:].flip(-1)
batch, _, channels, _ = aligned.shape
row = aligned[:, 0].reshape(batch, channels, height, width)
column = aligned[:, 1].reshape(batch, channels, width, height)
return row + column.transpose(2, 3)5. Put local mixing and global scanning in the same operator
Original paper
SS2D adapts a one-dimensional selective operator to image features. The released final variant supplies the projection, local convolution, normalization and output details.
Math and tensor shapes
A pointwise projection mixes channels without moving information spatially. The depthwise convolution adds local context before the four full-image scans. Each direction has its own learned parameters. Merge brings the directional results together, and the output projection returns to the block width. The selected v05_noz variant has no separate multiplicative z branch.
VMamba-T stage 1: [b, 96, 56, 56] → [b, 96, 56, 56]
Python implementation
def forward(self, x):
"""Mix locally, scan globally, align routes, normalize and project."""
x = F.silu(self.local(self.in_proj(x)))
batch, channels, height, width = x.shape
routes = cross_scan(x)
delta, a, b, c = self.selective_parameters(routes)
outputs = selective_scan(
routes.flatten(1, 2), delta, a, b, c, self.d, self.dt_bias
)
outputs = outputs.reshape(batch, 4, channels, height * width)
merged = cross_merge(outputs, height, width)
return self.out_proj(self.norm(merged))6. Build the final VSS block with two residual updates
Original paper
The final paper uses a normalized SS2D residual followed by a normalized MLP residual. This is the improved block, distinct from Vanilla VMamba in Figure 3(c).
Math and tensor shapes
SS2D communicates across positions, while the MLP transforms the channels at each position. Each module receives normalized features and adds its result back to its input. These two block residuals are separate from D·u inside the scan recurrence. DropPath is a training regularizer; evaluation keeps both branches. The teaching code omits DropPath, showing that evaluation behavior directly.
The block preserves channels and spatial size; its MLP expands channels by 4
Python implementation
class VSSBlock(nn.Module):
"""Two pre-normalized residuals; the final block has no separate z gate.
Drop-path is omitted in this teaching model (identity during evaluation).
The scan's D*u skip is inside SS2D and separate from these two residuals.
"""
def __init__(self, channels):
super().__init__()
self.norm1 = ChannelNorm(channels)
self.ss2d = SS2D(channels)
self.norm2 = ChannelNorm(channels)
self.mlp = nn.Sequential(
nn.Conv2d(channels, 4 * channels, 1),
nn.GELU(),
nn.Conv2d(4 * channels, channels, 1),
)
def forward(self, x):
x = x + self.ss2d(self.norm1(x))
return x + self.mlp(self.norm2(x))7. Stack the blocks into a hierarchical image backbone
Original paper
The stem enters a quarter-resolution feature grid. Four stages progressively reduce spatial size and increase channel width, before a classification head pools the final grid.
Math and tensor shapes
The selected Tiny model uses a two-convolution stem and convolutional downsampling between stages. More channels give later positions a richer representation as the grid shrinks. The classifier pools the final normalized features; dense prediction tasks instead attach their own heads to the hierarchy. Random-weight smoke tests verify these mechanics, while released weights are required for useful predictions.
224 × 224 image; stage repeats 2, 2, 8, 2; 1000 ImageNet logits
Python implementation
class VMamba(nn.Module):
"""Four-stage teaching backbone; defaults match Tiny stage dimensions.
Initialization and state-dictionary names are teaching choices. Use the
official exporter for pretrained results, never load released weights here.
"""
def __init__(
self, depths=(2, 2, 8, 2), dims=(96, 192, 384, 768), num_classes=1000
):
super().__init__()
self.stem = nn.Sequential(
nn.Conv2d(3, dims[0] // 2, 3, stride=2, padding=1),
ChannelNorm(dims[0] // 2),
nn.GELU(),
nn.Conv2d(dims[0] // 2, dims[0], 3, stride=2, padding=1),
ChannelNorm(dims[0]),
)
self.stages = nn.ModuleList(
[
nn.Sequential(*(VSSBlock(dim) for _ in range(depth)))
for dim, depth in zip(dims, depths)
]
)
self.downsamples = nn.ModuleList(
[
nn.Sequential(
nn.Conv2d(left, right, 3, stride=2, padding=1),
ChannelNorm(right),
)
for left, right in zip(dims[:-1], dims[1:])
]
)
self.norm = ChannelNorm(dims[-1])
self.head = nn.Linear(dims[-1], num_classes)
def forward(self, image):
x = self.stem(image)
for index, stage in enumerate(self.stages):
x = stage(x)
if index < len(self.downsamples):
x = self.downsamples[index](x)
return self.head(self.norm(x).mean(dim=(2, 3)))The CPU reference exposes the scan as a loop so every state update remains inspectable and differentiable. Its teaching model uses random weights. Running it checks the mechanism; it does not reproduce pretrained ImageNet accuracy or the paper’s optimized GPU throughput. The official implementation at the pinned revision supplies the complete released model and optimized kernels.
Download the runnable Python reference and its requirements. The source behind the excerpts is the same downloadable file. Run python vmamba.py --smoke --backward to check a small random-weight model without downloading a checkpoint. To see what learned features produce, move from that mechanics check to a released model.
A real pretrained VMamba-T on three photographs
The next example executes the official VMamba-T s1l8 model with the released checkpoint's model weights. It is separate from the teaching network above. Each displayed prediction comes from a recorded CPU inference run, and the displayed crop contains exactly the pixels supplied to that run before normalization.
Select the cat, coffee, or astronaut photograph, then follow its recorded tensor shapes through the network. The astronaut's highest-ranked class is football helmet, not an astronaut label. That is the actual output of this ImageNet classifier: the example illustrates inference, including its mistakes, rather than an accuracy comparison or a semantic explanation of a feature map.
One photograph through a released VMamba-T
Measured pretrained example
These are saved outputs from the official model on CPU, using the released checkpoint’s model weights. Select a photograph to inspect the actual 224 × 224 crop and its five highest ImageNet probabilities.
Showing recorded VMamba-T predictions for Chelsea the cat.
VMamba-T (s1l8)
30,249,064 parameters · state size 1 · input 224 × 224
Softmax probability · 0–100% scale
- tiger cat45.12%
- Egyptian cat26.08%
- tabby11.30%
- lynx0.24%
- lens cap0.09%
A distribution over the 1,000 ImageNet categories. These probabilities are not calibrated certainty. Three example photographs do not estimate ImageNet accuracy.
Stage 1 · 2 VSS blocks
Input · batch, channels, then spatial axes
1 × 96 × 56 × 56
Output
1 × 96 × 56 × 56
Tensor shapes were traced during this model run. The planes show schematic geometry, not measured activations, attention, saliency, or object masks.
How these predictions were produced
The official vmamba_tiny_s1l8 factory loaded the checkpoint strictly, with no missing or unexpected tensors. Evaluation and inference mode use float32 on CPU with 2 threads and the official PyTorch scan reference.
Resize the short edge to 256 using bicubic PIL interpolation, center-crop to 224, convert RGB to float32 in [0,1], then normalize with mean [0.485, 0.456, 0.406] and standard deviation [0.229, 0.224, 0.225]. Every normalized crop matched the pinned official evaluation transform exactly.
The teaching scan also passed an independent output and gradient comparison against the pinned reference. The pretrained classifier here executes the official model directly; it is separate from the random-weight teaching program.
- Official code revision
- 2ed52ead062a51a64521ed3871d52914bf532876
- Checkpoint SHA256 · selected key: model
- d855b57224a652bc692804932f88dc3a39b9028e64be99f745a7fd6792ca672a
- Input crop SHA256
- ff9de1b8e229782de3f5f15371421046ae5d01fd55b480c708c55edf555fd34f
- Execution
- PyTorch 2.12.0 · torchvision 0.27.0 · Pillow 12.2.0 · exported 2026-10-10
Full measurements and provenance · Reproduce the export · Pinned requirements
The stored outputs establish what this checkpoint predicted on these three inputs. They do not measure speed. With both the readable recurrence and a genuine model run in view, we can now separate the amount of scan work from the time needed to execute it.
Linear work does not guarantee lower latency
Let the feature map contain L=H\times W positions. With channels and state size held fixed, four scans visit 4L positions. Doubling the number of positions doubles this scan work. Doubling both height and width gives four times as many positions, so scan work also grows fourfold.
Full dense attention considers L² query–key pairs, giving sixteen times as many pairs when both spatial dimensions double. This comparison concerns full pairwise attention. Windowed, sparse, and linear attention have different scaling; “all transformers are quadratic” would be the wrong conclusion.
Interactive mechanics
Count positions, not milliseconds
Hold channel width and state size fixed. Four scans visit 4L positions; full pairwise self-attention considers L² query–key pairs, where L = H×W.
Four complete scans
48
4 × 12 position visits
Row forward
Column forward
Row reverse
Column reverse
Full query–key pair matrix
144
12 queries × 12 keys
One row per query; one column per key.
Double the token count
Scan visits × 2
Double both pair axes
Token pairs × 4
Doubling both image height and width multiplies L by four: scan position visits grow by four, while full token pairs grow by sixteen. Linear sequence scaling is an asymptotic statement under fixed model dimensions.
The diagram counts operations implied by the sequence length. It does not measure milliseconds. Channel projections, the MLP, local convolution, four data rearrangements, and memory movement all contribute to actual execution time. The recurrent state is fixed-size per channel, but a training implementation also stores tensors or recomputes them for backward; linear scan work does not mean the entire model uses constant memory.
The Python loop executes time steps sequentially. Optimized implementations can use an associative parallel scan: affine state updates compose associatively, so they can be regrouped without changing the intended recurrence. Floating-point precision and accumulation order can still affect the numerical result. Kernel design, tensor layout, batch size, hardware, and synchronization determine whether the lower asymptotic work turns into lower latency. The paper’s acceleration sequence changes both architecture and kernels. Paper v4, §4.3 and Appendix B
That is why published accuracy and throughput belong with their experimental protocol, rather than being inferred from the arrows above.
Published results and their limits
The final paper reports the following ImageNet-1K results at 224×224, with models trained from scratch for 300 epochs. Small and Base here are the paper’s s2l15 variants; they are not the s1l20 alternatives listed elsewhere in the repository.
| Model | Parameters | FLOPs | ImageNet top-1 |
|---|---|---|---|
| VMamba-T · s1l8 | 30M | 4.9G | 82.6% |
| VMamba-S · s2l15 | 50M | 8.7G | 83.6% |
| VMamba-B · s2l15 | 89M | 15.4G | 83.9% |
Source: arXiv v4, Table 1 and Appendix E. These are published evaluations, not results from the teaching example. The paper’s throughput comparison uses an NVIDIA A100, AMD EPYC 7542 CPU, and batch size 128. Appendix E does not clearly specify the inference precision in that protocol description, so those batched measurements should not be read as an expected latency for one image in a different environment.
The same backbone also supports dense prediction. These Tiny results use separate task heads and fine-tuning protocols:
| Task and evaluation | VMamba-T result |
|---|---|
| COCO detection · Mask R-CNN · 1× schedule, 12 epochs | 47.3 box AP |
| COCO instance segmentation · same 1× model | 42.7 mask AP |
| ADE20K semantic segmentation · UperNet · single-scale test | 47.9% mIoU |
| ADE20K semantic segmentation · UperNet · multi-scale test | 48.8% mIoU |
Source: arXiv v4, Table 2 and Appendix F. A longer 36-epoch multi-scale COCO schedule is a different experiment. Classification top-1, box AP, mask AP, and mIoU measure different tasks; they cannot be combined into one accuracy score.
The central tradeoff remains visible in the small grid. Four orders supply global structural reachability, but each direction compresses its history into a small state and imposes an ordering bias. Long paths can attenuate information. Learned effective receptive fields must be measured on trained models, rather than read from a prefix highlight. The paper investigates those fields and alternative scan patterns; the mechanism alone does not guarantee that every distant pixel matters equally. Paper v4, §5.3 and Appendix H.1
VMamba’s contribution is a concrete way to give a hierarchical vision backbone input-dependent global mixing with linear scan work. The path from image to prediction is now explicit: local features enter four ordered recurrences, directional outputs return to the right pixels, residual blocks refine the map, and a task head reads the resulting hierarchy.
Related reading
- Mamba: derive the selective state update, associative scan and persistent buffers underlying the sequence operator.
- Mamba-2: connect a restricted state transition to structured attention and chunked matrix multiplication.
- Convolution operation: how the local stem and depthwise spatial mixing differ from a running state.
- Self-attention in Vision Transformers: direct token-to-token mixing and the full pairwise computation used in the scaling comparison.
- Hilbert-Guided Sparse Local Attention: another example of token order affecting the computation, this time by making local attention easier for a sparse kernel to execute.
- EfficientNet: why a backbone’s resolution, width, and depth must be considered together when comparing efficiency.
- Original VMamba paper, arXiv v4 and versioned official code: the source architecture, experiments, and implementation behind this walkthrough.
