欢迎关注『youcans的深度学习』系列,持续更新中…
【youcans的深度学习 01】安装环境之 miniconda
【youcans的深度学习 02】PyTorch CPU版本安装与环境配置
【youcans的深度学习 03】PyTorch CPU版本安装与环境配置
【youcans的深度学习 04】PyTorch入门教程:基础知识
【youcans的深度学习 05】PyTorch入门教程:快速入门
【youcans的深度学习 06】PyTorch入门教程:张量的基本操作 1
【youcans的深度学习 06】PyTorch入门教程:张量的基本操作 1
1. 张量及其数据结构
“张量”(Tensor)是 PyTorch 的基本数据结构。
PyTorch 中主要通过张量对数据进行存储和变换操作。张量的数据结构与操作与 Numpy 多维数组 ndarray 类似,但可以在GPU上使用以加速计算,更适合深度学习。
张量是一个多维数组,它是标量、向量、矩阵的高维拓展。标量(scalar)是 0 维张量,向量(vector)是 1 维张量,矩阵(matrix)是 2 维张量。
可以使用 ndim
检查张量的维数,使用shape
或size()
检查张量的形状,使用 dtype
查看数据类型,使用numel()
检查张量的元素个数。
# BasicTorch04_v1.py
# torch04 of PyTroch
# 导入PyTorch
import pytorch
# (1) 通过数据直接创建Tensor
x = torch.tensor([[1.0, 2.0, 3.6], [0.0, 4.0, 7.0]])
print(x)
# (2) 查看张量的维数,形状和类型
print("x.ndim:", x.ndim) # 张量的维数
print("x.shape:", x.shape) # 张量的形状
print("x.size:", x.size()) # 张量的形状
print("x.numel:", x.numel()) # 张量的元素个数
print("x.dtype:", x.dtype) # 张量的数据类型
输出为:
tensor([[1.0000, 2.0000, 3.6000],
[0.0000, 4.0000, 7.0000]])
x.ndim: 2
x.shape: torch.Size([2, 3])
x.size: torch.Size([2, 3])
x.numel: 6
x.dtype: torch.float32
说明:torch.Size
本质上是元组(typle),支持元组的各种操作。
注意 0 维张量虽然只有一个元素,但并不是一个数。
# (3) 0 维张量只有一个元素,但不是数值类型
x = torch.tensor([2009])
print("x = ", x) # x 是张量
print("x.ndim:", x.ndim) # 张量的维数
print("x.shape:", x.shape) # 张量的形状
print("x.type:", x.type()) # x 的类型是张量
n = 2009
print("n = ", n) # n 是标量,不是张量,没有维数、形状
print("type(n):", type(n)) # n 的类型是整型数值
输出结果:
x = tensor([2009])
x.ndim: 1
x.shape: torch.Size([1])
x.type: torch.LongTensor
n = 2009
type(n): <class ‘int’>
标准的 Python 数据结构是一个单层内存对象,可以保持数据和元数据。
PyTorch 的数据结构是分层设计的,其框架支持互操作,内核的计算密集部分通过 ATen 和 Caffe2 迁移到 C/C++ 后端。
PyTorch 面向用户的主要数据结构是一个 THTensor 对象,保存有关维度、偏移、步长等信息,另外还存储了一个指向 THStorage 对象的指针。
2. 张量的创建
2.1 torch.empty() 创建未初始化的张量
使用 ndim
检查张量的维度,使用shape
检查张量的形状。
# (4) 创建一个未初始化的张量
x = torch.empty(2, 3) # x=torch.empty(size=(2, 3)
print(x)
print("x.ndim:", x.ndim)
print("x.shape:", x.shape)
输出为:
tensor([[6.8943e+34, 1.6212e-19, 1.4585e-19],
[7.7179e+28, 1.6217e-19, 1.4586e-19]])
x.ndim: 2
x.shape: torch.Size([2, 3])
2.2 torch.rand() 创建随机数张量
机器学习模型通常从随机数的张量开始,并通过样本学习来调整和更新这些随机数值。
- 使用
torch.rand()
可以创建服从均匀分布的随机数张量,区间为[0,1) - 使用
torch.randint()
可以创建服从均匀分布的随机整数张量,区间为[low,high) - 使用
torch.randn()
可以创建服从标准正态分布的随机数张量,均值为0,方差为1
torch.rand(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
torch.randint(low=0, high, size, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
torch.randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
参数说明:
- size:定义tensor的形状,整数序列 list 或 元组tuple
- dtype:可选,指定返回tensor的数据类型
- layout:可选,表示torch.Tensor内存布局的对象
- device:可选,tensor存放的device
# (5) 创建随机数张量
x1 = torch.rand(2, 3) # 均匀分布随机数,[0,1) 区间
print(x1)
print("x1.shape:", x1.shape)
x2 = torch.randn(2, 3) # 正态分布随机数,均值为 0 方差为1
print(x2)
print("x2.shape:", x2.shape)
x3 = torch.randint(low=0, high=10, size=(2,3)) # 均匀分布随机整数,[low,high) 区间
print(x3)
print("x3.shape:", x3.shape)
输出为:
tensor([[0.5007, 0.1634, 0.4525],
[0.1331, 0.5705, 0.0439]])
x1.shape: torch.Size([2, 3])
tensor([[ 0.5210, 1.8041, -0.5655],
[-2.0804, 0.3897, 0.4336]])
x2.shape: torch.Size([2, 3])
tensor([[5, 0, 6],
[1, 8, 2]])
x3.shape: torch.Size([2, 3])
2.3 创建全0矩阵/全1矩阵/单位矩阵/对角矩阵等特殊张量
使用 torch.zeros()
可以创建 全0张量,使用 torch.ones()
可以创建 全1张量,使用 torch.eye()
可以创建单位矩阵张量。
使用 torch.diag()
可以创建对角矩阵张量,但需要用一维张量来创建。
# (6) 创建全0矩阵/全1矩阵/单位矩阵/对角矩阵等特殊张量
xZeros = torch.zeros(3, 5) # 全0矩阵
print(xZeros)
xOnes = torch.ones(3, 5) # 全1矩阵
print(xOnes)
xEye = torch.eye(3) # 单位矩阵
print(xEye)
x1 = torch.tensor([1.2, 2.5]) # 一维张量
xDiag = torch.diag(x1) # 对角矩阵
print(xDiag)
输出为:
tensor([[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.]])
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
tensor([[1.2000, 0.0000],
[0.0000, 2.5000]])
2.4 通过数据直接创建张量
也可以通过自己的数据直接创建 tensor,数据格式可以是列表、元组或 Numpy数组。
# (7) 通过数据直接创建Tensor
# 通过列表创建
x1 = torch.tensor([[1, 2, 3],
[4, 5, 6]])
print(x1)
# 通过元组创建
x2 = torch.tensor(((1, 2, 3), (4, 5, 6)))
print(x2)
# 通过Numpy创建
xnp = np.array([[1, 2, 3], [4, 5, 6]])
x3 = torch.tensor(xnp)
print(x3)
输出为:
tensor([[1, 2, 3],
[4, 5, 6]])
tensor([[1, 2, 3],
[4, 5, 6]])
tensor([[1, 2, 3],
[4, 5, 6]], dtype=torch.int32)
2.5 通过已有张量的形状创建新的张量
也可以通过已有张量的形状来创建新的张量,所创建张量的形状与已有张量相同。
根据指定对象的形状进行数值填充,只需要在上述函数后面加上 _like
即可,即 torch.*_like()
。此方法默认重用所输入tensor的一些属性,例如数据类型,但也可以自定义数据类型。
torch.zeros_like(input, *, dtype=None, layout=None, device=None) → Tensor
torch.ones_like(input, *, dtype=None, layout=None, device=None) → Tensor
torch.randn_like(input, *, dtype=None, layout=None, device=None) → Tensor
# (8) 通过已有张量的形状创建新的张量
x = torch.ones((2, 3), dtype=torch.float32) # 均匀分布随机数
print(x)
print("x:", x.shape, x.type(), x.device)
# 返回的张量默认具有相同的 dtype
y1 = torch.rand_like(x) # 默认具有相同的数据类型
y2 = torch.zeros_like(x, dtype=torch.int) # 用户指定新的数据类型
print("y1:", y1.shape, y1.type(), y1.device)
print("y2:", y2.shape, y2.type(), y2.device)
输出为:
tensor([[1., 1., 1.],
[1., 1., 1.]])
x: torch.Size([2, 3]) torch.FloatTensor cpu
y1: torch.Size([2, 3]) torch.FloatTensor cpu
y2: torch.Size([2, 3]) torch.IntTensor cpu
2.6 从Numpy数组创建张量
torch.from_numpy(ndarray)
函数 torch.from_numpy
将 numpy 数组转换为张量
# (9) 将 numpy 数组转换为张量
x_NP = np.random.rand(2, 3)
x = torch.from_numpy(x_NP)
print(x_NP)
print(x)
输出为:
[[0.02711595 0.35572182 0.67692876]
[0.73672641 0.01211524 0.22966701]]
tensor([[0.0271, 0.3557, 0.6769],
[0.7367, 0.0121, 0.2297]], dtype=torch.float64)
2.7 创建顺序的一维张量
函数 torch.arange() 返回一个一维张量,数值在区间 [start, end) (左闭右开),步长为 step。
函数 torch.range() 返回一个一维张量,数值在区间 [start, end) (左闭右闭),步长为 step。在以后版本中该函数被删除。
函数 torch.linspace() 返回一个一维张量,包含在区间
[
s
t
a
r
t
,
e
n
d
]
[start, end]
[start,end] 的等距的 steps 个数据点,步长自动计算。
函数 torch.logspace() 返回一个一维张量,包含以base为底、指数在区间
[
s
t
a
r
t
,
e
n
d
]
[start, end]
[start,end] 的等距的 steps 个数据点。
torch.arange(start=0, end, step=1, *, out=None, dtype=None)
torch.range(start=0, end, step=1, *, out=None, dtype=None) # 新版删除
torch.linspace(start, end, steps, *, out=None, dtype=None)
torch.logspace(start, end, steps, base=10.0, *, out=None, dtype=None)
参数说明:
- start:起始值,默认值为 0
- end:结束值
- step:步长,默认值为 1
- steps:数据点数
注意:张量的第一个元素不一定是 start,最后一个元素不一定是 end。
# (10) 创建顺序的一维张量
x1 = torch.arange(1, 3.6, 0.5) # 6 个元素,(3.6-1.0)//0.5+1
print(x1)
print("x1:", x1.shape)
x2 = torch.linspace(3, 6, 10) # 10 个元素,steps=10
print(x2)
print("x2:", x2.shape)
x3 = torch.logspace(3, 6, 10) # # 10 个元素,steps=10
print(x3)
print("x3:", x3.shape)
输出为:
tensor([1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000])
x1: torch.Size([6])
tensor([3.0000, 3.3333, 3.6667, 4.0000, 4.3333, 4.6667, 5.0000, 5.3333, 5.6667,
6.0000])
x2: torch.Size([10])
tensor([ 1000.0000, 2154.4346, 4641.5889, 10000.0000, 21544.3477,
46415.8867, 100000.0000, 215443.4688, 464158.8750, 1000000.0000])
x3: torch.Size([10])
其它创建张量的方法,详见【PyTorch官方文档】。
3. 张量的数据类型
3.1 张量的属性
张量在 PyTorch 中表示为 torch.Tensor,主要属性如下。
- data: 张量的数据,可以是数值、数值列表、Numpy数组等。
- dtype: 张量的数据类型
- shape: 张量的形状和维度
- device: 张量存储的设备类型,支持 CPU(‘cpu’)和 GPU(‘cuda’)
- layout: 张量在内存中的布局模式,支持 torch.strided 和 torch.sparse_coo
- grad: data 的梯度
- grad_fn: 创建张量的函数,用于自动求导
- requires_grad: 是否需要计算梯度,布尔值
- is_leaf: 是否叶子节点,布尔值
3.2 PyTorch 定义的张量类型
张量是一个多维矩阵,包含单一 数据类型的元素。
最常见的张量类型是 torch.float32 或 torch.float,被称为“32 位浮点数”。但也有 16 位浮点数 (torch.float16 or torch.half) 和 64 位浮点数 (torch.float64 or torch.double)。此外,还有 8 位、16 位、32 位和 64 位整数类型、布尔类型、复数类型。
注意 PyTorch 并没有 string 类型,但可以通过 one-hot 编码或 Word2vec 模型来表示。
特别地,PyTorch中某些张量类型专用于 CPU,有些则更适合 GPU。例如,带有 torch.cuda 的张量都被用于 GPU(Nvidia GPU 被称为 CUDA 的计算工具包)。
Torch 使用 CPU 和 GPU 变体定义了 9 种不同的张量类型,默认的数据类型是 32位浮点型( torch.float32)。
Data type | dtype | CPU tensor | GPU tensor |
---|---|---|---|
32-bit float | torch.float32 | torch.FloatTensor | torch.cuda.FloatTensor |
64-bit float | torch.float64 | torch.DoubleTensor | torch.cuda.DoubleTensor |
16-bit float | torch.float16 | torch.HalfTensor | torch.cuda.HalfTensor |
8-bit integer (unsigned) | torch.uint8 | torch.ByteTensor | torch.cuda.ByteTensor |
8-bit integer (signed) | torch.int8 | torch.CharTensor | torch.cuda.CharTensor |
16-bit integer (signed) | torch.int16 | torch.ShortTensor | torch.cuda.ShortTensor |
32-bit integer (signed) | torch.int32 | torch.IntTensor | torch.cuda.IntTensor |
64-bit integer (signed) | torch.int64 | torch.LongTensor | torch.cuda.LongTensor |
Boolean | torch.bool | torch.BoolTensor | torch.cuda.BoolTensor |
3.3 查看张量的数据类型
PyTorch 提供了几种方法来检查与判断数据类型:
- type(x):返回变量的数据类型,适用于张量、Numpy数组、列表、数值等类型。
- x.dtype:返回变量的数据类型,适用于张量、Numpy 数组,不适用于列表、数值等类型。
- x.type():返回变量的数据类型,适用于张量,不适用于 Numpy 数组、列表、数值等类型。
- isinstance(x, torch.FloatTensor):比较数据类型,返回 True/False
# (11) 张量的数据类型
x_numpy = np.random.rand(2, 3)
x_list = x_numpy.tolist()
x_data = x_numpy[0,0].item()
x_tensor = torch.from_numpy(x_numpy)
print(type(x_numpy)) # <class 'numpy.ndarray'>
print(type(x_list)) # <class 'list'>
print(type(x_data)) # <class 'float'>
print(type(x_tensor)) # <class 'torch.Tensor'>
# 查看张量的数据类型
print(x_tensor.type()) # torch.DoubleTensor
print(x_tensor.dtype) # torch.float64
# 判断张量的数据类型
print(isinstance(x_tensor, torch.FloatTensor)) # False
注意:
(1)对于张量 x,可以用 x.type() 或 type(x) 查看数据类型,但返回值的格式不同。x.type() 返回张量的具体数据类型,而 type(x) 返回数据类型的类名。
(2)对于 Numpy 数组、list 列表与数值,可以用 type(x) 查看数据类型,但不能使用 x.type() 方法。
3.3 指定张量的数据类型
创建张量时,默认的数据类型是 32位浮点型( torch.FloatTensor )。
用户可以在创建张量时指定张量的数据类型,也可以更改已有张量的数据类型。
更改张量 x 的数据类型,可以使用 x.int() 更改为 torch.int32,也可以使用 x.type(torch.int32)。
# (12) 指定张量的数据类型
# 在创建时指定张量的数据类型
x1 = torch.zeros(3, 3)
x2 = torch.zeros(3, 3, dtype=torch.float64)
x3 = torch.zeros(3, 3, dtype=torch.long)
print("x1.dtype: ", x1.dtype)
print("x2.dtype: ", x2.dtype)
print("x3.dtype: ", x3.dtype)
# 更改张量的数据类型
x1 = x1.long() # x1=x1.type(torch.int64)
x2 = x2.int() # x2=x2.type(torch.int32)
x3 = x3.type(torch.float64)
print("x1.long: ", x1.dtype)
print("x2.int: ", x2.dtype)
print("x3.float64: ", x3.dtype)
输出为:
x1.dtype: torch.float32
x2.dtype: torch.float64
x3.dtype: torch.int64x1.long: torch.int64
x2.int: torch.int32
x3.float64: torch.float64
4. 张量的存储设备
张量可以存储在 CPU 或 GPU 设备上。对于复杂网络模型和大规模数据,使用 GPU 进行特定类型的运算(如矩阵乘法)比 CPU 快得多。
注意两个张量只有在同一设备上才可以运算(CPU或者同一个GPU) 。存放在 CPU 上的数据不能与存放在 GPU 上的数据进行运算,位于不同 GPU 上的数据也不能直接运算。
4.1 检查 GPU 设备
在 PyTorch 中用 torch.device('cpu')
表示 CPU 设备,用 torch.device('cuda')
表示 GPU 设备。
CPU 设备包括所有物理 CPU 和内存,即 PyTorch 计算将尝试使用所有 CPU 核心。而 GPU 设备只代表一个 GPU 显卡与相应的显存。如果系统中有多个 GPU,使用 torch.device('cuda:{i}')
表示第 i 块 GPU 显卡,cuda:0 也可以以简写为 cuda 。
使用 torch.cuda.is_available()
可以检查系统是否具有 GPU 设备。如果没有 GPU 设备,则张量只能在 CPU 设备存储和运算。通常,面向用户的 API 与设备无关,开发者编写代码时无需关注具体的存储和运算设备,代码将根据设备情况在 CPU 或 GPU(如果可用)上运行。
# (13) 检查 GPU 设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("device=", device)
print("CUDA版本: ", torch.version.cuda)
print("Pytorch版本: ", torch.__version__)
print("显卡是否可用: ", "GPU 可用" if(torch.cuda.is_available()) else " GPU 不可用")
print("显卡数量: ", torch.cuda.device_count())
print("是否支持BF16格式: ", "支持 BF16" if (torch.cuda.is_bf16_supported()) else "不支持 BF16")
print("当前显卡的型号: ", torch.cuda.get_device_name())
print("当前显卡的算力: ", torch.cuda.get_device_capability())
print("当前显卡的显存: ", torch.cuda.get_device_properties(0).total_memory/1024/1024/1024,'GB')
print("是否支持TensorCore: ", "支持" if (torch.cuda.get_device_properties(0).major >= 7) else "不支持")
print("当前显卡的使用率: ", torch.cuda.memory_allocated(0)/torch.cuda.get_device_properties(0).total_memory*100, "%")
输出结果:
device= cuda
CUDA版本: 11.7
Pytorch版本: 1.13.1
显卡是否可用: GPU 可用
显卡数量: 1
是否支持BF16格式: 支持 BF16
当前显卡的型号: NVIDIA GeForce RTX 3060
当前显卡的算力: (8, 6)
当前显卡的显存: 11.99951171875 GB
是否支持TensorCore: 支持
当前显卡的使用率: 0.0 %
4.2 指定张量的存储设备
创建张量时,默认的张量存储设备时。
通过 to(device) 方法可以把张量和模型放在特定设备上。
用户可以在创建张量时指定张量的存储设备,也可以更改已有张量的存储设备。更改张量 x 的存储设备,可以使用 x.cuda(0) 更改为 GPU,也可以使用 x.to(“cuda:0”) 方法。
由于 NumPy 不能使用 GPU,如果要使用 NumPy 与张量进行交互,就要将张量返回 CPU。
# (14) 指定张量的存储设备
# 在创建时指定张量的存储设备
x1 = torch.rand(3, 3, device="cpu")
x2 = torch.rand(3, 3, device="cuda")
x3 = torch.rand(3, 3, device="cuda:0")
# 获取张量的设备
print("x1: {}\nx2: {}\nx3: {}".format(x1.device, x2.device, x3.device))
# 修改张量的数据类型
x1 = x1.cuda(0) # 将张量 x1 从 CPU 转移到 0#GPU
x2 = x1.to("cuda:0") # # 将张量 x1 从 CPU 转移到 GPU
x3 = x3.cpu() # # 将张量 x2 从 GPU 转移到 CPU
print("x1: {}\nx2: {}\nx3: {}".format(x1.device, x2.device, x3.device))
输出结果:
x1: cpu
x2: cuda:0
x3: cuda:0x1: cuda:0
x2: cuda:0
x3: cpu
4.3 模型的 GPU 运算
PyTorch 模型也可以存储在 CPU 或 GPU 上。 默认情况 PyTorch 将数据创建在内存,利用 CPU 来计算。
类似地,可以检查模型参数的 device
属性来查看模型存放的设备,通过 to()
方法将模型转移到指定设备。
# (15) 模型的存储设备
model = torch.nn.Linear(3, 1) # 线性模型
print("Linear model:\n", list(model.parameters()))
print("device of model: ", list(model.parameters())[0].device)
x = torch.rand(2, 3, device="cuda") # 输入张量 x 在 GPU 设备
# print(model(x)) # 模型 model 与 输入张量 x 不在同一设备,程序报错
model.cuda() # 将模型转移到 GPU
print("device of model: ", list(model.parameters())[0].device)
print(model(x))
输出结果:
Linear model:
[Parameter containing:
tensor([[ 0.3656, -0.1920, 0.5609]], requires_grad=True), Parameter containing:
tensor([-0.0030], requires_grad=True)]
device of model: cpu
device of model: cuda:0
tensor([[0.4553],
[0.4906]], device=‘cuda:0’, grad_fn=)
程序说明:
(1)Pytorch 模型需要与模型输入的 Tensor 在同一设备上,才能进行运算,否则将会报错:
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument mat1 in method wrapper_addmm)
(2)由于输入参数存储在 GPU 设备,将模型转移到 GPU后,才能进行运算。
版权声明:
欢迎关注『youcans的深度学习』系列,转发请注明原文链接:
【youcans的深度学习 04】PyTorch入门教程:张量的基本操作(https://youcans.blog.csdn.net/article/details/130158748)
Copyright 2023 youcans, XUPT
Crated:2023-04-12