一、神经网络复习与目标
神经网络是多个神经元层层叠加的模型,核心是通过调节权重参数 Θ\ThetaΘ,让网络输出逼近目标结果。
- 输入层:接收特征 xxx
- 隐藏层:通过激活函数 ggg 变换输入,增加模型表达能力
- 输出层:生成最终预测结果 hΘ(x)h_\Theta(x)hΘ(x)
目标:通过训练找到一组参数 Θ\ThetaΘ,使得代价函数 J(Θ)J(\Theta)J(Θ) 最小,模型预测更准确。
二、代价函数(Cost Function)
神经网络的代价函数是对所有训练样本误差的平均,外加正则化避免过拟合:
J(Θ)=−1m∑i=1m∑k=1K[yk(i)log(hΘ(x(i))k)+(1−yk(i))log(1−hΘ(x(i))k)]+λ2m∑l=1L−1∑i,j(Θij(l))2
J(\Theta) = - \frac{1}{m} \sum_{i=1}^m \sum_{k=1}^K \left[ y_k^{(i)} \log(h_\Theta(x^{(i)})_k) + (1 - y_k^{(i)}) \log(1 - h_\Theta(x^{(i)})_k) \right] + \frac{\lambda}{2m} \sum_{l=1}^{L-1} \sum_{i,j} (\Theta_{ij}^{(l)})^2
J(Θ)=−m1i=1∑mk=1∑K[yk(i)log(hΘ(x(i))k)+(1−yk(i))log(1−hΘ(x(i))k)]+2mλl=1∑L−1i,j∑(Θij(l))2
- mmm:训练样本数
- KKK:类别数(输出层神经元数)
- λ\lambdaλ:正则化参数
- 注意:正则化不包含偏置参数(Θi0(l)\Theta_{i0}^{(l)}Θi0(l))
为什么用交叉熵?
它衡量两个概率分布间的差异,适合分类问题,且能加速训练收敛。
三、前向传播(Forward Propagation)
计算预测值的过程:
-
激活值计算:
对于第 lll 层神经元:
z(l)=Θ(l−1)a(l−1) z^{(l)} = \Theta^{(l-1)} a^{(l-1)} z(l)=Θ(l−1)a(l−1)
其中,a(l−1)a^{(l-1)}a(l−1) 是第 l−1l-1l−1 层输出,且 a(1)=xa^{(1)} = xa(1)=x(输入层),Θ(l−1)\Theta^{(l-1)}Θ(l−1) 是第 l−1l-1l−1 层到第 lll 层的权重矩阵。 -
激活函数应用:
a(l)=g(z(l)) a^{(l)} = g(z^{(l)}) a(l)=g(z(l))
常用激活函数:sigmoid
g(z)=11+e−z g(z) = \frac{1}{1 + e^{-z}} g(z)=1+e−z1
作用是非线性映射,使网络具备拟合复杂函数的能力。
四、反向传播(Backpropagation)核心原理
目标
计算代价函数对每个权重参数的偏导数 ∂J(Θ)∂Θij(l)\frac{\partial J(\Theta)}{\partial \Theta_{ij}^{(l)}}∂Θij(l)∂J(Θ),即梯度,供梯度下降优化。
1. 误差项定义
误差项 δj(l)\delta_j^{(l)}δj(l) 表示第 lll 层第 jjj 个神经元的“误差”,其含义是:该神经元对最终误差的贡献。
2. 输出层误差计算
δ(L)=a(L)−y \delta^{(L)} = a^{(L)} - y δ(L)=a(L)−y
- a(L)a^{(L)}a(L):输出层的激活值(预测值)
- yyy:真实标签(one-hot 编码)
解释:输出层误差即预测值与真实值差异。
3. 隐藏层误差传播
误差从输出层 “反向” 传播:
δ(l)=(Θ(l))Tδ(l+1)∘g′(z(l))
\delta^{(l)} = \left( \Theta^{(l)} \right)^T \delta^{(l+1)} \circ g'(z^{(l)})
δ(l)=(Θ(l))Tδ(l+1)∘g′(z(l))
- ∘\circ∘ 表示元素逐个相乘(Hadamard 乘积)
- g′(z)g'(z)g′(z) 是激活函数导数,sigmoid导数:
g′(z)=g(z)⋅(1−g(z)) g'(z) = g(z) \cdot (1 - g(z)) g′(z)=g(z)⋅(1−g(z))
- 注意偏置项不参与误差计算,要从Θ\ThetaΘ中剔除相应列
4. 梯度累积
对所有样本求和:
Δ(l):=Δ(l)+δ(l+1)(a(l))T
\Delta^{(l)} := \Delta^{(l)} + \delta^{(l+1)} (a^{(l)})^T
Δ(l):=Δ(l)+δ(l+1)(a(l))T
最后计算平均梯度:
D(l)=1mΔ(l)+λmΘ(l)(偏置项除外)
D^{(l)} = \frac{1}{m} \Delta^{(l)} + \frac{\lambda}{m} \Theta^{(l)} \quad (\text{偏置项除外})
D(l)=m1Δ(l)+mλΘ(l)(偏置项除外)
五、为什么反向传播有效?
- 利用链式法则,高效计算复杂函数复合的导数
- 只需一次前向计算和一次反向传播,即可得到所有参数梯度
- 计算复杂度随层数线性增加,不爆炸
六、梯度检查(Gradient Checking)
验证反向传播实现是否正确,采用数值微分方法。
数值梯度计算
对单个参数 θ\thetaθ:
∂J(θ)∂θ≈J(θ+ϵ)−J(θ−ϵ)2ϵ
\frac{\partial J(\theta)}{\partial \theta} \approx \frac{J(\theta + \epsilon) - J(\theta - \epsilon)}{2 \epsilon}
∂θ∂J(θ)≈2ϵJ(θ+ϵ)−J(θ−ϵ)
- ϵ\epsilonϵ 为很小的数值(如 10−410^{-4}10−4)
- 对所有参数逐一检查,比较数值梯度和反向传播梯度
七、参数初始化技巧
全部初始化为 0 会导致网络所有节点学习相同的参数,失去学习能力。
推荐初始化方法:
均匀分布随机初始化:
Θij(l)∼Uniform[−ϵ,ϵ]
\Theta^{(l)}_{ij} \sim \text{Uniform} \left[-\epsilon, \epsilon\right]
Θij(l)∼Uniform[−ϵ,ϵ]
ϵ=6Lin+Lout _\epsilon = \frac{\sqrt{6}}{\sqrt{L_{in} + L_{out}}} ϵ=Lin+Lout6
- LinL_{in}Lin:输入层神经元数
- LoutL_{out}Lout:输出层神经元数
随机打破对称性,保证神经元学习不同特征。
八、Python 代码示例
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def sigmoid_gradient(z):
s = sigmoid(z)
return s * (1 - s)
def initialize_weights(L_in, L_out):
epsilon = np.sqrt(6) / np.sqrt(L_in + L_out)
return np.random.uniform(-epsilon, epsilon, (L_out, L_in + 1))
def forward_propagate(X, theta1, theta2):
m = X.shape[0]
a1 = np.c_[np.ones(m), X] # Add bias
z2 = a1.dot(theta1.T)
a2 = np.c_[np.ones(m), sigmoid(z2)] # Add bias
z3 = a2.dot(theta2.T)
a3 = sigmoid(z3)
return a1, z2, a2, z3, a3
def back_propagate(X, y, theta1, theta2, lambda_):
m = X.shape[0]
Delta1 = np.zeros(theta1.shape)
Delta2 = np.zeros(theta2.shape)
a1, z2, a2, z3, a3 = forward_propagate(X, theta1, theta2)
d3 = a3 - y # 输出层误差
d2 = d3.dot(theta2[:,1:]) * sigmoid_gradient(z2) # 隐藏层误差
Delta1 += d2.T.dot(a1)
Delta2 += d3.T.dot(a2)
theta1_grad = Delta1 / m
theta2_grad = Delta2 / m
# 正则化(偏置项除外)
theta1_grad[:, 1:] += (lambda_ / m) * theta1[:, 1:]
theta2_grad[:, 1:] += (lambda_ / m) * theta2[:, 1:]
return theta1_grad, theta2_grad