Back to notes
Field notebook
/
11:05:36
/
Note

深度学习笔记

Course 1:神经网络与深度学习 学习目标 :从零开始理解神经网络的核心原理,掌握前向传播与反向传播的数学推导,能够用纯 NumPy 搭建一个任意深度的神经网络。 目录 第一章:深度学习引言 第一章深度学习引言 第二章:神经网络编程基础——逻辑回归 第二章神经网络编程基础逻辑回归 第三章:浅层神经网络 第三章浅层神经网络 第四章:深层神经网络 第四章深层神经网络 本课小结与关键公式速查 本课小结与关键公式速查 第一章:深度学习引言…

Reading signalRoute: 深度学习47 sections3 notes nearby
Follow 深度学习 route

At a glance

Reading effort and structure before you settle in.

Reading time
34 min
Images
1
Views
413

Reader briefing

Primary route: 深度学习47 sections
Section 1 of 5

Reading deck

Quiet body34 min47 sections深度学习 route

Course 1:神经网络与深度学习

学习目标:从零开始理解神经网络的核心原理,掌握前向传播与反向传播的数学推导,能够用纯 NumPy 搭建一个任意深度的神经网络。


目录


第一章:深度学习引言

1.1 什么是神经网络?

直觉理解

想象你是一个房产中介,客户问你:"这套房子值多少钱?"你脑子里会自动考虑面积、地段、楼层等因素,然后给出一个预估价格。神经网络做的事情本质上是一样的——它是一个"从输入到输出的函数",只不过这个函数的参数是通过数据自动学习的。

最简单的神经网络就是一个单神经元

输入 x (面积) --→ [神经元] --→ 输出 y (价格)

这个神经元内部做的事情:

  1. 计算 z=wx+bz = wx + b(线性变换)
  2. 通过激活函数得到 y^=max(0,z)\hat{y} = \max(0, z)(ReLU 激活)

为什么用 max(0,z)\max(0, z) 而不是直接用 zz?因为房价不能为负数!这个 max(0,z)\max(0, z) 函数叫做 ReLU(Rectified Linear Unit,修正线性单元),它是深度学习中最常用的激活函数。

从单神经元到神经网络

当输入特征变多(面积、卧室数、邮编、财富水平...),我们可以把多个神经元组合起来:

graph LR
    x1[面积] --> h1((家庭大小))
    x2[卧室数] --> h1
    x1 --> h2((步行适宜度))
    x3[邮编] --> h2
    x3 --> h3((学区质量))
    x4[财富水平] --> h3
    h1 --> y((预测价格))
    h2 --> y
    h3 --> y

中间的 h1,h2,h3h_1, h_2, h_3 就是隐藏层神经元。有趣的是,我们不需要手动告诉网络"用面积和卧室数来判断家庭大小"——给它足够的数据,它会自己学到这些中间表示。这就是神经网络的魅力所在。

1.2 监督学习的类型

深度学习近年来最大的实际价值来自监督学习(Supervised Learning)——给定输入 XX 和标签 YY,学习映射 XYX \to Y

应用场景输入 XX输出 YY网络类型
房价预测房屋特征价格标准 NN
广告点击预测广告+用户信息是否点击(0/1)标准 NN
图片分类图像像素类别标签(1~1000)CNN(卷积神经网络)
语音识别音频片段文字转写RNN(循环神经网络)
机器翻译英文文本中文文本RNN / Transformer
自动驾驶图像+雷达其他车辆位置混合架构

经验法则

  • 结构化数据(表格、数据库)→ 标准全连接网络
  • 图像数据 → CNN
  • 序列数据(文本、音频、时间序列)→ RNN / Transformer

1.3 为什么深度学习现在才火起来?

深度学习的核心想法(多层神经网络)在 1980 年代就存在了,为什么直到 2012 年才爆发?三个驱动力:

