PyTorch中Tensor的基本用法与动手学深度学习的预备知识

  • 第一部分是PyTorch中有关Tensor的一些基本用法,因为之前并没有系统学习过PyTorch,所以现在看书的同时慢慢学习PyTorch的知识

  • 第二部分是原书的知识和一些自己的理解

    • 一、PyTorch 中的Tensor
      • 1.1 Tensor的创建
      • 1.2 Tensor的数据类型
        • 1.2.1 torch.FloatTensor
        • 1.2.2 torch.IntTensor
        • 1.2.3 torch.rand
        • 1.2.4 torch.randn
        • 1.2.5 torch.range
        • 1.2.6 torch.zeros
      • 1.3 Tensor的运算
        • 1.3.1 torch.abs
        • 1.3.2 torch.add
        • 1.3.3 torch.clamp
        • 1.3.4 torch.div
        • 1.3.5 torch.mul
        • 1.3.6 torch.pow
        • 1.3.7 torch.mm
        • 1.3.8 torch.mv
    • 二、原书
      • 2.1 数据操作
        • 2.1.1 索引
        • 2.1.2 改变形状
      • 2.2 线性代数
      • 2.3 广播机制
      • 2.4 运算内存开销
      • 2.5 Tensor和NumPy相互转换
      • 2.2.6 Tensor on GPU

张量 Tensor

张量包含了一个数据集合,这个数据集合就是原始值变形而来的,它可以是一个任何维度的数据。tensor的rank就是其维度。

Rank本意是矩阵的秩,不过Tensor Rank和Matrix Rank的意义不太一样,这里就还叫Rank。Tensor Rank的意义看起来更像是维度,比如Rank =1就是向量,Rank=2 就是矩阵了,Rank = 0 就是一个值。

一、PyTorch 中的Tensor

在PyTorch中,**torch.Tensor**是存储和变换数据的主要工具。TensorNumPy 的多维数组非常类似。

首先导入PyTorch

import torch

1.1 Tensor的创建

创建一个5x3的未初始化的 Tensor

x = torch.empty(5, 3)
print(x)
tensor([[5.4880e+23, 4.5886e-41, 2.7434e-24],
        [3.0915e-41, 4.4842e-44, 0.0000e+00],
        [4.4842e-44, 0.0000e+00, 2.7450e-24],
        [3.0915e-41, 5.4880e+23, 4.5886e-41],
        [4.2039e-45, 0.0000e+00, 4.6243e-44]])

创建一个5x3的随机初始化的 Tensor

x = torch.rand(5, 3)  # 这里rand的用法后面会讲到
print(x)
tensor([[0.7787, 0.8019, 0.3431],
        [0.1335, 0.3062, 0.2305],
        [0.6151, 0.5777, 0.2794],
        [0.4701, 0.6086, 0.9624],
        [0.6524, 0.6794, 0.8206]])

创建一个5x3的long类型全0的 Tensor

x = torch.zeros(5, 3, dtype=torch.long)
print(x)
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])

直接根据数据创建

x = torch.tensor([5.5, 3])
print(x)
tensor([5.5000, 3.0000])

通过现有的 Tensor 来创建,此方法会默认重用输入 Tensor 的一些属性,例如数据类型,除非自定义数据类型。

x = x.new_ones(5, 3, dtype=torch.float64)  # new_ones 返回一个与size大小相同的用1填充的张量,默认具有相同的torch.dtype和torch.device
print(x)

x = torch.randn_like(x, dtype=torch.float) # randn_like形状与输入的张量相同,指定新的数据类型
print(x) 
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
tensor([[-0.9532,  0.4367, -0.1972],
        [ 2.1078,  0.3750, -0.2939],
        [-0.3682,  1.3246, -0.7197],
        [-0.4119,  0.2093, -0.3431],
        [-1.7094,  0.0638, -0.4597]])

通过 shape 或者size() 来获取 Tensor 的形状

print(x.size())
print(x.shape)
torch.Size([5, 3])
torch.Size([5, 3])

✨ 注意:返回的torch.Size其实就是一个tuple, 支持所有tuple的操作。

