type
status
date
slug
summary
tags
category
icon
password
Property
Sep 14, 2024 09:22 AM
而我们 面朝大海
看潮涨了
潮又落

2023悄无声息地快溜走一个月了,旧岁也在爆竹声中被赶走了,那就让自己努力写点什么吧。

关于学习

感觉没什么有意思的可以拿出来写写,拿最近看到的数组中的stride来水一下吧(
存储一个多维矩阵时,内存中实际存储的是一个一维数组,在二维的情况下,熟知的有行主序,列主序的方式,stride就是不同于这两类的一个存储方式。
stride存储的映射方式为
A[i, j] => Adata[i * A.strides[0] + j * A.strides[1]]
以2x3的矩阵为例,stride为[3,1]时就等同于行主序,为[1,2]时就等同于列主序,当然stride的映射方式可以推广到更高维度。
而为什么要有stride这种存储方式呢?
有以下几点好处;
  • 做转置时,也只需要交换stride就可以
  • 做广播操作时,只需要插入一个值为0的stride
  • 做数组切片时,只需要修改初始偏移量和形状就可以,不需要拷贝底层数据
接下来对其一一解释一下:
首先,考虑对一个矩阵,如何求出对应的stride?
在dlsys hw3中可以看到一段代码
def compact_strides(shape): """ Utility function to compute compact strides """ stride = 1 res = [] for i in range(1, len(shape) + 1): res.append(stride) stride *= shape[-i] return tuple(res[::-1])
如何理解呢?举一个具体的例子一个shape为(4,3,2)的矩阵,把它看作4个3*2的小矩阵放在一起,那么第0维每跨一步就是3*2=6,第1维跨一步就是2,最后一维跨一步就是1,stride即(6,2,1)
notion image
所以stride其实就是每一维跨的步长。
在明白stride的本质后再看这三个问题:
  • 做转置时,也只需要交换stride就可以
    • notion image
  • 做广播操作时,只需要插入一个值为0的stride
    • 例如如果要把2×3的张量广播到2×3×4,在变换shape以后只需要把strides置为(3, 1, 0),对照上文映射关系式,即
      A[i, j] => Adata[i * 2 + j * 3 + k * 0]
      0不会影响在内存一维数组中索引到的值,但k为4,相当于循环索引了4次,达到广播的效果
  • 做数组切片时,只需要修改初始偏移量和形状就可以,不需要拷贝底层数据
    • 通过给定每一维的start,end,step,即每一维的起始位置,结束位置,子步长,即可计算出对应切分的子矩阵的strides以及shape,offset,从而得到子矩阵。
相关资料
CMU dlsys 深度学习系统13. 硬件加速的实现
本节课将利用前两节课学到的知识,快速过一下底层的具体实现,以为第三次作业打基础。C++和CUDA的底层实现文件在 src目录下,而Python的NDArray后端高层实现在 needle/backend_ndarray 下。本次作业的目的就是创造 NDArray这个加速库,替换原有的numpy实现。根目录下的 CMakeLists.txt和 Makefile 是为了构建库所需要的,有兴趣也可以查阅,但非硬性要求 对 handle 的作用可能大家会觉得比较费解,那我们来跟踪一些操作的执行过程。考虑如下代码 对第一条语句,首先我们希望在GPU上创建一个一维数组,包含三个元素。对应的,可以看一下 NDArray的__init__构造函数。首先,程序会把输入的python列表转化为一个numpy的array,然后走 elif isinstance(other, np.ndarray)的分支。在这个分支里,先会调用 self.make(other.shape, device=device这条语句,创建数据结构,然后调用具体 device的 from_numpy方法,将这个numpy的ndarray压缩到连续空间,再用压缩后的数组初始化这个 array的_handle 成员变量(实际上是一个内存拷贝) 对于 make 这个类方法,其签名为 对于CPU后端,具体实现在 src/ndarray_backend_cpu.cc中,通过 pybind 暴露。 实际上调用的是 AlignedArray 的构造函数,它会对分配一个指针并开辟指定大小的内存空间 另一种构造数组的方法是 from_numpy()(也是上面示例代码中构造的方法)。在C++后端中,实现为一个数组拷贝,从numpy数组拷贝到对应指针指向的区域(即_handle 指向的区域) 对于GPU后端,具体实现在 src/ndarray_backend_cuda.cu中, Array对应于一个 CudaArray结构体。构造函数使用 cudaMalloc根据指定元素数量分配显存, from_numpy 的实现和C++后端的实现大同小异 对于 y = x + 1,实际上是重载了 NDArray的加法运算符,定义在__add__方法中。该方法进一步调用 ewise_or_scalar,根据操作数类型(是否为
CMU dlsys 深度学习系统13. 硬件加速的实现

关于动漫

最近把春物补完了,看着大老师的一步步变成现充的样子,我还是更喜欢他前面桀骜不驯说圣经的调调(误

关于阅读

最近看了《麦田里的守望者》,还没看完,emm,没怎么看懂,感觉行文挺琐碎的,没看出什么内涵,大概我没有那种时代背景带来的感受吧。
另外,机缘巧合下看了看余华的《第七天》,果然,挺惨的,这下不止活着惨,死了也挺惨的,不过今早我忽然想到,从旁观者的角度看主人公的生活确实尽是悲惨之事,但代入主人公视角进去,好像又能从悲惨的故事中发现些幸福的片段?至于作者到底想表达什么,我这个没有文学性的脑袋大抵是读不懂了,就当睡前读物吧。

不知不觉又虚度了人生的几个小时,那就,下次见吧,ma ta ne(またね)~
 
 
 
 
hello World2022-碎碎念-01