graph TD
    A[深度学习的崛起] --> B[📊 数据规模]
    A --> C[💻 计算能力]
    A --> D[🧮 算法创新]
    B --> B1[互联网 + 移动设备<br>产生海量标注数据]
    C --> C1[GPU / TPU 大规模并行计算]
    D --> D1[ReLU 替代 Sigmoid<br>加速梯度下降收敛]

关键洞察:在数据量较小的时候,传统机器学习(SVM、随机森林等)可能表现得和神经网络一样好甚至更好。但随着数据量增大,大型神经网络的性能会持续提升,而传统算法会趋于平坦。

Performance=f(数据量,模型大小,算法效率)\text{Performance} = f(\text{数据量}, \text{模型大小}, \text{算法效率})

这就是为什么在大数据时代,深度学习成为了王者。


第二章:神经网络编程基础——逻辑回归

逻辑回归(Logistic Regression)不只是一个简单的分类算法——它是理解整个神经网络的基石。把逻辑回归彻底搞懂,神经网络就只是"多个逻辑回归的堆叠"。

2.1 二分类问题与符号约定

问题定义:给定一张图片,判断是不是猫。输出 y{0,1}y \in \{0, 1\}

符号约定(贯穿整个课程,请牢记):

符号含义维度
mm训练样本数量标量
nxn_x输入特征维度标量
x(i)x^{(i)}ii 个训练样本(nx,1)(n_x, 1)
XX输入矩阵(所有样本列拼接)(nx,m)(n_x, m)
y(i)y^{(i)}ii 个样本标签标量
YY标签向量(1,m)(1, m)

图像表示:一张 64×64 的 RGB 图像会被展平成一个 nx=64×64×3=12288n_x = 64 \times 64 \times 3 = 12288 维的向量。

为什么 XX(nx,m)(n_x, m) 而不是 (m,nx)(m, n_x) 这是深度学习的约定——每个样本是一列。这样做的好处是:WTXW^T X 可以一次性计算所有样本的线性变换,代码更简洁。

2.2 逻辑回归模型

目标:学习参数 wwbb,使得 y^=P(y=1x)\hat{y} = P(y=1 \mid x)

第一步:线性变换

z=wTx+bz = w^T x + b

其中 wRnxw \in \mathbb{R}^{n_x}bRb \in \mathbb{R}。但是 zz 的范围是 (,+)(-\infty, +\infty),而我们需要概率值在 [0,1][0, 1] 之间。

第二步:Sigmoid 挤压

y^=σ(z)=11+ez\hat{y} = \sigma(z) = \frac{1}{1 + e^{-z}}

Sigmoid 函数的关键性质:

  • z+z \to +\infty 时,σ(z)1\sigma(z) \to 1
  • zz \to -\infty 时,σ(z)0\sigma(z) \to 0
  • z=0z = 0 时,σ(z)=0.5\sigma(z) = 0.5
  • 导数σ(z)=σ(z)(1σ(z))\sigma'(z) = \sigma(z)(1 - \sigma(z))(后面反向传播要用!)
import numpy as np

def sigmoid(z):
    """Sigmoid 激活函数"""
    return 1 / (1 + np.exp(-z))

2.3 损失函数与代价函数

损失函数(Loss Function)——衡量单个样本的预测好坏:

L(y^,y)=[ylog(y^)+(1y)log(1y^)]L(\hat{y}, y) = -\left[ y \log(\hat{y}) + (1-y) \log(1 - \hat{y}) \right]

直觉理解

  • y=1y = 1 时,L=log(y^)L = -\log(\hat{y}),要让 LL 最小,就要让 y^\hat{y} 尽可能大(接近 1)
  • y=0y = 0 时,L=log(1y^)L = -\log(1 - \hat{y}),要让 LL 最小,就要让 y^\hat{y} 尽可能小(接近 0)

