本文是经过严格查阅相关权威文献和资料,形成的专业的可靠的内容。全文数据都有据可依,可回溯。特别申明:数据和资料已获得授权。本文内容,不涉及任何偏颇观点,用中立态度客观事实描述事情本身
一、导读
在深度学习的广阔天地里,数据操作是每一位AI算法工程师必须掌握的基本技能。今天我们将通过PyTorch这一流行的深度学习框架,深入探讨数据操作的核心内容,包括张量的定义、基本操作、广播机制、索引与切片、内存管理,以及与其他Python对象的转换。希望借助这篇文章,你能对深度学习的数据操作有更深入的认知,在实际项目里运用得更得心应手。
二、张量的定义与基本操作
张量是深度学习中用于存储和操作数据的基本单位,它是一个n维数组。在PyTorch中,张量类名为torch.Tensor
,与NumPy的ndarray
类似,但支持GPU加速计算和自动微分,更适合深度学习应用。
1. 张量的创建
我们可以通过多种方式创建张量,例如使用torch.arange
、torch.zeros
、torch.ones
、torch.random
等函数。以下是一些示例代码:
import torch
# 创建一个行向量,包含0到11的整数
x = torch.arange(12)
print(x)
# 输出:tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
# 创建一个形状为(2,3,4)的全0张量
zeros_tensor = torch.zeros((2, 3, 4))
print(zeros_tensor)
# 输出: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.]]])
# 创建一个形状为(3,4)的标准高斯分布随机张量
random_tensor = torch.random(3, 4)
print(random_tensor)
# 输出:tensor([[ 0.0561, -0.2157, 0.3538, -0.1382],
# [-0.2219, -0.3074, -0.5218, -0.4200],
# [ 0.3139, -0.2678, -0.2274, -0.3605]])
2. 张量的形状与大小
通过.shape
属性可以获取张量的形状,通过.numel()
方法或.size()
属性可以获取张量中元素的总数。
print(x.shape) # 输出:torch.Size([12])
print(x.numel()) # 输出:12
print(x.size()) # 输出:torch.Size([12])
3. 张量的重塑
使用.reshape
方法可以改变张量的形状而不改变其元素值。
# 将x重塑为形状为(3,4)的矩阵
X = x.reshape(3, 4)
print(X)
# 输出:tensor([[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]])
4. 张量的按元素运算
PyTorch支持常见的标准算术运算符(+、-、*、/、**)的按元素运算。
y = torch.tensor([2, 2, 2, 2])
print(X + y, X - y, X * y, X / y, X ** y)
# 输出:
# tensor([[ 2., 3., 4., 5.],
# [ 6., 7., 8., 9.],
# [10., 11., 12., 13.]])
# tensor([[-2., -1., 0., 1.],
# [ 2., 3., 4., 5.],
# [ 6., 7., 8., 9.]])
# tensor([[ 0., 2., 4., 6.],
# [ 8., 10., 12., 14.],
# [16., 18., 20., 22.]])
# tensor([0.0000, 0.5000, 1.0000, 1.5000])
# [2.0000, 2.5000, 3.0000, 3.5000])
# [4.0000, 4.5000, 5.0000, 5.5000]])
# tensor([[ 1., 1., 1., 1.],
# [16., 25., 36., 49.],
# [256., 512., 1024., 2048.]])
三、广播机制
广播机制允许PyTorch在执行按元素运算时自动扩展张量的形状,以匹配另一个张量的形状。
# 创建两个形状不同的张量
a = torch.arange(3).reshape(3, 1)
b = torch.arange(2).reshape(1, 2)
print(a, b)
# 输出:
# tensor([[0.],
# [1.],
# [2.]])
# tensor([[0, 1]])
# 通过广播机制进行按元素相加
print(a + b)
# 输出:
# tensor([[0., 1.],
# [1., 2.],
# [2., 3.]])
四、索引与切片
在PyTorch中,张量的元素可以通过索引和切片进行访问和修改。
# 访问最后一个元素
print(X[-1])
# 输出:tensor([ 8., 9., 10., 11.])
# 访问第二行到第三行的所有列
print(X[1:3, :])
# 输出:tensor([[ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]])
# 修改第二行第三列的元素值
X[1, 2] = 99
print(X)
# 输出:tensor([[ 0., 1., 2., 3.],
# [ 4., 5., 99., 7.],
# [ 8., 9., 10., 11.]])
五、内存管理
在PyTorch中,原地操作可以节省内存开销。原地操作是指直接修改现有张量而不创建新的张量。
# 创建一个新的张量Y,形状与X相同
Y = torch.zeros_like(X)
print('id(Y) before:', id(Y))
# 使用原地操作将X+Y的结果赋值给Y
Y[:] = X + Y
print('id(Y) after:', id(Y))
# 输出:id(Y) before 和 id(Y) after 的值相同,说明Y没有指向新的内存位置
六、与其他Python对象的转换
PyTorch张量可以轻松地转换为NumPy数组,反之亦然。但需要注意的是,转换后的结果不共享内存。
# 将PyTorch张量转换为NumPy数组
A = X.numpy()
print(type(A)) # 输出:<class 'numpy.ndarray'>
# 将NumPy数组转换为PyTorch张量
B = torch.tensor(A)
print(type(B)) # 输出:<class 'torch.Tensor'>
参考文献:
动手学深度学习在线课程(https://zh-v2.d2l.ai/chapter_introduction/index.html)