Bootstrap

PyTorch基础知识(可入门)

PyTorch基础

  1. 核心是张量Tensor,一种多维数据的数学对象。
  2. 使用torch包创建张量,具体的很简单,不多说了。
    (1)如果想用特定的值填充张量,可以使用 fill_() 方法。【任何带有下划线(_)的PyTorch方法都是指原位操作,即不用创建新对象就地修改内容】
    (2)当使用torch.Tensor构造函数时,默认张量类型是torch.FloatTensor。可以在使用时进行类型转换 或 利用torch.tensor()中的dtype参数。
  3. 加减乘除操作都和其他类似。
  4. torch.transpose():转置操作,很简单,可参考https://blog.csdn.net/qq_50001789/article/details/120451717
  5. 普通索引和切片:基本上同numpy。
  6. 复杂索引:
    (1) 张量的非连续索引
def describe(x):
    print("Type: {}".format(x.type()))
    print("Shape/size: {}".format(x.shape))
    print("Values: \n{}".format(x))

import torch

# 创建一个2D张量
x = torch.arange(6).view(2, 3)
describe(x)
# 1、获取2D张量的第2个维度且索引号为0和2的张量子集
indices = torch.LongTensor([0, 2])
describe(torch.index_select(x, dim=1, index=indices))

# 2、获取2D张量的第1个维度且索引号为0和0的张量子集
indices = torch.LongTensor([0, 0])
describe(torch.index_select(x, dim=0, index=indices))

# 3、row_indices结果是个tensor([0., 1.]),然后col_indices是tensor([1, 2])
row_indices = torch.arange(2).long()
col_indices = torch.LongTensor([1, 2])
describe(x[row_indices, col_indices])

输出结果:

Type: torch.LongTensor
Shape/size: torch.Size([2, 3])
Values: 
tensor([[0, 1, 2],
        [3, 4, 5]])
Type: torch.LongTensor
Shape/size: torch.Size([2, 2])
Values: 
tensor([[0, 2],
        [3, 5]])
Type: torch.LongTensor
Shape/size: torch.Size([2, 3])
Values: 
tensor([[0, 1, 2],
        [0, 1, 2]])
Type: torch.LongTensor
Shape/size: torch.Size([2])
Values: 
tensor([1, 5])

Process finished with exit code 0

解释一下最后一个操作(3),在这里插入图片描述
(2)连接张量

import torch
x = torch.arange(6).view(2, 3)
describe(x)

describe(torch.cat([x, x], dim=0))

describe(torch.cat([x, x], dim=1))

describe(torch.stack([x, x]))

结果:

Type: torch.LongTensor
Shape/size: torch.Size([2, 3])
Values: 
tensor([[0, 1, 2],
        [3, 4, 5]])
Type: torch.LongTensor
Shape/size: torch.Size([4, 3])
Values: 
tensor([[0, 1, 2],
        [3, 4, 5],
        [0, 1, 2],
        [3, 4, 5]])
Type: torch.LongTensor
Shape/size: torch.Size([2, 6])
Values: 
tensor([[0, 1, 2, 0, 1, 2],
        [3, 4, 5, 3, 4, 5]])
Type: torch.LongTensor
Shape/size: torch.Size([2, 2, 3])
Values: 
tensor([[[0, 1, 2],
         [3, 4, 5]],

        [[0, 1, 2],
         [3, 4, 5]]])

Process finished with exit code 0
  1. 张量的requires_grad=True时,可以追踪梯度张量以及梯度函数。这两个东西需要基于梯度的学习“监督学习范式”。

创建张量并计算梯度:

import torch
x = torch.ones(2, 2, requires_grad=True)
describe(x)
print(x.grad is None)

y = (x+2)*(x+5)+3
describe(y)
print(x.grad is None)

z = y.mean()
describe(z)
z.backward()
print(x.grad is None)

结果:

Type: torch.FloatTensor
Shape/size: torch.Size([2, 2])
Values: 
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
True
Type: torch.FloatTensor
Shape/size: torch.Size([2, 2])
Values: 
tensor([[21., 21.],
        [21., 21.]], grad_fn=<AddBackward0>)
