根据this的说法,numpy.transpose似乎只节省了步幅,实际上是懒惰地进行转置
那么,数据移动实际上是什么时候发生的,如何移动呢?用多多memcpy?或者其他的把戏?
我遵循以下路径:array_reshape、PyArray_Newshape、PyArray_NewCopy、PyArray_NewLikeArray、PyArray_NewFromDescr、PyArray_NewFromDescrAndBase、PyArray_NewFromDescr_int,但对轴置换一无所知。它到底是什么时候发生的?
更新2021/1/19
感谢您的回答,numpy数组拷贝转置算法是here,它使用一个通用的macro来实现,该算法非常本地,并且它没有考虑任何simd加速和缓存友好性
发布于 2019-01-05 01:12:03
跟踪整个numpy C代码是一个缓慢而乏味的过程。我更喜欢从时间推断出行为模式。
制作一个样本数组及其转置:
In [168]: A = np.random.rand(1000,1000)
In [169]: At = A.T首先是一个快速视图--没有数据缓冲区的拷贝:
In [171]: timeit B = A.ravel()
262 ns ± 4.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)快速拷贝(可能使用一些快速块内存拷贝):
In [172]: timeit B = A.copy()
2.2 ms ± 26.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)慢速复制(假设需要以跨步顺序遍历源,并以其自己的顺序遍历源):
In [173]: timeit B = A.copy(order='F')
6.29 ms ± 2.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)在不更改顺序的情况下复制At -快速:
In [174]: timeit B = At.copy(order='F')
2.23 ms ± 51.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)像173,但从“F”到“C”:
In [175]: timeit B = At.copy(order='C')
6.29 ms ± 4.16 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [176]: timeit B = At.ravel()
6.54 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)具有更简单的跨步重新排序的副本位于以下两者之间:
In [177]: timeit B = A[::-1,::-1].copy()
3.75 ms ± 4.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [178]: timeit B = A[::-1].copy()
3.73 ms ± 6.48 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [179]: timeit B = At[::-1].copy(order='K')
3.98 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)此astype还需要较慢的复制速度:
In [182]: timeit B = A.astype('float128')
6.7 ms ± 8.12 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)PyArray_NewFromDescr_int被描述为Generic new array creation routine.,虽然我找不出它将数据从源复制到目标的位置,但它显然是在检查order、strides和dtype。据推测,它可以处理所有需要通用副本的情况。轴排列并不是特例。
https://stackoverflow.com/questions/54039225
复制相似问题