← All tutorials

On this page

1 Convolution plus self-attention 2 Inside the block 3 Reported results 4 Branchformer and Squeezeformer 5 References

The Conformer Block

Convolution plus attention for speech recognition, and the variants that rewired it

Waveform, 16 kHz80 filterbank bands, 10 msSubsample 4×, 40 ms framesConformer block × N½ feed-forwardSelf-attentionConvolution½ feed-forwardLayerNormOutput head, CTC lossbuilt in Conformer in PyTorch111.12
Figure 1. From waveform to text; the green numbers are this page's sections.

Speech enters as filterbank frames, is shortened in time, then passes through a stack of identical blocks that mix attention and convolution; a head turns each frame into text scores.

1 Convolution plus self-attention

An ASR (automatic speech recognition) model has to capture both a short sound and the whole sentence. A phoneme, one distinct sound of a language, lasts from under 18 ms to over 150 ms on average in the TIMIT corpus, a standard set of read American English with hand-marked phoneme boundaries (Toledano et al. 2018). Transformers catch global context but blur local detail like phoneme edges and formants (the resonant bands that give each vowel its identity); CNNs do the reverse. The Conformer (Gulati et al., 2020), a "convolution-augmented transformer," takes both.

The Conformer is an encoder architecture, not a training method. The speech recognition loss on its output (CTC, written out in Conformer in PyTorch: Training and Streaming; the paper uses a transducer decoder, a one-layer LSTM that predicts each token from the audio and the tokens already output, see Beyond CTC) trains all of its weights together, batch by batch. At inference the same forward pass runs once per utterance, or chunk by chunk when streaming (Conformer in PyTorch: Training and Streaming).

Unlike text tokens, speech is a continuous waveform, typically sampled at 16 kHz, so the first job is turning it into features (Figure 2): usually 80-dim filterbank frames, the energies in 80 frequency bands on the mel scale (a pitch scale spaced by how pitch is perceived), each over a 25 ms window, a new frame every 10 ms (the features are built step by step in MFCC and Other Audio Features). A projection to the model dimension then does the job an embedding layer does for text. The whole recording the model takes in at once is one utterance. The listing below makes these frames; watch the printed shape.

import torch, torchaudio as ta
K = ta.compliance.kaldi
wav = torch.randn(1, 16000)
fb = K.fbank(wav, num_mel_bins=80)
print(fb.shape)  # (98, 80)
  1. 1One second of 16 kHz audio, random here in place of speech.
  2. 298 frames of 80 bands, because the last 25 ms window must end inside the second; about 100 a second.
1 second of audio, 16 kHz waveformone frame100 × 80100 frames,80 bands eachfilterbankframesproject each frame up100 × 256: each row is one frame's token
Figure 2. One slice of sound becomes one row of 80 filterbank energies.

1.1 Strided subsampling

Before the blocks, the encoder (the part that reads the frames and turns them into learned representations) shrinks time with a convolution subsampling layer.

