Fourier features: positions as waves
Read these first if they are new to you
- Sine waves Basic
- Embeddings: things as vectors Intermediate
The idea in one paragraph
A network that reads a raw coordinate, such as x = 0.30, finds it hard to treat nearby positions very differently. Fourier features replace the coordinate by the sine and cosine of it at several frequencies. Low frequencies say roughly where the position is. High frequencies change fast, so they tell nearby positions apart. A linear layer then turns these features into the position's embedding. Think of a clock: the hour hand gives the rough time, and the minute and second hands give the detail.
A raw coordinate makes nearby positions hard to tell apart
Suppose a shape has an edge at x = 0.31: positions just left of it are inside, positions just right of it are outside. A network must give opposite answers for x = 0.30 and x = 0.32. Yet the two inputs differ by only 0.02. The first layer computes weighted sums of x, and those sums differ by only 0.02 times a weight. To make the two sums very different, the layer needs very large weights.
In practice, networks trained on raw coordinates learn the smooth, slowly changing parts of a function first, and sharp detail very slowly. This tendency is called spectral bias. Fourier features work around it by handing the network inputs that already change fast.
Each frequency turns a position into a sine and a cosine
Pick a frequency f: the number of full waves per unit of position. For a position x, compute the pair sin(2πfx) and cos(2πfx), as in the sine waves unit. The factor 2π makes f count full turns: as x runs from 0 to 1, the pair goes around a circle f times. With k frequencies, the Fourier features of x are 2k numbers. We write them as φ(x), with the Greek letter phi:
φ(x) = [ sin(2πf1x), cos(2πf1x), …, sin(2πfkx), cos(2πfkx) ]
The name honors Joseph Fourier, who showed that sums of sines and cosines can build almost any repeating curve. A layer that reads φ(x) can mix these waves with its weights, so fast-changing functions of x become easy to make.
| f | sin, cos at 0.30 | sin, cos at 0.32 | gap between the pairs |
|---|---|---|---|
| 1 | 0.951, −0.309 | 0.905, −0.426 | 0.126 |
| 4 | 0.951, 0.309 | 0.982, −0.187 | 0.497 |
| 16 | −0.951, 0.309 | 0.685, 0.729 | 1.689 |
- For f = 4 and x = 0.30, the angle is 2π × 4 × 0.30 = 7.540 radians. Its sine is 0.951 and its cosine is 0.309.
- The "gap" is the straight-line distance between the two (sin, cos) pairs. For f = 4 it is √((0.951 − 0.982)2 + (0.309 + 0.187)2) = 0.497.
- Put the three pairs together into six features per position. The distance between the two feature vectors is √(0.1262 + 0.4972 + 1.6892) = 1.765.
The raw positions differ by 0.02. Their Fourier features differ by 1.765, about 88 times as much. The frequency-16 pair does most of that work.
One high frequency alone repeats itself
Predict first. Frequency 16 separates the two positions better than frequency 4. Will frequency 50 separate them better still?
Try it. Drag the slider to find the frequency that puts the two positions farthest apart. Then keep going to f = 50. What happens there, and why?
Answer
The gap peaks at f = 25, where the two points sit on opposite sides of the circle. At f = 50, position 0.32 is exactly one full wave ahead of 0.30 (50 × 0.02 = 1), so both positions get the same features and the gap is 0. In general the gap is 2 × |sin(πf × 0.02)|.
So a single frequency is ambiguous: any two positions a whole number of waves apart look the same to it. This is why Fourier features use several frequencies, from low to high. The low frequencies tell distant positions apart without repeating. The high frequencies tell close positions apart. Together they pin down the position, like the hands of a clock.
Models choose the frequencies in one of three common ways
| Choice | Frequencies | Where you meet it |
|---|---|---|
| Powers of two | 1, 2, 4, …, 2k−1 waves across the range of the data | Neural fields that map a 3D position to a color or density |
| A geometric spread | wavelengths from 2π up to 10,000 × 2π | The original transformer's encoding of word positions; the encoding of time in diffusion and flow models |
| Random | drawn from a bell curve whose spread you choose | The 2020 study of Fourier features for networks that read coordinates (Tancik and others) |
The lowest frequency should not repeat inside the range of the data. With f = 1 as the lowest, positions 0 and 1 get the same features, so the data should lie in [0, 1). The highest frequency sets the finest detail the network can easily make.
A 3D point p = (x, y, z) works the same way. Either encode each coordinate separately, or choose frequency vectors b and use sin(2π b · p) and cos(2π b · p), where · is the dot product. A model that must know the time t of a process, such as a step in a generative model, encodes t the same way (see time conditioning).
fourier_features.py
import numpy as np
def fourier_features(x, freqs):
angles = 2 * np.pi * np.outer(x, freqs) # row i: 2π x[i] times each frequency
# The sine columns, then the cosine columns, side by side in one array.
return np.concatenate([np.sin(angles), np.cos(angles)], axis=1)
freqs = np.array([1.0, 4.0, 16.0])
F = fourier_features(np.array([0.30, 0.32]), freqs)
print(np.round(F, 3)) # sines first, then cosines
print(round(np.linalg.norm(F[0] - F[1]), 3)) # gap between the feature vectors
[[ 0.951 0.951 -0.951 -0.309 0.309 0.309] [ 0.905 0.982 0.685 -0.426 -0.187 0.729]] 1.765
Spectral bias is a tendency that experiments and theory for very wide networks support, not a law. A network on raw coordinates can learn fine detail; it is just slow. Frequencies that are too high also cause trouble: the network can fit noise in the training data and produce a speckled result, so the frequency range is a setting to tune. Some models also skip fixed waves and learn a table of position embeddings instead.
Check yourself
-
A model encodes each coordinate of a 3D point with 8 frequencies, sine and cosine. How many features does one point get?
Answer
3 coordinates × 8 frequencies × 2 (sine and cosine) = 48 features. Some models also keep the 3 raw coordinates, for 51.
-
Work a similar problem. Positions 0.1 and 0.6 are encoded with the single frequency 2. What are their features? Which of the frequencies 1 or 4 would tell them apart?
Answer
At f = 2 they are 2 × 0.5 = 1 full wave apart, so both get sin = 0.951 and cos = 0.309. At f = 4 they are 2 full waves apart and still look the same. At f = 1 they are half a wave apart: (0.588, 0.809) against (−0.588, −0.809), opposite points of the circle, with the largest possible gap of 2.
-
Why use both a sine and a cosine at each frequency? Hint: compare positions 0.1 and 0.4 at frequency 1.
Answer
Both positions have sin(2πx) = 0.588, so the sine alone cannot tell them apart. Their cosines are 0.809 and −0.809. Together, the pair is a point on a circle, which fixes where in the wave the position sits.
Go further
Optional background, for readers who want more than this page.
-
Fourier Features Let Networks Learn High Frequency Functions in Low Dimensional Domains Tancik, Srinivasan, Mildenhall and others (NeurIPS 2020) Project page and paper Advanced
The paper behind the name. The project page shows images fitted with and without Fourier features, side by side, which makes spectral bias easy to see.
-
Transformer Architecture: The Positional Encoding, "Proposed method" Amirhossein Kazemnejad Article Advanced
Explains the transformer's sine and cosine position encoding with pictures, including why a shift in position is a rotation of each (sin, cos) pair.
-
The Illustrated Transformer: "Representing The Order of The Sequence Using Positional Encoding" Jay Alammar Illustrated article Advanced
A short section with a color picture of the encoding for many positions at once.