为什么不用均方误差 (y^y)2(\hat{y} - y)^2 因为当 y^=σ(z)\hat{y} = \sigma(z) 时,MSE 是非凸的,梯度下降容易陷入局部最优。而交叉熵损失是凸函数,保证能找到全局最优。

代价函数(Cost Function)——衡量所有样本的平均损失:

J(w,b)=1mi=1mL(y^(i),y(i))=1mi=1m[y(i)log(y^(i))+(1y(i))log(1y^(i))]J(w, b) = \frac{1}{m} \sum_{i=1}^{m} L(\hat{y}^{(i)}, y^{(i)}) = -\frac{1}{m} \sum_{i=1}^{m} \left[ y^{(i)} \log(\hat{y}^{(i)}) + (1-y^{(i)}) \log(1 - \hat{y}^{(i)}) \right]

2.4 梯度下降

直觉:想象你站在一座山上(代价函数的曲面),闭着眼睛想要走到最低点。策略很简单——每一步都沿着最陡峭的方向往下走。

更新规则

w:=wαJww := w - \alpha \frac{\partial J}{\partial w} b:=bαJbb := b - \alpha \frac{\partial J}{\partial b}

其中 α\alpha学习率(Learning Rate),控制每一步走多远。

  • α\alpha 太大 → 步子迈太大,可能越过最低点,来回震荡
  • α\alpha 太小 → 步子太小,收敛极慢
  • 通常从 0.01 开始尝试

2.5 计算图与反向传播

计算图是理解反向传播的关键工具。以逻辑回归为例(单个样本):

前向传播(从左到右):
x, w, b → z = w^Tx + b → a = σ(z) → L(a, y)

反向传播(从右到左,利用链式法则):
dL/da → dL/dz → dL/dw, dL/db

逐步推导

Step 1La\frac{\partial L}{\partial a}(输出对激活值的导数)

La=ya+1y1a\frac{\partial L}{\partial a} = -\frac{y}{a} + \frac{1-y}{1-a}

Step 2Lz\frac{\partial L}{\partial z}(利用链式法则 + sigmoid 导数)

Lz=Laaz=ay\frac{\partial L}{\partial z} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z} = a - y

这个结果非常简洁优美!dz=aydz = a - y 就是"预测值减去真实值"。

Step 3Lw\frac{\partial L}{\partial w}Lb\frac{\partial L}{\partial b}

Lw=xdz=x(ay)\frac{\partial L}{\partial w} = x \cdot dz = x(a - y) Lb=dz=ay\frac{\partial L}{\partial b} = dz = a - y

整个训练集的梯度(取平均):

Jw=1mi=1mx(i)(a(i)y(i))\frac{\partial J}{\partial w} = \frac{1}{m} \sum_{i=1}^{m} x^{(i)}(a^{(i)} - y^{(i)}) Jb=1mi=1m(a(i)y(i))\frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^{m} (a^{(i)} - y^{(i)})

2.6 向量化:告别 for 循环

核心原则:在深度学习中,显式的 for 循环是性能杀手。NumPy 的向量化运算利用了 CPU/GPU 的 SIMD 指令,速度快几百倍。

for 循环版本(慢)

# 不要这样写!
z = 0
for i in range(n_x):
    z += w[i] * x[i]
z += b

向量化版本(快)

# 要这样写!
z = np.dot(w.T, x) + b

Benchmark 对比

import time

n = 1000000
a = np.random.rand(n)
b = np.random.rand(n)

# for 循环
tic = time.time()
c = 0
for i in range(n):
    c += a[i] * b[i]
print(f"for 循环: {(time.time()-tic)*1000:.1f} ms")

# 向量化
tic = time.time()
c = np.dot(a, b)
print(f"向量化:  {(time.time()-tic)*1000:.1f} ms")

# 典型结果:for 循环 ~500ms,向量化 ~1ms,快约 500 倍!

逻辑回归的完全向量化

前向传播:

Z=wTX+bshape: (1, m)Z = w^T X + b \quad \text{shape: (1, m)} A=σ(Z)shape: (1, m)A = \sigma(Z) \quad \text{shape: (1, m)}