Strided subsampling folds each group of s neighboring frames, the stride, into one wider output frame, so T frames become T/s. A common implementation (ESPnet's Conv2dSubsampling) stacks two 3 by 3 stride-2 convolutions, 4× in total, so each frame then covers 40 ms. This listing is the one-layer version: a Conv1d whose kernel and stride are both s turns 98 frames into 49.

import torch, torch.nn as nn
fb = torch.randn(98, 80)
s = 2  # kernel and stride
sub = nn.Conv1d(80, 256, s, s)
# Conv1d wants (B, channels, T)
x = fb.T.unsqueeze(0)
# (1, 256, 49) to (1, 49, 256)
y = sub(x).transpose(1, 2)
  1. 180 filterbank bands per frame, and a stride-2 convolution to the model width 256.
  2. 2Conv1d needs channels first; the output has half as many frames.

Why shrink time? Attention scores every frame against every other, so its cost grows with T2 at 100 frames a second, and merging neighbors cuts it by the merge factor squared.

Strided subsampling shrinks time before the blocks, and attention cost shrinks with the square of the length.
output length = Ts
Each group of s frames becomes one output frame. T is the number of input frames, 100 per second of speech.
attention cost ∝ (Ts)2
∝ reads proportional to. Attention scores every frame against every other, so its cost follows the square: stride 2 makes it one quarter and stride 4 one sixteenth.
Stride

40 frames in

20 frames out

Figure 3. Folding cuts attention cost; a sound shorter than a fold can vanish.


2 Inside the block

A Conformer block keeps the Transformer's attention, adds a convolution module after it, and splits the feed-forward into two halves around both.

Figure 1 of the Conformer paper: the Conformer encoder block diagram, read bottom to top

Figure 4. From the paper's Figure 1: "Conformer encoder model architecture. …" arXiv:2005.08100

Figure 5. Bold borders mark what Conformer adds to the Transformer block.

The two halves are a macaron-style feed-forward network: the attention and convolution modules sit between them like the filling in a macaron. They add capacity and non-linearity but don't mix across time, and each is scaled by half so the pair matches the one FFN of a vanilla transformer.

The block is five residual lines, one per stage. In them, x is the input frame vector and x̃, x′, x″, x‴ are the frame after each stage (Figure 6).

One frame through the block

frame vector

Figure 6. Each module adds to the frame; its shape never changes.

One frame through the block in five lines.
x̃ = x + ½·FFN(x)
Add a half-strength feed-forward pass to the frame, so the frame gets richer on its own before anything mixes across time.
x′ = x̃ + MHSA(x̃)
Add attention, so the frame borrows context from far away frames and adds it to itself.
x″ = x′ + Conv(x′)
Add the convolution module, so the frame sharpens its local edges using only its close neighbors.
x‴ = x″ + ½·FFN(x″)
Add the second half-strength feed-forward pass, so the two halves together make one full feed-forward.
y = LayerNorm(x‴)
Run layer norm on the result, so the frame steadies its scale and leaves the block with the same shape it entered.
x the input frame vector; x̃ the frame after the first feed-forward stagex′ the frame after the attention stagex″ the frame after the convolution stagex‴ the frame after the second feed-forward stage½·FFN half-strength feed-forward, steps 2 and 5; two halves make one whole (the blue bar grows)MHSA multi-head self-attention, step 3: the gray arcs borrow context from far framesConv the convolution module, step 4: the green bracket sharpens local edgesLayerNorm step 6: steadies the frame for the next block (the blue bar settles)y the block's output, same shape as x+ residual add, each module's output joins the frame= defines the frame's next state

The first FFN is a 2-layer MLP (multilayer perceptron) applied to each frame on its own, as the card below gives.

The feed-forward network, one frame at a time.
FFN(x) = W2·Swish(W1·x)
W1 expands the frame x from the model dimension, 256, to the feed-forward width, 1024 (the usual 4×); Swish is a smooth activation; W2 projects back to 256. The output is halved before the residual add, the macaron half-step.

2.1 Attention with relative positions

The input is a batch of frames, each a 256-dimensional vector, and attention runs as multi-head self-attention (MHSA) on the Attention page, with queries, keys and values mixed by softmax weights in 4 heads of 64 dimensions each.

Unlike a vanilla transformer, which adds absolute position encodings (sine and cosine waves, see Position and Masking) to each input, Conformer uses relative positions, which generalize better to long sequences and relative timing. Speech is shift-invariant: a "ba" at 1 second and at 10 seconds should be treated the same.

So the inputs stay untouched and the score gains a bonus for the distance between two frames. The paper uses the relative encoding of Transformer-XL, a long-context language model, which builds each offset's vector from sine and cosine waves of the distance; this page shows the simpler learned-table version, one vector per offset up to a maximum distance, shared across heads.

MHSA in line 2 of the block scores each pair of frames by the content match plus a position bias.
score(i, j) = qi · kj√dk
The usual query-key match. Each · is a dot product. qi is the query vector of frame i, kj the key vector of frame j, and dk the head dimension; dividing by its square root keeps the scores in a range softmax can handle.
+ qi · ri-j
Plus a learned bonus for how far apart the two frames are. ri-j is the relative embedding for the offset i minus j, the signed distance between the two frames. Two pairs with the same offset get the same position term no matter where they sit.

The score in PyTorch, for a batch of B utterances of T frames: content is the first eq line, position the second, and rel is the learned table of offset vectors, clipped at 32 frames.

import torch, torch.nn as nn
B, H, T, dk = 8, 4, 100, 64
R = 32  # clip offsets at 32
qkv = torch.randn(3, B, H, T, dk)
q, k, v = qkv
rel = nn.Embedding(2*R + 1, dk)
pos = torch.arange(T)
d = pos[:, None] - pos[None, :]
off = d.clamp(-R, R)
# (T, T, dk), a vector per offset
r = rel(off + R)
content = q @ k.transpose(-2, -1)
qe = q.unsqueeze(-2)
position = (qe * r).sum(-1)
scale = dk ** 0.5
score = content / scale + position
out = score.softmax(-1) @ v
  1. 1Random queries, keys and values, each (B, H, T, dk), already split into 4 heads of 64.
  2. 2The signed distance d from frame j to frame i, clipped to ±R, picks one learned vector from the relative-position table.
  3. 3Score is content match plus position term, then softmax and the weighted sum of values.

Attention weights (illustrative scores)

Figure 7. Relative positions track distance; absolute ones track the clock.

2.2 The convolution module

The convolution module is a depthwise separable convolution (see Efficient CNNs: MobileNet and EfficientNet) that models local structure explicitly. Convolution itself, a small filter slid along the signal, is taught in Convolutions and Receptive Fields; the depthwise separable form comes from MobileNet.

mixes channelsmixes over timeinput, d = model widthwidthLayerNormdPointwise conv2dGLU gatedDepthwise conv, 31 tapsdBatchNorm, SwishdPointwise convdDropoutdresidual addoutput, same shape as input
Figure 8. The convolution module, top to bottom; the output keeps the input's shape.

The depthwise kernel size k sets how many neighboring frames each output sees: raising it widens that local window at more compute per frame, lowering it narrows the window, and k = 1 removes the time mixing entirely. Conformer (M) uses 32 (the paper's Table 1).

Take the edge from "k" to "ae" in "cat" (Figure 3): each frequency band changes over a few neighboring 40 ms frames, so each channel needs its own filter over time. The three lines build that filter.

Conv(x′) in line 3 of the block runs a pointwise conv, the GLU gate, then the depthwise conv.
ut = W·xt
In the pointwise step, a 1 by 1 convolution, the matrix W mixes the channels of frame t, xt, into ut, twice as wide, and never looks at neighboring frames.
GLU(a, b) = a ⊙ σ(b)
The GLU (Gated Linear Unit) splits ut into halves a and b; its output is the gated frame gt. σ, the sigmoid, squashes b into gates between 0 and 1, and ⊙ multiplies entry by entry, so b decides how much of a passes. That is why the projection before it expands to twice the width.
vt,c = Σm wc,m·gt+m,c
In the depthwise step, channel c of the gated frames has its own filter wc, and m runs over the filter's taps around frame t, so vt,c mixes neighbors in time while channels never mix.

Each output frame of the depthwise convolution (kernel 31 in the PyTorch ports of Conformer in PyTorch: Training and Streaming, 32 in the paper) sees a local window of input frames, its receptive field. 'Same' padding keeps the length unchanged.

2.3 LayerNorm or BatchNorm

The Conformer uses LayerNorm before each module and BatchNorm right after the depthwise convolution (section 2.2 of the paper), because batch statistics help the convolution train but break on the short chunks of streaming (Conformer in PyTorch: Training and Streaming). Normalization Layers teaches LayerNorm and BatchNorm side by side. A Swish then lets small negative values through instead of clipping them to zero.

2.4 Pointwise mixing, then the last feed-forward

After BatchNorm and Swish, a second pointwise convolution (the last boxes of Figure 8) with dropout (randomly zeroing values in training) maps the model dimension back to itself, and a residual joins the module's start to its output.

After the convolution module, a second half-strength feed-forward with its residual completes the macaron. Same shape in, same shape out, so blocks stack.

The two modules split the work over time. The conv reads a fixed window of neighbors, 31 taps or about 1.2 s at 40 ms frames, and attention reads the whole utterance (Figure 9).

Local conv and global attention

Depthwise conv, kernel 7 (toy-scaled from 31)

Attention from the probe (illustrative)

bars sum to 1.0 at every probe position

Figure 9. The conv sees nearby frames; attention reaches similar ones.

The whole block as four PyTorch classes, trained with CTC, is in Conformer in PyTorch: Training and Streaming.


3 Reported results

The paper's reported models, all trained and scored on LibriSpeech, a standard dataset of read speech with its text (Figure 10). Here d is the model dimension; all three Conformers use a convolution kernel of 32 taps (filter weights, one per frame the filter covers):

Conformer (S)16 blocks, d = 14410.3MConformer (M)16 blocks, d = 25630.7MConformer (L)17 blocks, d = 512118.8MTransformer transducerno convolution module139Mparameters, millions
Figure 10. Model sizes reported in the Conformer paper.

The Transformer transducer streams text as audio arrives, with no convolution; ContextNet (L) is the strongest convolution-only baseline. WER is word error rate, lower is better, scored on test-clean (cleaner, easier recordings) and test-other (harder ones), with no external language model.

test-cleantest-otherTransformer (transducer)2.45.6ContextNet (L)2.14.6Conformer (M)2.35.0Conformer (L) (lowest test-other)2.14.3
Figure 11. Conformer paper, LibriSpeech WER (%); lower is better.

The medium Conformer, at 30.7M params, already beats the 139M-param transformer transducer.

3.1 Removing one component at a time

The paper's ablation (Table 3) starts from Conformer (L) and removes one feature per row (Figure 12); the authors single out the convolution block as the most important (section 3.4.1).

test-cleantest-otherConformer (L)2.14.3Swish replaced by ReLU2.04.5No convolution block2.14.9One full FFN instead of two halves2.15.0Vanilla attention, no relative positions2.45.6
Figure 12. WER (%) in Table 3; each row also removes everything above it.

The convolution module is cheap. Its two pointwise projections hold about 3d² parameters per block, about 3.1M of Conformer (M)'s 30.7M.

4 Branchformer and Squeezeformer

Both keep local convolution and global attention and change how they are wired or how long a sequence attention sees. Streaming the Conformer itself, with training on random chunk sizes, is in Conformer in PyTorch: Training and Streaming.

Figure 13. Two later rewirings; Figure 5 has the Conformer order.

4.1 Branchformer

The Branchformer (Peng et al., ICML 2022) replaces the FFN-attention-conv-FFN order with two parallel branches per layer: self-attention for long range and a conv-gated MLP (an MLP whose output a convolutional gate controls) for local detail, combined by learned merge weights. It matches or beats Conformer.

4.2 Squeezeformer

The Squeezeformer (Kim et al., NeurIPS 2022) replaces the macaron layout with attention, feed-forward, convolution, feed-forward blocks and adds a Temporal U-Net, which downsamples the timeline for attention and upsamples it back (Figure 13), for the same accuracy at lower compute.

How do you write, train and stream this block? Conformer in PyTorch: Training and Streaming does all three.


5 References

  1. Gulati, A., et al. (2020). Conformer: Convolution-augmented Transformer for Speech Recognition. Interspeech. arXiv:2005.08100.
  2. Peng, Y., et al. (2022). Branchformer: Parallel MLP-Attention Architectures to Capture Local and Global Context for Speech Recognition and Understanding. ICML. arXiv:2207.02971.
  3. Kim, S., et al. (2022). Squeezeformer: An Efficient Transformer for Automatic Speech Recognition. NeurIPS. arXiv:2206.00888.
  4. Toledano, D. T., Fernández-Gallego, M. P., Lozano-Diez, A. (2018). Multi-resolution speech analysis for automatic speech recognition using deep neural networks: Experiments on TIMIT. PLOS ONE 13(10): e0205355.