Week7:卷积神经网络、深度网络原理与循环神经网络专题
Week7:卷积神经网络、深度网络原理与循环神经网络专题
摘要
本周学习李宏毅《机器学习》卷积网络、深度网络成因、循环神经网络相关内容。课程先讲解卷积神经网络 CNN 的结构、核心运算与图像任务优势,对比全连接网络的缺陷;随后分析深层网络效果优于浅层网络的底层逻辑;接着完整介绍循环神经网络 RNN,讲解序列数据建模思路、RNN 前向计算、梯度消失问题,以及 LSTM、GRU 优化结构,分别结合图像、文本序列两类任务理解网络适配逻辑,补齐计算机视觉与时序数据两大主流深度学习模型知识。
1 卷积神经网络 CNN
1.1 全连接网络处理图像的固有缺陷
此前 MNIST 使用的全连接网络需要把二维图片展平为一维向量,存在两处明显短板:
丢失像素空间位置信息,无法利用图片局部相邻像素的关联特征;
参数量巨大,28×28 图片输入层就有 784 个权重,高分辨率图像会产生海量参数,极易过拟合、训练成本高。
卷积神经网络 CNN 专门针对图像数据设计,通过局部感受野、权值共享、下采样大幅降低参数量,同时保留空间结构信息。
1.2 CNN 三大核心特性
局部感受野:
神经元不再和整张图片所有像素连接,仅和一小块相邻像素区域(感受野)做运算,只提取局部纹理、边缘特征,符合图像局部关联性。
权值共享:
同一个卷积核(滤波器)在整张图片滑动时,共用同一套权重参数。一张图片内所有位置使用相同特征提取模板,大幅减少总参数量,同时让模型具备平移不变性,物体轻微移位不影响识别结果。
池化下采样 Pooling:
卷积后接入池化层压缩特征图尺寸,降低计算量。常用两种池化:最大池化 Max Pooling 取区域内最大值,保留最强特征;平均池化 Average Pooling 取区域均值,平滑特征。池化进一步降低参数量,轻微提升缩放、形变鲁棒性。
1.3 卷积完整计算流程
输入原始图像;
卷积层:多组卷积核滑动遍历图像,完成线性运算 + 激活函数,输出多张特征图;
池化层:缩小特征图长宽,精简特征;
重复堆叠多组「卷积 + 池化」模块,逐层提取底层边缘、中层纹理、高层物体轮廓;
末端将二维特征图展平,接入全连接层 + Softmax 输出分类结果。
1.4 CNN 实战优势与适用场景
CNN 天然适配二维网格结构数据,图像识别、目标检测、图像分割任务均以 CNN 为基础;相比全连接网络,参数量更少、不易过拟合,能充分利用空间位置信息,图像识别精度远高于全连接网络。
2 为什么深层网络效果更好 Why Deep
2.1 万能逼近定理的局限
理论上单隐藏层足够宽的网络可以拟合任意连续函数,但实际训练效果远不如深层网络。单层宽网络需要海量神经元,参数量爆炸、训练难度大,泛化能力弱。
2.2 深层网络分层特征提取逻辑
深层网络具备分层表达能力,每层负责提取一类抽象程度不同的特征:
浅层:提取基础底层特征,线条、边缘、色块;
中层:组合底层特征,形成纹理、局部部件;
深层:整合中层特征,得到完整物体、全局语义。
这种分层结构贴合人类视觉、语音的特征提取逻辑,更容易学习到数据内在规律。
2.3 参数效率对比
实现同等拟合能力,深层窄网络所需参数远少于单层宽网络。多层结构复用基础特征,不用为每一类物体单独设置独立神经元,参数利用率更高,不易过拟合。
2.4 深层网络训练难点与对应方案
深层网络层数加深后极易出现梯度消失,课程前面介绍的对应解决手段:
使用 ReLU 激活函数替代 Sigmoid/Tanh;
残差网络 Residual Connection;
合理权重初始化、梯度裁剪、自适应优化器。
3 循环神经网络 RNN 基础
3.1 序列数据建模需求
此前 CNN、全连接网络仅处理固定长度独立样本,无法处理时序、文本这类变长序列数据(文字、语音、时间序列)。序列数据存在前后依赖关系,前一段内容会影响后续输出,循环神经网络 RNN 专门建模带时序依赖的数据。
3.2 RNN 基础结构与前向传播
RNN 引入隐藏状态ht,存储前文时序信息,每一步输入结合上一时刻隐藏状态共同计算当前输出:
输入xt:当前时刻序列特征;
融合历史状态与当前输入;
输出
依据当前综合状态给出预测;
每一个时间步共享同一套权重矩阵,实现任意长度序列建模。
3.3 三类 RNN 任务范式
一对一:固定输入输出长度,传统分类;
多对一:输入完整序列,输出单一结果(文本情感分类);
多对多:输入输出等长序列(词性标注、语音识别)。
3.4 RNN 梯度消失问题
训练 RNN 使用时序反向传播 BPTT,梯度需要沿时间步反向传递,多层时间步连续相乘后梯度会快速衰减。远距离时序依赖无法传递梯度,模型只能学习短期依赖,无法捕捉长距离上下文关系。
4 LSTM 与 GRU:长依赖优化结构
4.1 LSTM 长短时记忆单元设计目标
解决基础 RNN 长序列梯度消失,通过门控机制控制历史信息留存、遗忘、输出,让网络自主选择保留远距离时序特征。
LSTM 包含三类门控:遗忘门、输入门、输出门,搭配细胞状态ct长期存储时序信息。
遗忘门:控制上一时刻细胞状态保留多少信息;
输入门:控制当前时刻新信息存入细胞状态;
细胞状态ct:线性传递,梯度衰减极慢,用于长期记忆;
输出门:控制细胞状态哪些内容输出到当前隐藏层ht。
4.2 GRU 简化门控结构
GRU 是 LSTM 轻量化变体,合并遗忘门与输入门为更新门,仅保留更新门、重置门,减少参数、加快训练速度,效果与 LSTM 接近,工程中使用广泛。
更新门:决定保留多少历史状态;
重置门:控制历史状态与当前输入的融合程度。
4.3 时序任务适用场景
文本分类、机器翻译、语音识别、时间序列预测等存在上下文依赖的任务,均使用 LSTM/GRU 作为基础模型,解决基础 RNN 无法捕捉长距离依赖的缺陷。
4 本周拓展思考
CNN 依靠局部感受野与权值共享适配图像空间数据,RNN 依靠循环状态适配时序序列数据,两类网络针对不同数据结构设计,不存在绝对优劣,需根据任务数据类型选择;
深层网络分层抽象特征是其性能优势核心,单层宽网络仅理论等价,实际训练效率、泛化能力均不及深层窄网络;
基础 RNN 天然存在长距离梯度消失,LSTM、GRU 通过门控与细胞状态线性通路缓解该问题,是处理长文本、长时序任务的必备结构;
权值共享是 CNN、RNN 共有的设计思路,CNN 空间维度共享权重,RNN 时间维度共享权重,二者都能减少参数量、提升泛化能力。
总结
本周学习卷积网络、深层网络原理、循环神经网络完整内容。先掌握 CNN 三大核心设计、完整卷积计算流程,理解其相比全连接网络处理图像的优势;随后弄懂深层网络分层特征提取、参数高效利用的核心优势,同时清楚深层网络梯度消失的训练痛点;之后学习基础 RNN 结构与时序建模逻辑,发现基础 RNN 无法捕捉长距离依赖的缺陷;最后学习 LSTM、GRU 门控结构,依靠细胞状态与门控机制解决长序列梯度消失问题。
后续我会使用 Python 搭建简易 CNN 完成 MNIST 图像分类,同时搭建基础 RNN、LSTM 模型完成简单时序预测实验,对比三类网络的训练效果,加深对空间、时序网络的理解。
Python 复现代码(简易 CNN分类)
import os
os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
def get_mnist_local():
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data(path="mnist.npz")
return (x_train, y_train), (x_test, y_test)
(x_train, y_train), (x_test, y_test) = get_mnist_local()
x_train = x_train.reshape((60000, 28, 28, 1)) / 255.0
x_test = x_test.reshape((10000, 28, 28, 1)) / 255.0
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation="relu", input_shape=(28,28,1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation="relu"),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation="relu"),
layers.Flatten(),
layers.Dense(64, activation="relu"),
layers.Dense(10, activation="softmax")
])
model.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
history = model.fit(x_train, y_train, epochs=10, batch_size=64, validation_split=0.1)
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print(f"测试集最终准确率: {test_acc:.4f}")
plt.figure(figsize=(8, 3))
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.title('CNN模型准确率变化曲线')
plt.xlabel('Epoch 训练轮次')
plt.ylabel('Accuracy 准确率')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
plt.figure(figsize=(8, 3))
plt.plot(history.history['loss'], label='训练损失')
plt.plot(history.history['val_loss'], label='验证损失')
plt.title('CNN模型损失变化曲线')
plt.xlabel('Epoch 训练轮次')
plt.ylabel('Loss 损失值')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
Python 简易 LSTM 时序预测复现代码
import os
os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, LSTM, Dense
from tensorflow.keras.models import Model
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False
time_steps = 10
def create_seq_data():
x, y = [], []
seq = np.sin(np.linspace(0, 20*np.pi, 2000))
for i in range(len(seq)-time_steps):
x.append(seq[i:i+time_steps])
y.append(seq[i+time_steps])
x = np.array(x).reshape(-1, time_steps, 1)
y = np.array(y)
return x, y
x_train, y_train = create_seq_data()
inputs = Input(shape=(time_steps, 1))
lstm_out = LSTM(32)(inputs)
output = Dense(1)(lstm_out)
model = Model(inputs, output)
model.compile(optimizer="adam", loss="mse")
history = model.fit(x_train, y_train, epochs=20, batch_size=32, validation_split=0.1)
pred_result = model.predict(x_train[:100], verbose=0)
plt.figure(figsize=(10, 4))
plt.plot(y_train[:100], label='真实正弦序列', linewidth=1.2)
plt.plot(pred_result.flatten(), label='LSTM预测序列', linewidth=1.2)
plt.title('LSTM时序预测拟合效果')
plt.xlabel('序列步序号')
plt.ylabel('数值')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