反向传播:

dZ=AYshape: (1, m)dZ = A - Y \quad \text{shape: (1, m)} dw=1mXdZTshape: (n_x, 1)dw = \frac{1}{m} X \cdot dZ^T \quad \text{shape: (n\_x, 1)} db=1mdZ标量db = \frac{1}{m} \sum dZ \quad \text{标量}

参数更新:

w:=wαdww := w - \alpha \cdot dw b:=bαdbb := b - \alpha \cdot db

注意:整个过程只需要一个外层 for 循环——迭代次数的循环,而没有遍历样本的 for 循环。

2.7 Python 广播机制与常见陷阱

广播(Broadcasting) 是 NumPy 自动扩展维度以匹配运算的机制:

# (4,1) + (1,3) → (4,3):自动复制行和列
A = np.array([[1],[2],[3],[4]])  # shape (4,1)
B = np.array([[10, 20, 30]])     # shape (1,3)
C = A + B  # shape (4,3)
# [[11, 21, 31],
#  [12, 22, 32],
#  [13, 23, 33],
#  [14, 24, 34]]

广播规则:从右向左对齐维度,如果某个维度是 1 或不存在,就自动扩展。

常见陷阱:Rank-1 数组

# 危险!这不是列向量也不是行向量
a = np.random.randn(5)
print(a.shape)       # (5,) —— rank-1 array
print(a.T.shape)     # (5,) —— 转置后还是一样!
print(np.dot(a, a.T))  # 得到标量而不是矩阵!

# 安全做法:总是显式指定维度
a = np.random.randn(5, 1)  # 列向量 (5,1)
print(a.shape)       # (5, 1)
print(a.T.shape)     # (1, 5)
print(np.dot(a, a.T))  # 得到 (5,5) 矩阵 ✓

最佳实践

# 在关键位置加 assert 检查维度
assert w.shape == (n_x, 1), f"Expected ({n_x}, 1), got {w.shape}"
assert X.shape[0] == n_x, f"Expected first dim {n_x}, got {X.shape[0]}"

# 如果不确定,用 reshape 强制指定
a = np.random.randn(5)
a = a.reshape(5, 1)  # 确保是列向量

第三章:浅层神经网络

从逻辑回归(0 个隐藏层)到 1 个隐藏层——这一小步,是从线性模型到非线性模型的一大步。

3.1 神经网络的表示

graph LR
    subgraph 输入层 Layer 0
        x1[x₁]
        x2[x₂]
        x3[x₃]
    end
    subgraph 隐藏层 Layer 1
        h1((a₁⁽¹⁾))
        h2((a₂⁽¹⁾))
        h3((a₃⁽¹⁾))
        h4((a₄⁽¹⁾))
    end
    subgraph 输出层 Layer 2
        o1((a⁽²⁾ = ŷ))
    end
    x1 --> h1 & h2 & h3 & h4
    x2 --> h1 & h2 & h3 & h4
    x3 --> h1 & h2 & h3 & h4
    h1 --> o1
    h2 --> o1
    h3 --> o1
    h4 --> o1

层的编号约定

  • 输入层 = 第 0 层(不计入网络层数)
  • 隐藏层 = 第 1 层
  • 输出层 = 第 2 层
  • 这是一个 2 层神经网络(有 1 个隐藏层)

参数符号

  • W[l]W^{[l]}:第 ll 层的权重矩阵
  • b[l]b^{[l]}:第 ll 层的偏置向量
  • a[l]a^{[l]}:第 ll 层的激活值

3.2 前向传播公式

单个样本的前向传播

z[1]=W[1]x+b[1]z^{[1]} = W^{[1]} x + b^{[1]} a[1]=g[1](z[1])a^{[1]} = g^{[1]}(z^{[1]}) z[2]=W[2]a[1]+b[2]z^{[2]} = W^{[2]} a^{[1]} + b^{[2]} a[2]=g[2](z[2])=σ(z[2])a^{[2]} = g^{[2]}(z^{[2]}) = \sigma(z^{[2]})

