本文将带你不依赖任何深度学习框架(如 TensorFlow 或 PyTorch),仅用 NumPy 从头实现一个完整的深层神经网络(Deep Neural Network, DNN)。我们将一步步构建前向传播、反向传播、参数更新等核心模块,并在真实的猫图识别数据集上训练模型——真正“手搓”AI!

🧱 第一步:初始化网络参数
神经网络的“大脑”就是它的参数:权重矩阵 W 和偏置向量 b。我们需要为每一层随机初始化这些参数。
1def initialize_parameters_deep(layer_dims): 2 np.random.seed(1) 3 parameters = {} 4 L = len(layer_dims) 5 6 for l in range(1, L): 7 # 使用 Xavier 初始化(除以 sqrt(前一层神经元数)) 8 parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) / np.sqrt(layer_dims[l-1]) 9 parameters['b' + str(l)] = np.zeros((layer_dims[l], 1)) 10 return parameters 11
- 为什么除以
sqrt(layer_dims[l-1])?
这是为了防止梯度爆炸或消失,让激活值的方差保持稳定(Xavier 初始化)。 - 示例:
layer_dims = [12288, 20, 7, 5, 1]表示输入是 64×64×3=12288 维的图像,网络有 4 层隐藏/输出层。
🔁 第二步:前向传播(Forward Propagation)
前向传播分为两部分:线性变换 + 非线性激活。
2.1 线性部分:Z = W·A + b
1def linear_forward(A, W, b): 2 Z = np.dot(W, A) + b 3 cache = (A, W, b) # 缓存用于反向传播 4 return Z, cache 5
2.2 激活函数:ReLU 或 Sigmoid
1def linear_activation_forward(A_prev, W, b, activation): 2 Z, linear_cache = linear_forward(A_prev, W, b) 3 if activation == "sigmoid": 4 A = sigmoid(Z) 5 elif activation == "relu": 6 A = relu(Z) 7 cache = (linear_cache, Z) 8 return A, cache 9
- 隐藏层用 ReLU:加速训练,缓解梯度消失。
- 输出层用 Sigmoid:将结果压缩到 (0,1),适合二分类。
2.3 整个网络的前向传播
1def L_model_forward(X, parameters): 2 caches = [] 3 A = X 4 L = len(parameters) // 2 # 总层数 5 6 # 前 L-1 层:ReLU 7 for l in range(1, L): 8 A, cache = linear_activation_forward(A, parameters['W'+str(l)], parameters['b'+str(l)], 'relu') 9 caches.append(cache) 10 11 # 最后一层:Sigmoid 12 AL, cache = linear_activation_forward(A, parameters['W'+str(L)], parameters['b'+str(L)], 'sigmoid') 13 caches.append(cache) 14 return AL, caches 15
💰 第三步:计算损失(Cost Function)
我们使用二分类交叉熵损失:
1def compute_cost(AL, Y): 2 m = Y.shape[1] 3 cost = (-1/m) * np.sum(Y * np.log(AL) + (1 - Y) * np.log(1 - AL)) 4 return np.squeeze(cost) 5
⚠️ 实际应用中建议加上
np.clip(AL, 1e-8, 1-1e-8)防止 log(0)。
🔙 第四步:反向传播(Backpropagation)
反向传播的核心思想:链式法则 + 缓存复用。
4.1 线性部分的梯度
1def linear_backward(dZ, cache): 2 A_prev, W, b = cache 3 m = A_prev.shape[1] 4 5 dW = np.dot(dZ, A_prev.T) / m 6 db = np.sum(dZ, axis=1, keepdims=True) / m 7 dA_prev = np.dot(W.T, dZ) 8 9 return dA_prev, dW, db 10
4.2 激活函数的梯度
1def linear_activation_backward(dA, cache, activation): 2 linear_cache, Z = cache 3 if activation == "relu": 4 dZ = relu_backward(dA, Z) 5 elif activation == "sigmoid": 6 dZ = sigmoid_backward(dA, Z) 7 return linear_backward(dZ, linear_cache) 8
4.3 全网络反向传播
1def L_model_backward(AL, Y, caches): 2 grads = {} 3 L = len(caches) 4 Y = Y.reshape(AL.shape) 5 6 # 最后一层(Sigmoid) 7 dAL = -(np.divide(Y, AL) - np.divide(1 - Y, 1 - AL)) 8 current_cache = caches[-1] 9 grads["dA"+str(L-1)], grads["dW"+str(L)], grads["db"+str(L)] = \ 10 linear_activation_backward(dAL, current_cache, "sigmoid") 11 12 # 前面各层(ReLU) 13 for l in reversed(range(1, L)): 14 current_cache = caches[l-1] 15 dA_prev, dW, db = linear_activation_backward(grads["dA"+str(l)], current_cache, "relu") 16 grads["dA"+str(l-1)] = dA_prev 17 grads["dW"+str(l)] = dW 18 grads["db"+str(l)] = db 19 20 return grads 21
🔄 第五步:参数更新(Gradient Descent)
有了梯度,就可以用梯度下降法更新参数:
1def update_parameters(parameters, grads, learning_rate): 2 L = len(parameters) // 2 3 for l in range(1, L + 1): 4 parameters["W" + str(l)] -= learning_rate * grads["dW" + str(l)] 5 parameters["b" + str(l)] -= learning_rate * grads["db" + str(l)] 6 return parameters 7
🏗️ 第六步:整合训练流程
把所有模块组装成一个完整的训练函数:
1def dnn_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=2000, print_cost=True): 2 parameters = initialize_parameters_deep(layers_dims) 3 costs = [] 4 5 for i in range(num_iterations): 6 AL, caches = L_model_forward(X, parameters) 7 cost = compute_cost(AL, Y) 8 grads = L_model_backward(AL, Y, caches) 9 parameters = update_parameters(parameters, grads, learning_rate) 10 11 if print_cost and i % 100 == 0: 12 print(f"训练 {i} 次后成本是: {cost:.6f}") 13 costs.append(cost) 14 15 plt.plot(costs) 16 plt.title(f"Learning rate = {learning_rate}") 17 plt.xlabel("Iterations (per hundreds)") 18 plt.ylabel("Cost") 19 plt.show() 20 21 return parameters 22
🐱 第七步:在真实数据上训练
我们使用经典的 猫图识别数据集(来自 Coursera Deep Learning 课程):
1# 加载并预处理数据 2train_x_orig, train_y, test_x_orig, test_y, classes = load_data() 3train_x = train_x_orig.reshape(train_x_orig.shape[0], -1).T / 255. 4test_x = test_x_orig.reshape(test_x_orig.shape[0], -1).T / 255. 5 6# 构建 4 层网络:12288 → 20 → 7 → 5 → 1 7layers_dims = [12288, 20, 7, 5, 1] 8parameters = dnn_model(train_x, train_y, layers_dims, num_iterations=2000, print_cost=True) 9
🎯 总结
通过这篇文章,我们亲手实现了:
- 参数初始化
- 前向传播(含 ReLU/Sigmoid)
- 成本计算
- 反向传播(链式求导 + 缓存机制)
- 梯度下降更新
- 完整训练循环
没有调用任何高级 API,一切尽在掌握之中!
这不仅加深了对神经网络内部机制的理解,也为后续学习更复杂的模型(如 CNN、RNN)打下坚实基础。
💡 真正的深度学习,始于手搓一行代码。
《深度学习:从零开始手搓一个深层神经网络》 是转载文章,点击查看原文。