1.2 Tensor的数据类型

1.2.1 torch.FloatTensor

此变量用于生成数据类型为浮点型的 Tensor,传递给 torch.FloatTensor 的参数可以是一个列表,也可以是一个维度值。

a = torch.FloatTensor(2, 3)  # 两行三列
print(a)
tensor([[5.4880e+23, 4.5886e-41, 5.4880e+23],
        [4.5886e-41, 1.4584e-19, 7.8458e+17]])
b = torch.FloatTensor([[2, 3], [4, 5]])
print(b, b.shape, b.dtype)
tensor([[2., 3.],
        [4., 5.]]) torch.Size([2, 2]) torch.float32

1.2.2 torch.IntTensor

用于生成数据类型为整型的 Tensor,传递给 torch.IntTensor 的参数可以是一个列表,也可以是一个维度值。

a = torch.IntTensor(2, 3)
print(a)
tensor([[1726508320,      32745,  407958368],
        [     22062, 1953384789, 1701869908]], dtype=torch.int32)
b = torch.IntTensor([[2, 3], [4, 5]])
print(b, b.dtype)
tensor([[2, 3],
        [4, 5]], dtype=torch.int32) torch.int32

1.2.3 torch.rand

用于生成数据类型为浮点型且维度指定的随机 Tensor,和在 Numpy 中使用 numpy.rand 生成随机数的方法类似,随机生成的浮点数据在 0~1区间均匀分布。

a = torch.rand(2, 3)
print(a, a.dtype)
tensor([[0.8055, 0.3392, 0.5802],
        [0.3333, 0.7156, 0.3415]]) torch.float32

1.2.4 torch.randn

用于生成数据类型为浮点型且维度指定的随机 Tensor,和在 Numpy 中使用 numpy.randn生成随机数的方法类似,随机生成的浮点数的取值满足均值为0,方差为1的正态分布

a = torch.randn(2, 3)
print(a, a.dtype)
tensor([[ 0.4737,  0.3686, -1.1102],
        [ 0.9147, -0.3446, -0.7511]]) torch.float32

1.2.5 torch.range

用于生成数据类型为浮点型且自定义其实范围和结束范围的 Tensor,所以传递给 torch.range 的参数有三个,分别是范围的起始值,范围的结束值步长,其中,步长用于指定从起始值到结束值的每步的数据间隔。

a = torch.range(2, 8, 3)
print(a, a.dtype)
tensor([2., 5., 8.]) torch.float32


/opt/conda/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: torch.range is deprecated in favor of torch.arange and will be removed in 0.5. Note that arange generates values in [start; end), not [start; end].

1.2.6 torch.zeros

用于生成数据类型为浮点型且维度指定的 Tensor,不过这个浮点型的 Tensor 中的元素值全部为0

