课程地址
最近做实验发现自己还是基础框架上掌握得不好,于是开始重学一遍PyTorch框架,这个是课程笔记

1. 张量Tensor

张量是一种特殊的数据结构,与数组和矩阵非常相似。在 PyTorch 中,我们使用张量对模型的输入和输出以及模型的参数进行编码。张量与NumPy 的ndarray类似,不同之处在于张量可以在 GPU 或其他硬件加速器上运行。事实上,张量和 NumPy 数组通常可以共享相同的底层内存(原地操作),从而无需复制数据。张量还针对自动微分进行了优化。
PyTorch导入包的过程:

import torch
import numpy as np

1.1 创建张量

1.1.1 从列表中创建一个张量tensor

data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)

x_data的结果:
tensor([[1, 2],
[3, 4]])

创建一个浮点型的列表:

import torch
import numpy as np
data = [[1, 2.0],[3, 4]]
x_data = torch.tensor(data)
print(x_data)
print(type(x_data))  # 打印存储张量的变量的类型
print(x_data.dtype)  # 打印张量中每一个元素的类型

运行结果:
tensor([[1., 2.],
[3., 4.]])
<class ‘torch.Tensor’>
torch.float32

1.1.2 从numpy数组中创建张量tensor

import torch
import numpy as np
a = np.random.normal((2, 3)) # 按正态分布创建一个ndarray
tensor_a = torch.tensor(a)
print(tensor_a)

运行结果:
tensor([0.5312, 3.4150], dtype=torch.float64)

import torch
import numpy as np
a = np.random.normal((2, 3)) # 按正态分布创建一个ndarray
tensor_a = torch.from_numpy(a)
print(tensor_a)

运行结果:
tensor([2.1416, 2.2480], dtype=torch.float64)

1.1.3 从其他张量创建张量tensor

新张量保留参数张量的属性(形状、数据类型),除非显式覆盖。

import torch
import numpy as np
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
x_ones = torch.ones_like(x_data) # 创建一个和x_data张量大小一样的全为1的张量
print(f"Ones Tensor: \n {x_ones} \n")

x_ones = torch.zeros_like(x_data) # 创建一个和x_data张量大小一样的全为0的张量
print(f"Zeros Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float) # 创建一个和x_data张量大小一样的全为随机数的张量
print(f"Random Tensor: \n {x_rand} \n")

运行结果:
Ones Tensor:
tensor([[1, 1],
[1, 1]])

Zeros Tensor:
tensor([[0, 0],
[0, 0]])

Random Tensor:
tensor([[0.5124, 0.8001],
[0.8218, 0.9406]])

1.1.4 使用随机值或常数创建张量tensor

shape是张量维度的元组,如果将shape 改成列表也是可以的,但是不能写成集合{2,3},那样会报错。在下面的函数中,它确定输出张量的维数。

import torch
import numpy as np
shape = (2,3,)  # 张量维度的元组,最后一个逗号能去掉,这是一个2×3的张量
rand_tensor = torch.rand(shape)  # 按shape的维度大小创建一个随机值的张量
ones_tensor = torch.ones(shape)  # 按shape的维度大小创建一个全为1的张量
zeros_tensor = torch.zeros(shape)  # 按shape的维度大小创建一个全为0的张量

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")

运行结果:
Random Tensor:
tensor([[0.0758, 0.3495, 0.7840],
[0.9438, 0.8045, 0.4455]])

Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])

Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])

1.2 张量的属性

张量属性描述了它们的形状、数据类型以及存储它们的设备。

import torch
import numpy as np
tensor = torch.rand(3,4)

print(f"张量的维度: {tensor.shape}")
print(f"张量的元素的数据类型: {tensor.dtype}")
print(f"存储当前张量的设备: {tensor.device}")

运行结果:
张量的维度: torch.Size([3, 4])
张量的元素的数据类型: torch.float32
存储当前张量的设备: cpu

1.3 张量的操作

PyTorch有 100 多种张量运算,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。这些操作中的每一个都可以在 GPU 上运行(速度通常高于 CPU)。默认情况下,张量是在 CPU 上创建的。我们需要使用 .to方法显式地将张量移动到 GPU(在检查 GPU 可用性之后)。请记住,跨设备复制大张量在时间和内存方面可能会很昂贵!

import torch
import numpy as np
tensor = torch.rand(3,4)

# 将张量移动到GPU(显卡)中,如果有独立显卡,可以移动
if torch.cuda.is_available():
    tensor = tensor.to("cuda")

