介绍
本篇主要是模仿numpy的部分功能,搭建一个数值计算框架。目的是实现机器学习算法中涉及到基本的矩阵运算或操作。
1.Vector类
矩阵运算首先得要有矩阵,numpy里面矩阵的展现形式是ndarray这个类,pytorch或者tensorflow都叫Tensor。我这里起个名字叫Vector吧,用于存储矩阵的数据结构。
- 1 初始化函数
关于Vector类,有两个必不可少的类成员属性,一是用于存储数值的变量array,二是用于表示矩阵形状的变量shape。
题外话:关于变量array存储数据的形式,我在这里还踩了两个坑。一开始我很天真,以为多维矩阵就是list的嵌套,但是随着进度继续,我发现单纯list的嵌套会有很多麻烦的地方。其中第一不和谐的点是,如果array为list的嵌套,对Vector的某个维度进行索引的时候,取出来是个list,而不是一个Vector。尽管可以在复写__getitem__的时候,构造一个新的Vector实例,但这会影响索引时的速度...另外一点是,我发现一旦维度大于2,list嵌套实在太难写转置操作了。于是我打算尽可能维持这个vector取数据的过程类似线性表(当然python里没有严格的线性表,list是线性表和链表的结合)的特性,二是希望这个存储结构有利于转置操作。我的第二个想法是,array的存储结构就是一个一维的list。对vector取值时,可以根据shape对index进行映射到array相应的index上,来达到索引指定位置的目的,思路类似下图(图一)。据说numpy的C实现的底层就是这么设计的,不过这种设计转置写起来感觉更麻烦了。于是放弃了这个方案。
总之,我们希望如果对Vector进行索引的话,得到的东西还是个vector。所以最简单的想法就是,array里装的是低一维的Vector。这样索引的时候直接可以对array索引直接取到响应的Vector了。这样,array在初始化的时候需要做一些额外的操作,直接看代码好了:
class Vector:
def __init__(self, data, shape=None, requires_grad=True, _creator=None, grad=None, name='Unknown'):
if not shape:
shape = _inference_shape(data)
else:
shape = deepcopy(shape)
if len(shape) > 1:
self.array = [elem if isinstance(elem, Vector) else Vector