深度学习-11-可变长参数

深度学习-11-可变长参数

本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也是鼓励更多优秀作品问世。

当前笔记内容主要为:步骤 11 可变长参数 章节的相关理解。

书籍总共分为5个阶段,每个阶段分很多步骤,最终是一步一步实现一个深度学习框架。例如前两个阶段为:

第 1 阶段共包括 10 个步骤 。 在这个阶段,将创建自动微分的机制
第 2 阶段,从步骤11-24,该阶段的主要目标是扩展当前的 DeZero ,使它能够执行更复杂的计算 ,使它能 够处理接收多个输入的函数和返回多个输出的函数

1.修改Function 类

我们之前的框架代码,都是支持一个参数 例如 y=square(x) y = exp(x) 但是现实中,我们的函数可能是多元函数,我们在大学里面也学习过多元函数的微积分,那么如何让我们的框架支持多元参数输入呢?


用列表来实现多元参数。
现在修改 Function 类以支持多个输入输出 。 为此,我们考虑将变量放 入一个列表(或元组)中进行处理 。

修改Function 里面的__call__方法:

class Function:
    def __call__(self, inputs):
        #x = input.data
        xs = [x.data for x in inputs]  #列表生成式写法创建新的列表
        ys = self.forward(xs)
        outputs = [Variable(as_array(y)) for y in ys]  # 转成 ndarray 类型
        for output in outputs:
            output.set_creator(self)

        self.inputs = inputs
        self.outputs = outputs # 保存输出者。我是创造者的信息,这是动态建立 "连接"这 一 机制的核心
        return outputs

注意点


xs = [x.data for x in inputs]        # 列表生成式写法创建新的列表

2.Add类的实现

定义一个支持多个参数的Add 类:

class Add(Function) :
    def forward(self, xs):
        x0, x1 = xs
        y = x0+ x1
        return (y,)  # 注意写法

执行测试:

if __name__ == '__main__':
    xs = [Variable(np.array(2)), Variable(np.array(3))]
    f = Add()
    ys = f(xs)
    y = ys[0]
    print(y.data)


输出结果:

5

3.全部代码
'''
step09.py
优化-可变长参数(正向传播)
'''

import numpy as np
import unittest

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

    def set_creator(self, func):
        self.creator = func

    def backward(self):
        if self.grad is None:
            self.grad = np.ones_like(self.data)

        funcs = [self.creator]
        while funcs:
            f = funcs.pop()
            x, y = f.input, f.output
            x.grad = f.backward(y.grad)

            if x.creator is not None:
                funcs.append(x.creator)


class Function:
    def __call__(self, inputs):
        #x = input.data
        xs = [x.data for x in inputs]  #列表生成式写法创建新的列表
        ys = self.forward(xs)
        outputs = [Variable(as_array(y)) for y in ys]  # 转成 ndarray 类型
        for output in outputs:
            output.set_creator(self)

        self.inputs = inputs
        self.outputs = outputs # 保存输出者。我是创造者的信息,这是动态建立 "连接"这 一 机制的核心
        return outputs

    def forward(self, xs):
        raise NotImplementedError()  # 使用Function  这个方法forward 方法的人 , 这个方法应该通过继承采实现

    def backward(self, gys):
        raise NotImplementedError()


class Add(Function) :
    def forward(self, xs):
        x0, x1 = xs
        y = x0+ x1
        return y, #return (y,)  # 注意写法,或者:return y, 返回一个元组 

class Square(Function):
    def forward(self, x):
        y = x ** 2
        return y

    def backward(self, gy):
        x = self.input.data
        gx = 2 * x * gy  # 方法的参数 gy 是 一个 ndarray 实例 , 它是从输出传播而来的导数 。
        return gx


class Exp(Function):
    def forward(self, x):
        y = np.exp(x)
        return y

    def backward(self, gy):
        x = self.input.data
        gx = np.exp(x) * gy
        return gx


def square(x):
    f = Square()
    return f(x)


def exp(x):
    f = Exp()
    return f(x)


def as_array(x):  # 新增
    if np.isscalar(x):  # 使用 np.isscalar 函数来检查 numpy.float64 等属于标量
        return np.array(x)
    return x


# 求导公式计算任意函数倒数
def numberical_diff(f, x, eps= 13-4) :
    x0= Variable(x.data -eps)
    x1 = Variable(x.data + eps)
    y0 = f(x0)
    y1 = f(x1)

    return (y1.data -y0.data) /(2*eps)

if __name__ == '__main__':
    xs = [Variable(np.array(2)), Variable(np.array(3))]
    f = Add()
    ys = f(xs)
    y = ys[0]
    print(y.data)
4.总结

这一节比较简单,简述了如何支持多个参数的函数支持,如何使用列表生成式写法创建新的列表 ,如何返回一个列表


    

上一篇:选择排序(直接选择排序与堆排序)----数据结构-排序②


下一篇:聪明人社交的基本顺序:千万别搞反了,越早明白越好