当前位置: 首页 > article >正文

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

上一篇文章介绍了反向传播的自动化,但也存在一些问题,本章用于说明这些问题,并修改原有框架,使其支持复杂计算图的运行:

问题一:重复使用一个变量,梯度不会累计

也就是说,反向传播时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)
'''

运行结果:

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


http://www.kler.cn/a/576226.html

相关文章:

  • C#实现应用程序单个运行,防止重复启动
  • 算法随打:拼写单词
  • oracle通过dmp导入数据
  • 【JAVA架构师成长之路】【Redis】第17集:Redis热点Key问题分析与解决方案
  • 【CSS】Tailwind CSS 与传统 CSS:设计理念与使用场景对比
  • .NET高级应用---自定义Ioc容器(附带源码)
  • Qt6.8.2创建WebAssmebly项目使用FFmpeg资源
  • 论文阅读《TrustRAG: An Information Assistant with Retrieval AugmentedGeneration》
  • K8S学习之基础十四:k8s中Deployment控制器概述
  • 【五.LangChain技术与应用】【31.LangChain ReAct Agent:反应式智能代理的实现】
  • 从开源大模型工具Ollama存在安全隐患思考企业级大模型应用如何严守安全红线
  • Process-based Self-Rewarding Language Models 论文简介
  • React基础之组件
  • 开发环境搭建-完善登录功能
  • 系统架构评估方法-SAAM方法
  • C++20的简写函数模板
  • 初次使用 IDE 搭配 Lombok 注解的配置
  • Android APP 启动流程详解(含冷启动、热启动)
  • html流程图
  • RabbitTemplate类介绍、应用场景和示例代码