news 2026/4/25 15:48:26

吴恩达《深度学习》第一课笔记:我用Python和NumPy手搓了一个神经网络

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
吴恩达《深度学习》第一课笔记:我用Python和NumPy手搓了一个神经网络

用Python和NumPy从零实现神经网络:吴恩达深度学习课实践指南

在咖啡厅里盯着吴恩达教授的《深度学习》课程视频,我反复拖动进度条试图理解那些矩阵运算的含义。直到有一天,我决定关掉视频,打开Jupyter笔记本,用最基础的Python和NumPy库亲手实现一个神经网络——这个决定让我真正理解了反向传播的优雅和向量化的威力。

1. 环境准备与基础概念

工欲善其事,必先利其器。我们需要准备最精简的工具链:

import numpy as np import matplotlib.pyplot as plt

神经网络的核心在于用数学函数模拟生物神经元。一个最简单的神经网络单元可以表示为:

输出 = 激活函数(权重·输入 + 偏置)

这个公式看似简单,却蕴含着几个关键概念:

  • 权重(Weights): 决定每个输入特征的重要性
  • 偏置(Bias): 调整神经元的激活阈值
  • 激活函数: 引入非线性(常用Sigmoid、ReLU等)

初学者常犯的错误是直接使用线性函数作为激活——这会导致网络退化为线性回归,失去"深度"的意义。

2. 实现逻辑回归模型

逻辑回归实际上是单层神经网络,非常适合作为入门案例。我们需要实现三个核心组件:

2.1 Sigmoid激活函数

def sigmoid(z): return 1 / (1 + np.exp(-z))

这个函数的输出范围是(0,1),非常适合二分类问题。它的导数有个优雅的性质:

def sigmoid_derivative(z): return sigmoid(z) * (1 - sigmoid(z))

2.2 前向传播

前向传播就是数据通过网络流动的过程:

def forward_prop(X, W, b): Z = np.dot(W.T, X) + b # 线性部分 A = sigmoid(Z) # 激活部分 return A

2.3 损失函数与梯度计算

二元交叉熵损失函数衡量预测与真实的差距:

def compute_cost(A, Y): m = Y.shape[1] cost = -np.mean(Y * np.log(A) + (1-Y) * np.log(1-A)) return cost

反向传播计算梯度时,初学者常困惑于矩阵维度。记住这个黄金法则:

dW = (1/m) * X · (A-Y).T db = (1/m) * np.sum(A-Y)

3. 构建单隐层神经网络

现在升级到真正的神经网络——包含一个隐藏层。这需要管理两组参数(W1,b1)和(W2,b2)。

3.1 参数初始化

随机初始化打破对称性很重要:

def initialize_parameters(n_x, n_h, n_y): 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)) return {"W1": W1, "b1": b1, "W2": W2, "b2": b2}

3.2 完整的前向传播

def forward_propagation(X, parameters): W1, b1, W2, b2 = parameters['W1'], parameters['b1'], parameters['W2'], parameters['b2'] Z1 = np.dot(W1, X) + b1 A1 = np.tanh(Z1) # 隐藏层使用tanh激活 Z2 = np.dot(W2, A1) + b2 A2 = sigmoid(Z2) # 输出层仍用sigmoid cache = {"Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2} return A2, cache

3.3 反向传播的实现

这是最考验理解的部分,需要计算四个梯度:

def backward_propagation(parameters, cache, X, Y): m = X.shape[1] W2 = parameters['W2'] A1 = cache['A1'] A2 = cache['A2'] dZ2 = A2 - Y dW2 = (1/m) * np.dot(dZ2, A1.T) db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True) dZ1 = np.dot(W2.T, dZ2) * (1 - np.power(A1, 2)) # tanh的导数是1-A^2 dW1 = (1/m) * np.dot(dZ1, X.T) db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True) return {"dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2}

4. 训练过程与可视化

4.1 参数更新

