本文面向算法入门者,详细介绍深度学习和机器学习中常用的各种函数,包括其数学定义、核心作用、应用场景和实现细节。
目录
- 激活函数
- 线性变换函数
- 归一化函数
- [Batch Normalization](#Batch Normalization)
- [Layer Normalization](#Layer Normalization)
- [Group Normalization](#Group Normalization)
- 损失函数
- [交叉熵损失(Cross Entropy Loss)](#交叉熵损失(Cross Entropy Loss))
- [均方误差损失(MSE Loss)](#均方误差损失(MSE Loss))
- [二元交叉熵损失(Binary Cross Entropy)](#二元交叉熵损失(Binary Cross Entropy))
- 池化函数
- [Max Pooling](#Max Pooling)
- [Average Pooling](#Average Pooling)
- [Global Average Pooling](#Global Average Pooling)
- 优化器相关函数
- [梯度裁剪(Gradient Clipping)](#梯度裁剪(Gradient Clipping))
- 学习率调度
- 正则化函数
- 注意力机制函数
- [Scaled Dot-Product Attention](#Scaled Dot-Product Attention)
- [Multi-Head Attention](#Multi-Head Attention)
- 其他重要函数
激活函数
激活函数是神经网络中的核心组件,它们引入非线性,使神经网络能够学习复杂的模式。
ReLU
全称:Rectified Linear Unit(线性整流单元)
数学定义:
f(x) = max(0, x) = {
x, if x > 0
0, if x ≤ 0
}
导数:
f'(x) = {
1, if x > 0
0, if x ≤ 0
}
核心作用:
- 引入非线性:使神经网络能够学习非线性关系
- 计算高效:只需要简单的阈值操作,计算速度快
- 缓解梯度消失:在正区间梯度恒为1,避免了深层网络的梯度消失问题
优点:
- 计算简单,训练速度快
- 在正区间不会出现梯度消失
- 稀疏激活(约50%的神经元输出为0)
缺点:
- 死亡ReLU问题:如果输入始终为负,神经元永远不会被激活,梯度永远为0
- 输出不是零中心的
应用场景:
- 卷积神经网络(CNN)的隐藏层
- 深度前馈网络
- 大多数现代深度学习架构的默认选择
Python实现:
python
import numpy as np
def relu(x):
return np.maximum(0, x)
def relu_derivative(x):
return (x > 0).astype(float)
Sigmoid
数学定义:
σ(x) = 1 / (1 + e^(-x))
值域:(0, 1)
导数:
σ'(x) = σ(x) * (1 - σ(x))
核心作用:
- 将输入压缩到(0,1)区间:适合表示概率
- 平滑可微:处处可导,梯度连续
- 单调递增:保证输入越大,输出越大
优点:
- 输出范围有限,适合概率输出
- 函数平滑,梯度计算稳定
缺点:
- 梯度消失:当输入很大或很小时,梯度接近0,导致深层网络难以训练
- 输出不是零中心的:可能导致梯度更新效率低
- 计算涉及指数:计算成本较高
应用场景:
- 二分类问题的输出层
- 逻辑回归
- 门控机制(如LSTM、GRU)
Python实现:
python
import numpy as np
def sigmoid(x):
# 防止溢出
x = np.clip(x, -500, 500)
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
s = sigmoid(x)
return s * (1 - s)
Tanh
全称:Hyperbolic Tangent(双曲正切)
数学定义:
tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x))
= 2 * σ(2x) - 1
值域:(-1, 1)
导数:
tanh'(x) = 1 - tanh²(x)
核心作用:
- 零中心输出:输出范围(-1,1),均值接近0
- 更强的梯度:相比Sigmoid,梯度更大,训练更快
- 平滑可微:类似Sigmoid的平滑特性
优点:
- 零中心输出,梯度更新更高效
- 比Sigmoid梯度更大,训练更快
缺点:
- 仍然存在梯度消失问题(虽然比Sigmoid好)
- 计算涉及指数
应用场景:
- RNN的隐藏层
- 需要零中心输出的场景
- 某些分类问题的输出层
Python实现:
python
import numpy as np
def tanh(x):
return np.tanh(x)
def tanh_derivative(x):
return 1 - np.tanh(x) ** 2
Softmax
数学定义 :
对于输入向量 x = [x₁, x₂, ..., xₙ],Softmax函数定义为:
softmax(x_i) = e^(x_i) / Σⱼ e^(x_j)
其中,分母是所有元素的指数和。
核心作用:
- 将任意实数向量转换为概率分布:输出所有元素和为1,每个元素在[0,1]区间
- 多分类问题的标准输出:适合多分类任务
- 保持相对大小关系:输入越大,输出概率越大
数学性质:
- 输出和为1:Σᵢ softmax(xᵢ) = 1
- 所有输出非负:softmax(xᵢ) ≥ 0
- 可微且单调
数值稳定性 :
为了避免指数溢出,通常使用以下技巧:
softmax(x_i) = e^(x_i - max(x)) / Σⱼ e^(x_j - max(x))
应用场景:
- 多分类问题的输出层
- 注意力机制中的注意力权重计算
- 任何需要概率分布输出的场景
Python实现:
python
import numpy as np
def softmax(x, axis=-1):
# 数值稳定版本
x_shifted = x - np.max(x, axis=axis, keepdims=True)
exp_x = np.exp(x_shifted)
return exp_x / np.sum(exp_x, axis=axis, keepdims=True)
# 示例
x = np.array([1.0, 2.0, 3.0])
print(softmax(x)) # [0.09003057 0.24472847 0.66524096]
与交叉熵损失的关系 :
Softmax通常与交叉熵损失函数配合使用,形成softmax交叉熵损失,这是多分类问题的标准组合。
Leaky ReLU
数学定义:
f(x) = {
x, if x > 0
αx, if x ≤ 0
}
其中 α 是一个小的正数(通常为0.01)。
核心作用:
- 解决死亡ReLU问题:在负区间给予小的梯度,避免神经元完全死亡
- 保持ReLU的优点:计算简单,正区间梯度为1
优点:
- 解决了ReLU的死亡问题
- 保持了ReLU的计算效率
- 在负区间有小的梯度,允许信息流动
缺点:
- 需要选择超参数α
- 输出仍然不是零中心的
变体:
- Parametric ReLU (PReLU):将α作为可学习参数
- Randomized ReLU (RReLU):在训练时α随机采样
应用场景:
- 需要避免死亡ReLU问题的场景
- GAN(生成对抗网络)
- 某些CNN架构
Python实现:
python
import numpy as np
def leaky_relu(x, alpha=0.01):
return np.where(x > 0, x, alpha * x)
def leaky_relu_derivative(x, alpha=0.01):
return np.where(x > 0, 1, alpha)
ELU
全称:Exponential Linear Unit(指数线性单元)
数学定义:
f(x) = {
x, if x > 0
α(e^x - 1), if x ≤ 0
}
其中 α 通常为1。
核心作用:
- 结合ReLU和Sigmoid的优点:正区间类似ReLU,负区间平滑
- 零中心输出:负区间的输出均值接近-α,有助于梯度更新
- 更强的梯度:负区间梯度不会消失
优点:
- 负区间平滑,梯度连续
- 零中心特性
- 避免死亡神经元问题
缺点:
- 计算涉及指数,比ReLU慢
- 需要选择超参数α
应用场景:
- 需要平滑激活的场景
- 某些深度网络架构
Python实现:
python
import numpy as np
def elu(x, alpha=1.0):
return np.where(x > 0, x, alpha * (np.exp(x) - 1))
def elu_derivative(x, alpha=1.0):
return np.where(x > 0, 1, elu(x, alpha) + alpha)
GELU
全称:Gaussian Error Linear Unit(高斯误差线性单元)
数学定义:
GELU(x) = x * Φ(x)
其中 Φ(x) 是标准正态分布的累积分布函数(CDF):
Φ(x) = 0.5 * (1 + erf(x / √2))
近似公式:
GELU(x) ≈ 0.5 * x * (1 + tanh(√(2/π) * (x + 0.044715 * x³)))
核心作用:
- 平滑的非线性:比ReLU更平滑
- 概率视角:可以理解为根据输入的概率进行门控
- 在Transformer中表现优异:BERT、GPT等模型使用
优点:
- 平滑且可微
- 在自然语言处理任务中表现优异
- 概率解释更直观
缺点:
- 计算比ReLU复杂
- 需要近似计算
应用场景:
- Transformer模型(BERT、GPT等)
- 自然语言处理任务
- 需要平滑激活的深度网络
Python实现:
python
import numpy as np
def gelu(x):
# 使用近似公式
return 0.5 * x * (1 + np.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * x**3)))
def gelu_exact(x):
# 精确版本(需要scipy)
from scipy.special import erf
return 0.5 * x * (1 + erf(x / np.sqrt(2)))
Swish
数学定义:
Swish(x) = x * σ(x) = x / (1 + e^(-x))
其中 σ(x) 是Sigmoid函数。
核心作用:
- 自门控机制:输入自己作为门控信号
- 平滑且非单调:在小负值区域有小的负输出
- 在深度网络中表现优异:Google研究发现性能优于ReLU
优点:
- 平滑可微
- 在深层网络中表现好
- 无上界,有下界
缺点:
- 计算涉及Sigmoid,比ReLU慢
- 在浅层网络中优势不明显
变体:
- Hard-Swish:使用分段线性函数近似,计算更快
应用场景:
- 移动端神经网络(MobileNet等)
- 某些高效的CNN架构
Python实现:
python
import numpy as np
def swish(x):
return x * (1 / (1 + np.exp(-x)))
def swish_derivative(x):
sigmoid_x = 1 / (1 + np.exp(-x))
return sigmoid_x * (1 + x * (1 - sigmoid_x))
线性变换函数
Affine(仿射变换)
数学定义 :
对于输入向量 x,仿射变换定义为:
y = Wx + b
其中:
- W 是权重矩阵(weight matrix)
- b 是偏置向量(bias vector)
- x 是输入向量
矩阵形式 :
如果输入是 n 维向量,输出是 m 维向量,则:
- W 的形状为 (m, n)
- b 的形状为 (m,)
- y 的形状为 (m,)
核心作用:
- 线性变换:通过矩阵乘法进行线性变换
- 维度变换:可以改变向量的维度
- 特征组合:将输入特征进行线性组合
- 偏置调整:通过偏置项调整输出
与线性变换的区别:
- 线性变换:y = Wx(无偏置)
- 仿射变换:y = Wx + b(有偏置)
在神经网络中的应用:
- 全连接层(Dense Layer):就是仿射变换
- 卷积层:可以看作特殊的仿射变换
- 注意力机制:包含多个仿射变换
前向传播:
python
def affine_forward(x, W, b):
"""
x: (N, D) - N个样本,每个样本D维
W: (M, D) - 权重矩阵
b: (M,) - 偏置向量
返回: (N, M)
"""
out = x.dot(W.T) + b # 广播
cache = (x, W, b)
return out, cache
反向传播:
python
def affine_backward(dout, cache):
"""
dout: (N, M) - 上游梯度
cache: 前向传播的缓存
返回: dx, dW, db
"""
x, W, b = cache
dx = dout.dot(W) # (N, M) @ (M, D) -> (N, D)
dW = dout.T.dot(x) # (M, N) @ (N, D) -> (M, D)
db = np.sum(dout, axis=0) # (M,)
return dx, dW, db
参数数量 :
对于输入维度 D,输出维度 M:
- 权重参数:D × M
- 偏置参数:M
- 总参数:D × M + M
应用场景:
- 全连接神经网络层
- 线性分类器
- 特征变换
- 几乎所有深度学习架构的基础组件
注意事项:
- 仿射变换本身是线性的,需要配合激活函数引入非线性
- 参数初始化很重要,影响训练稳定性
- 在深层网络中,仿射变换的参数数量可能非常大
归一化函数
归一化技术是现代深度学习的核心,它们通过标准化中间层的输入分布来加速训练并提高稳定性。
Batch Normalization
全称:批量归一化
数学定义 :
对于一个小批量(batch)的数据 x:
-
计算均值和方差:
μ_B = (1/m) Σᵢ xᵢ
σ²_B = (1/m) Σᵢ (xᵢ - μ_B)² -
归一化:
x̂ᵢ = (xᵢ - μ_B) / √(σ²_B + ε)
-
缩放和平移:
yᵢ = γ * x̂ᵢ + β
其中:
- m 是batch大小
- ε 是小的常数(防止除零,通常为1e-5)
- γ 和 β 是可学习的参数
核心作用:
- 内部协变量偏移:减少训练过程中各层输入分布的变化
- 允许更大的学习率:归一化后的输入更稳定
- 正则化效果:有一定的正则化作用,可以减少过拟合
- 加速训练:通常可以加快收敛速度
训练和推理的区别:
- 训练时:使用当前batch的统计量
- 推理时:使用训练时累积的移动平均统计量
优点:
- 允许更大的学习率
- 减少对初始化的依赖
- 有正则化效果
- 加速训练
缺点:
- 依赖batch大小,小batch时效果差
- 在RNN中应用困难
- 推理时需要额外存储统计量
应用场景:
- CNN的卷积层和全连接层
- 大多数现代CNN架构(ResNet、Inception等)
Python实现:
python
import numpy as np
def batch_norm_forward(x, gamma, beta, bn_param):
"""
x: (N, D) - N个样本,D个特征
gamma: (D,) - 缩放参数
beta: (D,) - 平移参数
"""
mode = bn_param['mode'] # 'train' or 'test'
eps = bn_param.get('eps', 1e-5)
momentum = bn_param.get('momentum', 0.9)
N, D = x.shape
running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
running_var = bn_param.get('running_var', np.ones(D, dtype=x.dtype))
if mode == 'train':
# 计算batch统计量
sample_mean = np.mean(x, axis=0)
sample_var = np.var(x, axis=0)
# 归一化
x_normalized = (x - sample_mean) / np.sqrt(sample_var + eps)
# 更新移动平均
running_mean = momentum * running_mean + (1 - momentum) * sample_mean
running_var = momentum * running_var + (1 - momentum) * sample_var
out = gamma * x_normalized + beta
cache = (x, x_normalized, sample_mean, sample_var, gamma, eps)
else:
# 推理时使用移动平均
x_normalized = (x - running_mean) / np.sqrt(running_var + eps)
out = gamma * x_normalized + beta
cache = None
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var
return out, cache
Layer Normalization
全称:层归一化
数学定义 :
对于单个样本的特征向量 x:
-
计算均值和方差:
μ = (1/D) Σᵢ xᵢ
σ² = (1/D) Σᵢ (xᵢ - μ)² -
归一化:
x̂ᵢ = (xᵢ - μ) / √(σ² + ε)
-
缩放和平移:
yᵢ = γ * x̂ᵢ + β
与Batch Normalization的区别:
- Batch Norm:在batch维度上归一化(跨样本)
- Layer Norm:在特征维度上归一化(跨特征)
核心作用:
- 不依赖batch大小:对单个样本进行归一化
- 适合序列模型:在RNN、Transformer中表现优异
- 稳定训练:减少内部协变量偏移
优点:
- 不依赖batch大小
- 适合RNN和Transformer
- 训练和推理一致
缺点:
- 在CNN中效果不如Batch Norm
- 计算成本略高
应用场景:
- Transformer模型(BERT、GPT等)
- RNN和LSTM
- 小batch或在线学习场景
Python实现:
python
import numpy as np
def layer_norm(x, gamma, beta, eps=1e-5):
"""
x: (N, D) - N个样本,D个特征
gamma: (D,) - 缩放参数
beta: (D,) - 平移参数
"""
# 在特征维度上计算统计量
mean = np.mean(x, axis=-1, keepdims=True)
var = np.var(x, axis=-1, keepdims=True)
# 归一化
x_normalized = (x - mean) / np.sqrt(var + eps)
# 缩放和平移
out = gamma * x_normalized + beta
return out
Group Normalization
全称:组归一化
核心思想 :
将通道(channels)分成若干组,在每组内进行归一化。
数学定义 :
对于特征图 x 的形状 (N, C, H, W):
- 将C个通道分成G组,每组C/G个通道
- 对每组内的特征进行归一化
与Batch/Layer Norm的区别:
- Batch Norm:在(N, H, W)维度归一化
- Layer Norm:在(C, H, W)维度归一化
- Group Norm:在(H, W)和部分C维度归一化
应用场景:
- 小batch训练
- 目标检测(batch size通常为1或2)
- 某些CNN架构
损失函数
损失函数衡量模型预测与真实值之间的差距,是训练优化的目标。
交叉熵损失(Cross Entropy Loss)
数学定义 :
对于多分类问题,给定真实标签 y (one-hot编码)和预测概率 ŷ:
L = -Σᵢ yᵢ * log(ŷᵢ)
对于单个样本:
L = -log(ŷ_k)
其中 k 是真实类别。
与Softmax的组合 :
通常与Softmax结合使用:
L = -log(softmax(logits)[k])
数值稳定性 :
为了避免数值问题,通常直接计算:
L = -logits[k] + log(Σⱼ exp(logits[j]))
核心作用:
- 概率解释:适合分类问题
- 梯度特性:当预测错误时梯度大,正确时梯度小
- 信息论基础:衡量两个概率分布的差异
优点:
- 适合多分类问题
- 梯度特性好,训练稳定
- 有概率解释
缺点:
- 假设类别互斥
- 对异常值敏感
应用场景:
- 多分类问题
- 与Softmax配合使用
- 大多数分类任务
Python实现:
python
import numpy as np
def cross_entropy_loss(y_pred, y_true):
"""
y_pred: (N, C) - N个样本,C个类别,已通过softmax
y_true: (N,) - 真实类别索引
"""
N = y_pred.shape[0]
# 获取每个样本真实类别的预测概率
correct_logprobs = -np.log(y_pred[range(N), y_true])
loss = np.sum(correct_logprobs) / N
return loss
def softmax_cross_entropy_loss(logits, y_true):
"""
数值稳定的版本
logits: (N, C) - 未归一化的分数
y_true: (N,) - 真实类别索引
"""
N, C = logits.shape
# 数值稳定:减去最大值
logits_shifted = logits - np.max(logits, axis=1, keepdims=True)
exp_logits = np.exp(logits_shifted)
probs = exp_logits / np.sum(exp_logits, axis=1, keepdims=True)
# 计算损失
correct_logprobs = -np.log(probs[range(N), y_true])
loss = np.sum(correct_logprobs) / N
return loss
均方误差损失(MSE Loss)
全称:Mean Squared Error
数学定义:
MSE = (1/n) Σᵢ (yᵢ - ŷᵢ)²
核心作用:
- 回归问题:适合连续值预测
- 惩罚大误差:平方项使大误差被更严重惩罚
- 可微性:处处可微,梯度计算简单
优点:
- 数学性质好,易于优化
- 适合回归问题
- 计算简单
缺点:
- 对异常值敏感(平方项放大)
- 假设误差服从高斯分布
变体:
- RMSE(Root MSE):√MSE,与目标值同量纲
- MAE(Mean Absolute Error):|y - ŷ|,对异常值更鲁棒
应用场景:
- 回归问题
- 图像重建
- 数值预测
Python实现:
python
import numpy as np
def mse_loss(y_pred, y_true):
"""
y_pred: (N, D) - 预测值
y_true: (N, D) - 真实值
"""
return np.mean((y_pred - y_true) ** 2)
def mse_loss_derivative(y_pred, y_true):
"""梯度"""
return 2 * (y_pred - y_true) / y_pred.size
二元交叉熵损失(Binary Cross Entropy)
数学定义 :
对于二分类问题:
L = -(y * log(ŷ) + (1-y) * log(1-ŷ))
其中:
- y 是真实标签(0或1)
- ŷ 是预测概率(0到1之间)
核心作用:
- 二分类专用:专门用于二分类问题
- 概率解释:适合输出概率的场景
- 梯度特性:预测接近真实值时梯度小,远离时梯度大
应用场景:
- 二分类问题
- 多标签分类(每个标签独立使用BCE)
- 与Sigmoid配合使用
Python实现:
python
import numpy as np
def binary_cross_entropy_loss(y_pred, y_true, eps=1e-15):
"""
y_pred: (N,) - 预测概率
y_true: (N,) - 真实标签(0或1)
"""
# 防止log(0)
y_pred = np.clip(y_pred, eps, 1 - eps)
loss = -(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
return np.mean(loss)
池化函数
池化操作用于降低特征图的空间维度,减少参数数量,增加感受野。
Max Pooling
数学定义 :
在池化窗口内取最大值:
y = max(x₁, x₂, ..., xₙ)
核心作用:
- 降维:减少特征图尺寸
- 平移不变性:对小的平移具有鲁棒性
- 减少参数:降低计算量
- 特征选择:保留最显著的特征
常见配置:
- 2×2 Max Pooling:stride=2,将尺寸减半
- 3×3 Max Pooling:stride=2,常用于某些架构
优点:
- 计算简单
- 保留最显著特征
- 对平移鲁棒
缺点:
- 丢失空间细节
- 不可微(但可以通过近似实现反向传播)
应用场景:
- CNN的标准组件
- 大多数现代CNN架构
Python实现:
python
import numpy as np
def max_pool_forward(x, pool_param):
"""
x: (N, C, H, W)
pool_param: {'pool_height': 2, 'pool_width': 2, 'stride': 2}
"""
N, C, H, W = x.shape
pool_h = pool_param['pool_height']
pool_w = pool_param['pool_width']
stride = pool_param['stride']
out_h = (H - pool_h) // stride + 1
out_w = (W - pool_w) // stride + 1
out = np.zeros((N, C, out_h, out_w))
for i in range(out_h):
for j in range(out_w):
h_start = i * stride
h_end = h_start + pool_h
w_start = j * stride
w_end = w_start + pool_w
out[:, :, i, j] = np.max(x[:, :, h_start:h_end, w_start:w_end],
axis=(2, 3))
cache = (x, pool_param)
return out, cache
Average Pooling
数学定义 :
在池化窗口内取平均值:
y = (1/n) Σᵢ xᵢ
核心作用:
- 降维:减少特征图尺寸
- 平滑特征:对噪声更鲁棒
- 全局信息:保留整体信息而非局部最大值
与Max Pooling的对比:
- Max Pooling:保留最显著特征,更常用
- Average Pooling:保留平均信息,对噪声更鲁棒
应用场景:
- 某些CNN架构
- 全局平均池化(Global Average Pooling)
- 需要平滑特征的场景
Global Average Pooling
全称:全局平均池化
数学定义 :
对整个特征图取平均:
y = (1/(H×W)) Σᵢⱼ xᵢⱼ
核心作用:
- 全局信息:将整个特征图压缩为单个值
- 减少参数:避免全连接层的大量参数
- 防止过拟合:减少模型复杂度
应用场景:
- ResNet等现代架构
- 替代全连接层
- 减少模型参数
优化器相关函数
梯度裁剪(Gradient Clipping)
数学定义 :
限制梯度的大小:
按值裁剪:
g = {
g, if |g| ≤ threshold
threshold, if g > threshold
-threshold, if g < -threshold
}
按范数裁剪:
g = {
g, if ||g|| ≤ threshold
g * threshold / ||g||, if ||g|| > threshold
}
核心作用:
- 防止梯度爆炸:限制梯度大小,稳定训练
- 稳定训练:特别是在RNN中非常重要
- 允许更大学习率:通过限制梯度,可以使用更大的学习率
应用场景:
- RNN和LSTM训练
- 深层网络
- 训练不稳定时
Python实现:
python
import numpy as np
def clip_gradients(grads, max_norm):
"""
按范数裁剪梯度
grads: 梯度列表
max_norm: 最大范数
"""
total_norm = 0
for grad in grads:
total_norm += np.sum(grad ** 2)
total_norm = np.sqrt(total_norm)
clip_coef = max_norm / (total_norm + 1e-6)
if clip_coef < 1:
for grad in grads:
grad *= clip_coef
return grads
学习率调度
常见策略:
- 固定学习率:整个训练过程保持不变
- 阶梯衰减:每隔一定epoch降低学习率
- 指数衰减:lr = lr₀ * decay^epoch
- 余弦退火:lr = lr_min + (lr_max - lr_min) * (1 + cos(π * epoch / max_epoch)) / 2
- Warmup:训练初期逐渐增加学习率
核心作用:
- 加速收敛:初期大学习率快速学习
- 精细调优:后期小学习率精细调整
- 避免震荡:防止训练后期震荡
正则化函数
Dropout
数学定义 :
训练时,以概率 p 随机将神经元输出置为0:
y = {
x / (1-p), if 保留(概率1-p)
0, if 丢弃(概率p)
}
推理时,所有神经元都保留,但输出要乘以 (1-p)。
核心作用:
- 防止过拟合:随机丢弃神经元,减少模型复杂度
- 集成效果:相当于训练多个子网络的集成
- 提高泛化:强制模型学习更鲁棒的特征
优点:
- 简单有效
- 计算开销小
- 广泛适用
缺点:
- 训练时间可能增加
- 需要调整dropout率
应用场景:
- 全连接层
- 某些CNN架构
- 防止过拟合
Python实现:
python
import numpy as np
def dropout_forward(x, dropout_param):
"""
x: 输入
dropout_param: {'mode': 'train', 'p': 0.5, 'seed': None}
"""
p, mode = dropout_param['p'], dropout_param['mode']
if mode == 'train':
mask = (np.random.rand(*x.shape) > p) / (1 - p)
out = x * mask
cache = mask
else:
out = x
cache = None
return out, cache
def dropout_backward(dout, cache):
"""
dout: 上游梯度
cache: 前向传播的mask
"""
if cache is not None:
dx = dout * cache
else:
dx = dout
return dx
L1/L2正则化
L2正则化(权重衰减):
L_total = L_data + λ * Σᵢ wᵢ²
L1正则化:
L_total = L_data + λ * Σᵢ |wᵢ|
核心作用:
- 防止过拟合:惩罚大权重
- 特征选择:L1可以产生稀疏权重
- 模型简化:鼓励模型使用更少的特征
区别:
- L2:平滑,权重接近0但不为0
- L1:产生稀疏解,某些权重为0
注意力机制函数
Scaled Dot-Product Attention
数学定义:
Attention(Q, K, V) = softmax(QK^T / √d_k) * V
其中:
- Q:查询(Query)矩阵
- K:键(Key)矩阵
- V:值(Value)矩阵
- d_k:键的维度
缩放因子 √d_k :
防止点积过大导致softmax梯度消失。
核心作用:
- 序列建模:捕捉序列中的依赖关系
- 并行计算:相比RNN可以并行计算
- 长距离依赖:直接建模任意距离的依赖
应用场景:
- Transformer模型
- 机器翻译
- 自然语言处理
Python实现:
python
import numpy as np
def scaled_dot_product_attention(Q, K, V, mask=None):
"""
Q: (..., seq_len_q, d_k)
K: (..., seq_len_k, d_k)
V: (..., seq_len_v, d_v)
"""
d_k = Q.shape[-1]
# 计算注意力分数
scores = np.matmul(Q, K.transpose(-2, -1)) / np.sqrt(d_k)
# 应用mask(如果有)
if mask is not None:
scores = np.where(mask == 0, -1e9, scores)
# Softmax
attention_weights = softmax(scores, axis=-1)
# 加权求和
output = np.matmul(attention_weights, V)
return output, attention_weights
Multi-Head Attention
核心思想 :
将Q、K、V分成多个头(heads),分别计算注意力,然后拼接。
数学定义:
MultiHead(Q, K, V) = Concat(head₁, ..., headₕ)W^O
其中:
headᵢ = Attention(QWᵢ^Q, KWᵢ^K, VWᵢ^V)
核心作用:
- 多视角:从多个角度捕捉信息
- 表达能力:增强模型的表达能力
- 并行计算:多个头可以并行计算
应用场景:
- Transformer的核心组件
- BERT、GPT等模型
其他重要函数
One-Hot编码
定义 :
将类别索引转换为向量表示,只有对应位置为1,其他为0。
示例:
类别 0 -> [1, 0, 0, 0]
类别 1 -> [0, 1, 0, 0]
类别 2 -> [0, 0, 1, 0]
类别 3 -> [0, 0, 0, 1]
核心作用:
- 类别表示:将离散类别转换为数值向量
- 损失计算:用于交叉熵损失
- 无大小关系:避免类别间的数值大小关系
Python实现:
python
import numpy as np
def one_hot_encode(labels, num_classes):
"""
labels: (N,) - 类别索引
num_classes: 类别数量
返回: (N, num_classes)
"""
N = len(labels)
one_hot = np.zeros((N, num_classes))
one_hot[np.arange(N), labels] = 1
return one_hot
Embedding
核心思想 :
将离散的符号(如单词)映射到连续的向量空间。
数学定义:
e = E[i]
其中 E 是嵌入矩阵,i 是索引。
核心作用:
- 语义表示:将符号转换为有意义的向量
- 可学习:嵌入向量可以通过训练学习
- 降维/升维:可以改变表示维度
应用场景:
- 词嵌入(Word Embedding)
- 类别特征编码
- 推荐系统
Python实现:
python
import numpy as np
class Embedding:
def __init__(self, vocab_size, embed_dim):
self.weight = np.random.randn(vocab_size, embed_dim) * 0.01
def forward(self, indices):
"""
indices: (N,) - 索引
返回: (N, embed_dim)
"""
return self.weight[indices]
Positional Encoding
核心思想 :
为序列中的每个位置添加位置信息,因为Transformer没有循环结构,无法感知位置。
数学定义(Transformer中的正弦位置编码):
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
其中:
- pos:位置
- i:维度索引
- d_model:模型维度
核心作用:
- 位置信息:为序列添加位置信息
- 相对位置:可以表示相对位置关系
- 外推能力:可以处理比训练时更长的序列
应用场景:
- Transformer模型
- 序列到序列任务
Python实现:
python
import numpy as np
def positional_encoding(seq_len, d_model):
"""
seq_len: 序列长度
d_model: 模型维度
返回: (seq_len, d_model)
"""
pe = np.zeros((seq_len, d_model))
position = np.arange(seq_len).reshape(-1, 1)
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model))
pe[:, 0::2] = np.sin(position * div_term)
pe[:, 1::2] = np.cos(position * div_term)
return pe
总结
本文详细介绍了算法学习中常用的各种函数,包括:
- 激活函数:ReLU、Sigmoid、Tanh、Softmax等,引入非线性
- 线性变换:Affine变换,神经网络的基础
- 归一化:Batch Norm、Layer Norm等,稳定训练
- 损失函数:交叉熵、MSE等,衡量预测误差
- 池化函数:Max Pooling、Average Pooling等,降维
- 正则化:Dropout、L1/L2等,防止过拟合
- 注意力机制:Self-Attention、Multi-Head等,序列建模
- 其他函数:One-Hot、Embedding、Positional Encoding等
学习建议:
- 理解每个函数的数学定义和几何意义
- 掌握前向传播和反向传播的实现
- 了解各函数的优缺点和适用场景
- 通过实践加深理解
进一步学习:
- 深入理解反向传播算法
- 学习优化算法(SGD、Adam等)
- 研究现代架构(ResNet、Transformer等)
- 实践项目,应用这些函数
希望本文能帮助算法入门者更好地理解和掌握这些常用函数!
参考文献
- Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep Learning. MIT Press.
- Vaswani, A., et al. (2017). "Attention is All You Need." Neural Information Processing Systems.
- Ioffe, S., & Szegedy, C. (2015). "Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift." ICML.