马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
上一篇文章先容了反向传播的自动化,但也存在一些题目,本章用于分析这些题目,并修改原有框架,使其支持复杂盘算图的运行:
题目一:重复利用一个变量,梯度不会累计
也就是说,反向传播时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 | [ ] |
怎样办理
代码验证
完备代码
- import numpy as np
- class Variable:
- def __init__(self, data):
- if data is not None:
- if not isinstance(data, np.ndarray):
- raise TypeError('{} is not supported'.format(type(data)))
- self.data = data
- self.grad = None
- self.creator = None
- self.generation = 0
- def set_creator(self, func):
- self.creator = func
- self.generation = func.generation + 1
- def cleargrad(self):
- self.grad = None
- def backward(self):
- if self.grad is None:
- self.grad = np.ones_like(self.data)
- funcs = []
- seen_set = set()
- def addfunc(f):
- if f not in seen_set:
- funcs.append(f)
- seen_set.add(f)
- funcs.sort(key=lambda x: x.generation)#funcs按照从小到大的辈分排序
- addfunc(self.creator)
- while funcs:
- f = funcs.pop()
- gys = [output.grad for output in f.outputs] # 获取所有输出的梯度
- gxs = f.backward(*gys) # 调用 backward 方法
- if not isinstance(gxs, tuple): # 确保 gxs 是元组
- gxs = (gxs,)
- for x, gx in zip(f.inputs, gxs): # 为每个输入分配梯度
- if x.grad is None:
- x.grad = gx
- else:
- x.grad = x.grad + gx
- if x.creator is not None:
- addfunc(x.creator)
- class Function:
- def __call__(self, *inputs):
- xs = [x.data for x in inputs] # 提取输入数据
- ys = self.forward(*xs) # 前向传播(解包)
- if not isinstance(ys, tuple): # 确保 ys 是元组
- ys = (ys,)
- outputs = [Variable(as_array(y)) for y in ys] # 创建输出变量
- self.generation = max([x.generation for x in inputs])
- for output in outputs:
- output.set_creator(self)
- self.inputs = inputs # 保存输入
- self.outputs = outputs # 保存输出
- return outputs if len(outputs) > 1 else outputs[0] # 根据输出数量返回
- def forward(self, *xs):
- raise NotImplementedError()
- def backward(self, *gys):
- raise NotImplementedError()
- # 实现具体的函数类
- class Square(Function):
- def forward(self, x):
- return x ** 2
- def backward(self, gy):
- x = self.inputs[0].data # 从 inputs 中获取数据
- gx = 2 * x * gy
- return gx
- class Add(Function):
- def forward(self, x0, x1):
- y = x0 + x1
- return y
- def backward(self, gy):
- return gy, gy # 对两个输入返回相同的梯度
- # 定义便捷函数
- def square(x):
- return Square()(x)
- def add(x0, x1):
- return Add()(x0, x1)
- # 定义 as_array 函数
- def as_array(x):
- if np.isscalar(x):
- return np.array(x)
- return x
- x = Variable(np.array(2.0))
- a = square(x)
- y = add(square(a) , square(a))
- y.backward()
- print(y.data)
- print(x.grad)
- '''
- # 测试代码
- x = Variable(np.array(2.0))
- y = Variable(np.array(3.0))
- z = add(square(x), square(y))
- z.backward()
- print(z.data) # 输出结果: 13.0 (2^2 + 3^2 = 4 + 9 = 13)
- print(x.grad) # 输出梯度: 4.0 (dz/dx = 2 * 2 = 4)
- print(y.grad) # 输出梯度: 6.0 (dz/dy = 2 * 3 = 6)
- '''
复制代码 运行效果:

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