《深度学习入门(基于 Python 的理论与实现)》中「类(class)」的核心作用
这本书大量用面向对象类封装神经网络、梯度计算、层结构、优化器,把零散函数打包成可复用、易维护、模块化的代码,是全书代码框架的根基。
一、通用层面:Python 类基础作用(书本前置知识点)
-
封装:把数据和绑定的方法打包在一起 变量(属性)+ 操作变量的函数(方法)放在同一个类里,不用全局变量乱传参数。 例:神经网络权重
W、偏置b是属性;前向传播forward()、反向传播backward()是方法。 -
实例化:批量创建独立对象 一个类可以生成多个互不干扰的实例。 比如同一种 Affine 层,可以实例化第一层、第二层,各自保存自己的参数,不会互相覆盖。
-
代码复用,减少重复冗余 不用每次写全连接层、激活函数都复制粘贴 forward/backward 代码,定义一次类即可反复调用。
-
便于扩展与继承 可以基于基础层类派生出新层,比如给基础激活层新增带 dropout 的子类。
二、本书深度学习代码里类的具体用途(对应书中网络结构)
1. 封装网络层(最核心)
书中所有网络组件全部用类实现:
Affine(全连接层):保存权重W、偏置b,实现正向计算与反向求导更新参数ReLU、Sigmoid:激活函数层,记录中间输入用于反向传播梯度回传SoftmaxWithLoss:softmax 输出 + 交叉熵损失合为一类,同时计算损失与梯度
核心逻辑:每一层只需要实现两个固定接口
python
运行
python
forward(x) # 前向传播,输出下一层输入
backward(dout) # 接收上游梯度,返回本层梯度、更新参数
类把层内状态(缓存输入、参数) 保存下来,反向传播时直接取用,不用手动存中间变量。
2. 搭建整体神经网络模型
TwoLayerNet(二层神经网络)是典型类:
- 属性:各层实例、权重参数、超参(学习率、权重衰减系数)
- 方法:
predict():推理预测loss():计算损失值gradient():数值梯度 / 解析梯度update():参数迭代更新
整个网络被封装成一个对象,外部只需调用少量方法就能完成训练,结构清晰。
3. 封装优化器(梯度下降更新策略)
书中 SGD、Momentum、AdaGrad、Adam 全部写成类:
- 保存优化器自身状态(比如动量累积量、历史梯度平方和)
- 统一
update(params, grads)方法,一键更新网络所有参数 后续更换优化器只需要换一个类实例,主体训练代码完全不用改动。
4. 管理训练过程与参数状态
- 层在反向传播时需要缓存
x、W等中间数据,类的实例属性天然用来存储临时变量; - 训练时参数不断迭代,每个层实例独占自己的
W/b,多网络并行训练不会参数混淆。
三、对比不用类(纯函数写法)的缺点
- 所有权重、中间结果要用字典 / 列表手动传递,参数极易混乱;
- 前向、反向代码高度重复,新增网络结构要大量复制代码;
- 无法单独复用某一层,代码耦合度极高;
- 可读性极差,很难区分哪段代码属于网络哪一部分。
四、极简总结(应试 / 笔记版)
- 封装:将网络层参数、中间数据、前向 / 反向运算方法绑定为整体;
- 模块化:拆分全连接、激活、损失、优化器等独立模块;
- 复用性:单类多次实例化,快速搭建多层神经网络;
- 规范化:统一 forward/backward 接口,构建链式反向传播计算图;
- 易维护扩展:新增网络结构、优化算法只需新增类,不改动原有代码
类定义与 __init__ 构造函数逐行注释
python
# 定义Affine全连接层类
class Affine:
# 构造方法:创建实例时自动执行,初始化层所有属性
# W:权重矩阵 b:偏置向量,由上层网络传入
def __init__(self, W, b):
# 实例属性1:保存本层权重W
self.W = W
# 实例属性2:保存本层偏置b
self.b = b
# 实例属性3:缓存正向传播的输入x,反向求导必须用到
self.x = None
# 实例属性4:记录输入原始形状,兼容卷积后多维输入(图片四维数据)
self.original_x_shape = None
# 实例属性5:权重W的梯度,后续梯度下降更新W使用
self.dW = None
# 实例属性6:偏置b的梯度,后续梯度下降更新b使用
self.db = None
forward 前向传播逐行拆解
python
# 前向传播方法:接收输入x,输出本层计算结果out
def forward(self, x):
# 步骤1:记录输入x最开始的形状(比如卷积输出是(N,C,H,W)四维)
self.original_x_shape = x.shape
# 步骤2:将除第一维(批量维度N)外所有维度展平,变成二维矩阵 (N, 特征总数)
# -1 代表自动计算列数,把单张图片多维数据拉成一维向量
x = x.reshape(x.shape[0], -1)
# 步骤3:把展平后的x存入实例变量,反向传播要用
self.x = x
# 步骤4:核心仿射运算 X·W + b
# np.dot矩阵乘法:(N,in) × (in,out) = (N,out),再加偏置b
out = np.dot(self.x, self.W) + self.b
# 返回输出给下一层(激活函数/下一个Affine层)
return out
backward 反向传播逐行拆解(梯度回传核心)
python
# 反向传播:dout是上一层传回来的输出梯度 dL/dout
def backward(self, dout):
# 公式推导:dx = dout · W^T
# dout(N, out) × W.T(out, in) → dx(N, in)
dx = np.dot(dout, self.W.T)
# dW = X^T · dout 权重梯度,本层核心待更新梯度
self.dW = np.dot(self.x.T, dout)
# db:偏置梯度,按batch维度求和,axis=0压缩批量维度
# dout形状(N,out),sum后得到(1,out)即偏置梯度
self.db = np.sum(dout, axis=0)
# 把展平后的dx恢复成最开始输入x的原始四维/三维形状
dx = dx.reshape(*self.original_x_shape)
# 将dx(dL/dx)传回上一层,继续反向链式求导
return dx