Paper · 2021-08-25 · cs.CV
Transformer for Single Image Super-Resolution
ESRT is a lightweight super-resolution network: a CNN backbone that processes features at half resolution while keeping a high-frequency residual, then one efficient Transformer whose attention runs over unfolded 3×3 patches split into 4 segments. Author-reported: ~0.75M params, best or near-best PSNR among lightweight ×3/×4 models, 4,191M vs 16,057M training memory for a plain Transformer.
Image super-resolutionVision Transformer (ViT) backbonesSelf-attentionsuper-resolutionimage-restorationefficient-attentionlightweight-model
arXivPDFCodeMarkdown15 min read
AI-compiled by claude-opus-5-5 on 2026-10-18, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Super-resolution means taking a small, blurry image and producing a larger, sharper one. The network has to guess fine detail that is not in the input. A useful trick is that images repeat themselves: bricks in a wall, windows on a building or letters in a comic look alike, so a clear copy of a pattern in one place can help reconstruct a blurred copy elsewhere. Transformers, with their attention mechanism, are good at finding such look-alikes, but on full images they need far too much GPU memory.
ESRT splits the work in two. A small convolutional network first does most of the work cheaply: it shrinks the feature maps to half size to save compute, but before shrinking it subtracts a blurred copy from the original and keeps the leftover "edges and texture" signal, which it adds back after upsampling. Then a single, slimmed-down Transformer lets every position look at similar positions, but only within one quarter of the image at a time and with half the usual feature width. That keeps memory to about a quarter of a standard Transformer layer.
The result is a model with well under a million parameters that matches or beats other small super-resolution networks on standard test sets, with the biggest gains on Urban100, a dataset full of repeating building facades.
TL;DR
ESRT is a hybrid CNN + Transformer for lightweight single-image super-resolution (SISR) §3. The CNN part (LCB) stacks 3 High Preserving Blocks that process features at half resolution and carry a high-frequency residual (feature minus its blurred, upsampled copy) around the downsampling §3.1 §3.2. The Transformer part (LTB) is one Efficient Transformer whose tokens are unfolded 3×3 neighbourhoods (one per pixel); attention halves the channel width and splits the token sequence into s=4 segments that attend only within themselves §3.3. Author-reported ×4: 751K parameters, Set5 32.19 dB, Urban100 26.39 dB; training memory 4,191M vs 16,057M with an original Transformer tab. 1 tab. 4. The paper has several internal inconsistencies (parameter counts, a probably mislabeled SwinIR table, no ×2 numbers), and the code adds a channel-attention layer inside every ARFB and uses 3×3 instead of 1×1 convs in the residual units.
Problem
CNN-based SISR models reach good quality with many layers but are expensive; lightweight CNNs cut cost at the price of capacity, and pure CNNs only see local context §1 §2.1. Image patches often recur within an image and could serve as references for each other, which suggests self-attention §1 fig. 1. But vision Transformers (ViT, Swin, IPT, SwinIR) need large GPU memory and, in the authors' view, lots of training data; SR inputs are large images, so the token count N is large and the N×N attention matrix is the bottleneck §1 §2.2 §3.3.2. Assumption: a predicted SR pixel depends mostly on a local neighbourhood of the LR image, so attention can be restricted to a local segment §1 §3.3.2.
Method
Four stages: shallow 3×3 conv, Lightweight CNN Backbone (LCB, a chain of HPBs), Lightweight Transformer Backbone (LTB, ETs over the concatenated HPB outputs), reconstruction with two PixelShuffle branches §3 fig. 2.
Paper equations eq. 1–4:
F_0 = f_s(I_{LR}) eq. 1
F_n = \zeta^{n}(\zeta^{n-1}(\dots(\zeta^{1}(F_0)))) eq. 2
F_d = \phi^{n}(\phi^{n-1}(\dots(\phi^{1}([F_1, F_2, \dots, F_n])))) eq. 3
I_{SR} = f(f_p(f(F_d))) + f(f_p(F_0)) eq. 4
with \zeta^n the n-th HPB, \phi an ET, [\cdot] concatenation, f a conv and f_p PixelShuffle.
-
High Preserving Block (HPB) §3.1 fig. 3 eq. 5. An ARFB processes F_{n-1}; HFM extracts its high-frequency part P_{high}; the ARFB output is downsampled (×1/2) and passed 5 times through one weight-shared ARFB; P_{high} goes through its own ARFB; the low branch is bilinearly upsampled and concatenated with the high branch; then a 1×1 conv halves channels, channel attention (SE-style) reweights channels, a final ARFB runs, and F_{n-1} is added back (global residual) §3.1.
F_{n-1}^{''} = [f_{a}(P_{high}),\ \uparrow f_{a}^{\circlearrowright^5}(\downarrow F_{n-1}^{'})] eq. 5
-
High-frequency Filtering Module (HFM) §3.2 fig. 4 eq. 6. T_A = \mathrm{avgpool}(T_L, k) with k=2, upsample T_A back to C\times H\times W to get T_U, and output T_L - T_U §3.2 §4.2. The paper presents it as a differentiable stand-in for a Fourier high-pass filter; it has no learnable weights.
-
Adaptive Residual Feature Block (ARFB) §3.2.1 fig. 6 eq. 7. Two residual units (RUs) in sequence, then concat of both RU outputs → 1×1 conv → 3×3 conv. Each RU is a channel Reduction (to C/2) and Expansion (back to C) with learnable scalars on both paths:
y_{ru} = \lambda_{res}\cdot f_{ex}(f_{re}(x_{ru})) + \lambda_{x}\cdot x eq. 7
Both λ initialised to 1 §4.2. (The paper writes x for x_{ru} on the right-hand side.)
-
Pre/post-processing for ET §3.3.1 fig. 7. Unfold the C\times H\times W map with a k×k kernel (k=3) into N = H·W tokens of size k^2 C; no position embedding; after the ET, Fold back to C\times H\times W §3.3.1 §4.2.
-
Efficient Transformer (ET) §3.3.2 fig. 8 eq. 8. Pre-norm encoder block:
E_{m1} = \mathrm{EMHA}(\mathrm{Norm}(E_i)) + E_i,\quad E_o = \mathrm{MLP}(\mathrm{Norm}(E_{m1})) + E_{m1} eq. 8
-
Efficient Multi-Head Attention (EMHA) §3.3.2 fig. 8. Reduction linear layer C → C/2; one linear layer to Q, K, V; reshape to B\times m\times N\times \frac{C_1}{m} with m=8 heads; Feature Split cuts Q, K, V along the token axis into s=4 equal segments; scaled dot-product attention (no mask) within each segment, so the attention matrix is \frac{N}{s}\times\frac{N}{s}; concat segment outputs; Expansion linear layer back to C §3.3.2 §4.2.
Forward pass as implemented in the official code (which differs from the paper in places; see Paper vs code):
# ESRT forward [§3] [eq. 1-4] [code: model/esrt.py#L204-L221]
# Input: lr_image (B, 3, h, w) in [0, 1]; scale in {2, 3, 4}
# Output: sr_image (B, 3, scale*h, scale*w)
def esrt(lr_image):
# shallow 3x3 conv, 3 -> 32 channels [eq. 1] [code: model/esrt.py#L181]
shallow = conv3x3(lr_image, out=32)
# LCB + LTB with outer learnable-scaled residual [code: model/esrt.py#L149-L161]
body = backbone(shallow)
# extra 3x3 conv (n_blocks=1, so 32 -> 32) [code: model/esrt.py#L201]
body = conv3x3(body, out=32)
# deep branch: conv + PixelShuffle, then conv to RGB [eq. 4]
# [code: model/esrt.py#L190-L193] [code: model/common.py#L87-L114]
deep = conv3x3(pixel_shuffle_upsampler(body, scale), out=3)
# shallow branch: same upsampler, then conv WITHOUT bias, followed by ReLU
# [code: model/esrt.py#L196-L197] [code: model/esrt.py#L61-L87]
skip = relu(conv3x3_nobias(pixel_shuffle_upsampler(shallow, scale), out=3))
return deep + skip
# Lightweight CNN + Transformer backbone [§3.1] [§3.3]
# [code: model/esrt.py#L137-L161]
def backbone(features): # (B, 32, h, w)
out1 = hpb_1(features)
out2 = hpb_2(out1)
out3 = hpb_3(out2)
# concat HPB outputs, 3x3 conv 96 -> 32 (conv not in the paper)
fused = conv3x3(concat([out1, out2, out3]), out=32)
# one ET over unfolded 3x3 patches [§3.3.1] [code: util/transformer.py#L150-L165]
tokens = unfold(fused, kernel=3, stride=1, zero_pad="same") # (B, 288, h*w)
tokens = efficient_transformer(transpose(tokens)) # (B, h*w, 288)
# Fold sums the 9 overlapping contributions per pixel (no averaging)
# [code: util/tools.py#L59-L76]
folded = fold(transpose(tokens), out_size=(h, w), kernel=3, padding=1)
folded = conv3x3(folded, out=32)
return scale_a * features + scale_b * folded # learnable scalars, init 1
# High Preserving Block [§3.1] [eq. 5] [code: model/esrt.py#L112-L135]
def hpb(x): # (B, 32, h, w)
x1 = arfb_in(x)
# HFM with k=2 [§3.2] [eq. 6]
low = avg_pool(x1, kernel=2) # (B, 32, h/2, w/2)
high = x1 - bilinear_resize(low, (h, w), align_corners=True)
# five passes through ONE shared ARFB at half resolution [eq. 5]
for repeat in range(5):
low = arfb_low(low)
high = arfb_high(high)
up = bilinear_resize(low, (h, w), align_corners=True)
# 1x1 fusion conv 64 -> 32 (with ReLU in code), then channel attention
fused = channel_attention(relu(conv1x1_nobias(concat([up, high]))))
return arfb_out(fused) + x
# Adaptive Residual Feature Block [§3.2.1] [eq. 7]
# [code: model/esrt.py#L89-L110]
def arfb(x):
r1 = residual_unit(x)
r2 = residual_unit_2(r1)
# concat of both RUs (each with a learnable scalar), 1x1 conv 64 -> 32
merged = relu(conv1x1_nobias(concat([w_a * r2, w_b * r1])))
# code inserts channel attention here; not in the paper
merged = channel_attention(merged)
merged = relu(conv3x3_nobias(merged))
return w_c * x + w_d * merged
# Residual unit with adaptive weights (RSA) [eq. 7]
# [code: model/esrt.py#L43-L59]
def residual_unit(x): # (B, 32, h, w)
# code uses 3x3 convs, paper says 1x1
reduced = prelu(conv3x3(x, out=16))
expanded = conv3x3(reduced, out=32)
return lambda_x * x + lambda_res * expanded
# Efficient Transformer, pre-norm [§3.3.2] [eq. 8]
# [code: util/transformer.py#L138-L165]
def efficient_transformer(tokens): # (B, N, 288)
tokens = tokens + emha(layer_norm_1(tokens))
tokens = tokens + mlp(layer_norm_2(tokens))
return tokens
# MLP: 288 -> 72 -> 288, ReLU, no dropout [code: util/transformer.py#L60-L76]
def mlp(tokens):
return linear_2(relu(linear_1(tokens)))
# Efficient multi-head attention [§3.3.2] [code: util/transformer.py#L81-L132]
def emha(tokens): # (B, N, 288)
# Reduction: 288 -> 144, no bias
reduced = linear_reduce(tokens)
# Q, K, V from one linear layer, no bias; 8 heads of 18 dims
queries, keys, values = split_heads(linear_qkv(reduced), heads=8)
# Feature Split: contiguous chunks of N // 4 tokens in raster order
segment = N // 4
outputs = []
for q_seg, k_seg, v_seg in zip(
chunk(queries, segment), chunk(keys, segment),
chunk(values, segment)):
# scale uses 288 / 8 = 36, i.e. 1/6, not 1/sqrt(18)
weights = softmax(q_seg @ transpose(k_seg) * 36 ** -0.5)
outputs.append(weights @ v_seg)
merged = merge_heads(concat(outputs, axis=tokens)) # (B, N, 144)
# Expansion: 144 -> 288, with bias
return linear_expand(merged)Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| training data | DIV2K | §4.1 | code reads 800 images, repeated 10× per epoch train.py DIV2K.py |
| LR patch size | 48×48 | §4.2 | code takes HR patch size; README uses 96/144/192 for ×2/×3/×4 README.md |
| batch size | 16 | §4.2 | train.py |
| augmentation | random horizontal flip, 90° rotation | §4.2 | code also flips vertically common.py |
| optimizer | Adam, "momentum" 0.9 | §4.2 | code: optim.Adam with default betas, no weight decay train.py |
| initial learning rate | 2e-4 | §4.2 | train.py |
| LR schedule | halve every 200 epochs | §4.2 | step decay utils.py |
| total epochs | not stated | code default 1000 train.py | |
| loss | L1 | §4.2 | train.py |
| hardware / time | 1× GTX 1080Ti, about two days | §4.2 | |
| conv kernel size | 3×3, except Reduction (1×1) | §4.2 | code RUs use 3×3 (see Paper vs code) |
| channels | 32; fusion layer 64 | §4.2 | esrt.py |
| number of HPBs | 3 | §4.2 | esrt.py |
| ARFB repeats at low resolution | 5 (shared weights) | §3.1 eq. 5 | esrt.py |
| HFM pooling kernel k | 2 | §4.2 | text calls it "HFP" |
| RSA weight initial value | 1 | §4.2 | Scale(1) esrt.py |
| number of ETs | 1 | §4.2 | esrt.py |
| unfold kernel k (ET) | 3 | §4.2 | stride 1, zero "same" padding transformer.py |
| token dim | not stated | 288 = 32·3² in code esrt.py | |
| heads m | 8 | §4.2 | transformer.py |
| splitting factor s | 4 | §4.2 | hard-coded as N//4 transformer.py |
| MLP hidden size / activation | not stated | 72 (dim/4) with ReLU in code transformer.py | |
| dropout / drop path | not stated | 0 in code transformer.py | |
| channel attention reduction | not stated | 16 (32 → 2 channels) esrt.py | |
| HPB downsampling | not stated beyond "downsample" | AvgPool2d(2) of the ARFB output esrt.py | |
| upsampling in HPB/HFM | bilinear | §3.1 | align_corners=True esrt.py esrt.py |
| evaluation | PSNR / SSIM | §4.1 | code: Y channel, border of scale pixels shaved train.py |
Results
Author-reported. Trained on DIV2K only, bicubic degradation (implied by the code's
DIV2K_train_LR_bicubic path DIV2K.py); evaluated on Set5, Set14, BSD100, Urban100 and Manga109 §4.1.
Main comparison, PSNR / SSIM tab. 1:
| Method | Scale | Params | Set5 | Set14 | BSD100 | Urban100 | Manga109 |
|---|---|---|---|---|---|---|---|
| VDSR | ×3 | 666K | 33.66 / 0.9213 | 29.77 / 0.8314 | 28.82 / 0.7976 | 27.14 / 0.8279 | 32.01 / 0.9340 |
| MemNet | ×3 | 678K | 34.09 / 0.9248 | 30.00 / 0.8350 | 28.96 / 0.8001 | 27.56 / 0.8376 | 32.51 / 0.9369 |
| EDSR-baseline | ×3 | 1,555K | 34.37 / 0.9270 | 30.28 / 0.8417 | 29.09 / 0.8052 | 28.15 / 0.8527 | 33.45 / 0.9439 |
| SRMDNF | ×3 | 1,528K | 34.12 / 0.9254 | 30.04 / 0.8382 | 28.97 / 0.8025 | 27.57 / 0.8398 | 33.00 / 0.9403 |
| CARN | ×3 | 1,592K | 34.29 / 0.9255 | 30.29 / 0.8407 | 29.06 / 0.8034 | 28.06 / 0.8493 | 33.50 / 0.9440 |
| IMDN | ×3 | 703K | 34.36 / 0.9270 | 30.32 / 0.8417 | 29.09 / 0.8046 | 28.17 / 0.8519 | 33.61 / 0.9445 |
| RFDN-L | ×3 | 633K | 34.47 / 0.9280 | 30.35 / 0.8421 | 29.11 / 0.8053 | 28.32 / 0.8547 | 33.78 / 0.9458 |
| MAFFSRN | ×3 | 807K | 34.45 / 0.9277 | 30.40 / 0.8432 | 29.13 / 0.8061 | 28.26 / 0.8552 | - / - |
| LatticeNet | ×3 | 765K | 34.53 / 0.9281 | 30.39 / 0.8424 | 29.15 / 0.8059 | 28.33 / 0.8538 | - / - |
| ESRT | ×3 | 770K | 34.42 / 0.9268 | 30.43 / 0.8433 | 29.15 / 0.8063 | 28.46 / 0.8574 | 33.95 / 0.9455 |
| VDSR | ×4 | 666K | 31.35 / 0.8838 | 28.01 / 0.7674 | 27.29 / 0.7251 | 25.18 / 0.7524 | 28.83 / 0.8870 |
| MemNet | ×4 | 678K | 31.74 / 0.8893 | 28.26 / 0.7723 | 27.40 / 0.7281 | 25.50 / 0.7630 | 29.42 / 0.8942 |
| EDSR-baseline | ×4 | 1,518K | 32.09 / 0.8938 | 28.58 / 0.7813 | 27.57 / 0.7357 | 26.04 / 0.7849 | 30.35 / 0.9067 |
| SRMDNF | ×4 | 1,552K | 31.96 / 0.8925 | 28.35 / 0.7787 | 27.49 / 0.7337 | 25.68 / 0.7731 | 30.09 / 0.9024 |
| CARN | ×4 | 1,592K | 32.13 / 0.8937 | 28.60 / 0.7806 | 27.58 / 0.7349 | 26.07 / 0.7837 | 30.47 / 0.9084 |
| IMDN | ×4 | 715K | 32.21 / 0.8948 | 28.58 / 0.7811 | 27.56 / 0.7353 | 26.04 / 0.7838 | 30.45 / 0.9075 |
| RFDN-L | ×4 | 643K | 32.28 / 0.8957 | 28.61 / 0.7818 | 27.58 / 0.7363 | 26.20 / 0.7883 | 30.61 / 0.9096 |
| MAFFSRN | ×4 | 830K | 32.20 / 0.8953 | 26.62 / 0.7822 | 27.59 / 0.7370 | 26.16 / 0.7887 | - / - |
| LatticeNet | ×4 | 777K | 32.30 / 0.8962 | 28.68 / 0.7830 | 27.62 / 0.7367 | 26.25 / 0.7873 | - / - |
| ESRT | ×4 | 751K | 32.19 / 0.8947 | 28.69 / 0.7833 | 27.69 / 0.7379 | 26.39 / 0.7962 | 30.75 / 0.9100 |
Cost comparison, input 1280×720 tab. 2:
| Method | Layers | RL | Param. | FLOPs (×4) | Running time |
|---|---|---|---|---|---|
| VDSR | 20 | Yes | 0.67M | 612.6G | 0.00597s |
| LapSRN | 27 | Yes | 0.25M | 149.4G | 0.00330s |
| DRRN | 52 | No | 0.30M | 6796.9G | 0.08387s |
| CARN | 34 | Yes | 1.6M | 90.9G | 0.00278s |
| IMDN | 34 | Yes | 0.7M | 40.9G | 0.00258s |
| ESRT | 163 | Yes | 0.68M | 67.7G | 0.01085s |
HPB ablation on Set5 ×4 tab. 3 (RB = plain residual block in place of ARFB):
| Case | HFM | CA | ARFB | RB | Params | PSNR |
|---|---|---|---|---|---|---|
| 1 | ✓ | ✓ | 658K | 32.02 dB | ||
| 2 | ✓ | ✓ | ✓ | 751K | 32.19 dB | |
| 3 | ✓ | ✓ | 724K | 32.08 dB | ||
| 4 | ✓ | ✓ | ✓ | 972K | 32.20 dB |
ET ablation on Set5 ×4; GPU memory measured during training at 48×48 patches, batch 16 tab. 4:
| Case | PSNR (dB) | Params (K) | GPU memory |
|---|---|---|---|
| w/o Transformer | 31.96 | 554 | 1931M |
| Original Transformer | 32.14 | 971 | 16057M |
| 1 ET | 32.18 | 751 | 4191M |
| 2 ET | 32.25 | 949 | 6499M |
ET added to a half-depth RCAN (5 residual groups), ET placed before reconstruction §4.5.2 tab. 5:
| Scale | Model | Params | Set5 | Set14 | Urban100 |
|---|---|---|---|---|---|
| ×3 | RCAN | 16M | 34.74 dB | 30.65 dB | 29.09 dB |
| ×3 | RCAN/2+ET | 8.7M | 34.69 dB | 30.63 dB | 29.16 dB |
| ×4 | RCAN | 16M | 32.63 dB | 28.87 dB | 26.82 dB |
| ×4 | RCAN/2+ET | 8.7M | 32.60 dB | 28.90 dB | 26.87 dB |
RealSR tab. 6:
| Scale | IMDN PSNR / SSIM | LK-KPN PSNR / SSIM | ESRT PSNR / SSIM |
|---|---|---|---|
| ×3 | 30.29 / 0.857 | 30.60 / 0.863 | 30.38 / 0.857 |
| ×4 | 28.68 / 0.815 | 28.65 / 0.820 | 28.78 / 0.815 |
Versus SwinIR, caption says ×4 tab. 7; SwinIR was trained with extra Flickr2K data, ESRT was not §4.7:
| Method | Params | GPU memory | BSD100 | Manga109 |
|---|---|---|---|---|
| SwinIR | 886K | 6966M | 29.20 / 0.8082 | 33.98 / 0.9478 |
| ESRT | 770K | 4191M | 29.15 / 0.8063 | 33.95 / 0.9455 |
Headline: at ×4, ESRT has the best Set14, BSD100, Urban100 and Manga109 scores among the listed lightweight models, with the largest margin on Urban100 (26.39 vs 26.25 dB for LatticeNet), which the authors attribute to repeated patches in that dataset tab. 1 §4.3. It is behind LatticeNet and RFDN-L on Set5 tab. 1. It is about 4× slower than CARN/IMDN at inference tab. 2.
Paper vs code
Checked against model/esrt.py, util/transformer.py, util/tools.py and train.py at the
recorded commit.
- RU kernel size. Paper: Reduction/Expansion are 1×1 convs §3.2.1 §4.2. Code: both are 3×3 convs with a PReLU between them esrt.py. This changes parameter count and receptive field substantially.
- Extra channel attention inside every ARFB. Paper's ARFB is two RUs → concat → 1×1 → 3×3
§3.2.1 fig. 6. Code inserts a CA layer after the 1×1 conv, adds ReLU after the 1×1 and 3×3
convs (
BasicConvdefaults to ReLU, no bias), puts learnable scalars on both RU outputs before the concat, and adds an outer learnable-weighted residual around the whole ARFB esrt.py esrt.py. - HPB fusion conv is followed by ReLU in code (
BasicConv) esrt.py; the paper does not mention an activation §3.1. - Extra convs in the backbone. Code applies a 3×3 conv to the concatenated HPB outputs before the ET (96 → 32 channels), a 3×3 conv after Fold, wraps LCB+LTB in a residual with learnable scalars, and applies another 3×3 conv before reconstruction esrt.py esrt.py esrt.py. Eq. 3 shows the concat going straight into the ET eq. 3.
- Reconstruction. Eq. 4 puts a conv before PixelShuffle only on the deep branch; in code both
branches are
Upsampler(conv to 4C or 9C channels, PixelShuffle) followed by a 3×3 conv to RGB; the shallow branch's final conv has no bias and is followed by ReLU esrt.py common.py. No mean shift is applied (commented out) esrt.py. - Attention scale. Code computes the scale from the un-reduced dim: (288/8)^-0.5 = 1/6, although heads have 144/8 = 18 dims transformer.py. The paper does not state the scale.
- Feature Split is
torch.split(q, N//4)on the raster-ordered token axis transformer.py: segments are horizontal bands of the feature map, and if N is not divisible by 4 a fifth, smaller segment appears. The paper says "s equal segments" §3.3.2. - MLP is a bottleneck (288 → 72 → 288, ReLU) although
mlp_ratio=4.is passed and ignored transformer.py transformer.py; the paper gives no MLP size. - Augmentation includes vertical flips in code common.py; the paper lists horizontal flips and 90° rotation §4.2.
- Inference splits the LR input into 4 overlapping quadrants (10-pixel overlap), recursively,
until each piece is under 60,000 pixels test.py test.py; not
mentioned in the paper.
forward_chopintest.pyhard-codesscale = 4test.py, so ×2 and ×3 evaluation with that script needs a fix.
Pitfalls
- Inconsistent parameter counts. ESRT is 770K (×3) and 751K (×4) in tab. 1, 0.68M in tab. 2, 751K in tab. 3 and tab. 4, and 770K in the "×4" SwinIR table tab. 7. Do not use any single number as a target without counting the code's model.
- The SwinIR table is probably ×3, not ×4. ESRT's BSD100 and Manga109 values in tab. 7 (29.15 / 0.8063, 33.95 / 0.9455) and its 770K parameters are exactly the ×3 row of tab. 1, while the caption says ×4. The 4,191M memory figure comes from the ×4 ablation tab. 4.
- No ×2 numbers. The text discusses ×2 visual results and a ×2 trade-off plot §4.3 fig. 10, and the code trains ×2 by default train.py, but tab. 1 only has ×3 and ×4 rows.
- Small cross-table mismatches. Set5 ×4 is 32.19 dB in tab. 1 and tab. 3 but 32.18 dB for "1 ET" in tab. 4. MAFFSRN ×4 Set14 is printed as 26.62 in tab. 1, far below every other ×4 model; likely a transcription error, but that is our inference.
- "Original Transformer" baseline is underspecified. tab. 4 cites a plain Transformer (16,057M memory) but the paper does not say how its tokens, width or depth were configured, so the 4× memory saving is hard to reproduce exactly.
- Attention range depends on input size. Because the split is by contiguous quarters of the token sequence, each token attends to a band of about H/4 rows of the current input. During training (48×48 LR) that is 12 rows; at test time with chopping it is a quarter of each chopped piece. With N not divisible by 4 a fifth, smaller segment appears. Results may change if you remove chopping or use a different tile size.
- Fold sums, it does not average. The 3×3 Fold adds up to 9 overlapping contributions per pixel (fewer at borders) tools.py. A reimplementation that averages will change scale at borders vs interior, and pretrained weights will not match.
- Memory is still O((N/4)²). Splitting into 4 segments only cuts the attention matrix 16×; for a full 1280×720 LR input (921,600 tokens) one segment's attention matrix would be about 5.3×10¹⁰ entries per head, which is why inference must be tiled. The paper's "low memory" figure is measured on 48×48 training patches tab. 4.
- Runtime is not low. ESRT has 163 layers and is about 4× slower than IMDN/CARN on a 1280×720 input despite comparable FLOPs tab. 2; the five shared-weight ARFB passes per HPB add depth without adding parameters.
- "Momentum 0.9" for Adam §4.2 maps to β1 = 0.9; β2 is not stated (code uses the PyTorch default) train.py.
- HFM upsampling method is not stated in the paper (only "upsampled") §3.2; code uses bilinear
with
align_corners=Trueesrt.py. - Code repository hygiene.
train.pyimportsmodel.architecture, which is not in the repository's file list, andesrt.pyimportsthopat module level train.py esrt.py; expect to patch imports before training.
Lineage
- Builds on: ViT (arXiv:2010.11929) for the encoder-only pre-norm block and patch tokens, replacing non-overlapping patches with overlapping unfolded 3×3 neighbourhoods §3.3.1 §3.3.2; IMDN (arXiv:1909.11856), whose png-to-npy data preparation the README follows; SE channel attention (arXiv:1709.01507) inside HPB §3.1.
- Compared against: VDSR, MemNet, EDSR-baseline, SRMDNF, CARN, IMDN, RFDN-L, MAFFSRN, LatticeNet tab. 1; RCAN tab. 5; LK-KPN on RealSR tab. 6; SwinIR (arXiv:2108.10257) tab. 7.
- Superseded by: not known from content in this wiki.
Source and license
Adapted from “Transformer for Single Image Super-Resolution” by Zhisheng Lu, Juncheng Li, Hong Liu, Chaoyan Huang, Linlin Zhang, Tieyong Zeng (arXiv:2108.11084), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/luissen/ESRT at commit 14b5aa159c14 (MIT). Any quoted code is shown under that license.