a = torch.zeros(3, 4)
print(a, a.dtype)
tensor([[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]) torch.float32

1.3 Tensor的运算

这里通常对 Tensor 数据类型的变量进行运算,来组合一些简单或者复杂的算法,常用的 Tensor 运算如下:

1.3.1 torch.abs

将参数传递到 torch.abs 后返回输入参数的绝对值作为输出,输出参数必须是一个 Tensor 数据类型的变量

a = torch.randn(2, 3)
print(a)
b = torch.abs(a)
print(b)
tensor([[-1.5257,  0.1174, -0.2927],
        [ 0.4662,  0.7019,  0.2605]])
tensor([[1.5257, 0.1174, 0.2927],
        [0.4662, 0.7019, 0.2605]])

1.3.2 torch.add

将参数传递到 torch.add 后返回输入参数的求和结果作为输出,输入参数既可以全部是 Tensor 数据类型的变量,也可以是一个 Tensor 数据类型的变量,另一个是标量。

a = torch.randn(2, 3)
print(a)

b = torch.randn(2, 3)
print(b)

c = torch.add(a, b)
print(c)

d = torch.randn(2, 3)
print(d)

e = torch.add(d, 10)
print(e)
tensor([[-1.5090, -1.1659, -0.7795],
        [ 0.8453, -0.0334,  0.2251]])
tensor([[-1.5168, -1.2602,  0.8775],
        [ 1.8206, -0.0880, -1.1371]])
tensor([[-3.0258, -2.4261,  0.0980],
        [ 2.6659, -0.1213, -0.9120]])
tensor([[0.2818, 1.4852, 2.0287],
        [1.1209, 1.6720, 1.0154]])
tensor([[10.2818, 11.4852, 12.0287],
        [11.1209, 11.6720, 11.0154]])

可以指定输出

result = torch.empty(2, 3)
torch.add(a, b, out=result)
print(result)
tensor([[-3.0258, -2.4261,  0.0980],
        [ 2.6659, -0.1213, -0.9120]])

关于加法还有两种方式:

  • 第一种,+号
  • 第二种,inplace

✨ 注:PyTorch操作inplace版本都有后缀_, 例如x.copy_(y), x.t_()

print(a+b)
tensor([[-3.0258, -2.4261,  0.0980],
        [ 2.6659, -0.1213, -0.9120]])
b.add_(a)
print(b)
tensor([[-3.0258, -2.4261,  0.0980],
        [ 2.6659, -0.1213, -0.9120]])

1.3.3 torch.clamp

对输入参数按照自定义的范围进行裁剪,最后将参数裁剪的结果作为输出。所以输入参数一共有三个,分别是需要进行裁剪的Tensor数据类型的变量裁剪的上边界裁剪的下边界

具体的裁剪过程是:使用变量中的每个元素分别和裁剪的上边界及裁剪的下边界的值进行比较,如果元素的值小于裁剪的下边界的值,该元素就被重写成裁剪的下边界的值;

同理,如果元素的值大于裁剪的上边界的值,该元素就被重写成裁剪的上边界的值。

a = torch.randn(2, 3)
print(a)

b = torch.clamp(a, -0.1, 0.1)
print(b)
tensor([[ 0.5965,  2.1073, -1.2866],
        [-0.1101, -1.6736, -2.2357]])
tensor([[ 0.1000,  0.1000, -0.1000],
        [-0.1000, -0.1000, -0.1000]])

1.3.4 torch.div

将参数传递到 torch.div 后返回输入参数的求商结果作为输出,同样,参与运算的参数可以全部是 Tensor 数据类型的变量,也可以是 Tensor 数据类型的变量和标量的组合。

a = torch.randn(2,3)
print(a)
 
b = torch.randn(2,3)
print(b)
 
c = torch.div(a,b)
print(c)
 
d = torch.randn(2,3)
print(d)
 
e = torch.div(d,10)
print(e)
tensor([[ 0.4518,  0.1334,  1.7579],
        [ 0.0349, -0.2346,  1.6790]])
tensor([[ 1.2516, -1.1198,  1.1351],
        [-0.6222, -0.6472, -0.0758]])
tensor([[  0.3610,  -0.1191,   1.5486],
        [ -0.0561,   0.3624, -22.1492]])
tensor([[ 0.2908,  0.0664, -1.4821],
        [ 0.4358,  0.3226,  1.0338]])
tensor([[ 0.0291,  0.0066, -0.1482],
        [ 0.0436,  0.0323,  0.1034]])

1.3.5 torch.mul

将参数传递到 torch.mul 后返回输入参数求积的结果作为输出,参与运算的参数可以全部是 Tensor 数据类型的变量,也可以是 Tensor 数据类型的变量和标量的组合。

a = torch.randn(2, 3)
print(a)

b = torch.randn(2, 3)
print(b)

c = torch.mul(a, b)
print(c)

d = torch.randn(2, 3)
print(d)

e = torch.mul(d, 10)
print(e)
tensor([[ 0.5851,  0.2113,  0.6891],
        [ 1.1177, -0.0177,  1.5595]])
tensor([[ 0.9094, -0.0707, -0.3900],
        [ 0.2990, -0.9827,  0.7165]])
tensor([[ 0.5321, -0.0149, -0.2687],
        [ 0.3342,  0.0174,  1.1174]])
tensor([[-0.7012,  1.2348,  1.6156],
        [ 0.5412,  0.2345, -0.5753]])
tensor([[-7.0115, 12.3478, 16.1558],
        [ 5.4116,  2.3447, -5.7526]])

1.3.6 torch.pow

将参数传递到 torch.pow 后返回输入参数的求幂结果作为输出,参与运算的参数可以全部是 Tensor 数据类型的变量,也可以是 Tensor 数据类型的变量和标量的组合。

a = torch.randn(2, 3)
print(a)

b = torch.pow(a, 2)
print(b)
tensor([[-0.9387,  1.0499, -1.6718],
        [-0.3190, -1.1677, -0.0666]])
tensor([[0.8812, 1.1024, 2.7948],
        [0.1018, 1.3635, 0.0044]])

1.3.7 torch.mm

将参数传递到 torch.mm 后返回输入参数的求积结果作为输出,不过这个求积的方式和之前的 torch.mul运算方式不太样,

torch.mm 运用矩阵之间的乘法规则进行计算,所以被传入的参数会被当作矩阵进行处理,参数的维度自然也要满足矩阵乘法的前提条件,

前一个矩阵的行数必须和后一个矩阵的列数相等,否则不能进行计算。

a = torch.randn(2, 3)
print(a)

b = torch.randn(3, 2)
print(b)

b = torch.mm(a, b)
print(b)
tensor([[ 0.1701,  0.9539, -0.3128],
        [-0.2466,  2.4600, -1.6023]])
tensor([[-1.0573, -1.0292],
        [-0.2707,  0.2992],
        [-1.0913, -3.1058]])
tensor([[-0.0967,  1.0818],
        [ 1.3436,  5.9664]])

1.3.8 torch.mv

将参数传递到 torch.mv 后返回输入参数的求积结果作为输出,torch.mv 运用矩阵与向量之间的乘法规则进行计算,被传入的参数中的第1个参数代表矩阵,第2个参数代表向量,顺序不能颠倒。

a = torch.randn(2, 3)
print(a)

b = torch.randn(3)
print(b)

c = torch.mv(a, b)
print(c)
tensor([[ 1.7745,  0.8665, -0.5622],
        [-0.6072,  0.5540, -1.0647]])
tensor([ 0.0553, -0.5526, -1.0924])
tensor([0.2335, 0.8233])

二、原书

2.1 数据操作

部分操作已经在前面提及

2.1.1 索引

索引出来的结果与原数据共享内存,也即修改一个,另一个会跟着修改。

x = torch.randn(2, 4)
print(x)
y = x[:, :3]
print(y)
y += 1
print(y)
print(x[:, :3]) # 源tensor也被改了
print(x)
tensor([[ 0.5706,  0.3683,  1.4869,  1.2791],
        [-0.1592, -1.7226, -1.1192, -0.9729]])
tensor([[ 0.5706,  0.3683,  1.4869],
        [-0.1592, -1.7226, -1.1192]])
tensor([[ 1.5706,  1.3683,  2.4869],
        [ 0.8408, -0.7226, -0.1192]])
tensor([[ 1.5706,  1.3683,  2.4869],
        [ 0.8408, -0.7226, -0.1192]])
tensor([[ 1.5706,  1.3683,  2.4869,  1.2791],
        [ 0.8408, -0.7226, -0.1192, -0.9729]])

除了常用的索引选择数据之外,PyTorch还提供了一些高级的选择函数:

函数 功能
index_select(input, dim, index) 在指定维度dim上选取,比如选取某些行、某些列
masked_select(input, mask,out=None) 根据布尔掩码 (boolean mask) 索引输入张量的 1D 张量
nonzero(input) 非0元素的下标
gather(input, dim, index) 根据index,在dim维度上选取数据,输出的size与index一样

index_select

index_select(
    input,
    dim,
    index
)

参数:

  • input:索引的对象
  • dim:表示从第几维挑选数据,类型为int值;0表示按行索引,1表示按列索引
  • index:表示从第一个参数维度中的哪个位置挑选数据,类型为torch.Tensor类的实例;
print(torch.index_select(x,0,torch.tensor([0, 1])))
print(torch.index_select(x,1,torch.tensor([0, 1])))
tensor([[ 1.5706,  1.3683,  2.4869,  1.2791],
        [ 0.8408, -0.7226, -0.1192, -0.9729]])
tensor([[ 1.5706,  1.3683],
        [ 0.8408, -0.7226]])

masked_select

masked_select(
    input,
    mask,
    out
)

参数:

  • input(Tensor) :需要进行索引操作的输入张量;
  • mask(BoolTensor) :要进行索引的布尔掩码
  • out(Tensor, optional) :指定输出的张量。比如执行 torch.zeros([2, 2], out = tensor_a),相当于执行 tensor_a = torch.zeros([2, 2]);

⚠️ 注意:「 masked_select 函数最关键的参数就是布尔掩码 mask,

传入 mask 参数的布尔张量通过 True 和 False (或 1 和 0) 来决定输入张量对应位置的元素是否保留,

既然是一一对应的关系,这就需要传入 mask 中的布尔张量和传入 input 中的输入张量形状要相同。

mask = x.ge(0.5)
print(mask)
print(torch.masked_select(x, mask))
tensor([[ True,  True,  True,  True],
        [ True, False, False, False]])
tensor([1.5706, 1.3683, 2.4869, 1.2791, 0.8408])
print(x)
print(torch.nonzero(x))
tensor([[ 1.5706,  1.3683,  2.4869,  1.2791],
        [ 0.8408, -0.7226, -0.1192, -0.9729]])
tensor([[0, 0],
        [0, 1],
        [0, 2],
        [0, 3],
        [1, 0],
        [1, 1],
        [1, 2],
        [1, 3]])

gather

gather(
    input, 
    dim,
    index
)

参数:

  • input (Tensor) – 需要进行索引操作的输入张量;
  • dim (int) – 表示从第几维挑选数据,类型为int值;
  • index (LongTensor) – 要收集的元素的索引;
  • out (Tensor, optional) – 指定输出的张量。
print(torch.gather(x, dim=1, index=torch.LongTensor([[0, 1],[0, 0]])))  # dim为1说明按列索引,[0, 1]表示第一行的第0列和第1列,就是1.5706和1.3683,同理[0, 0]是0.8408和0.8408
print(torch.gather(x, dim=0, index=torch.LongTensor([[0,1,1,0],[0,0,0,0]])))   # dim为0说明按行索引,[0, 1, 1, 0]表示第0行,第1行,第1行,第0行
tensor([[1.5706, 1.3683],
        [0.8408, 0.8408]])
tensor([[ 1.5706, -0.7226, -0.1192,  1.2791],
        [ 1.5706,  1.3683,  2.4869,  1.2791]])

2.1.2 改变形状

view() 来改变 Tensor 的形状:

⚠️ 需要注意的是:-1所指的维度可以根据其他维度的值推出来,这个用法在很多地方都见过,应该要记住

y = x.view(8)
z = x.view(-1, 2)  # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size())
torch.Size([2, 4]) torch.Size([8]) torch.Size([4, 2])

view()返回的新 Tensor 与源 Tensor 虽然可能有不同的 size,但是是共享 data 的,也即更改其中的一个,另外一个也会跟着改变。(顾名思义,view 仅仅是改变了对这个张量的观察角度,内部数据并未改变)

x += 1
print(x)
print(y)
tensor([[2.5706, 2.3683, 3.4869, 2.2791],
        [1.8408, 0.2774, 0.8808, 0.0271]])
tensor([2.5706, 2.3683, 3.4869, 2.2791, 1.8408, 0.2774, 0.8808, 0.0271])

所以如果我们想返回一个真正新的副本(即不共享data内存)该怎么办呢?

Pytorch还提供了一个 reshape() 可以改变形状,但是此函数并不能保证返回的是其拷贝,所以不推荐使用。推荐先用 clone 创造一个副本然后再使用 view

x_cp = x.clone().view(8)
x -= 1
print(x)
print(x_cp)
tensor([[ 1.5706,  1.3683,  2.4869,  1.2791],
        [ 0.8408, -0.7226, -0.1192, -0.9729]])
tensor([2.5706, 2.3683, 3.4869, 2.2791, 1.8408, 0.2774, 0.8808, 0.0271])

✨ 使用 clone 还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor

另外一个常用的函数就是 item(), 它可以将一个标量 Tensor 转换成一个Python number:

x = torch.randn(1)
print(x)
print(x.item())
tensor([1.0600])
1.059958815574646

2.2 线性代数

另外,PyTorch还支持一些线性函数,这里提一下,免得用起来的时候自己造轮子,具体用法参考官方文档。如下表所示:

函数 功能
trace 对角线元素之和(矩阵的迹)
diag 对角线元素
triu/tril 矩阵的上三角/下三角,可指定偏移量
mm/bmm 矩阵乘法,batch的矩阵乘法
addmm/addbmm/addmv/addr/baddbmm… 矩阵运算
t 转置
dot/cross 内积/外积
inverse 求逆矩阵
svd 奇异值分解

2.3 广播机制

当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。

x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])

