A masked autoencoder that knows how big a pixel is. By feeding ground sample distance into the positional encoding and reconstructing a Laplacian pyramid, Scale-MAE learns satellite representations that transfer across a 3.3× range of resolutions.
You have two photographs of the same parking lot. The first comes from a drone flying at 100 metres: each pixel covers 10 centimetres of ground, and a single car fills roughly 45 pixels across. The second comes from a Sentinel-2 satellite at 786 kilometres: each pixel covers 10 metres, and that same car is now smaller than one pixel — it does not even register. Same object, same world, but the two images live in completely different visual regimes.
Now hand both images to a vision model that was pre-trained on ImageNet. ImageNet photos are taken from a hand-held camera at human scale, where "how big is a pixel?" is a meaningless question — the answer is always "whatever the photographer's distance and zoom happened to be." So the model never learned to care about absolute scale. It treats the drone car and the satellite parking lot as if they were the same kind of input, and it has no idea that one pixel in the first image and one pixel in the second represent a 100× difference in real-world size.
This is the central problem Scale-MAE attacks. In remote sensing, ground sample distance (GSD) — the real-world length that one pixel spans on the Earth's surface, measured in metres per pixel — is a first-class physical quantity. A model that ignores GSD is throwing away the single most informative piece of metadata a satellite image carries. The paper's thesis: a representation that is aware of scale will transfer far better across the wildly varying resolutions of real geospatial data.
A fixed 0.5 m wide object (a car) rendered at three ground sample distances. As GSD grows (metres per pixel), the same object shrinks to fewer pixels. Drag the slider to sweep GSD and watch a standard model lose the object entirely.
The naive fix is to resample every image to a common pixel grid. But resampling changes pixel resolution while leaving ground resolution untouched. Upsampling a 10 m/px Sentinel tile to look like a 0.3 m/px drone tile does not invent the missing detail — it just blurs. The model still has no signal telling it that the "high-resolution-looking" upsample is in fact a coarse measurement. Conversely, a model trained only on one GSD overfits to that scale's texture statistics and collapses when shown another.
Worse, a single satellite collection often spans a huge GSD range within itself: a sensor might capture 0.3 m/px panchromatic and 10 m/px multispectral bands of the very same scene. Functional Map of the World (fMoW), the benchmark Scale-MAE pre-trains on, contains imagery from roughly 0.3 m/px to over 10 m/px. Any pre-training recipe that bakes in one fixed scale is fighting the data.
The strongest geospatial self-supervised baseline at the time was SatMAE (Cong et al., 2022), which applied vanilla MAE to satellite imagery and added temporal/spectral positional encodings. SatMAE was a real advance, but it used the standard scale-blind positional encoding from the original ViT: position index → sinusoid. Two patches at the same grid index get the same encoding whether the tile is 0.3 m/px or 10 m/px. The network literally cannot tell the two regimes apart from position alone.
Scale-MAE keeps the MAE backbone but makes two surgical changes, both of which we will derive in full: (1) a GSD-based positional encoding that scales the sinusoid frequencies by the physical resolution, so position now means "where on the ground," not "where on the grid"; and (2) a Laplacian-pyramid decoder that reconstructs the image at multiple scales at once, forcing the encoder to produce features useful for both coarse structure and fine texture.
| Property | Vanilla MAE / SatMAE | Scale-MAE |
|---|---|---|
| Position encoding | Grid index → sinusoid (scale-blind) | Ground coordinate → sinusoid (GSD-scaled) |
| Decoder target | Single-scale pixel reconstruction | Laplacian pyramid (low + high frequency) |
| Knows GSD? | No | Yes — passed in as metadata each forward pass |
| Cross-scale transfer | Degrades sharply off the training GSD | Robust across a wide GSD range |
| Encoder | ViT (unchanged) | ViT (unchanged) — only the PE and decoder differ |
The beauty of the design is its minimalism: the ViT encoder is untouched. Everything new lives in how positions are encoded going in and how the reconstruction target is structured coming out. Let's build both pieces from zero, starting with a quick MAE refresher so the surgery is clear.
Scale-MAE is a masked autoencoder (He et al., 2022), so we need the MAE recipe crisp before we modify it. The idea: hide most of an image, ask a network to fill in the blanks, and the representations it learns along the way turn out to be excellent for downstream tasks.
Concretely, MAE works on a Vision Transformer. An input image of shape [H, W, 3] is split into non-overlapping patches of size p×p. For a 224×224 image with p = 16, that is (224/16)² = 14² = 196 patches, each a vector of 16·16·3 = 768 numbers. A large fraction of patches — MAE uses 75% — are masked (thrown away). Only the visible 25% (here, 49 patches) are fed to the encoder.
The asymmetry is the trick. The encoder is large and sees only 25% of patches — so it is cheap and forced to reason about global structure from sparse evidence. The decoder is small and lightweight; its only job is reconstruction during pre-training and it is discarded afterward. The loss is mean squared error on the masked patches only:
where M is the set of masked patch indices, xi is the ground-truth pixels of patch i, and x̂i is the decoder's prediction. Computing loss only on masked patches stops the model from cheating by copying visible patches through.
Take a tiny 4×4 patch grid (16 patches). With a 75% mask ratio we keep 16×0.25 = 4 patches. Suppose the random permutation keeps patches {2, 5, 11, 14}. The encoder receives a length-4 sequence. The decoder then builds a length-16 sequence: it places the 4 encoded tokens back at indices {2,5,11,14} and fills the other 12 slots with a single shared learned mask token. Positional encodings are added to all 16 so each knows where it belongs, and the decoder predicts pixels for all 16, but loss is summed only over the 12 masked indices.
Visible patches (teal) go to the encoder; masked patches (faded) are reconstructed. Click "Re-roll mask" to draw a new random 75% mask. Notice the encoder only ever sees the teal tokens.
Everything Scale-MAE changes lives in two spots of this pipeline: the positional encoding that gets added to tokens (Chapter 3) and the decoder target (Chapter 4). The encoder, the masking, the asymmetry — all untouched. So the upgrades are bolt-on, which is exactly why they are easy to adopt.
Before we can encode GSD, we must pin down what it is. Ground sample distance is the distance on the Earth's surface between the centres of two adjacent pixels, expressed in metres per pixel. If a satellite reports GSD = 0.5 m, then a 224-pixel-wide tile covers 224 × 0.5 = 112 metres of ground. A car 4.5 m long spans 4.5 / 0.5 = 9 pixels.
GSD is set by the sensor's geometry: focal length, detector pixel pitch, and altitude. From orbit it is essentially fixed per sensor; for aerial platforms it varies with altitude. The number we care about is purely "metres of world per pixel," and it is shipped as metadata alongside almost every serious geospatial image product.
Here is the equation Scale-MAE hinges on. A patch at grid index (r, c) — row r, column c — sits at ground position:
where p is the patch size in pixels. Two patches at the same grid index (r, c) but from tiles of different GSD are at different ground coordinates. That is the whole insight: a position encoding built on the grid index is scale-blind; a position encoding built on the ground coordinate is scale-aware. The conversion is a single multiply by GSD.
Take patch index c = 3, patch size p = 16. Compare two tiles:
| Quantity | Drone tile | Satellite tile |
|---|---|---|
| GSD | 0.3 m/px | 10 m/px |
| Pixel column of patch start (c·p) | 3 × 16 = 48 px | 3 × 16 = 48 px |
| Ground x (c·p·GSD) | 48 × 0.3 = 14.4 m | 48 × 10 = 480 m |
Same grid index (48 px), but 14.4 m versus 480 m of ground — a 33× difference. A scale-blind encoder assigns both the identical positional vector; a GSD-aware encoder gives them vectors as different as their physical positions warrant. The drone tile's 196 patches span 0–108 m of ground; the satellite tile's 196 patches span 0–3600 m. The positional encoding must reflect that the satellite patches are spread across 33× more world.
The same 8-patch row drawn twice. Top: pixel-index spacing (identical for both tiles). Bottom: ground spacing, where each patch is placed at c·p·GSD metres. Slide GSD to watch the ground ruler stretch while the pixel ruler stays fixed.
Now the core mechanism. Recall the standard 2D sinusoidal positional encoding used by ViT and MAE. For a 1D position u and embedding dimension d, the encoding interleaves sines and cosines at geometrically spaced frequencies:
In a 2D image, ViT builds the encoding by computing a 1D encoding for the row coordinate and a 1D encoding for the column coordinate (each using half of d), then concatenating. Crucially, in standard ViT the position u is just the integer grid index: u = c for column, u = r for row. That is the scale-blind part — the same index always yields the same encoding.
Scale-MAE replaces the grid index with the ground coordinate from Chapter 2. Instead of u = c, it uses u = c · (GSD / GSDref), where GSDref is a reference resolution that keeps the numbers in a sensible range. Equivalently, the paper scales the position fed to the sinusoid by the resolution ratio. Writing the scale factor as s = GSD / GSDref:
Read that carefully: multiplying the position by s is identical to multiplying every sinusoid's frequency by s. A coarse tile (large GSD → large s) gets higher-frequency positional sinusoids: each patch step covers more ground, so the encoding cycles faster across the grid. A fine tile (small GSD → small s) gets lower-frequency sinusoids: each step covers little ground, so the encoding changes slowly. The frequency of the position code now literally reports the resolution.
Let d = 4 (so we have frequencies for i = 0 and i = 1) and pick GSDref = 1 m/px so s = GSD. The two frequency divisors are 100000/4 = 1 and 100002/4 = 100. For column c = 3:
Fine tile, GSD = 0.3 → s = 0.3, argument base = s·c = 0.9:
dim 0: sin(0.9 / 1) = sin(0.90) = 0.783
dim 1: cos(0.9 / 1) = cos(0.90) = 0.622
dim 2: sin(0.9 / 100) = sin(0.009) = 0.009
dim 3: cos(0.9 / 100) = cos(0.009) = 1.000
Coarse tile, GSD = 10 → s = 10, argument base = s·c = 30:
dim 0: sin(30 / 1) = sin(30.0) = −0.988
dim 1: cos(30 / 1) = cos(30.0) = 0.154
dim 2: sin(30 / 100) = sin(0.30) = 0.296
dim 3: cos(30 / 100) = cos(0.30) = 0.955
Same grid index c = 3, but the two encoding vectors are completely different — the coarse tile has wrapped many times around the high-frequency sinusoid (sin(30) is far into its cycles) while the fine tile barely moved. The encoder receives an unambiguous signal of which resolution it is looking at, per patch, for free.
Rows = patch position (0–31), columns = encoding dimension. Color = PE value (warm positive, teal negative). Slide GSD: the stripes pack tighter (higher frequency) as GSD grows, because each step covers more ground. This packing IS the scale signal the encoder reads.
Sinusoidal encodings have a celebrated trait: PE(u + k) is a fixed linear function of PE(u), which lets attention reason about relative offsets. Multiplying the argument by s does not break this — it just rescales what "one step" means. PEscale(c + 1) is still a linear (rotation) function of PEscale(c), with the rotation angle now proportional to s. So the model can still learn "attend k ground-steps away," and the size of a ground-step is set by GSD. Relative-position reasoning survives; it simply becomes resolution-relative.
python # GSD-aware 1D sinusoidal positional encoding for one axis import numpy as np def gsd_pe_1d(n_pos, d, gsd, gsd_ref=1.0): """n_pos patch positions, embed dim d (even), resolution gsd.""" s = gsd / gsd_ref # scale factor pos = (np.arange(n_pos) * s)[:, None] # ground coordinate i = np.arange(d // 2)[None, :] div = np.power(10000.0, 2 * i / d) # geometric frequencies ang = pos / div # [n_pos, d/2] pe = np.zeros((n_pos, d)) pe[:, 0::2] = np.sin(ang) pe[:, 1::2] = np.cos(ang) return pe # Same grid, different resolution -> different encoding fine = gsd_pe_1d(32, 64, gsd=0.3) coarse = gsd_pe_1d(32, 64, gsd=10.0) print(np.allclose(fine, coarse)) # False -- scale-aware!
The GSD positional encoding fixes the input side. The Laplacian decoder fixes the output side. The motivation: a single-scale pixel reconstruction target lets the model get away with modelling one band of spatial frequencies. We want representations that are good at every scale — coarse layout (where is the runway?) and fine texture (what is the road surface?). So we make the model reconstruct both simultaneously.
Start with an image I0. Blur and downsample it to get I1 (half resolution), again to get I2, and so on — that chain is the Gaussian pyramid. The Laplacian pyramid stores the differences: each level Lk = Ik − upsample(Ik+1). Lk captures exactly the detail that level k has but level k+1 lost — a band of spatial frequency. The coarsest Gaussian level plus all the Laplacian bands losslessly reconstruct the original.
Intuitively: the bottom Laplacian level holds fine edges and texture (high frequency); higher levels hold progressively coarser structure (low frequency). By decomposing the reconstruction target this way, we can ask the decoder to produce a low-frequency reconstruction and a high-frequency reconstruction as separate heads, and grade each.
Scale-MAE replaces MAE's plain decoder with a multi-scale, progressive decoder. After the lightweight transformer decoder produces a feature map, it is split into two branches that build a small Laplacian pyramid of the reconstruction:
A subtle and important detail: the high-frequency branch targets a resolution higher than the masked input. Scale-MAE's decoder is super-resolving — it asks the encoder to support reconstructing detail finer than what it was given. This pushes the representation to encode information that generalizes to finer GSDs, which is precisely the cross-scale transfer we want. The low-frequency branch, conversely, targets a coarser version, anchoring global structure.
A 1D signal (top) decomposed into a coarse Gaussian level (low frequency) plus a Laplacian residual (high frequency). The two sum back to the original. Drag the cutoff to move energy between the low and high bands — the reconstruction stays exact.
Take the 8-sample signal I = [4, 6, 8, 6, 4, 2, 4, 6]. Blur it with a 3-tap moving average (reflect at edges) to get the low band G:
G[1] = (4+6+8)/3 = 6.00
G[2] = (6+8+6)/3 = 6.67
G[3] = (8+6+4)/3 = 6.00
G[4] = (6+4+2)/3 = 4.00
... (edges reflected)
The Laplacian residual is L = I − G:
L[2] = 8 − 6.67 = +1.33 (a local peak — high frequency)
L[3] = 6 − 6.00 = 0.00
L[4] = 4 − 4.00 = 0.00
where the signal is smooth, L is near zero; where it has a sharp local feature (the peak at index 2), L spikes. The decoder's high-frequency head is graded against exactly these L values, so it is forced to encode sharp local structure. The low-frequency head is graded against G. Reconstruction is G + L = I exactly.
We now have both pieces. Let's assemble the complete Scale-MAE forward pass and loss, with tensor shapes, so you could implement it.
| Stage | Operation | Shape |
|---|---|---|
| Input | Tile + scalar GSD metadata | [3, 224, 224], gsd |
| Patchify | 16×16 patches | [196, 768] |
| + GSD pos enc | add PEscale(r, c; GSD) | [196, d] |
| Mask | keep 25% | [49, d] |
| ViT encoder | self-attention × depth | [49, d] |
| Insert mask tokens | + GSD pos enc again | [196, d′] |
| Transformer decoder | light attention stack | [196, d′] |
| Reshape to map | tokens → spatial | [d′, 14, 14] |
| Low branch | deconv → coarse image | [3, Hlo, Hlo] |
| High branch | deconv → fine residual | [3, Hhi, Hhi] |
The encoder's gradient comes from grading both pyramid bands. Let GTlo be the ground-truth low-frequency (downsampled, blurred) image and GThi be the ground-truth high-frequency (Laplacian residual, at the super-resolved target size). The total loss is:
As in MAE, the reconstruction loss is taken over the masked regions. The two weights λlo and λhi balance how much the model invests in coarse structure versus fine texture; the paper finds both bands contribute, and an ablation (next chapter) shows that dropping either hurts downstream transfer. The takeaway: the loss explicitly grades the encoder on producing features useful at two distinct spatial-frequency bands, which is the mechanism behind scale-robust representations.
Suppose on a batch the low-band MSE is Llo = 0.040 and the high-band MSE is Lhi = 0.120 (the high band is typically harder, so larger). With equal weights λlo = λhi = 1.0:
L = 1.0 × 0.040 + 1.0 × 0.120 = 0.160
If instead we down-weight the noisy high band to λhi = 0.5 to stabilize early training:
L = 1.0 × 0.040 + 0.5 × 0.120 = 0.100
The gradient to the encoder is now weighted toward coarse structure early on, then you can anneal λhi up. The point of the worked numbers: the two bands enter the loss additively, each with its own knob, and the encoder receives the sum of both gradients.
Stacked bars show the contribution of the low-frequency and high-frequency reconstruction terms to the total loss as you change their weights. Slide the high-band weight λhi and watch the composition shift.
python # Scale-MAE total loss = weighted sum of two pyramid-band MSEs import torch.nn.functional as F def scale_mae_loss(recon_lo, gt_lo, recon_hi, gt_hi, mask, lam_lo=1.0, lam_hi=1.0): # grade each band only on masked regions l_lo = (F.mse_loss(recon_lo, gt_lo, reduction='none') * mask).mean() l_hi = (F.mse_loss(recon_hi, gt_hi, reduction='none') * mask).mean() return lam_lo * l_lo + lam_hi * l_hi
Scale-MAE pre-trains a ViT on Functional Map of the World (fMoW) RGB imagery, then is evaluated by freezing the encoder and probing it on downstream geospatial tasks. The headline question: do scale-aware features transfer better, especially across resolutions the model did not see at the probed scale?
The paper's signature experiment evaluates linear-probe / kNN classification accuracy as the evaluation GSD is swept away from the pre-training distribution. A scale-blind model peaks near its training scale and falls off steeply as the test imagery gets coarser or finer. Scale-MAE's accuracy curve is markedly flatter — it holds up across a roughly 3.3× range of ground sample distances, the property the whole method was designed to produce.
Reed et al. report that across a suite of remote-sensing classification datasets, Scale-MAE's frozen representations beat the strongest prior self-supervised geospatial baselines (including SatMAE and a vanilla-MAE control) on average, with the largest gains exactly where you would predict: at evaluation resolutions far from the training resolution. On in-distribution scales the gain is modest; off-distribution it is large. That asymmetry is the evidence that the improvement comes from scale awareness specifically, not from generic better features.
Qualitative shape of the result: a scale-blind model (teal) peaks at its training GSD and decays off-scale; Scale-MAE (warm) stays flatter across the GSD sweep. Slide the training GSD to see the scale-blind peak track it while Scale-MAE remains robust.
The scale-aware encoder also transfers to dense prediction. On semantic segmentation of aerial imagery, fine-tuning the Scale-MAE encoder yields competitive-to-improved mean IoU relative to scale-blind pre-training, again with the gains concentrated where train/test resolution differ. The pattern is consistent across tasks: when scale matters, encoding scale helps; when it does not, it is neutral.
| Setting | What is measured | Scale-MAE vs scale-blind baseline |
|---|---|---|
| kNN / linear probe (in-distribution GSD) | Classification accuracy at the training scale | Modest improvement |
| kNN / linear probe (off-distribution GSD) | Accuracy at coarser/finer test scales | Large improvement — the flatter curve |
| Semantic segmentation (fine-tune) | Mean IoU on aerial imagery | Competitive to improved |
| Average over RS benchmarks | Frozen-feature transfer | Beats SatMAE and vanilla-MAE controls |
A two-contribution paper invites the obvious question: does each piece matter, or is one carrying the result? Scale-MAE's ablations isolate the GSD positional encoding and the Laplacian decoder.
Swap the GSD-scaled PE back to the standard scale-blind PE, keeping everything else. The cross-scale robustness curve sags toward the baseline shape — the off-distribution accuracy drops. This confirms that the flatness of the accuracy-vs-GSD curve is attributable to the positional encoding carrying resolution information. Without it, the model is back to "this index is always this vector," and it cannot distinguish a coarse tile from a fine one.
Replace the two-band pyramid decoder with a single-scale pixel reconstruction (vanilla MAE decoder), keeping the GSD PE. Downstream transfer weakens, particularly the model's ability to produce features good at both coarse and fine tasks. The multi-scale target is what forces the encoder to allocate capacity across spatial-frequency bands; remove it and the encoder is free to specialize to one band.
The clean finding is that the best results need both. The GSD PE tells the model what resolution it is at (input side); the Laplacian decoder forces multi-scale feature quality (output side). They attack scale-robustness from two different ends, and the combination beats either alone. This is the ideal ablation outcome: each contribution is independently positive and they stack.
Schematic cross-scale transfer score for four configurations. Click a bar to highlight: baseline (neither), +GSD PE only, +Laplacian only, and the full model. Both contributions are positive and they add.
| Configuration | GSD PE | Laplacian decoder | Cross-scale transfer |
|---|---|---|---|
| Vanilla MAE control | No | No | Weakest off-distribution |
| + GSD PE only | Yes | No | Better off-distribution; flatter curve |
| + Laplacian only | No | Yes | Better multi-scale features; helps transfer |
| Scale-MAE (full) | Yes | Yes | Best — the two stack |
Suppose (schematically) the baseline cross-scale score is 0.55, adding GSD PE alone gives 0.64 (a +0.09 lift), adding Laplacian alone gives 0.61 (a +0.06 lift), and the full model reaches 0.70. If the effects were perfectly additive we would predict 0.55 + 0.09 + 0.06 = 0.70 — which matches, indicating the two contributions are near-independent and additive rather than redundant. If the full model had only reached 0.64, we would conclude they overlap; if it reached 0.75, we would conclude they synergize. The arithmetic is how you read an ablation table.
This is the payoff. The showcase lets you drive Scale-MAE's central mechanism end-to-end: pick a GSD, watch the ground coordinates of the patches stretch, watch the GSD-scaled positional encoding's frequency change, and watch a toy reconstruction split into its low- and high-frequency Laplacian bands. Everything you derived in Chapters 3–5 is wired together here.
Use the controls to sweep the resolution and the band weighting. Toggle between the scale-blind encoding (standard ViT/MAE) and the GSD-aware encoding to see, side by side, why the same grid index produces different position codes once GSD enters — and how the reconstruction target decomposes into bands the decoder grades separately.
GSD sets the ground spacing and the positional-encoding frequency; the band-weight slider shifts the reconstruction emphasis between coarse and fine. Toggle GSD-aware encoding on/off to compare against scale-blind. Three panels: ground ruler, positional-encoding row, and the Laplacian band split.
Notice three things as you experiment. First, when GSD-aware is off, sliding GSD does nothing to the positional-encoding panel — that is the scale-blind failure mode the paper fixes. Turn it on and the encoding's stripe frequency now tracks GSD. Second, the ground ruler always stretches with GSD regardless of the toggle, because physics does not care what the encoder knows — only the encoder's awareness of it changes. Third, the band-emphasis slider redistributes energy between the coarse and fine reconstruction targets without changing their sum, exactly as the Laplacian decomposition guarantees.
Scale-MAE is elegant and effective, but it is not the end of the story. Knowing where it stops is part of understanding it.
Scale-MAE is a focused modification of three ideas you can study deeper on this site:
Related directions worth chasing: rotary positional encoding (RoPE), which injects relative position into the attention dot-product and is a cousin of the "scale the position" idea; SatMAE, the temporal/spectral MAE baseline Scale-MAE compares against; and the broader multi-scale feature literature (feature pyramid networks, Laplacian pyramids in classical vision) that the decoder draws on. On this site, the Transformer veanor and the ViT gleam are the natural prerequisites; the diffusion lessons share the Laplacian/multi-scale theme from a different angle.
| Concept | One-line summary |
|---|---|
| Problem | Satellite imagery spans a huge GSD range; scale-blind models do not transfer across resolutions. |
| GSD | Ground sample distance = metres of Earth per pixel; smaller is sharper. |
| Ground coord | ground = index × patch × GSD — the physical position of a patch. |
| GSD pos enc | Feed ground coord (not index) into the sinusoid ≡ scale the PE frequencies by GSD. |
| Effect | Coarse tiles get higher-frequency position codes; the encoder reads resolution per patch. |
| Laplacian decoder | Reconstruct a low band + high (super-resolved) residual; grade each separately. |
| Loss | L = λlo·MSElo + λhi·MSEhi on masked regions. |
| Encoder | Plain ViT, unchanged — only the PE in and the target out differ. |
| Result | Flatter accuracy-vs-GSD curve; biggest gains off the training resolution. |
| Ablation | GSD PE and Laplacian decoder are independently positive and stack. |