向量化(所有样本)

Z[1]=W[1]X+b[1]Z^{[1]} = W^{[1]} X + b^{[1]} A[1]=g[1](Z[1])A^{[1]} = g^{[1]}(Z^{[1]}) Z[2]=W[2]A[1]+b[2]Z^{[2]} = W^{[2]} A^{[1]} + b^{[2]} A[2]=σ(Z[2])A^{[2]} = \sigma(Z^{[2]})

矩阵维度速查(设输入 nx=3n_x = 3,隐藏层 nh=4n_h = 4,输出 ny=1n_y = 1,样本数 mm):

矩阵维度计算方式
W[1]W^{[1]}(4,3)(4, 3)(nh,nx)(n_h, n_x)
b[1]b^{[1]}(4,1)(4, 1)(nh,1)(n_h, 1)
Z[1]Z^{[1]}(4,m)(4, m)(nh,m)(n_h, m)
A[1]A^{[1]}(4,m)(4, m)(nh,m)(n_h, m)
W[2]W^{[2]}(1,4)(1, 4)(ny,nh)(n_y, n_h)
b[2]b^{[2]}(1,1)(1, 1)(ny,1)(n_y, 1)
Z[2]Z^{[2]}(1,m)(1, m)(ny,m)(n_y, m)
A[2]A^{[2]}(1,m)(1, m)(ny,m)(n_y, m)

维度记忆技巧W[l]W^{[l]} 的维度是"本层 × 前一层",即 (n[l],n[l1])(n^{[l]}, n^{[l-1]})

3.3 激活函数大全