由于 xy 分别是1行2列和3行1列的矩阵,如果要计算 x + y,那么 x 中第一行的2个元素被广播(复制)到了第二行和第三行,

y 中第一列的3个元素被广播(复制)到了第二列。如此,就可以对2个3行2列的矩阵按元素相加。

2.4 运算内存开销

前面说了,索引操作是不会开辟新内存的,而像y = x + y 这样的运算是会新开内存的,然后将y指向新内存。

为了演示这一点,我们可以使用Python自带的 id 函数:如果两个实例的ID一致,那么它们所对应的内存地址相同;反之则不同。

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before) # False 
False

如果想指定结果到原来的 y 的内存,我们可以使用前面介绍的索引来进行替换操作。在下面的例子中,我们把x + y的结果通过 [:] 写进 y 对应的内存中。

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before) # True
True

我们还可以使用运算符全名函数中的 out 参数或者自加运算符 += (也即 add_() )达到上述效果,例如 torch.add(x, y, out=y)y += x(y.add_(x))

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
torch.add(x, y, out=y) # y += x, y.add_(x)
print(id(y) == id_before) # True
True

✨ 注:虽然 view 返回的 Tensor 与源 Tensor 是共享data的,但是依然是一个新的 Tensor(因为 Tensor 除了包含data外还有一些其他属性),二者id(内存地址)并不一致。

