深度学习(斋藤康毅)学习条记(六)反向传播3

[复制链接]
发表于 2025-10-19 15:10:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
上一篇文章先容了反向传播的自动化,但也存在一些题目,本章用于分析这些题目,并修改原有框架,使其支持复杂盘算图的运行:
题目一:重复利用一个变量,梯度不会累计




也就是说,反向传播时gx=[1,1],f.inputs=[x,x],在循环中第二次赋值把第一次赋的值给覆盖了。

怎样办理




题目二:重复盘算导数,梯度不会自动清零


第一次盘算,x的导数是2,第二次盘算x的导数是3。但是两次的导数值累加了。

设置x.cleargrad() 手动清空梯度


题目三:不支持复杂盘算图







循环funs中的函数
0(初始化)[D]
1[B,C]
2[B,A]
3[B]
4[A]
5[ ]

怎样办理













代码验证






完备代码

  1. import numpy as np
  2. class Variable:
  3.     def __init__(self, data):
  4.         if data is not None:
  5.             if not isinstance(data, np.ndarray):
  6.                 raise TypeError('{} is not supported'.format(type(data)))
  7.         self.data = data
  8.         self.grad = None
  9.         self.creator = None
  10.         self.generation = 0
  11.     def set_creator(self, func):
  12.         self.creator = func
  13.         self.generation = func.generation + 1
  14.     def cleargrad(self):
  15.         self.grad = None
  16.     def backward(self):
  17.         if self.grad is None:
  18.             self.grad = np.ones_like(self.data)
  19.         funcs = []
  20.         seen_set = set()
  21.         def addfunc(f):
  22.             if f not in seen_set:
  23.                 funcs.append(f)
  24.                 seen_set.add(f)
  25.                 funcs.sort(key=lambda x: x.generation)#funcs按照从小到大的辈分排序
  26.         addfunc(self.creator)
  27.         while funcs:
  28.             f = funcs.pop()
  29.             gys = [output.grad for output in f.outputs]  # 获取所有输出的梯度
  30.             gxs = f.backward(*gys)                       # 调用 backward 方法
  31.             if not isinstance(gxs, tuple):               # 确保 gxs 是元组
  32.                 gxs = (gxs,)
  33.             for x, gx in zip(f.inputs, gxs):            # 为每个输入分配梯度
  34.                 if x.grad is None:
  35.                     x.grad = gx
  36.                 else:
  37.                     x.grad = x.grad + gx
  38.                 if x.creator is not None:
  39.                     addfunc(x.creator)
  40. class Function:
  41.     def __call__(self, *inputs):
  42.         xs = [x.data for x in inputs]               # 提取输入数据
  43.         ys = self.forward(*xs)                      # 前向传播(解包)
  44.         if not isinstance(ys, tuple):               # 确保 ys 是元组
  45.             ys = (ys,)
  46.         outputs = [Variable(as_array(y)) for y in ys]  # 创建输出变量
  47.         self.generation = max([x.generation for x in inputs])
  48.         for output in outputs:
  49.             output.set_creator(self)
  50.         self.inputs = inputs                        # 保存输入
  51.         self.outputs = outputs                      # 保存输出
  52.         return outputs if len(outputs) > 1 else outputs[0]  # 根据输出数量返回
  53.     def forward(self, *xs):
  54.         raise NotImplementedError()
  55.     def backward(self, *gys):
  56.         raise NotImplementedError()
  57. # 实现具体的函数类
  58. class Square(Function):
  59.     def forward(self, x):
  60.         return x ** 2
  61.     def backward(self, gy):
  62.         x = self.inputs[0].data                     # 从 inputs 中获取数据
  63.         gx = 2 * x * gy
  64.         return gx
  65. class Add(Function):
  66.     def forward(self, x0, x1):
  67.         y = x0 + x1
  68.         return y
  69.     def backward(self, gy):
  70.         return gy, gy                               # 对两个输入返回相同的梯度
  71. # 定义便捷函数
  72. def square(x):
  73.     return Square()(x)
  74. def add(x0, x1):
  75.     return Add()(x0, x1)
  76. # 定义 as_array 函数
  77. def as_array(x):
  78.     if np.isscalar(x):
  79.         return np.array(x)
  80.     return x
  81. x = Variable(np.array(2.0))
  82. a = square(x)
  83. y = add(square(a) , square(a))
  84. y.backward()
  85. print(y.data)
  86. print(x.grad)
  87. '''
  88. # 测试代码
  89. x = Variable(np.array(2.0))
  90. y = Variable(np.array(3.0))
  91. z = add(square(x), square(y))
  92. z.backward()
  93. print(z.data)    # 输出结果: 13.0 (2^2 + 3^2 = 4 + 9 = 13)
  94. print(x.grad)    # 输出梯度: 4.0 (dz/dx = 2 * 2 = 4)
  95. print(y.grad)    # 输出梯度: 6.0 (dz/dy = 2 * 3 = 6)
  96. '''
复制代码
运行效果:

下一章将会深入实践深度学习中的内存管理部分,把握代码技能
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表