一、 为什么要用神经网络?
- 逻辑回归只能处理线性可分问题。
- 例如,经典的 XOR 异或问题无法用单层逻辑回归准确分类。
- 神经网络通过多层结构和非线性激活函数,能学习复杂的决策边界,解决非线性问题。
二、神经网络的基本组成
神经网络由多层组成:
层级 | 说明 |
---|---|
输入层 | 接收输入特征,比如像素或数值。 |
隐藏层 | 通过若干个神经元(单元)进行非线性变换。 |
输出层 | 输出最终结果,如分类概率。 |
三、神经元和权重的定义
- 每个神经元代表一个计算单元,输出称为“激活值” ai(j)a_i^{(j)}ai(j),表示第 jjj 层第 iii 个神经元的输出。
- 每层之间的连接由权重矩阵 Θ(j)\Theta^{(j)}Θ(j) 表示,从第 jjj 层到第 j+1j+1j+1 层。
- 权重矩阵的维度为:sj+1×(sj+1)s_{j+1} \times (s_j + 1)sj+1×(sj+1),其中 sjs_jsj 是第 jjj 层神经元数(不包含偏置单元),+1+1+1 是因为偏置项。
四、前向传播(Forward Propagation)
假设有一个3层神经网络(输入层-隐藏层-输出层),执行前向传播的过程如下:
- 输入层激活 a(1)=xa^{(1)} = xa(1)=x,在输入层加上偏置单元 a0(1)=1a_0^{(1)} = 1a0(1)=1。
- 计算隐藏层的输入值:
z(2)=Θ(1)a(1) z^{(2)} = \Theta^{(1)} a^{(1)} z(2)=Θ(1)a(1)
这里,z(2)z^{(2)}z(2) 是隐藏层每个神经元的线性组合输入(权重 * 输入 + 偏置)。
- 对 z(2)z^{(2)}z(2) 使用激活函数(sigmoid)得到隐藏层激活:
a(2)=g(z(2))=11+e−z(2) a^{(2)} = g(z^{(2)}) = \frac{1}{1 + e^{-z^{(2)}}} a(2)=g(z(2))=1+e−z(2)1
- 在隐藏层激活前加偏置单元 a0(2)=1a_0^{(2)} = 1a0(2)=1。
- 计算输出层的输入:
z(3)=Θ(2)a(2) z^{(3)} = \Theta^{(2)} a^{(2)} z(3)=Θ(2)a(2)
- 输出层激活:
a(3)=hΘ(x)=g(z(3)) a^{(3)} = h_\Theta(x) = g(z^{(3)}) a(3)=hΘ(x)=g(z(3))
a(3)a^{(3)}a(3) 就是网络最终的输出,可能是多类分类的概率向量。
五、激活函数:sigmoid 函数
- 公式:
g(z)=11+e−z g(z) = \frac{1}{1 + e^{-z}} g(z)=1+e−z1
- 作用:
- 将任意实数映射到 (0, 1) 之间。
- 模拟生物神经元“激活”的概率。
- 输出值可解释为概率,方便做分类。
- 形状:
- z→+∞z \to +\inftyz→+∞, g(z)→1g(z) \to 1g(z)→1
- z→−∞z \to -\inftyz→−∞, g(z)→0g(z) \to 0g(z)→0
- z=0z = 0z=0, g(z)=0.5g(z) = 0.5g(z)=0.5
六、神经网络举例:用来实现 XOR 函数
XOR 真值表:
x1x_1x1 | x2x_2x2 | XOR 输出 yyy |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
逻辑回归不能拟合这个非线性边界,但神经网络可以。
七、Python代码示例:手写3层神经网络实现 XOR
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 输入数据:4个样本,2个特征
X = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
m = X.shape[0]
# 添加偏置单元
X = np.hstack((np.ones((m,1)), X)) # shape (4,3)
# 手动设定权重参数 Theta
# 输入层到隐藏层 (2隐藏单元 + 偏置),shape = (2,3)
Theta1 = np.array([[-30, 20, 20], # 模拟AND
[10, -20, -20]]) # 模拟NOR
# 隐藏层到输出层 (1输出单元 + 偏置), shape = (1,3)
Theta2 = np.array([-10, 20, 20]) # 模拟OR
def forward_propagation(X):
# 输入层到隐藏层
z2 = X @ Theta1.T # (4,3) @ (3,2).T => (4,2)
a2 = sigmoid(z2)
# 添加偏置单元到隐藏层激活
a2 = np.hstack((np.ones((m,1)), a2)) # (4,3)
# 隐藏层到输出层
z3 = a2 @ Theta2.T # (4,3) @ (3,1) => (4,1)
a3 = sigmoid(z3)
return a3
y_pred = forward_propagation(X)
print("预测结果(概率):\n", y_pred)
print("预测结果(四舍五入):\n", np.round(y_pred))
结果:
预测结果(概率):
[[0.0000454 ]
[0.9999546 ]
[0.9999546 ]
[0.0000454 ]]
预测结果(四舍五入):
[[0.]
[1.]
[1.]
[0.]]
成功模拟 XOR 输出。
八、神经网络参数维度
层间连接 | 权重矩阵维度 |
---|---|
输入层(含偏置)到隐藏层 | Θ(1)∈Rs2×(s1+1)\Theta^{(1)} \in \mathbb{R}^{s_2 \times (s_1 + 1)}Θ(1)∈Rs2×(s1+1) |
隐藏层(含偏置)到输出层 | Θ(2)∈Rs3×(s2+1)\Theta^{(2)} \in \mathbb{R}^{s_3 \times (s_2 + 1)}Θ(2)∈Rs3×(s2+1) |
- sjs_jsj:第 jjj 层神经元个数,不含偏置。
- 偏置项在矩阵维度中体现为多加的一列。
九、神经网络如何支持多分类?
- 输出层每个神经元对应一个类别。
- 网络输出是一个概率向量,表示输入属于各类别的概率。
- 常用于 One-vs-All 多分类。