def update_parameters(parameters, grads, learning_rate): W1 = parameters['W1'] - learning_rate * grads['dW1'] b1 = parameters['b1'] - learning_rate * grads['db1'] W2 = parameters['W2'] - learning_rate * grads['dW2'] b2 = parameters['b2'] - learning_rate * grads['db2'] return {"W1": W1, "b1": b1, "W2": W2, "b2": b2}

4.2 训练循环

完整的训练过程需要迭代以下步骤:

  1. 初始化参数
  2. 前向传播计算预测值
  3. 计算损失函数
  4. 反向传播计算梯度
  5. 更新参数
  6. 重复直到收敛
def train(X, Y, n_h, learning_rate=0.01, num_iterations=10000): n_x = X.shape[0] n_y = Y.shape[0] parameters = initialize_parameters(n_x, n_h, n_y) costs = [] for i in range(num_iterations): A2, cache = forward_propagation(X, parameters) cost = compute_cost(A2, Y) grads = backward_propagation(parameters, cache, X, Y) parameters = update_parameters(parameters, grads, learning_rate) if i % 1000 == 0: costs.append(cost) print(f"迭代次数 {i}: 损失值 {cost}") return parameters, costs

4.3 结果可视化

训练完成后,我们可以绘制学习曲线:

plt.plot(costs) plt.ylabel('损失值') plt.xlabel('迭代次数(每1000次)') plt.title(f"学习率 = {learning_rate}") plt.show()

以及决策边界:

def plot_decision_boundary(X, Y, parameters): # 创建网格点 x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1 y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1 h = 0.01 xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) # 预测每个网格点 Z, _ = forward_propagation(np.c_[xx.ravel(), yy.ravel()].T, parameters) Z = Z.reshape(xx.shape) # 绘制等高线和散点 plt.contourf(xx, yy, Z, alpha=0.8) plt.scatter(X[0, :], X[1, :], c=Y.ravel(), edgecolors='k') plt.show()

5. 实战技巧与常见问题

5.1 调试技巧

当网络不收敛时,可以尝试:

  • 梯度检查:比较解析梯度与数值梯度
  • 学习率测试:尝试不同的学习率(0.001, 0.01, 0.1等)
  • 小数据集测试:先在少量数据上过拟合,确保代码正确

5.2 性能优化

  • 向量化:避免Python循环,使用NumPy矩阵运算
  • 内存管理:及时删除大中间变量
  • 提前停止:当验证集误差开始上升时停止训练

5.3 扩展思路

掌握了基础实现后,可以尝试:

  • 添加更多隐藏层实现深度网络
  • 实现不同的激活函数(ReLU, LeakyReLU等)
  • 加入正则化技术(L2, Dropout)
  • 实现更高级的优化器(Adam, RMSprop)

第一次看到自己手写的神经网络在简单的分类任务上达到90%准确率时,那种成就感是看十遍理论推导也无法替代的。建议读者在理解本文代码后,尝试用不同的数据集测试,比如经典的鸢尾花数据集或MNIST数字识别——这才是真正掌握神经网络的开始。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 15:48:25

用SAM做图像分割时,你的提示(点/框)是怎么被模型“看懂”的?

SAM图像分割中的提示编码:点与框如何转化为模型语言 当你用鼠标在图像上轻轻一点或画出一个矩形框,Segment Anything Model(SAM)就能精准识别目标区域完成分割——这看似简单的交互背后,隐藏着复杂的提示编码机制。作为…

作者头像 李华
网站建设 2026/4/25 15:46:46

热键侦探:3步找出抢占你快捷键的“幕后黑手“

热键侦探:3步找出抢占你快捷键的"幕后黑手" 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 想象一下…

作者头像 李华
网站建设 2026/4/25 15:46:43

人工智能之大模型应用 基础入门第一章 人工智能演进与大模型兴起

人工智能之大模型应用 第一章 人工智能演进与大模型兴起 文章目录人工智能之大模型应用**1.1 人工智能演进与大模型兴起:从AI1.0到AI2.0的变迁****1.1.1 什么是AI?****1.1.2 AI1.0时代解析****1.1.2.1 AI1.0的核心定义****1.1.2.2 传统AI1.0代表产品***…

作者头像 李华