《动手学深度学习 Pytorch版》 2.1 数据操作

文章介绍了PyTorch中的张量操作,包括创建、形状变换、运算符使用、广播机制和内存管理。通过示例展示了如何进行张量的初始化、按元素运算、索引切片,并讨论了原地操作和转换为NumPy数组的方法。此外,还涉及了张量间按元素比较的逻辑运算及广播规则的应用。
摘要由CSDN通过智能技术生成

2.1.1 数据操作

注意此处 import 的不是 pytorch 而是 torch。Torch 是采用 lua 语言实现的,从某种程度上说,PyTorch 是 Torch 的 Python 版本。(当然还是有部分差别的)

import torch

张量(tensor)可以说是机器学习中的数组,直观的看张量像是封装了数组以及一系列相关操作的数据结构。

一个轴的张量对应数学上的向量(vector),两个轴的张量对应数学上的矩阵(matrix),两个轴以上的张量还没有特定的数学名称。

可以调用 arange 函数创建指定范围、元素类型的行向量。除非额外指定,否则张量默认存储在内存中并采用基于CPU的运算。

可以通过张量的 shape 属性访问张量的形状,即张量由外向内的维度。

可以调用 numel 函数获取张量中的元素数量。

x = torch.arange(12)
x, x.shape, x.numel()
(tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]),
 torch.Size([12]),
 12)

可以调用 reshape 函数改变张量的形状而不改变元素数量与元素值。其中参数可用 -1 替代可自行计算补全参数

X = x.reshape(3, 4) # (3, 4)等价于(-1, 4)等价于(3, -1)
X, X.shape, X.numel()
(tensor([[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]]),
 torch.Size([3, 4]),
 12)

可以调用 zeros 函数和 ones 函数创建指定形状的元素全0/1的张量。

可以调用 randn 函数创建指定形状的元素从均值为0、标准差为1的正态分布中随机采样的张量。

当然也可以调用 tensor 函数直接使用列表创建张量。

torch.zeros((2,3,4)), torch.ones((2,3,4))
(tensor([[[0., 0., 0., 0.],
          [0., 0., 0., 0.],
          [0., 0., 0., 0.]],
 
         [[0., 0., 0., 0.],
          [0., 0., 0., 0.],
          [0., 0., 0., 0.]]]),
 tensor([[[1., 1., 1., 1.],
          [1., 1., 1., 1.],
          [1., 1., 1., 1.]],
 
         [[1., 1., 1., 1.],
          [1., 1., 1., 1.],
          [1., 1., 1., 1.]]]))
torch.randn(3, 4), torch.randn((2,3,4))
(tensor([[ 1.6222,  0.7231, -1.4024,  0.7588],
         [-0.1125,  0.5207,  0.6089,  1.2352],
         [ 2.0539,  1.1926,  0.5572,  0.6947]]),
 tensor([[[-0.7136, -1.2191, -1.2900, -1.5955],
          [ 0.4796, -1.0602, -0.7268, -0.4906],
          [ 0.5334, -0.3188, -1.2223,  1.4670]],
 
         [[ 0.3615,  0.4890, -1.0624, -0.3882],
          [ 0.1696, -1.2423,  0.4243,  0.7088],
          [-0.2190,  1.1008,  1.2330,  0.3669]]]))
torch.tensor([[2, 1, 4, 3], [9, 1, 4, 3], [2, 1, 0, 3]])
tensor([[2, 1, 4, 3],
        [9, 1, 4, 3],
        [2, 1, 0, 3]])

2.1.2 运算符

常见的标准运算符都可以进行按元素(elementwise)运算,按元素方式可以应用于更多的计算,包括 exp 函数。

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y, torch.exp(x) # **是求幂运算
(tensor([ 3.,  4.,  6., 10.]),
 tensor([-1.,  0.,  2.,  6.]),
 tensor([ 2.,  4.,  8., 16.]),
 tensor([0.5000, 1.0000, 2.0000, 4.0000]),
 tensor([ 1.,  4., 16., 64.]),
 tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03]))