True
Type: torch.FloatTensor
Shape/size: torch.Size([])
Values: 
21.0
False

Process finished with exit code 0

梯度是一个值(函数输出对于函数输入的斜率)。

  1. CUDA张量

(1)创建cuda张量

import torch

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

x = torch.rand(3, 3).to(device)
describe(x)

结果:

cuda
Type: torch.cuda.FloatTensor
Shape/size: torch.Size([3, 3])
Values: 
tensor([[0.2369, 0.9929, 0.6972],
        [0.1366, 0.0594, 0.0726],
        [0.4803, 0.1209, 0.6055]], device='cuda:0')

(2)CUDA张量与CPU绑定张量混合

# 将CUDA张量和CPU绑定张量混合(CUDA和非CUDA对象),y在CPU上,x在GPU上。这种情况就会报错
y = torch.rand(3, 3)
x + y

结果报错:

Traceback (most recent call last):
  File "C:/Users/27692/PycharmProjects/Quinn/test/test.py", line 60, in <module>
    x + y
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

要想对cuda和非cuda对象进行操作,必须确保它们在同一个设备上:

cpu_device = torch.device("cpu")
y = y.to(cpu_device)
x = x.to(cpu_device)
print(x + y)

结果:

tensor([[0.9204, 0.8360, 0.6289],
        [1.2421, 1.4353, 1.2174],
        [0.9342, 1.0427, 1.1978]])

Process finished with exit code 0

【练习扩展】

  • unsqueeze()函数和squeeze()函数:
a = torch.rand(2, 3)
print(describe(a))

# 在第0维增加1个维度
b = a.unsqueeze(0)
print(describe(b))

# 在第1维增加1个维度
b = a.unsqueeze(1)
print(describe(b))

# 在倒数第2个维度增加1个维度
b = a.unsqueeze(-2)
print(describe(b))

注意看输出结果:!!!张量形状(torch.size)

Type: torch.FloatTensor
Shape/size: torch.Size([2, 3])
Values: 
tensor([[0.2643, 0.1925, 0.2562],
        [0.7674, 0.9930, 0.2341]])
None
Type: torch.FloatTensor
Shape/size: torch.Size([1, 2, 3])
Values: 
tensor([[[0.2643, 0.1925, 0.2562],
         [0.7674, 0.9930, 0.2341]]])
None
Type: torch.FloatTensor
Shape/size: torch.Size([2, 1, 3])
Values: 
tensor([[[0.2643, 0.1925, 0.2562]],

        [[0.7674, 0.9930, 0.2341]]])
None
Type: torch.FloatTensor
Shape/size: torch.Size([2, 1, 3])
Values: 
tensor([[[0.2643, 0.1925, 0.2562]],

        [[0.7674, 0.9930, 0.2341]]])
None

Process finished with exit code 0
# ======squeeze()======   
# 上面是插入/增加,这个是删除/去掉
a = torch.rand(2, 1, 3)
print(describe(a))

# 将第1维去掉
b = a.squeeze(1)  # a.squeeze(-2)有同样作用 倒数第二个
print(describe(b))

# 试试-3
b = a.squeeze(-3)   # 这块结果不变,因为只有维度为1时才会去掉
print(describe(b))

输出结果:

Type: torch.FloatTensor
Shape/size: torch.Size([2, 1, 3])
Values: 
tensor([[[0.4349, 0.0568, 0.0304]],

        [[0.2712, 0.3612, 0.3238]]])
None
Type: torch.FloatTensor
Shape/size: torch.Size([2, 3])
Values: 
tensor([[0.4349, 0.0568, 0.0304],
        [0.2712, 0.3612, 0.3238]])
None
Type: torch.FloatTensor
Shape/size: torch.Size([2, 1, 3])
Values: 
tensor([[[0.4349, 0.0568, 0.0304]],

        [[0.2712, 0.3612, 0.3238]]])
None

Process finished with exit code 0
  • 创建一个具有正态分布的张量:
a = torch.rand(3,3)
a.normal_()
;