鱼书-PH4-类的作用
《深度学习入门基于 Python 的理论与实现》中「类class」的核心作用这本书大量用面向对象类封装神经网络、梯度计算、层结构、优化器把零散函数打包成可复用、易维护、模块化的代码是全书代码框架的根基。一、通用层面Python 类基础作用书本前置知识点封装把数据和绑定的方法打包在一起变量属性 操作变量的函数方法放在同一个类里不用全局变量乱传参数。 例神经网络权重W、偏置b是属性前向传播forward()、反向传播backward()是方法。实例化批量创建独立对象一个类可以生成多个互不干扰的实例。比如同一种 Affine 层可以实例化第一层、第二层各自保存自己的参数不会互相覆盖。代码复用减少重复冗余不用每次写全连接层、激活函数都复制粘贴 forward/backward 代码定义一次类即可反复调用。便于扩展与继承可以基于基础层类派生出新层比如给基础激活层新增带 dropout 的子类。二、本书深度学习代码里类的具体用途对应书中网络结构1. 封装网络层最核心书中所有网络组件全部用类实现Affine全连接层保存权重W、偏置b实现正向计算与反向求导更新参数ReLU、Sigmoid激活函数层记录中间输入用于反向传播梯度回传SoftmaxWithLosssoftmax 输出 交叉熵损失合为一类同时计算损失与梯度核心逻辑每一层只需要实现两个固定接口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__构造函数逐行注释# 定义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 Noneforward 前向传播逐行拆解# 前向传播方法接收输入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 outbackward 反向传播逐行拆解梯度回传核心# 反向传播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维度求和axis0压缩批量维度 # dout形状(N,out)sum后得到(1,out)即偏置梯度 self.db np.sum(dout, axis0) # 把展平后的dx恢复成最开始输入x的原始四维/三维形状 dx dx.reshape(*self.original_x_shape) # 将dxdL/dx传回上一层继续反向链式求导 return dx
