Course 2:神经网络与 TensorFlow
课程简介
用 TensorFlow 搭建神经网络,理解前向传播与反向传播。
一、神经网络基础
1.1 从逻辑回归到神经元
神经网络由多个感知器(神经元)组成,每个神经元本质上是逻辑回归单元。一个隐藏层神经元的计算:
$$z = w^T x + b$$
$$a = g(z)$$
其中 g 是激活函数。多个神经元并行工作,其输出组合后送入下一层。
1.2 神经网络的层结构
神经网络由三层组成:
- 输入层:接收原始特征
- 隐藏层:对输入进行非线性变换
- 输出层:产生最终预测
层之间的全连接意味着当前层的每个神经元与上一层的所有神经元相连。
1.3 为什么需要隐藏层
隐藏层让网络能够学习特征之间的交互作用。例如在 XOR 问题中,单个逻辑回归无法学习非线性决策边界,而带有一个隐藏层的网络可以轻松解决。
从理论上讲,一个足够宽的单隐藏层网络可以逼近任意连续函数(通用近似定理)。
二、TensorFlow 与 Keras
2.1 TensorFlow 简介
TensorFlow 由 Google 开发,是目前最流行的深度学习框架之一。Keras 是 TensorFlow 的高层 API,提供了简洁的模型构建接口。
2.2 使用 Keras 构建网络
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
# 方法1:Sequential API(适合简单堆叠)
model = keras.Sequential([
layers.Dense(25, activation='relu', input_shape=(10,)), # 第一隐藏层
layers.Dense(15, activation='relu'), # 第二隐藏层
layers.Dense(1, activation='sigmoid') # 输出层
])
# 编译模型
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
# 训练
history = model.fit(X_train, y_train,
epochs=100,
batch_size=32,
validation_split=0.2,
verbose=1)
# 评估
test_loss, test_acc = model.evaluate(X_test, y_test)
print(f'Test accuracy: {test_acc:.4f}')
# 预测
predictions = model.predict(X_test)
2.3 模型的保存与加载
# 保存整个模型
model.save('my_model.h5')
# 加载模型
loaded_model = keras.models.load_model('my_model.h5')
三、前向传播与反向传播
3.1 前向传播计算图
前向传播是信息从输入层流到输出层的过程。对于 L 层网络:
初始化:A^{[0]} = X
对于第 l 层:
$$Z^{[l]} = W^{[l]} A^{[l-1]} + b^{[l]}$$
$$A^{[l]} = g^{[l]}(Z^{[l]})$$
最终输出:ŷ = A^{[L]}
3.2 反向传播
反向传播是训练的引擎,通过链式法则计算各层参数的梯度。
损失对第 l 层权重和偏置的梯度:
$$\frac{\partial J}{\partial W^{[l]}} = \frac{1}{m} \delta^{[l]} (A^{[l-1]})^T$$
$$\frac{\partial J}{\partial b^{[l]}} = \frac{1}{m} \sum_i \delta^{[l]}_i$$
其中 δ^{[l]} 是第 l 层的误差项:
$$\delta^{[l]} = (W^{[l+1]})^T \delta^{[l+1]} \odot g^{[l]'}(Z^{[l]})$$
这个公式表明:当前层的误差由上层误差加权传播而来,再乘以当前层激活函数的局部梯度。
3.3 Keras 的反向传播
在 Keras 中,反向传播通过 model.fit() 自动完成,但我们仍然需要理解它的工作原理:
# 手动实现训练循环(用于理解原理)
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
for epoch in range(epochs):
with tf.GradientTape() as tape:
predictions = model(X_train)
loss = loss_fn(y_train, predictions)
# 自动计算所有参数的梯度
grads = tape.gradient(loss, model.trainable_weights)
# 应用梯度更新
optimizer.apply_gradients(zip(grads, model.trainable_weights))
四、激活函数详解
4.1 ReLU
$$g(z) = \max(0, z)$$
- 当 z > 0 时梯度恒为 1,无梯度消失
- 计算简单,只需一次比较
- 问题:z < 0 时梯度为 0,"神经元死亡"
4.2 其他激活函数
Sigmoid:输出 (0,1),适合输出层做概率预测
tanh:输出 (-1,1),均值为 0,比 Sigmoid 更有利于梯度传播
Leaky ReLU:g(z) = max(0.01z, z),解决神经元死亡
Softmax:多分类输出层,输出类别概率分布
4.3 选择指南
- 隐藏层:优先使用 ReLU
- 二分类输出层:Sigmoid
- 多分类输出层:Softmax
- 回归输出层:线性激活函数(无激活函数)
五、实战:手写数字识别
# MNIST 手写数字识别
(X_train, y_train), (X_test, y_test) = keras.datasets.mnist.load_data()
# 预处理
X_train = X_train.reshape(-1, 784).astype('float32') / 255.0
X_test = X_test.reshape(-1, 784).astype('float32') / 255.0
model = keras.Sequential([
layers.Dense(128, activation='relu', input_shape=(784,)),
layers.Dropout(0.2),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.1)
test_loss, test_acc = model.evaluate(X_test, y_test)
print(f'Test accuracy: {test_acc:.4f}') # 通常 ~0.98
延伸阅读
- 📺 B 站播放列表:Machine Learning Specialization (2022) — 新版机器学习
- 📚 更多学习资源,请访问 deeplearning.ai 官网