函数公式导数适用场景优点缺点
Sigmoid11+ez\frac{1}{1+e^{-z}}a(1a)a(1-a)二分类输出层输出范围 (0,1)梯度消失;输出非零中心
Tanhezezez+ez\frac{e^z - e^{-z}}{e^z + e^{-z}}1a21 - a^2隐藏层输出零中心化 (1,1)(-1,1)仍有梯度消失问题
ReLUmax(0,z)\max(0, z){0z<01z0\begin{cases} 0 & z < 0 \\ 1 & z \geq 0 \end{cases}隐藏层默认首选计算快;缓解梯度消失"死神经元"问题
Leaky ReLUmax(0.01z,z)\max(0.01z, z){0.01z<01z0\begin{cases} 0.01 & z < 0 \\ 1 & z \geq 0 \end{cases}隐藏层避免死神经元多一个超参数

代码实现

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

def tanh(z):
    return np.tanh(z)

def relu(z):
    return np.maximum(0, z)

def leaky_relu(z, alpha=0.01):
    return np.maximum(alpha * z, z)

导数实现(反向传播要用):

def sigmoid_backward(dA, Z):
    A = sigmoid(Z)
    return dA * A * (1 - A)

def relu_backward(dA, Z):
    dZ = np.array(dA, copy=True)
    dZ[Z <= 0] = 0
    return dZ

3.4 为什么需要非线性激活函数?

数学证明:如果所有层都用线性激活函数 g(z)=zg(z) = z,那么:

a[2]=W[2](W[1]x+b[1])+b[2]=(W[2]W[1])x+(W[2]b[1]+b[2])=Wx+ba^{[2]} = W^{[2]}(W^{[1]}x + b^{[1]}) + b^{[2]} = (W^{[2]}W^{[1]})x + (W^{[2]}b^{[1]} + b^{[2]}) = W'x + b'

无论堆叠多少层,最终都等价于一个线性变换!隐藏层完全没有意义。

结论:非线性激活函数是神经网络能够学习复杂函数的根本原因。没有非线性,深层网络退化为逻辑回归。

唯一的例外:输出层在做回归任务时可以用线性激活(预测任意实数值)。

3.5 反向传播完整推导

目标:计算 dW[1],db[1],dW[2],db[2]dW^{[1]}, db^{[1]}, dW^{[2]}, db^{[2]}

输出层(第 2 层)

dZ[2]=A[2]Yshape: (1, m)dZ^{[2]} = A^{[2]} - Y \quad \text{shape: (1, m)} dW[2]=1mdZ[2]A[1]Tshape: (1, n_h)dW^{[2]} = \frac{1}{m} dZ^{[2]} {A^{[1]}}^T \quad \text{shape: (1, n\_h)} db[2]=1maxis=1dZ[2]shape: (1, 1)db^{[2]} = \frac{1}{m} \sum_{axis=1} dZ^{[2]} \quad \text{shape: (1, 1)}

隐藏层(第 1 层)

dZ[1]=W[2]TdZ[2]g[1](Z[1])shape: (n_h, m)dZ^{[1]} = {W^{[2]}}^T dZ^{[2]} \ast g'^{[1]}(Z^{[1]}) \quad \text{shape: (n\_h, m)} dW[1]=1mdZ[1]XTshape: (n_h, n_x)dW^{[1]} = \frac{1}{m} dZ^{[1]} X^T \quad \text{shape: (n\_h, n\_x)} db[1]=1maxis=1dZ[1]shape: (n_h, 1)db^{[1]} = \frac{1}{m} \sum_{axis=1} dZ^{[1]} \quad \text{shape: (n\_h, 1)}

其中 \ast 表示逐元素乘法(element-wise),g[1]g'^{[1]} 是第 1 层激活函数的导数。

反向传播的通用模式(请牢记!):

dZ[l]=dA[l]g[l](Z[l])dZ^{[l]} = dA^{[l]} \ast g'^{[l]}(Z^{[l]}) dW[l]=1mdZ[l]A[l1]TdW^{[l]} = \frac{1}{m} dZ^{[l]} {A^{[l-1]}}^T db[l]=1maxis=1dZ[l]db^{[l]} = \frac{1}{m} \sum_{axis=1} dZ^{[l]} dA[l1]=W[l]TdZ[l]dA^{[l-1]} = {W^{[l]}}^T dZ^{[l]}

这四个公式是一切反向传播的核心,从 2 层到 100 层,每一层都是重复这个模式。

3.6 随机初始化

问题:如果把所有权重初始化为 0 会怎样?

# 错误的初始化!
W = np.zeros((n_h, n_x))

答案:同一层的所有神经元会学到完全相同的东西!这叫对称性问题(Symmetry Problem)

原因:如果 W[1]W^{[1]} 所有行相同,那么 a[1]a^{[1]} 的每个元素也相同 → dW[1]dW^{[1]} 的每行也相同 → 更新后 W[1]W^{[1]} 仍然每行相同。无论训练多久,所有隐藏单元永远做同样的事。

正确做法:随机初始化 + 小权重

W1 = np.random.randn(n_h, n_x) * 0.01  # 乘 0.01 保持值较小
b1 = np.zeros((n_h, 1))                  # b 可以初始化为 0
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros((n_y, 1))

为什么乘 0.01? 如果权重太大,zz 值会很大,sigmoid/tanh 的导数会趋近于 0(梯度消失),训练很慢。后续课程会学到更好的初始化方法(He 初始化、Xavier 初始化)。


第四章:深层神经网络

从 2 层到 LL 层——深层神经网络的力量来自层级化的特征学习

4.1 为什么深层更好?

直觉:层级化特征学习

以人脸识别为例,深层网络会自动学习这样的层级结构:

第 1 层 → 检测边缘(水平线、垂直线、对角线)
第 2 层 → 组合边缘 → 检测局部特征(眼睛、鼻子、嘴巴的部件)
第 3 层 → 组合部件 → 检测完整的人脸
graph LR
    A[像素] -->|第1层| B[边缘/纹理]
    B -->|第2层| C[局部特征<br>眼/鼻/嘴]
    C -->|第3层| D[人脸]

类似的层级在其他领域

  • 语音识别:音素 → 音节 → 词 → 句子
  • 自然语言:字符 → 词 → 短语 → 句子 → 段落

电路理论的论据:存在一些函数,用深层网络(O(logn)O(\log n) 个神经元)就能表示,但用浅层网络需要指数级(O(2n)O(2^n))个神经元。例如,计算 nn 个变量的异或(XOR),深层网络只需 O(logn)O(\log n) 层,每层常数个神经元。

4.2 深层网络的符号约定

符号含义
LL网络总层数(不含输入层)
n[l]n^{[l]}ll 层的神经元数量
a[l]a^{[l]}ll 层的激活值
W[l]W^{[l]}ll 层的权重,shape: (n[l],n[l1])(n^{[l]}, n^{[l-1]})
b[l]b^{[l]}ll 层的偏置,shape: (n[l],1)(n^{[l]}, 1)

输入a[0]=Xa^{[0]} = X输出Y^=a[L]\hat{Y} = a^{[L]}

4.3 通用前向传播

对于第 ll 层(l=1,2,,Ll = 1, 2, \dots, L):

Z[l]=W[l]A[l1]+b[l]Z^{[l]} = W^{[l]} A^{[l-1]} + b^{[l]} A[l]=g[l](Z[l])A^{[l]} = g^{[l]}(Z^{[l]})
def L_model_forward(X, parameters):
    """L 层前向传播"""
    caches = []
    A = X
    L = len(parameters) // 2  # 参数字典包含 W1,b1,...,WL,bL
    
    # 前 L-1 层使用 ReLU
    for l in range(1, L):
        A_prev = A
        W = parameters[f'W{l}']
        b = parameters[f'b{l}']
        Z = np.dot(W, A_prev) + b
        A = np.maximum(0, Z)  # ReLU
        caches.append((A_prev, W, b, Z))
    
    # 第 L 层使用 Sigmoid(二分类)
    WL = parameters[f'W{L}']
    bL = parameters[f'b{L}']
    ZL = np.dot(WL, A) + bL
    AL = 1 / (1 + np.exp(-ZL))  # Sigmoid
    caches.append((A, WL, bL, ZL))
    
    return AL, caches

4.4 矩阵维度速查表

这是调试深度学习代码最重要的工具——维度不对是最常见的 bug

变量维度说明
W[l]W^{[l]}(n[l],n[l1])(n^{[l]}, n^{[l-1]})"本层 × 前一层"
b[l]b^{[l]}(n[l],1)(n^{[l]}, 1)与本层神经元数匹配
Z[l],A[l]Z^{[l]}, A^{[l]}(n[l],m)(n^{[l]}, m)本层神经元 × 样本数
dW[l]dW^{[l]}W[l]W^{[l]} 相同梯度维度总是与参数维度相同
db[l]db^{[l]}b[l]b^{[l]} 相同同上

4.5 前向传播与反向传播的积木块

整个深度学习的训练过程,可以看作是在反复堆叠这样的"积木块":

┌─────────────────────────────────────────────────────────┐
│  第 l 层的积木块                                         │
│                                                          │
│  前向:输入 A[l-1] → 计算 Z[l], A[l] → 输出 A[l]        │
│                        缓存 (A[l-1], W[l], b[l], Z[l])  │
│                                                          │
│  反向:输入 dA[l]  → 计算 dZ[l], dW[l], db[l] → 输出 dA[l-1] │
│                        使用缓存中的值                      │
└─────────────────────────────────────────────────────────┘
graph LR
    subgraph 前向传播
        A0[A⁰=X] -->|W¹,b¹| Z1[Z¹→A¹]
        Z1 -->|W²,b²| Z2[Z²→A²]
        Z2 -->|W³,b³| Z3[Z³→A³=ŷ]
    end
    Z3 --> L[Loss]
    L --> dA3[dA³]
    subgraph 反向传播
        dA3 -->|cache³| dA2[dA²]
        dA2 -->|cache²| dA1[dA¹]
        dA1 -->|cache¹| dA0[dA⁰]
    end

为什么需要 cache? 反向传播需要用到前向传播中间计算的值(A[l1],W[l],Z[l]A^{[l-1]}, W^{[l]}, Z^{[l]})。如果不缓存,就得重新计算,浪费时间。这是空间换时间的经典策略。

4.6 参数 vs 超参数

参数(Parameters)超参数(Hyperparameters)
W[l],b[l]W^{[l]}, b^{[l]}学习率 α\alpha
通过梯度下降学习迭代次数
直接决定模型预测隐藏层数 LL
每层神经元数 n[l]n^{[l]}
激活函数选择
Mini-batch 大小

超参数之所以叫"超"参数,是因为它们控制着参数的学习过程。选择好的超参数目前更多依赖经验和实验,Course 2 会详细讨论调优策略。

4.7 深度学习与大脑

经常有人说"神经网络模拟了人脑"——这个说法不太准确

  • 生物神经元的工作机制远比人工神经元复杂得多
  • 人工神经网络只是从生物神经网络中获得了松散的灵感
  • 我们对大脑的理解仍然非常有限
  • 将深度学习类比为大脑可以作为入门直觉,但不要过度解读

本课小结与关键公式速查

核心概念回顾

  1. 单神经元 = 线性变换 + 激活函数:a=g(wTx+b)a = g(w^Tx + b)
  2. 神经网络 = 多层神经元的堆叠,通过非线性激活函数获得强大的表达能力
  3. 训练 = 前向传播计算损失 + 反向传播计算梯度 + 梯度下降更新参数
  4. 向量化 = 消除 for 循环,利用矩阵运算加速

关键公式速查

逻辑回归

公式表达式
模型y^=σ(wTx+b)\hat{y} = \sigma(w^Tx + b)
损失L=[ylogy^+(1y)log(1y^)]L = -[y\log\hat{y} + (1-y)\log(1-\hat{y})]
梯度dw=1mX(AY)Tdw = \frac{1}{m}X(A-Y)^Tdb=1m(AY)db = \frac{1}{m}\sum(A-Y)

L 层神经网络

步骤公式
前向传播Z[l]=W[l]A[l1]+b[l]Z^{[l]} = W^{[l]}A^{[l-1]} + b^{[l]}A[l]=g[l](Z[l])A^{[l]} = g^{[l]}(Z^{[l]})
反向传播dZ[l]=dA[l]g[l](Z[l])dZ^{[l]} = dA^{[l]} \ast g'^{[l]}(Z^{[l]})
权重梯度dW[l]=1mdZ[l]A[l1]TdW^{[l]} = \frac{1}{m}dZ^{[l]}{A^{[l-1]}}^T
偏置梯度db[l]=1maxis=1dZ[l]db^{[l]} = \frac{1}{m}\sum_{axis=1}dZ^{[l]}
传递梯度dA[l1]=W[l]TdZ[l]dA^{[l-1]} = {W^{[l]}}^TdZ^{[l]}
参数更新W[l]:=W[l]αdW[l]W^{[l]} := W^{[l]} - \alpha \cdot dW^{[l]}

维度速查

W[l]:(n[l],n[l1])b[l]:(n[l],1)Z[l],A[l]:(n[l],m)W^{[l]}: (n^{[l]}, n^{[l-1]}) \quad b^{[l]}: (n^{[l]}, 1) \quad Z^{[l]}, A^{[l]}: (n^{[l]}, m)
Section 1 of 5

Route control

After Reading

Choose the next trail: follow the same topic route, open the research shelf, or continue through nearby notes.

深度学习3 nearby notes