鱼书-PH4-类的作用

《深度学习入门(基于 Python 的理论与实现)》中「类(class)」的核心作用

这本书大量用面向对象类封装神经网络、梯度计算、层结构、优化器,把零散函数打包成可复用、易维护、模块化的代码,是全书代码框架的根基。

一、通用层面:Python 类基础作用(书本前置知识点)

  1. 封装:把数据和绑定的方法打包在一起 变量(属性)+ 操作变量的函数(方法)放在同一个类里,不用全局变量乱传参数。 例:神经网络权重W、偏置b是属性;前向传播forward()、反向传播backward()是方法。

  2. 实例化:批量创建独立对象 一个类可以生成多个互不干扰的实例。 比如同一种 Affine 层,可以实例化第一层、第二层,各自保存自己的参数,不会互相覆盖。

  3. 代码复用,减少重复冗余 不用每次写全连接层、激活函数都复制粘贴 forward/backward 代码,定义一次类即可反复调用。

  4. 便于扩展与继承 可以基于基础层类派生出新层,比如给基础激活层新增带 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,多网络并行训练不会参数混淆。

三、对比不用类(纯函数写法)的缺点

  1. 所有权重、中间结果要用字典 / 列表手动传递,参数极易混乱;
  2. 前向、反向代码高度重复,新增网络结构要大量复制代码;
  3. 无法单独复用某一层,代码耦合度极高;
  4. 可读性极差,很难区分哪段代码属于网络哪一部分。

四、极简总结(应试 / 笔记版)

  1. 封装:将网络层参数、中间数据、前向 / 反向运算方法绑定为整体;
  2. 模块化:拆分全连接、激活、损失、优化器等独立模块;
  3. 复用性:单类多次实例化,快速搭建多层神经网络;
  4. 规范化:统一 forward/backward 接口,构建链式反向传播计算图;
  5. 易维护扩展:新增网络结构、优化算法只需新增类,不改动原有代码

类定义与 __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
相关推荐
Zzj_tju7 小时前
准确率不变,概率质量也不变吗?
人工智能·深度学习·机器学习·语言模型
在所不辞兄9 小时前
【零基础学智能仿真-67】力学知识库与检索增强
人工智能·深度学习·神经网络·机器学习·智能仿真
拜小白9 小时前
【论文解读】ZInD:带标注平面图、360° 全景与 3D 房间布局的 Zillow 室内数据集
深度学习·计算机视觉·全景图
DevOps老兵10 小时前
Transformer拆解01:Transformer为什么出现,RNN到底卡在哪里
rnn·深度学习·大模型·transformer·注意力机制
zcg194212 小时前
通过UE制作segment和depth数据
人工智能·深度学习
Yolanda_202214 小时前
week3深度学习处理文本(上)
人工智能·深度学习
Smoothcloud润云15 小时前
GPU算力平台推荐:复现实验时,如何判断租用资源是否合适?
服务器·人工智能·深度学习·gpu算力·gpu
Rocky Ding*16 小时前
深入浅出Xiaomi-Lens-0技术解析:像素监督如何改变视觉推理
论文阅读·人工智能·深度学习·机器学习·aigc·多模态·ai-native
默|笙16 小时前
【AI应用】认识机器学习与深度学习
人工智能·深度学习·机器学习
JAVA_AI人工智能项目实战16 小时前
深度学习实验笔记
人工智能·深度学习·语言模型·自然语言处理