🚀 前言:从单细胞到神经网络帝国
"你的第一个神经元只能做直线分类,但今天我们要用神经元建造一个能画任意复杂曲线的智能画笔!"
上期我们实现了单个神经元,但它连简单的XOR问题都解决不了。本期将用纯Python+NumPy打造深度前馈网络,揭开"深度"的神秘面纱。文末还有动态决策边界可视化,让你亲眼见证神经网络的学习过程!
一、深度前馈网络设计蓝图
1.1 神经网络的三重境界
# 网络结构示例(3层MLP)
network = {
'input_size': 2, # 输入特征维度
'hidden1': 4, # 第一个隐藏层神经元数
'hidden2': 3, # 第二个隐藏层神经元数
'output': 1 # 输出层维度
}
🔥 架构解析:
-
输入层:数据入口(如:房价预测的房屋面积、卧室数)
-
隐藏层:特征加工厂(层数越多,抽象能力越强)
-
输出层:结果出口(分类概率/回归值)
二、从零搭建神经网络(完整代码实现)
2.1 网络初始化:给神经元装上"大脑"
class DeepNeuralNetwork:
def __init__(self, layer_dims):
self.params = {}
for l in range(1, len(layer_dims)):
# He初始化:缓解梯度消失
self.params['W' + str(l)] = np.random.randn(
layer_dims[l], layer_dims[l-1]) * np.sqrt(2./layer_dims[l-1])
self.params['b' + str(l)] = np.zeros((layer_dims[l], 1))
# 示例:创建2-4-3-1网络
dnn = DeepNeuralNetwork([2, 4, 3, 1])
print("第一层权重矩阵形状:", dnn.params['W1'].shape) # (4,2)
2.2 前向传播:数据的奇幻漂流
def relu(Z):
return np.maximum(0, Z)
def sigmoid(Z):
return 1/(1+np.exp(-Z))
def forward_propagation(X, params):
caches = []
A_prev = X
L = len(params) // 2
for l in range(1, L):
W = params['W' + str(l)]
b = params['b' + str(l)]
Z = np.dot(W, A_prev) + b
A = relu(Z)
caches.append((Z, A))
A_prev = A
# 输出层用sigmoid
WL = params['W' + str(L)]
bL = params['b' + str(L)]
ZL = np.dot(WL, A_prev) + bL
AL = sigmoid(ZL)
return AL, caches
# 测试前向传播
X_sample = np.array([[1, -2]]).T # 输入样本
output, _ = forward_propagation(X_sample, dnn.params)
print("网络输出概率:", output[0][0])
2.3 损失函数:AI的错题本
def compute_cost(AL, Y):
m = Y.shape[1]
cost = -np.mean(Y * np.log(AL) + (1-Y)*np.log(1-AL))
return np.squeeze(cost) # 去掉冗余维度
# 示例计算
Y_demo = np.array([[1, 0, 1]]) # 3个样本的标签
AL_demo = np.array([[0.9, 0.2, 0.8]])
print("交叉熵损失:", compute_cost(AL_demo, Y_demo)) # ≈0.07
三、反向传播:误差的逆流之旅
3.1 梯度计算:沿着误差溯源
def relu_derivative(Z):
return Z > 0 # ReLU导数是阶跃函数
def backward_propagation(AL, Y, caches):
grads = {}
L = len(caches) + 1
m = Y.shape[1]
# 输出层梯度
dZL = AL - Y
grads['dW' + str(L)] = np.dot(dZL, caches[-1][1].T) / m
grads['db' + str(L)] = np.sum(dZL, axis=1, keepdims=True) / m
# 隐藏层反向传播
for l in reversed(range(L-1)):
Z, A = caches[l]
dA_prev = np.dot(grads['dW' + str(l+2)].T, dZ_prev)
dZ = dA_prev * relu_derivative(Z)
grads['dW' + str(l+1)] = np.dot(dZ, A_prev.T) / m
grads['db' + str(l+1)] = np.sum(dZ, axis=1, keepdims=True) / m
A_prev = A_prev.T # 更新前一层的激活值
return grads
四、实战:解决XOR难题(动态可视化)
4.1 准备数据:经典非线性问题
# XOR输入输出
X_xor = np.array([[0,0], [0,1], [1,0], [1,1]]).T # (2,4)
Y_xor = np.array([[0, 1, 1, 0]]) # (1,4)
# 决策边界可视化函数
def plot_decision_boundary(model, X, Y):
x_min, x_max = X[0, :].min()-0.5, X[0, :].max()+0.5
y_min, y_max = X[1, :].min()-0.5, X[1, :].max()+0.5
h = 0.01
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model(np.c_[xx.ravel(), yy.ravel()].T)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.scatter(X[0, :], X[1, :], c=Y, cmap=plt.cm.Spectral)
4.2 训练过程:眼见为实的进化
# 训练循环
costs = []
for i in range(10000):
# 前向传播
AL, caches = forward_propagation(X_xor, dnn.params)
# 计算损失
cost = compute_cost(AL, Y_xor)
costs.append(cost)
# 反向传播
grads = backward_propagation(AL, Y_xor, caches)
# 更新参数(学习率0.1)
for l in range(1, L+1):
dnn.params['W' + str(l)] -= 0.1 * grads['dW' + str(l)]
dnn.params['b' + str(l)] -= 0.1 * grads['db' + str(l)]
# 可视化训练结果
plt.plot(costs)
plt.title("损失下降曲线")
plt.xlabel("迭代次数")
plt.ylabel("交叉熵损失")
plot_decision_boundary(lambda x: forward_propagation(x, dnn.params)[0], X_xor, Y_xor)
plt.title("XOR问题的决策边界")
🔥 核心知识点总结
组件 | 作用 | 类比现实 |
---|---|---|
隐藏层 | 特征抽象 | 快递中转站的分拣系统 |
ReLU | 引入非线性 | 快递中转站的分拣系统 |
反向传播 | 误差分配 | 财务核算(找出亏损部门) |
学习率 | 参数更新步长 | 刹车灵敏度 |