正常运行代码不报错证明能移动到GPU中

1.3.1 常见的张量操作

(1) is_tensor:如果当前对象是 PyTorch 张量,则返回 True 。

import torch
import numpy as np
tensor = torch.rand(3,4)

print(torch.is_tensor(tensor))

运行结果:
True
(2)is_complex:如果当前的数据类型input是复数类型,即torch.complex64或torch.complex128,则返回 True。
(3)is_floating_point:如果当前的数据类型input是浮点数据类型,即torch.float64、torch.float32、torch.float16或torch.bfloat16,则返回 True。
(4)is_nonzero:input如果是单元素张量且在类型转换后不等于 0,则返回 True。

import torch
import numpy as np
a = torch.tensor(1.0)  # 单一浮点数张量1.0
print(a)
print(torch.is_nonzero(a))  # 打印True就表明a张量是一个非0的标量

a = torch.tensor(0)  # 单一浮点数张量0
print(a)
print(torch.is_nonzero(a))  #  打印False就表明a张量是一个值为0的标量

运行结果:
tensor(1.)
True
tensor(0)
False

(5)numel:返回张量中的元素总数input。

import torch
import numpy as np

a = torch.rand([2, 2])  # 创建一个2X2的随机值张量
print(torch.numel(a))  # 返回2X2张量的元素个数4

运行结果:
4

1.3.2 常见的创建张量的操作

(1)tensor:通过复制构造一个没有自动求导过的张量,使用这个构造函数时(或者 torch.tensor(),它更加推荐用于创建新张量),PyTorch会创建一个复制了numpy数组数据的新张量。这种方式不会与原始numpy数组共享内存,因此,修改原numpy数组不会影响到PyTorch张量,反之亦然。

import torch
import numpy as np

b = np.array([1, 1.2])
a = torch.tensor(b)
print(a)

运行结果:
tensor([1.0000, 1.2000], dtype=torch.float64)
(2)as_tensor:转换data为张量,共享数据并保留 自动求导的历史记录(如果可能)。
如果data已经是具有请求的 dtype 和设备的张量,则data返回其本身,但如果data是具有不同 dtype 或设备的张量,则将其复制,就像使用 data.to(dtype=dtype, device=device)一样。如果data是具有相同数据类型和设备的 NumPy 数组(ndarray),则使用 构造张量torch.from_numpy()。

import torch
import numpy as np

# a默认在CPU中创建,t从a中创建,二者共享数据,所以修改一个,两个都变
a = np.array([1, 2, 3])
t = torch.as_tensor(a)
print(t)
t[0] = -1
print(a)

# 但是将t送入GPU后,a在CPU,t在GPU,修改t,a不变
a = np.array([1, 2, 3])
t = torch.as_tensor(a, device=torch.device('cuda'))
print(t)
t[0] = -1
print(a)

运行结果:
tensor([1, 2, 3], dtype=torch.int32)
[-1 2 3]
tensor([1, 2, 3], device=‘cuda:0’, dtype=torch.int32)
[1 2 3]
(3)from_numpy:从numpy.ndarray.创建一个张量, 这个方法创建的张量与原始的numpy数组共享相同的内存。这意味着如果你修改了numpy数组的内容,相应的PyTorch张量的内容也会随之改变,反之亦然。这种方法效率很高,因为它避免了数据复制,但也需要注意数据在numpy数组和张量间是同步的。

import torch
import numpy as np

a = np.array([1, 2, 3])
t = torch.from_numpy(a)
# a 和 t是共享相同的内存的,修改t,a也被修改
print(t)
t[0] = -1
print(a)

运行结果:
tensor([1, 2, 3], dtype=torch.int32)
[-1 2 3]
(4)zeros:返回一个全为0的张量,主要参数是整型序列,用来记录生成的张量的维度大小,
关键字参数

  • out ( Tensor ,可选) – 输出张量。
  • dtype ( torch.dtype, 可选) – 返回张量所需的数据类型。默认值:如果None,则使用全局默认值,通过 torch.set_default_dtype()这个API规定的。
  • layout ( torch.layout, 可选) – 返回张量的所需布局。默认:torch.strided。
  • device (torch.device, 可选) –返回张量所需的设备。默认值:如果None,则使用当前设备作为默认张量类型(请参阅torch.set_default_device())。
  • device对于CPU 张量类型,将是 CPU;对于 CUDA 张量类型,将是当前 CUDA 设备。
  • require_grad ( bool ,可选) – 自动求导 是否应记录对返回张量的操作。默认:False。
