线性代数视角下的神经网络层

神经网络可以看作是一系列线性变换与非线性激活的交织。本章从线性代数的视角,分析各类神经网络层的数学本质,揭示它们之间的内在联系。

全连接层

数学定义

全连接层(Fully Connected Layer / Dense Layer)是最基础的神经网络层:

其中:

  • :输入向量
  • :权重矩阵
  • :偏置向量
  • :逐元素激活函数

几何解释

全连接层实现了仿射变换(Affine Transformation):

  1. 线性变换 将输入向量旋转、反射、缩放、投影
  2. 平移 将原点移动

几何变换示例

权重矩阵类型几何效果
正交矩阵 纯旋转/反射
对角矩阵沿坐标轴缩放
稀疏矩阵选择性丢弃某些维度

PyTorch实现

import torch
import torch.nn as nn
 
# 手动实现
def fc_layer(x, W, b, sigma):
    """
    x: (batch, d_in)
    W: (d_in, d_out)
    b: (d_out,)
    """
    return sigma(x @ W + b)
 
# nn.Module实现
class FullyConnected(nn.Module):
    def __init__(self, d_in, d_out):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(d_in, d_out) * 0.01)
        self.bias = nn.Parameter(torch.zeros(d_out))
    
    def forward(self, x):
        return torch.relu(x @ self.weight + self.bias)

卷积层

卷积的矩阵形式

卷积操作可以通过Toeplitz矩阵转化为矩阵乘法。

一维卷积

对于输入 和卷积核

Toeplitz矩阵

则卷积等价于:

二维卷积(im2col)

对于图像 和卷积核

im2col将每个滑动窗口展开为一行:

卷积核展成列向量:

则输出为:

卷积的几何意义

视角解释
线性代数输入与卷积核的稀疏矩阵乘法
信号处理相关性/卷积运算
计算机视觉局部特征提取器
群论等变变换(Equivariant Transformation)

PyTorch卷积实现

import torch
import torch.nn as nn
 
# 标准2D卷积
conv2d = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)
 
# im2col实现示意
def im2col(x, kernel_size, stride, padding):
    """
    将2D图像转换为矩阵列
    x: (B, C, H, W)
    """
    x = torch.nn.functional.pad(x, (padding,)*4)
    B, C, H, W = x.shape
    
    # 计算输出尺寸
    out_H = (H - kernel_size) // stride + 1
    out_W = (W - kernel_size) // stride + 1
    
    # 使用unfold进行im2col
    cols = x.unfold(2, kernel_size, stride).unfold(3, kernel_size, stride)
    cols = cols.contiguous().view(B, C * kernel_size * kernel_size, -1)
    
    return cols, (out_H, out_W)
 
# 手写卷积(用于理解)
def conv2d_manual(x, weight, bias, stride=1, padding=0):
    B, C, H, W = x.shape
    K, _, kH, kW = weight.shape
    
    x_padded = torch.nn.functional.pad(x, (padding,)*4)
    out_H = (H + 2*padding - kH) // stride + 1
    out_W = (W + 2*padding - kW) // stride + 1
    
    out = torch.zeros(B, K, out_H, out_W)
    
    for i in range(out_H):
        for j in range(out_W):
            h_start = i * stride
            w_start = j * stride
            window = x_padded[:, :, h_start:h_start+kH, w_start:w_start+kW]
            out[:, :, i, j] = (window.unsqueeze(1) * weight).sum(dim=(2,3,4)) + bias
    
    return out

注意力层

Self-Attention的矩阵形式

Self-Attention是Transformer的核心组件:

为输入序列,则:

矩阵形式分解

  1. 投影 的三个不同线性投影
  2. 相似度矩阵
  3. 注意力权重
  4. 加权聚合

注意力的线性代数视角

视角解释
矩阵分解
图神经网络每个token是从所有其他token聚合信息
核方法softmax是径向基函数核的归一化形式
信息检索Query-Key-Value对应检索系统

多头注意力的矩阵拼接

其中每个头的输出:

PyTorch实现

import torch
import torch.nn as nn
import torch.nn.functional as F
import math
 
class SelfAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
    
    def forward(self, x, mask=None):
        B, N, C = x.shape
        
        # 线性投影并分头
        Q = self.W_q(x).view(B, N, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(x).view(B, N, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(x).view(B, N, self.num_heads, self.d_k).transpose(1, 2)
        
        # 缩放点积注意力
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        
        attn_weights = F.softmax(scores, dim=-1)
        context = torch.matmul(attn_weights, V)
        
        # 合并多头
        context = context.transpose(1, 2).contiguous().view(B, N, C)
        
        return self.W_o(context)

Embedding层

数学定义

Embedding层本质上是一个查表操作

给定词索引 ,输出对应词向量:

矩阵视角

Embedding可以看作是一个稀疏矩阵乘法

其中 是one-hot编码矩阵。

实际实现优化:直接用索引查表,避免稀疏矩阵运算。

几何解释

  • 语义相似的词在向量空间中距离更近
  • 词向量之间的夹角反映语义关系
  • 线性关系(如 )体现语言规律

PyTorch实现

import torch
import torch.nn as nn
 
class TokenEmbedding(nn.Module):
    def __init__(self, vocab_size, d_model):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.scale = math.sqrt(d_model)
    
    def forward(self, x):
        # x: (batch_size, seq_len) 整数索引
        return self.embedding(x) * self.scale
 
# 位置编码也可以看作是一种embedding
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1).float()
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        self.register_buffer('pe', pe.unsqueeze(0))
    
    def forward(self, x):
        # x: (batch_size, seq_len, d_model)
        return x + self.pe[:, :x.size(1)]

归一化层

BatchNorm的矩阵形式

对于形状 的张量:

LayerNorm的矩阵形式

对于形状 的张量(Transformer采用):

矩阵视角:LayerNorm对每个样本的嵌入维度进行归一化,相当于在特征空间做单位球面投影。

RMSNorm

去掉均值中心化,保留RMS归一化,计算更高效。

Dropout与矩阵稀疏化

Dropout的矩阵形式

训练时以概率 丢弃神经元:

其中 是掩码矩阵。

Dropout的期望

因此推理时使用 的缩放,保持期望一致。

Dropout的几何解释

  • 强制网络不依赖单个神经元
  • 在高维空间中进行稀疏采样
  • 近似贝叶斯推断中的模型集成

层之间的联系

全连接 vs 卷积

特性全连接层卷积层
权重共享局部权重共享
稀疏性密集连接稀疏连接
等变性不具备具有平移等变性
参数量

卷积 vs 注意力

特性卷积层注意力层
感受野局部(kernel大小)全局(整个序列)
连接模式固定(局部邻域)自适应(数据驱动)
计算复杂度

现代架构的统一视图

MetaFormer(Yu et al., 2022)提出:Transformer = Token Mixer + Channel Mixer

组件Token MixerChannel Mixer
TransformerSelf-AttentionFFN
CNNConvolution1x1 Conv
MLP-Mixer线性层(跨通道)线性层(跨Token)

参考


相关词条:Transformer与注意力机制ResNet与残差学习LSTM门控机制