深度学习-02-创建变量的函数
本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也是鼓励更多优秀作品问世。
当前笔记内容主要为:步骤2 创建变量的函数 章节的相关理解。
书籍总共分为5个阶段,每个阶段分很多步骤,最终是一步一步实现一个深度学习框架DeZero 。例如前两个阶段为:
- 第 1 阶段共包括 10 个步骤 。 在这个阶段,将创建自动微分的机制
- 第 2 阶段,从步骤11-24,该阶段的主要目标是扩展当前的 DeZero ,使它能够执行更复杂的计算 ,使它能 够处理接收多个输入的函数和返回多个输出的函数
1.什么是函数
在步骤1我们定义了箱子,定义了变量,了解了变量是什么,这一章如何将变量变成魔法箱子,就是如何使用变量。
使用变量,莫过于通过函数去实现,变普通箱子为魔法箱子。初中我们就学会了二次函数 f(x) = ax^2+bx+c 和反比例函数 f(x) = k/x ,再熟悉不过了。
在数学中,函数定义是指将一个或多个输入值(称为自变量)映射到一个输出值(称为因变量)的规则。
函数通常用符号表示,例如 f(x),其中 f 表示函数名称,x 表示自变量。
函数定义的要素
- 定义域: 函数定义域是指所有可以作为输入值的集合。
- 值域: 函数值域是指所有可能的输出值的集合。
- 映射规则: 函数的映射规则描述了如何将输入值映射到输出值。
函数与映射扩展
函数和映射在数学中有着密切的联系,它们之间既有区别又有相似之处。
相似点
- 对应关系: 映射和函数都是描述集合之间对应关系的概念。它们都将一个集合中的元素与另一个集合中的元素建立起对应关系。
- 输入输出: 映射和函数都涉及输入和输出。输入是来自定义域的元素,输出是来自值域的元素。
区别
- 唯一性: 函数要求每个输入值必须对应唯一一个输出值。而映射则允许一个输入值对应多个输出值。
- 定义域: 函数的定义域是所有可能的输入值的集合,而映射的定义域可以是任何集合,即使是空集。
- 值域: 函数的值域是所有可能的输出值的集合,而映射的值域可以是任何集合,即使是空集
2.Function 类的实现
具体来说,就是假设变 量iX 和 U 是之前实现的 Variable 实例。然后以 Function 类的形式实现可以处理它们的函数 f。
在 Function 类中实现的方法,只输入应为 Variable 实例,输出应为 Variable 实例
Variable 实例的实际数据存在于实例变:W: data 中
class Function:def __call__(self, input):x = input.datay = x ** 2output = Variable(y)return output
说明
问题1:python 里面如何使用另外一个文件里面自定义的类?
方法1
from step01 import *output = Variable(y)
方法2
import step01output = step01.Variable(y)
个人感觉,方法1更简洁,使用更为方便。
问题2:python 类里面 实现了 __call__ 方法,用途是什么,有什么含义?
在 Python 类中实现 __call__ 方法,意味着你将这个类实例化后的对象变成了可调用对象,就像函数一样。换句话说,你可以像调用函数一样直接使用这个对象。
用途和含义
使对象可调用: __call__ 方法允许你像调用函数一样调用对象。当你在代码中使用 object() 的形式调用对象时,实际上是调用了 object.__call__() 方法。
此处是定制对象行为: 你可以通过实现 __call__ 方法来定义对象被调用时的行为。例如,你可以让对象在被调用时执行一些特定的操作,或者返回一些特定的值。
定义了这个方法后,当 f = Function() 时,就可以通过编写 f( . .. ) 来调用 __call__ 方法
3.使用 Function 类
类Function 使用:
x = Variable(np.array(10))f = Function()y = f(x)print(type(y))print(y.data)
输出结果:
C:\Users\Administrator\AppData\Local\Programs\Python\Python39-32\python.exe D:/pyworkspace/dezero-01/step02.py
<class 'step01.Variable'>
100
4.项目代码
基础版定义
实现的 Function 类是 一 个"对输入值求平方"的具体的数
'''
简单版本函数,求某个数的平方 y = f(x)
'''import numpy as np
from step01 import *class Function:def __call__(self, input):x = input.datay = x ** 2output = Variable(y)return output# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':x = Variable(np.array(10))f = Function()y = f(x)print(type(y))print(y.data)
这里的Fuction 定义的是一个 求平方的函数。可能我们已经发现问题所在。
如果定义一个框架,如果只是求平方,肯定是远远不够的。如何扩展出一个基础的函数对象类,并且支持后续定义所有的函数呢?
高阶版定义
最好把 Function 类 作为基类 来实现,并在这个类的内部实现所有 DeZero 函数都有的功能 。
重新设计Function 类,达到以下目标:
- Function 类是基类,实现所有函数通用的功能
- 具体函数是在继承 Function 类的类中实现的
代码如下:
import numpy as np
from step01 import *class Function:def __call__(self, input):x = input.datay = self.forward(x) # 具体函数在forward 中调用,这样就可以用户自己定义自己的函数output = Variable(y)return outputdef forward(self, x):raise NotImplementedError()class Square(Function):def forward(self, x):return x ** 2
高阶版本函数Function 类使用
'''
实现的 Function 类是 一 个基础类
其他函数继承Function
'''
import numpy as np
from step01 import *class Function:def __call__(self, input):x = input.datay = self.forward(x)output = Variable(y)return outputdef forward(self, x):raise NotImplementedError()class Square(Function):def forward(self, x):return x ** 2# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':x = Variable(np.array(10))f = Square()y = f(x)print(type(y))print(y.data)
输出结果:
5.总结
本节主要实现了函数的定义,以及基础函数的定义,并以基础版,高阶版,一步一步进行扩展函数的定义,使得其更灵活,对于定义函数来说。
6.遇到问题
问题代码如下:
'''
实现的 Function 类是 一 个"对输入值求平方"的具体的数
'''
import numpy as np
from step01 import *class Function:def __init__(self, input):x = input.datay = x ** 2output = Variable(y)return output# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':print("hello world")x = Variable(np.array(10))f = Function()y = f(x)print(type(y))print(y.data)
提示报错信息:
Traceback (most recent call last):File "D:\pyworkspace\dezero-01\step02.py", line 20, in <module>f = Function()
TypeError: __init__() missing 1 required positional argument: 'input'
hello world
后来我发现我此处是定义一个类,定义了他的构造函数方法,而不是一个函数对象类,将 __init__ 改为 __call__ 即可修复此问题。