文章目录

  • ndarray的base和strides属性
    • base
    • strides
  • reshape
  • transpose
  • 总结

reshape和transpose都是非常高效的算子,究其原因,是因为二者均没有在内存中重新排列数据,只是对数据的shape或strides等信息进行了改变。下面分别简介。

ndarray的base和strides属性

为了更好地理解reshape和transpose算子,需要对ndarray的shape, base, strides三个属性有所了解,其中shape很容易理解,就不多说了,下面简单介绍一下base和strides。

base

base参考:https://numpy.org/doc/stable/reference/generated/numpy.ndarray.base.html

如果一个ndarray是通过其他ndarray经过某种操作创建出来的,那么其base就会指向最初的源头。
比如下面例子中,ab, c的源头,所以b.base 和 c.base 都等于a,而a本身没有base,所以是None。

import numpy as npa = np.array([0, 1, 2, 3, 4, 5])
print(a)  # ==> [0 1 2 3 4 5]
print(a.base)  # ==> Noneb = a.reshape([2, 3])
print(b)  # ==>
# [[0 1 2]
#  [3 4 5]]
print(b.base)  # ==> [0 1 2 3 4 5]c = b.transpose([1, 0])
print(c)  # ==>
# [[0 3]
#  [1 4]
#  [2 5]]
print(c.base)  # ==> [0 1 2 3 4 5]

strides

strides参考:https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html

ndarray的每一个维度(axis)都有一个strides,表示从数组在某个维度进行遍历的内存偏移量

比如在下面的例子中,数组a三个维度的strides分别是(48, 16, 4),意思是:

  • a[0, 0, 0]a[0, 0, 1] = 1的内存偏移量是4字节,1个int型数字是4字节
  • a[0, 0, 0]a[0, 1, 0] = 4的内存偏移量是16字节,因为需要偏移4个int型数字
  • a[0, 0, 0]a[1, 0, 0] = 12的内存偏移量是48字节,因为需要偏移12个int型数字
import numpy as npa = np.arange(24).reshape([2, 3, 4])print(a.strides)  # ==> (48, 16, 4)
print(a)  # ==>
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
#
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

reshape

reshape仅仅只是改变了数组的shape属性,比如把shape从(4,)(4,)(4,)改成(2,2)(2,2)(2,2)。通过下面的测试代码,可以明白reshape的下列性质:

  • 如果我们从最后一个维度开始,依次向前循环打印数组的话,会发现无论怎么样reshape,数组打印的顺序不会发生任何变化。也就是说无论reshape多少次,数组打印顺序不变。
  • 类似于python的浅拷贝,reshape之后,尽管变量发生了变化,但是变量内的数据体却未被碰过。下面列子中,改变reshape后的b的第一个值,发现所有相关的变量的第一个值都发生了变化,所以就可以知道,经reshape后,变量用于保存数据的那块内存没有被碰过。
import numpy as npa = np.arange(4)  # a = torch.arange(4)
print(a)  # ==> [0 1 2 3]
print(a.shape)  # ==> (4,)b = a.reshape([2, 2])  # b = a.reshape([2, 2])
print(b)  # ==> [[0 1], [2 3]]
print(b.shape)  # ==> (2, 2)c = b.reshape([-1])  # c = torch.reshape(b, [-1])
print(c)  # ==> [0 1 2 3]b[0, 0] = 100
print(a)  # ==> [100   1   2   3]
print(b)  # ==> [[100 1], [2 3]]
print(c)  # ==> [100   1   2   3]

transpose

transpose改变了数组的维度(axis)排列顺序。比如对于二维数组,如果我们把两个维度的顺序互换,那就是我们很熟悉的矩阵转置。而transpose可以在更多维度的情况下生效。transpose的入参是输出数组的维度排列顺序,序号从0开始计数。

下面例子中我们改变了transpose后的b的第一个元素的值,发现a也随之改变,说明transpose也没有去碰数组的内存。那么问题来了,既然数组没有在内存中重新排列,那么打印顺序是受什么影响而发生了改变呢?是strides。

import numpy as npa = np.arange(24).reshape([2, 3, 4])
print(a.base)  # ==>
# [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]print(a.shape)  # ==> (2, 3, 4)
print(a.strides)  # ==> (48, 16, 4)
print(a)  # ==>
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
#
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]b = a.transpose([1, 2, 0])
print(b.shape)  # ==>(3, 4, 2)
print(b.strides)  # ==> (16, 4, 48)
print(b)  # ==>
# [[[ 0 12]
#   [ 1 13]
#   [ 2 14]
#   [ 3 15]]
#
#  [[ 4 16]
#   [ 5 17]
#   [ 6 18]
#   [ 7 19]]
#
#  [[ 8 20]
#   [ 9 21]
#   [10 22]
#   [11 23]]]b[0, 0, 0] = 100
print(a)  # ==>
# [[[100   1   2   3]
#   [  4   5   6   7]
#   ...]]]print(b)  # ==>
# [[[100  12]
#   [  1  13]
#   ...]]]

下面图示一下strides的含义。

首先明确一个很重要的概念,strides都是相对于base数组而言进行遍历的,所以无论是a还是b,遍历时需要参考的源头都是a.base / b.base,也就是最上面的一维数组。

