深度学习入门【神经网络基本理论】
深度学习入门【神经网络基本理论】
前言
经过前面的实战,我们已经掌握了线性回归和逻辑回归。逻辑回归靠着 Sigmoid 函数和人为构造的高次特征(比如把 (x) 手动变成 (x^2, x^3)),确实能画出一条弯曲的决策边界来“勉强”对付一些非线性数据。
但是,这种方法有一个致命缺陷:它依赖“人工特征工程”。
如果我们要识别的是几千张像素极多、极其复杂的图片(比如区分猫和狗),我们根本没有办法靠人脑去想出“应该加什么复杂的高阶特征”才能把它分开。
于是,我们引入了神经网络。
神经网络并不会改变“梯度下降更新权重”的底层逻辑。它的革命性在于:它把“特征提取”和“画决策边界”这两件事,全部交给了机器自己。 通过隐藏层的“激活函数”,机器能够自动把原始数据弯折、扭曲,组合出极其复杂的形状。
本文将不依赖任何深度学习框架,从零开始推导一个包含“单隐藏层”的神经网络,彻底揭示**“它是如何自动把直线变弯曲”**的数学原理。
一、神经网络的结构组成
1.1 神经元模型
神经网络的基本单元是“神经元”。一个标准的神经元运算分为两步:
- 线性加权求和:Z = W * X + b
- 非线性激活:A = g(Z)
常用的激活函数有以下几种,它们的特性、优缺点及适用场景对比如下:
| 激活函数 | 公式 | 输出范围 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| Sigmoid | σ(x) = 1 / (1 + e^{-x}) | (0, 1) | 输出可解释为概率;处处可导 | 容易梯度消失;输出非零均值,收敛慢 | 二分类输出层 |
| tanh | tanh(x) = (e^x - e^{-x}) / (e^x + e^{-x}) | (-1, 1) | 零均值输出,收敛更快;形状与 Sigmoid 类似 | 仍存在梯度消失问题 | 隐藏层(浅层网络适用) |
| ReLU | ReLU(x) = max(0, x) | [0, +∞) | 计算极快;有效缓解梯度消失;稀疏激活 | x < 0 时梯度为 0,可能导致神经元“死亡” | 隐藏层(现代深层网络首选) |
1.2 单隐藏层网络架构
本文推导的网络由 输入层、隐藏层(1层) 和 输出层 组成。我们定义以下符号:
- X:输入矩阵(特征数 n_x,样本数 m)。维度:(n_x, m)
- y:真实标签(二分类任务,维度 1 * m)。
- (W[1], b[1]):输入层到隐藏层的权重和偏置。W[1] 维度:(n_h, n_x);b[1] 维度:(n_h, 1)
- (W[2], b[2]):隐藏层到输出层的权重和偏置。W[2] 维度:(1, n_h);b[2] 维度:(1, 1)
- n_h:隐藏层神经元的数量(这是一个超参数)。
二、前向传播
前向传播是指数据从输入层,经过层层计算,最终得出预测值的过程。
2.1 隐藏层计算(提取特征)
首先,我们将输入 X 传递给隐藏层,进行线性变换:
Z[1] = W[1] * X + b[1]
此时得到的 Z[1] 是一条“绝对笔直的线”。为了让它能够弯曲,我们必须引入激活函数(Activation Function)。这里我们选用 tanh 函数:
A[1] = tanh(Z[1])
为什么隐藏层必须要有激活函数?
如果没有激活函数,即 A[1] = Z[1],那么数学上经过两层推导,神经网络最终会变成:
A[2] = (W[2] * W[1]) * X + (W[2] * b[1] + b[2])
这依然是一个单纯的线性方程。无论你叠加多少层,没有激活函数,神经网络就等价于一个线性回归模型,绝对无法处理非线性问题。
2.2 输出层计算(得出概率)
隐藏层提取的特征 A[1] 被传递给输出层:
Z[2] = W[2] * A[1] + b[2]
因为我们完成的是二分类任务(输出 0 或 1),所以输出层需要使用 Sigmoid 函数将结果压缩到 0 到 1 之间:
A[2] = sigma(Z[2])
2.3 计算损失(Cost Function)
神经网络衡量预测误差的方法依然是对数损失函数(交叉熵):
J = - (1/m) * sum( y * log(A[2]) + (1-y) * log(1-A[2]) )
目标就是通过优化,让这个 J 的值最小。
三、反向传播
如果说前向传播是“做预测”,那么反向传播(Backpropagation)就是“找原因”。
反向传播的核心逻辑是链式法则(Chain Rule)。它把输出层的计算误差,像倒放一样一层一层回传给前面的权重,告诉模型:“为了降低误差,你应该往哪个方向修改 W 和 b”。
3.1 输出层的梯度计算
我们先计算损失函数对输出层线性输出 Z[2] 的偏导:
dZ[2] = A[2] - y
(这是数学推导中一个极其优雅的简化结果,等于“预测值减去真实值”)。
由此可以推导出 W[2] 和 b[2] 的更新梯度:
dW[2] = (1/m) * dZ[2] * (A[1])^T
db[2] = (1/m) * sum(dZ[2])
3.2 隐藏层的梯度计算(误差回传)
隐藏层的神经元无法直接接触真实标签,它怎么知道自己的权重该不该改?答案是:它将输出层传回来的误差“分享”给自己。
从输出层反向传回的误差为:
dA[1] = (W[2])^T * dZ[2]
接下来,误差要穿过隐藏层的激活函数。由于激活函数是 tanh,其导数为 1 - tanh(z)^2,所以隐藏层最终的误差项为:
dZ[1] = dA[1] * (1 - (A[1])^2)
最后,求出隐藏层参数的梯度:
dW[1] = (1/m) * dZ[1] * X^T
db[1] = (1/m) * sum(dZ[1])
四、参数更新
求出了每一层的梯度后,我们使用和逻辑回归完全一样的梯度下降公式来更新参数:
W[2] = W[2] - alpha * dW[2]
b[2] = b[2] - alpha * db[2]
W[1] = W[1] - alpha * dW[1]
b[1] = b[1] - alpha * db[1]
其中 alpha 是学习率(步长)。重复执行前向传播 -> 反向传播 -> 梯度下降的过程,直到损失函数不再下降,模型就训练好了。
总结
通过这次数学推导,我们可以得出神经网络的四个核心真相:
1. 激活函数是“非线性的灵魂”:
如果没有 tanh、ReLU 或 Sigmoid 这类激活函数,无论你的神经网络叠加多少层,它在数学上都等价于一个简单的线性回归,永远无法弯折出曲线,也永远无法处理现实世界复杂的数据。
2. 前向传播是做“特征变形”:
数据在隐藏层中经过加权求和与非线性激活,被不断折叠、扭曲,从原本难以区分的原始像素或特征,变成能被输出层轻松切分的高维形态。
3. 反向传播是做“误差调查”:
反向传播的数学根基是链式法则。它把输出层的误差,顺着连接权重一层一层倒传回输入层,精确告诉每一个神经元:“为了降低总误差,你的参数该往哪个方向调整”。
4. 梯度下降是做“参数修复”:
拿着反向传播查出的梯度方向,乘以学习率,更新所有权重和偏置。只有完成这一步,神经网络才算真正完成了一次有效学习。
深度学习框架没有魔法。 PyTorch 和 TensorFlow 等工具,只不过是用极其高效的矩阵运算替我们自动完成了上述繁琐的求导和更新过程。只要理解了今天的四大核心真相,我们就掌握了所有深度网络(CNN、RNN、Transformer)最底层的数学基因。
附录:极简核心代码
如果上面的推导让你觉得有点抽象,不用担心。下面这段极简的 Numpy 代码,把这个神经网络的“一次训练轮回”原汁原味地还原了出来。后面我们将逐步走进实战。
import numpy as np
# 1. 随机初始化(不能全为0)
W1 = np.random.randn(n_h, n_x) * 0.01
b1 = np.zeros((n_h, 1))
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros((n_y, 1))
# 2. 开始迭代训练
for i in range(iterations):
# ========= 前向传播 =========
Z1 = np.dot(W1, X) + b1
A1 = np.tanh(Z1) # 隐藏层激活
Z2 = np.dot(W2, A1) + b2
A2 = 1 / (1 + np.exp(-Z2)) # 输出层激活(Sigmoid)
# ========= 计算损失 =========
loss = - (1/m) * np.sum(y * np.log(A2) + (1-y) * np.log(1-A2))
# ========= 反向传播 =========
dZ2 = A2 - y # 输出层误差
dW2 = (1/m) * np.dot(dZ2, A1.T)
db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True)
dA1 = np.dot(W2.T, dZ2) # 误差传回隐藏层
dZ1 = dA1 * (1 - np.power(A1, 2)) # tanh 的导数
dW1 = (1/m) * np.dot(dZ1, X.T)
db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True)
# ========= 梯度下降更新参数 =========
W1 = W1 - alpha * dW1
b1 = b1 - alpha * db1
W2 = W2 - alpha * dW2
b2 = b2 - alpha * db2
更多推荐
所有评论(0)