深度学习中的傅里叶位置编码

深度学习中的傅里叶位置编码

  • 介绍
      • [1. 核心矛盾:神经网络的"低通滤波器"特性](#1. 核心矛盾:神经网络的“低通滤波器”特性)
      • [2. 数学表达](#2. 数学表达)
      • [3. 两种主流的应用视角](#3. 两种主流的应用视角)
        • [A. 在 Transformer 中的"相对位置感知"](#A. 在 Transformer 中的“相对位置感知”)
        • [B. 在坐标感知任务(如 NeRF/3D 视觉)中的"特征增强"](#B. 在坐标感知任务(如 NeRF/3D 视觉)中的“特征增强”)
      • [4. 为什么它有效?(直观理解)](#4. 为什么它有效?(直观理解))
      • [5. 进阶形式:RFF (Random Fourier Features)](#5. 进阶形式:RFF (Random Fourier Features))
      • 代码实现示例
      • 总结

介绍

在深度学习中,傅里叶位置编码(Fourier Positional Encoding) 是一项将连续坐标(或离散索引)映射到高维特征空间的技术。无论是 Transformer 处理序列,还是 NeRF 处理 3D 坐标,其核心逻辑基本一致。


1. 核心矛盾:神经网络的"低通滤波器"特性

深度学习模型(尤其是多层感知机 MLP)存在一种现象,被称为 光谱偏差(Spectral Bias)

  • 问题: 神经网络倾向于优先学习数据中的低频分量 (平滑的部分),而很难捕捉高频分量(精细的纹理、急剧变化的边界)。
  • 表现: 如果直接将原始坐标 ( x , y , z ) (x, y, z) (x,y,z) 输入网络,生成的图像或模型往往非常模糊,丢失了大量细节。

傅里叶位置编码的作用就是预先将输入"拉伸"到高频空间,强迫模型感知细微的变化。


2. 数学表达

最常见的傅里叶编码形式(如在 NeRF 或 Transformer 中使用的)是将一个标量值 v v v 映射为一个向量:

γ ( v ) = [ sin ⁡ ( 2 0 π v ) , cos ⁡ ( 2 0 π v ) , ... , sin ⁡ ( 2 L − 1 π v ) , cos ⁡ ( 2 L − 1 π v ) ] \gamma(v) = [ \sin(2^0 \pi v), \cos(2^0 \pi v), \dots, \sin(2^{L-1} \pi v), \cos(2^{L-1} \pi v) ] γ(v)=[sin(20πv),cos(20πv),...,sin(2L−1πv),cos(2L−1πv)]

  • 多尺度频率: 通过指数级增加频率( 2 0 , 2 1 , ... 2^0, 2^1, \dots 20,21,...),编码涵盖了从全局(低频)到局部细节(高频)的所有特征。
  • 周期性: 使用 sin ⁡ \sin sin 和 cos ⁡ \cos cos 保证了编码在空间上的连续性。

3. 两种主流的应用视角

A. 在 Transformer 中的"相对位置感知"

在 NLP 中,模型本质上是无序的(词袋模型)。傅里叶编码(Sinusoidal Encoding)提供了位置信息:

  • 距离度量: 由于三角函数的特性,任意两个位置 p o s pos pos 和 p o s + k pos+k pos+k 之间的编码关系可以通过一个线性变换来表示。这意味着模型可以更容易地学到词与词之间的相对距离
B. 在坐标感知任务(如 NeRF/3D 视觉)中的"特征增强"

在处理几何数模或 3D 场景时:

  • 高维投影: 将 3 维坐标投影到(例如)256 维的空间。
  • 类似于算术: 就像我们用二进制表示数字一样,低位(高频)变化极快,代表微小的位移;高位(低频)变化缓慢,代表宏观的位置。这让 MLP 能够像"查表"一样精准地定位空间中的每一个点。

4. 为什么它有效?(直观理解)

想象你要在地图上定位一个点:

  1. 如果只给你经纬度(原始坐标),数值变化很小,模型很难区分 100.001 100.001 100.001 和 100.002 100.002 100.002 的区别。
  2. 傅里叶编码相当于给地图加了无数层不同粗细的网格
  • 第一层网格很大(低频)。
  • 最后一层网格细如发丝(高频)。
  • 模型通过查看点在所有网格中的相对位置,就能瞬间锁定极高精度的坐标。

5. 进阶形式:RFF (Random Fourier Features)

在最新的研究中,研究者发现不一定要用固定的 2 n 2^n 2n 频率,可以使用随机采样的高斯频率:

ϕ ( x ) = [ cos ⁡ ( 2 π B x ) , sin ⁡ ( 2 π B x ) ] T \phi(\mathbf{x}) = [\cos(2\pi \mathbf{B}\mathbf{x}), \sin(2\pi \mathbf{B}\mathbf{x})]^T ϕ(x)=[cos(2πBx),sin(2πBx)]T

其中 B \mathbf{B} B 是从高斯分布中随机生成的矩阵。这种方法(常见于 Fourier Feature Networks )可以根据任务需求,通过调整高斯分布的标准差( σ \sigma σ)来控制模型捕捉细节的能力:

  • σ \sigma σ 越大: 捕捉的细节越细,但如果过大可能导致混叠噪声。
  • σ \sigma σ 越小: 结果越平滑。

代码实现示例

常规实现
python 复制代码
class FourierPositionalEncoding(nn.Module):
    """Fourier feature encoding for spatial coordinates.
    Maps scalar values to high-dimensional space using sinusoidal functions,
    helping the network capture fine spatial details even with large coordinate values.
    """

    def __init__(self, input_dim: int, num_frequencies: int = 10, log_scale: bool = True):
        super().__init__()
        self.input_dim = input_dim
        self.num_frequencies = num_frequencies
        self.output_dim = input_dim * 2 * num_frequencies
        if log_scale:
            freq_bands = 2.0 ** torch.linspace(0, num_frequencies - 1, num_frequencies)
        else:
            freq_bands = torch.linspace(1.0, 2.0 ** (num_frequencies - 1), num_frequencies)
        # shape: (num_frequencies,)
        self.register_buffer("freq_bands", freq_bands)

    def forward(self, x: Tensor) -> Tensor:
        """
        Args:
            x: (..., input_dim)
        Returns:
            (..., output_dim)
        """
        # x_proj shape: (..., input_dim, num_frequencies)
        x_proj = x.unsqueeze(-1) * self.freq_bands * math.pi
        # sin/cos shape: (..., input_dim * num_frequencies)
        sin_feat = torch.sin(x_proj).flatten(-2)
        cos_feat = torch.cos(x_proj).flatten(-2)
        return torch.cat([sin_feat, cos_feat], dim=-1)
RFF
python 复制代码
import math

import torch
from torch import nn


class RandomFourierPositionEncoding(nn.Module):
    """
    随机傅里叶特征对 3D 坐标编码。
    坐标先归一化到 [-1,1](基于场景包围盒),再映射到高维。
    这样对"坐标值很大"的场景保持稳定。
    """

    def __init__(self, d_out: int, d_pos: int = 3, n_freq: int = 64, sigma: float = 1.0):
        super().__init__()
        # 固定随机频率矩阵,不参与梯度
        B = torch.randn(d_pos, n_freq) * sigma  # (d_pos, n_freq)
        self.register_buffer("B", B)
        self.proj = nn.Linear(n_freq * 2, d_out)  # sin+cos → d_out

    def forward(self, xyz: torch.Tensor) -> torch.Tensor:
        """
        xyz: (..., d_pos)  已归一化坐标
        return: (..., d_out)
        """
        x = 2 * math.pi * xyz @ self.B  # (..., n_freq)
        x = torch.cat([x.sin(), x.cos()], dim=-1)  # (..., 2*n_freq)
        return self.proj(x)

总结

傅里叶位置编码不仅仅是给输入加点"佐料",它是改变了模型观察数据的分辨率。它将简单的数值转化为一组丰富的频率信号,让神经网络这个"近视眼"戴上了一副高倍率的显微镜。

相关推荐
互联科技报7 小时前
2026年高清家用投影仪推荐:明基W系列领衔
人工智能
数智工坊8 小时前
【FDA论文阅读】: 傅里叶域自适应——零训练成本的语义分割无监督域适配方法
论文阅读·人工智能·学习·算法·自动驾驶
财迅通Ai8 小时前
利欧股份持续推进“制造业+科技投资”战略 主业与投资协同效应显现
人工智能·科技·利欧股份
技术小猪猪8 小时前
企业AI Agent部署痛点?MCP Gateway Lite:开源轻量级网关解决方案
人工智能·开源·gateway
蓦然回首却已人去楼空8 小时前
深度学习进阶:自然语言处理|3.2.3 QA|word2vec 中为什么输入和输出权重都可以表示单词
深度学习·自然语言处理·word2vec
XD7429716368 小时前
大模型可解释性-颠覆认知:大语言模型在预训练中并非“稳定变聪明”
人工智能·机器学习·语言模型
码农杂谈00078 小时前
GEA和Copilot的核心区别是什么?企业AI选型指南
人工智能·ai·gea
Agent产品评测局8 小时前
食品制造 | 品控AI自动化方案主流厂商横评:2026企业级智能体选型与落地实测
人工智能·ai·chatgpt·自动化·制造
youmiyoumiyoumi8 小时前
# 微信机器人测试与质量保障:确保稳定可靠的服务
人工智能