import torch
import numpy as np

a = torch.zeros(5, 5)
print(a)
print(a.dtype)

torch.set_default_dtype(torch.float64)  # 设置默认的数据类型为float64
a = torch.zeros(5, 5)
print(a)
print(a.dtype)

运行结果:
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., 0.]])
torch.float32
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., 0.]])
torch.float64
(5)zeros_like:返回一个用标量值0填充的张量,其大小与 相同input。(下面的与上面的类似,不试了)
(6)ones:返回一个用标量值1填充的张量,其形状由变量声明定义size(参数是int整型序列,写的是所要生成的张量的维度size。
(7)ones_like:返回一个用标量值1填充的张量,其大小与 相同input。
(8)arange:返回大小为 ⌈  start-end s t e p ⌉ \left\lceil\frac{\text { start-end}}{step}\right\rceil step start-end的1维张量,[start,end),左闭右开
参数:

  • start ( Number ) – 点集的起始值。默认:0。
  • end ( Number ) – 点集的结束值
  • step ( Number ) – 每对相邻点之间的间隙。默认:1。
import torch

a = torch.arange(5)  # step为1,默认从0开始
print(a)

a = torch.arange(start=2, end=5, step=2) 
print(a)

运行结果:
tensor([0, 1, 2, 3, 4])
tensor([2, 4])

(9)range:返回大小为 ⌊  end-start   step  ⌋ + 1 \left\lfloor\frac{\text { end-start }}{\text { step }}\right\rfloor+1  step  end-start +1的1维张量,

import torch

a = torch.range(start=0, step=1, end=5)  # step为1,默认从0开始
print(a)

运行结果:
tensor([0., 1., 2., 3., 4., 5.])

(10)linspace:创建一个从start到end的均匀分布,step为步长
(11)logspace:创建一个从 l o g 底数 s t a r t log_{底数}^{start} log底数start l o g 底数 e n d log_{底数}^{end} log底数end的一维张量,step为步长,base为底数
(12)eye:创建一个二维张量,对角线上全为1,其他全为0,只传一个参数默认是方阵

import torch

a = torch.eye(3)  # 只有一个参数,默认方阵
print(a)
a = torch.eye(3, 2)
print(a)

运行结果:
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
tensor([[1., 0.],
[0., 1.],
[0., 0.]])

(13)full:创建一个大小size为的张量,并且这个张量是用value填充的。

import torch

a = torch.full((3, 2), 10)  # 3x2张量,填充值为10
print(a)

运行结果:
tensor([[10, 10],
[10, 10],
[10, 10]])

(14)full_like:根据已有的维度大小创建一个填充值为value的张量。

import torch

b = torch.tensor([[1, 2], [3, 4]])
a = torch.full_like(b, 10)  # 用10填充一个和b维度一样的tensor
print(a)

运行结果:
tensor([[10, 10],
[10, 10]])

1.3.3 索引、切片、连接等操作

(1)cat:连接给定维度中给定的张量序列。传入的是一个多个张量的列表,这些张量除了被连接的那个维度以外,需要有同样的张量,dim参数是指定在哪个维度将这两个张量连接起来。

import torch

a = torch.rand([2, 2])  # 2x2拼左边
print(a)
b = torch.rand([2, 3])  # 2x3拼右侧
print(b)
print(torch.cat([a, b], dim= 1))

运行结果:
tensor([[0.3435, 0.4823],
[0.3059, 0.4247]])
tensor([[0.2637, 0.9875, 0.9034],
[0.5850, 0.1321, 0.2106]])
tensor([[0.3435, 0.4823, 0.2637, 0.9875, 0.9034],
[0.3059, 0.4247, 0.5850, 0.1321, 0.2106]])

在0维度拼接相当于上下拼接(2维):

import torch

a = torch.rand([2, 2])
print(a)
b = torch.rand([3, 2])
print(b)
print(torch.cat([a, b], dim= 0))

运行结果:
tensor([[0.5723, 0.7480],
[0.7629, 0.4247]])
tensor([[0.5585, 0.0881],
[0.6640, 0.8015],
[0.8188, 0.3602]])
tensor([[0.5723, 0.7480],
[0.7629, 0.4247],
[0.5585, 0.0881],
[0.6640, 0.8015],
[0.8188, 0.3602]])

此处我去年看李沐老师视频的时候有一段写的和这个类似,但是比较详细:按特定轴求和

04-28 05:48