可以调用 cat 函数把多个张量按某个轴连接(concatenate)在一起。

X = torch.arange(12, dtype=torch.float32).reshape((3, 4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
X, Y, torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.]]),
 tensor([[2., 1., 4., 3.],
         [1., 2., 3., 4.],
         [4., 3., 2., 1.]]),
 tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [ 2.,  1.,  4.,  3.],
         [ 1.,  2.,  3.,  4.],
         [ 4.,  3.,  2.,  1.]]),
 tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
         [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
         [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))

可以通过逻辑运算符构建二元张量,例如可以使用 == 符号比较每个位置元素的值。

调用 sum 函数会对张量中所有元素求和后产生一个单元素张量。

X == Y
tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])
X.sum()
tensor(66.)

2.1.3 广播机制

在某些情况下,不同形状的张量可以通过广播机制(broadcasting mechanism)自动扩展以进行按元素操作。

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b, a + b
(tensor([[0],
         [1],
         [2]]),
 tensor([[0, 1]]),
 tensor([[0, 1],
         [1, 2],
         [2, 3]]))

2.1.4 索引和切片

和任何的其他的Python数组一样,张量可以通过索引访问、写入等操作。

X, X[-1], X[1:3]
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.]]),
 tensor([ 8.,  9., 10., 11.]),
 tensor([[ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.]]))
X[1, 2] = 9
X
tensor([[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  9.,  7.],
        [ 8.,  9., 10., 11.]])
X[0:2, :] = 12 # 访问第1行和第2行的所有元素
X
tensor([[12., 12., 12., 12.],
        [12., 12., 12., 12.],
        [ 8.,  9., 10., 11.]])

2.1.5 节省内存

直接使用 Y = Y + X 则会在运算过程中给Y重新申请内存。
执行原地操作有两种方式:

  • 使用切片表示法将操作结果分配给原数组,例如Y[ : ] = <expression>
  • 也可以使用 += 运算符进行原地操作
before = id(Y)
Y = Y + X # 新Y会重新分配内存
id(Y) == before
False
Z = torch.zeros_like(Y)
print("id(Z):", id(Z))
Z[:] = X + Y # 使用切片表示法将操作结果分配给原数组以实现原地操作
print("id(Z):", id(Z))
id(Z): 2695200905792
id(Z): 2695200905792
before = id(X)
X += Y # 使用 += 运算符进行原地操作
id(X) == before
True

2.1.6 转换为其他Python对象

PyTorch张量可以很容易转换为NumPy张量。要将大小为1的张量转换为Python标量可以调用 item 函数,也可以使用Python内置的强制类型转换。

A = X.numpy()
B = torch.tensor(A)
type(A), type(B)
(numpy.ndarray, torch.Tensor)
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3)

练习

(1)将 == 替换为 > 或 < 得到的仍是按元素进行逻辑运算的结果。

X < Y, X > Y
(tensor([[False, False, False, False],
         [False, False, False, False],
         [False, False, False, False]]),
 tensor([[True, True, True, True],
         [True, True, True, True],
         [True, True, True, True]]))

(2)可广播的一对张量需满足以下规则:

  • 每个张量至少有一个维度。
  • 迭代维度尺寸时,从尾部的维度开始,维度尺寸满足以下某一情况:
    • 相等,
    • 其中一个张量的维度尺寸为 1 ,
    • 其中一个张量不存在这个维度。
x = torch.ones(5,3,4,1)
y = torch.ones(  3,1,1)
(x + y).shape # 可广播
torch.Size([5, 3, 4, 1])
x = torch.empty((0,))
y = torch.empty(2, 2)
# (x + y).shape # 不可广播 不满足第一条规则
x = torch.ones(5, 2, 4, 1)
y = torch.ones(   3, 1, 1)
# (x + y).shape # 不可广播 不满足第二条规则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值