2.5 Tensor和NumPy相互转换

我们很容易用 numpy()from_numpy()TensorNumPy 中的数组相互转换。

但是需要注意的一点是: 这两个函数所产生的的 TensorNumPy 中的数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变!!!

还有一个常用的将NumPy中的array转换成Tensor的方法就是torch.tensor(), 需要注意的是,此方法总是会进行数据拷贝(就会消耗更多的时间和空间),所以返回的Tensor和原来的数据不再共享内存。

Tensor转NumPy

使用 numpy()Tensor 转换成 NumPy 数组:

a = torch.ones(5)
b = a.numpy()
print(a, b)

a += 1
print(a, b)
b += 1
print(a, b)
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]

NumPy数组转Tensor

使用from_numpy()NumPy 数组转换成 Tensor :

import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a, b)

a += 1
print(a, b)
b += 1
print(a, b)
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)

所有在CPU上的 Tensor(除了 CharTensor)都支持与 NumPy 数组相互转换。

此外上面提到还有一个常用的方法就是直接用 torch.tensor()NumPy 数组转换成 Tensor

需要注意的是该方法总是会进行数据拷贝,返回的 Tensor 和原来的数据不再共享内存。

c = torch.tensor(a)
a += 1
print(a, c)
[4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)

2.2.6 Tensor on GPU

用方法 to() 可以将 Tensor 在CPU和GPU(需要硬件支持)之间相互移动。

# 以下代码只有在PyTorch GPU版本上才会执行
if torch.cuda.is_available():
    device = torch.device("cuda")          # GPU
    y = torch.ones_like(x, device=device)  # 直接创建一个在GPU上的Tensor
    x = x.to(device)                       # 等价于 .to("cuda")
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # to()还可以同时更改数据类型

你可能感兴趣的:(深度学习)