数组a的strides情况我们前面已经讲过了,接下来主要看看b

  • 由于b.strides最后一个维度的值是48,所以b[0, 0, 1]b[0, 0, 0]b.base中偏移48字节后的数字,也就是12
  • b.strides中间维度的值是4,所以b[0, 1, 0]b[0, 0, 0]b.base中偏移4字节后的数字,也就是1
  • b.strides第一个维度的值是16,所以b[1, 0, 0]b[0, 0, 0]b.base中偏移16字节后的数字,也就是4

所以ranspose操作只是改变了strides的顺序,没有重新排列内存中的数据。

总结

前面我们在解释reshape和transpose的机制时,分别从ndarray的shape和strides属性进行了侧重解释。实际上reshape既改变shape也改变strides,而transpose也可能会改变shape。

但这两个算子均不会在内存中重新排列数据。

numpy的reshape和transpose机制解释相关推荐

  1. numpy reshape和transpose的使用

    numpy reshape和transpose的使用 不熟悉numpy的时候,看到别人代码中的reshape和transpose不太懂,这里转载一下别人的解释,很强! Python numpy.tra ...

  2. Numpy和Opencv中的reshape 和 transpose的区别

    Numpy和Opencv中的reshape 和 transpose的区别 在Numpy和Opencv中,都有两个函数:reshape 和 transpose. 该两个函数都具有改变维度的作用,在使用中 ...

  3. Python精讲Numpy基础,大牛笔记详细解释

    https://www.toutiao.com/a6664936105076326920/ 总认为Numpy是渣渣,直到深入接触以后才知道功能这么强大.堪比Matlab啊.果然是人生苦短,我用Pyth ...

  4. numpy中的转置Transpose和.T以及轴对换swapaxis

    简 介: 本文对于 numpy中的转置Transpose和.T以及轴对换swapaxis 中关于numpy矩阵的轴交换函数进行了测试.并对于深度学习中的图像数据进行处理. 参考文章:https://b ...

  5. matlab imcrop 对应python函数_Python精讲Numpy基础,大牛笔记详细解释

    总认为Numpy是渣渣,直到深入接触以后才知道功能这么强大.堪比Matlab啊.果然是人生苦短,我用Python.所以本文作为一个记录&笔记,文章内容大多数取自网络以&官网快速入门等, ...

  6. pythonnumpy详解_Python精讲Numpy基础,大牛笔记详细解释

    以前总认为Numpy是渣渣,直到深入接触以后才知道功能这么强大.堪比Matlab啊.果然是人生苦短,我用Python.所以本文作为一个记录&笔记,文章内容大多数取自网络以&官网快速入门 ...

  7. 利用Python中的numpy.ndarray.reshape()对阵列形状进行调整

    我们在进行阵列运算的时候,常常要根据需要调整阵列的形状,numpy库中的函数reshape()可以方便地实现对阵列形状进行调整. 其函数原型如下: dst = numpy.ndarray.reshap ...

  8. numpy中reshape方法详解

    numpy中reshape方法详解_zhanggonglalala的博客-CSDN博客_reshape

  9. pythonreshape函数三个参数_Python Numpy中reshape函数参数-1的含义

    python numpy中reshape函数参数-1的含义,新数组的shape属性应该要与原来数组的一致,即新数组元素数量与原数组元素数量要相等.一个参数为-1时,那么reshape函数会根据另一个参 ...

最新文章

  1. 链接1: 学习Python以及SQL的好去处----仅链接
  2. 【每日一算法】买卖股票的最佳时机
  3. 整个世界都是你的绿幕:这个视频抠图换背景的方法着实真假难辨
  4. 如何快速成长为技术大牛?
  5. tinycore php,tinycore中文支持
  6. html中.inner样式,JavaScript-DOM动态控制Html标签对象样式和innerHTML、className属性
  7. 删除同目录下面txt文件(利用os,fnmacth模块)
  8. 域做文件服务器,linux 做域文件服务器
  9. Android 代码关于重构的一点体会
  10. 继承与data member之多重继承
  11. 中国大学MOOC伦理学试题题库及答案
  12. hashmap java 排序_Java HashMap 默认排序
  13. 有效地报告自动测试结果
  14. 3月4日 与柳传志面对面(谁是这个时代的思想家)
  15. 哪一款蓝牙耳机音质最好?2023发烧级音质蓝牙耳机推荐
  16. linux gic驱动
  17. Colab 上使用shutil.copytree()复制整个文件夹到另一个文件夹
  18. Qt实现天气信息显示和温度曲线绘制
  19. 安装python3.10.1教程
  20. linux内net.ipv4.tcp_tw_recycle参数一定不要启用

热门文章

  1. 如何提升美团渠道的快消商品销售-从搜索行为和转化率分析|倪钰桐谈电商
  2. Github下载慢解决了!「100%有效」
  3. U盘安装系统时,找不到磁盘的问题
  4. 模板消息(业务通知)
  5. 为啥Android手机总会越用越慢?
  6. 不知道怎么用?广百教你水性树脂涂料工业消泡剂EFKA8385破泡剂
  7. enclosing的意思_enclosing class是什么意思
  8. python 正则findall右斜杠_python中正则表达式的使用
  9. 深度讲解linux中fputc()函数
  10. 根据仙女的白富美程度匹配高富帅