当前位置:   article > 正文

Tensor和Numpy_tensor.numpy()

tensor.numpy()

Tensor和Numpy数组之间具有很高的相似性,彼此之间的互操作也非常简单高效。需要注意的是,Numpy和Tensor共享内存。由于Numpy历史悠久,支持丰富的操作,所以当遇到Tensor不支持的操作时,可先转成Numpy数组,处理后再转回tensor,其转换开销很小。

示例代码:

from __future__ import print_function
import torch as t
import numpy as np

a = np.ones([2, 3],dtype=np.float32)
"""
[[1. 1. 1.]
 [1. 1. 1.]]
"""
b = t.from_numpy(a)
"""
tensor([[1., 1., 1.],
        [1., 1., 1.]])
"""
b = t.Tensor(a) # 也可以直接将numpy对象传入Tensor
"""
tensor([[1., 1., 1.],
        [1., 1., 1.]])
"""
a[0, 1]=100
print(b)
"""
tensor([[  1., 100.,   1.],
        [  1.,   1.,   1.]])
"""
c = b.numpy() # a, b, c三个对象共享内存
print(c)
"""
[[  1. 100.   1.]
 [  1.   1.   1.]]
"""

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

注意: 当numpy的数据类型和Tensor的类型不一样的时候,数据会被复制,不会共享内存。

a = np.ones([2, 3])
# 注意和上面的a的区别(dtype不是float32)
print(a.dtype)  #float64

b = t.Tensor(a) # 此处进行拷贝,不共享内存
print(b.dtype)  #torch.float32
c = t.from_numpy(a) # 注意c的类型
print(c.dtype)  #torch.float64
a[0, 1]=100
print(b)# b与a不共享内存,所以即使a改变了,b也不变
"""
tensor([[1., 1., 1.],
        [1., 1., 1.]])
"""
print(c)# c与a共享内存
"""
tensor([[  1., 100.,   1.],
        [  1.,   1.,   1.]], dtype=torch.float64)
"""

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

注意: 不论输入的类型是什么,t.tensor都会进行数据拷贝,不会共享内存。

tensor = t.tensor(a)
tensor[0,0]=0
print(tensor)
print(a)
"""
tensor([[  0., 100.,   1.],
        [  1.,   1.,   1.]], dtype=torch.float64)
[[  1. 100.   1.]
 [  1.   1.   1.]]
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

广播法则(broadcast)是科学运算中经常使用的一个技巧,它在快速执行向量化的同时不会占用额外的内存/显存。 Numpy的广播法则定义如下:

  • 让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐

  • 两个数组要么在某一个维度的长度一致,要么其中一个为1,否则不能计算

  • 当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状

PyTorch当前已经支持了自动广播法则,还是建议通过以下两个函数的组合手动实现广播法则,这样更直观,更不易出错:

  • unsqueeze或者view,或者tensor[None],:为数据某一维的形状补1,实现法则1
  • expand或者expand_as,重复数组,实现法则3;该操作不会复制数组,所以不会占用额外的空间。

注意,repeat实现与expand相类似的功能,但是repeat会把相同数据复制多份,因此会占用额外的空间。

a = t.ones(3, 2)
b = t.zeros(2, 3,1)
# 自动广播法则
# 第一步:a是2维,b是3维,所以先在较小的a前面补1 ,
#               即:a.unsqueeze(0),a的形状变成(1,3,2),b的形状是(2,3,1),
# 第二步:   a和b在第一维和第三维形状不一样,其中一个为1 ,
#               可以利用广播法则扩展,两个形状都变成了(2,3,2)
a+b
"""
tensor([[[1., 1.],
         [1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.],
         [1., 1.]]])
"""
# 手动广播法则
# 或者 a.view(1,3,2).expand(2,3,2)+b.expand(2,3,2)
a[None].expand(2, 3, 2) + b.expand(2,3,2)
"""
tensor([[[1., 1.],
         [1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.],
         [1., 1.]]])
"""
# expand不会占用额外空间,只会在需要的时候才扩充,可极大节省内存
e = a.unsqueeze(0).expand(10000000000000, 3,2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/219418
推荐阅读
  

闽ICP备14008679号