ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

深度学习 pytorch的使用(张量2)

2026/10/1 10:15:13 拓冰建站 浏览量
深度学习 pytorch的使用(张量2)

深度学习 pytorch的使用(张量1)


五、张量索引操作

简单行、列索引、列表索引、范围索引、布尔索引、多维索引

import torch
# 数据
data = torch.randint(0,10,[4,5])
print(data)

tensor([[7, 6, 9, 4, 6],
        [1, 9, 0, 9, 2],
        [5, 7, 1, 7, 4],
        [1, 2, 7, 2, 1]])

"""1.简单行、列索引"""
print(data[0])  # 第一行
print(data[:,0])  # 第一列

tensor([7, 6, 9, 4, 6])
tensor([7, 1, 5, 1])

"""2.列表索引"""
# 返回(0,1)、(1,2)两个位置的元素
print(data[[0,1],[1,2]])

tensor([6, 0])

# 返回0、1行的1、2列共4个元素
# print(data[[0],[1],[1,2]])
"""3.范围索引"""
# 前3 行的前2列数据
print(data[:3,:2])
# 前2行到最后的前2列数据
print(data[2:,:2])

tensor([[7, 6],
        [1, 9],
        [5, 7]])
tensor([[5, 7],
        [1, 2]])

"""4.布尔索引"""
# 第三列大于5的行数据
print(data[data[:,2]>5])
# 第二行大于5的列数据
print(data[:,data[1]>5])

tensor([[7, 6, 9, 4, 6],
        [1, 2, 7, 2, 1]])
tensor([[6, 4],
        [9, 9],
        [7, 7],
        [2, 2]])

"""5.多维索引"""
data = torch.randint(0,10,[3,4,5])
print(data)
print('-'*50,'\n')print(data[0,:,:])
print(data[:,0,:])
print(data[:,:,0])

tensor([[[5, 5, 5, 9, 1],
         [1, 5, 3, 8, 0],
         [8, 3, 8, 2, 8],
         [7, 2, 5, 0, 4]],

        [[4, 7, 2, 1, 3],
         [9, 2, 7, 5, 2],
         [0, 0, 4, 8, 7],
         [3, 6, 6, 5, 3]],

        [[1, 7, 5, 5, 4],
         [7, 8, 9, 5, 0],
         [0, 0, 3, 5, 5],
         [2, 0, 8, 3, 6]]])
-------------------------------------------------- 

tensor([[5, 5, 5, 9, 1],
        [1, 5, 3, 8, 0],
        [8, 3, 8, 2, 8],
        [7, 2, 5, 0, 4]])
tensor([[5, 5, 5, 9, 1],
        [4, 7, 2, 1, 3],
        [1, 7, 5, 5, 4]])
tensor([[5, 1, 8, 7],
        [4, 9, 0, 3],
        [1, 7, 0, 2]])


六、张量形状操作

1.reshape 函数可以在保证张量数据不变的前提下改变数据的维度
2.transpose 函数可以实现交换张量形状的指定维度,permute可以一次交换更多的维度
3.view 函数也可以用于修改张量的形状,但是它要求被转换的张量内存必须连续,所以易班配合contiguous函数使用
4.squeeze 和 unsqueeze 函数可以用来增加或者减少维度

1、reshape 函数的用法

reshape 函数可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状,在神经网络学习时,会经常使用该函数来调节数据的形状,以适配不同网络层之间的数据传递

import torchdata = torch.tensor([[10,20,30],[40,50,60]])
print(data)
# tensor([[10, 20, 30],
#        [40, 50, 60]])# 1.使用shape属性或者size方法都可以获得张量的形状
print(data.shape,data.shape[0],data.shape[1])
# torch.Size([2, 3]) 2 3
print(data.size(),data.size(0),data.size(1))
# torch.Size([2, 3]) 2 3# 2.使用reshape函数修改张量形状
new_data = data.reshape(1,6)
print(new_data)
print(new_data.shape)
# tensor([[10, 20, 30, 40, 50, 60]])
# torch.Size([1, 6])

2、transpose 和 permute 函数的使用

transpose 函数可以实现交换张量形状的指定维度, 例如: 一个张量的形状为 (2, 3, 4) 可以通过 transpose 函数把 3 和 4 进行交换, 将张量的形状变为 (2, 4, 3) permute 函数可以一次交换更多的维度

import torch
import numpy as npdata = torch.tensor(np.random.randint(0, 10, [3, 4, 5]))
print('data shape:', data.size())
# data shape: torch.Size([3, 4, 5])# 1. 交换1和2维度
new_data = torch.transpose(data, 1, 2)
print('data shape:', new_data.size())
# data shape: torch.Size([3, 5, 4])# 2. 将 data 的形状修改为 (4, 5, 3)
new_data = torch.transpose(data, 0, 1)
new_data = torch.transpose(new_data, 1, 2)
print('new_data shape:', new_data.size())
# new_data shape: torch.Size([4, 5, 3])# 3. 使用 permute 函数将形状修改为 (4, 5, 3)
new_data = torch.permute(data, [1, 2, 0])
print('new_data shape:', new_data.size())
# new_data shape: torch.Size([4, 5, 3])

3、view 和 contigous 函数的用法

view 函数也可以用于修改张量的形状,但是其用法比较局限,只能用于存储在整块内存中的张量。 在 PyTorch 中,有些张量是由不同的数据块组成的,它们并没有存储在整块的内存中, view 函数无法对这样的张量进行变形处理,例如: 一个张量经过了 transpose 或者 permute 函数的处理之后,就无法使用 view 函数进行形状操作。

import torch
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
print('data shape:', data.size())
# data shape: torch.Size([2, 3])# 1. 使用 view 函数修改形状
new_data = data.view(3, 2)
print('new_data shape:', new_data.shape)
# new_data shape: torch.Size([3, 2])# 2. 判断张量是否使用整块内存
print('data:', data.is_contiguous())  # True
# data: True# 3. 使用 transpose 函数修改形状
new_data = torch.transpose(data, 0, 1)
print('new_data:', new_data.is_contiguous())  # False
# new_data = new_data.view(2, 3)  # RuntimeError# 需要先使用 contiguous 函数转换为整块内存的张量,再使用 view 函数
print(new_data.contiguous().is_contiguous())  # True
new_data = new_data.contiguous().view(2, 3)
print('new_data shape:', new_data.shape)  
# new_data shape: torch.Size([2, 3])

4、 squeeze 和 unsqueeze 函数的用法

import torch
import numpy as npdata = torch.tensor(np.random.randint(0, 10, [1, 3, 1, 5]))
print('data shape:', data.size())# 1. 去掉值为1的维度
new_data = data.squeeze()
print('new_data shape:', new_data.size())  # torch.Size([3, 5])# 2. 去掉指定位置为1的维度,注意: 如果指定位置不是1则不删除
new_data = data.squeeze(2)
print('new_data shape:', new_data.size())  # torch.Size([3, 5])# 3. 在2维度增加一个维度
new_data = data.unsqueeze(-1)
print('new_data shape:', new_data.size())  # torch.Size([3, 1, 5, 1])


七、张量运算函数

1、常见运算函数

PyTorch 为每个张量封装很多实用的计算函数,例如计算均值、平方根、求和等等

import torchdef test():data = torch.randint(0, 10, [2, 3], dtype=torch.float64)print(data)print('-' * 50)# 1. 计算均值# 注意: tensor 必须为 Float 或者 Double 类型print(data.mean())print(data.mean(dim=0))  # 按列计算均值print(data.mean(dim=1))  # 按行计算均值print('-' * 50)# 2. 计算总和print(data.sum())print(data.sum(dim=0))print(data.sum(dim=1))print('-' * 50)# 3. 计算平方print(data.pow(2))print('-' * 50)# 4. 计算平方根print(data.sqrt())print('-' * 50)# 5. 指数计算, e^n 次方print(data.exp())print('-' * 50)# 6. 对数计算print(data.log())  # 以 e 为底print(data.log2())print(data.log10())if __name__ == '__main__':test()

tensor([[7., 5., 9.],
        [6., 1., 6.]], dtype=torch.float64)
--------------------------------------------------
tensor(5.6667, dtype=torch.float64)
tensor([6.5000, 3.0000, 7.5000], dtype=torch.float64)
tensor([7.0000, 4.3333], dtype=torch.float64)
--------------------------------------------------
tensor(34., dtype=torch.float64)
tensor([13.,  6., 15.], dtype=torch.float64)
tensor([21., 13.], dtype=torch.float64)
--------------------------------------------------
tensor([[49., 25., 81.],
        [36.,  1., 36.]], dtype=torch.float64)
--------------------------------------------------
tensor([[2.6458, 2.2361, 3.0000],
        [2.4495, 1.0000, 2.4495]], dtype=torch.float64)
--------------------------------------------------
tensor([[1.0966e+03, 1.4841e+02, 8.1031e+03],
        [4.0343e+02, 2.7183e+00, 4.0343e+02]], dtype=torch.float64)
--------------------------------------------------
tensor([[1.9459, 1.6094, 2.1972],
        [1.7918, 0.0000, 1.7918]], dtype=torch.float64)
tensor([[2.8074, 2.3219, 3.1699],
        [2.5850, 0.0000, 2.5850]], dtype=torch.float64)
tensor([[0.8451, 0.6990, 0.9542],
        [0.7782, 0.0000, 0.7782]], dtype=torch.float64)
 


八、自动微分模块

自动微分(Autograd)模块对张量做了进一步的封装,具有自动求导功能。
自动微分模块是构成神经网络训练的必要模块,在神经网络的反向传播过程中,
Autograd 模块基于正向计算的结果对当前的参数进行微分计算,从而实现网络权重参数的更新pytorch 中非常重要的自动微分模型的使用和理解
对需要计算梯度的张量需要设置requires_grad=True属性,
并且需要注意的是梯度是累计的,在每次计算梯度前需要进行梯度清零。

1、梯度基本运算

使用 backward 方法、grad 属性来实现梯度的计算和访问

import torch# 1. 单标量梯度的计算
# y = x**2 + 20
def test01():# 定义需要求导的张量# 张量的值类型必须是浮点类型x = torch.tensor(10, requires_grad=True, dtype=torch.float64)# 变量经过中间运算f = x ** 2 + 20# 自动微分f.backward()# 打印 x 变量的梯度# backward 函数计算的梯度值会存储在张量的 grad 变量中print(x.grad)# 2. 单向量梯度的计算
# y = x**2 + 20
def test02():# 定义需要求导张量x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)# 变量经过中间计算f1 = x ** 2 + 20# 注意:# 由于求导的结果必须是标量# 而 f 的结果是: tensor([120., 420.])# 所以, 不能直接自动微分# 需要将结果计算为标量才能进行计算f2 = f1.mean()  # f2 = 1/2 * x# 自动微分f2.backward()# 打印 x 变量的梯度print(x.grad)# 3. 多标量梯度计算
# y = x1 ** 2 + x2 ** 2 + x1*x2
def test03():# 定义需要计算梯度的张量x1 = torch.tensor(10, requires_grad=True, dtype=torch.float64)x2 = torch.tensor(20, requires_grad=True, dtype=torch.float64)# 经过中间的计算y = x1**2 + x2**2 + x1*x2# 将输出结果变为标量y = y.sum()# 自动微分y.backward()# 打印两个变量的梯度print(x1.grad, x2.grad)# 4. 多向量梯度计算
def test04():# 定义需要计算梯度的张量x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)x2 = torch.tensor([30, 40], requires_grad=True, dtype=torch.float64)# 经过中间的计算y = x1 ** 2 + x2 ** 2 + x1 * x2print(y)# 将输出结果变为标量y = y.sum()# 自动微分y.backward()# 打印两个变量的梯度print(x1.grad, x2.grad)if __name__ == '__main__':test04()

tensor(20., dtype=torch.float64) tensor([ 5., 10., 15., 20.], dtype=torch.float64) tensor(40., dtype=torch.float64) tensor(50., dtype=torch.float64) tensor([1300., 2800.], dtype=torch.float64, grad_fn=<AddBackward0>) tensor([50., 80.], dtype=torch.float64) tensor([ 70., 100.], dtype=torch.float64)

2、控制梯度计算

通过一些方法使得在 requires_grad=True 的张量在某些时候计算不进行梯度计算。
import torch# 1. 控制不计算梯度
def test01():x = torch.tensor(10, requires_grad=True, dtype=torch.float64)print(x.requires_grad)# 第一种方式: 对代码进行装饰with torch.no_grad():y = x ** 2print(y.requires_grad)# 第二种方式: 对函数进行装饰@torch.no_grad()def my_func(x):return x ** 2print(my_func(x).requires_grad)# 第三种方式torch.set_grad_enabled(False)y = x ** 2print(y.requires_grad)# 2. 注意: 累计梯度
def test02():# 定义需要求导张量x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)for _ in range(3):f1 = x ** 2 + 20f2 = f1.mean()# 默认张量的 grad 属性会累计历史梯度值# 所以, 需要我们每次手动清理上次的梯度# 注意: 一开始梯度不存在, 需要做判断if x.grad is not None:x.grad.data.zero_()f2.backward()print(x.grad)# 3. 梯度下降优化最优解
def test03():# y = x**2x = torch.tensor(10, requires_grad=True, dtype=torch.float64)for _ in range(5000):# 正向计算f = x ** 2# 梯度清零if x.grad is not None:x.grad.data.zero_()# 反向传播计算梯度f.backward()# 更新参数x.data = x.data - 0.001 * x.gradprint('%.10f' % x.data)if __name__ == '__main__':test01()test02()test03()

True

False

False

False

tensor([ 5., 10., 15., 20.], dtype=torch.float64)

tensor([ 5., 10., 15., 20.], dtype=torch.float64)

tensor([ 5., 10., 15., 20.], dtype=torch.float64)

3、梯度计算注意

当对设置 requires_grad=True 的张量使用 numpy 函数进行转换时, 会出现如下报错:
Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
此时, 需要先使用 detach 函数将张量进行分离, 再使用 numpy 函数.
注意: detach 之后会产生一个新的张量, 新的张量作为叶子结点,并且该张量和原来的张量共享数据, 但是分离后的张量不需要计算梯度。
import torch# 1. detach 函数用法
def test01():x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)# Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.# print(x.numpy())  # 错误print(x.detach().numpy())  # 正确# 2. detach 前后张量共享内存
def test02():x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)# x2 作为叶子结点x2 = x1.detach()# 两个张量的值一样: 140421811165776 140421811165776print(id(x1.data), id(x2.data))x2.data = torch.tensor([100, 200])print(x1)print(x2)# x2 不会自动计算梯度: Falseprint(x2.requires_grad)if __name__ == '__main__':test01()test02()

[10. 20.]
1865743596496 1865743596496
tensor([10., 20.], dtype=torch.float64, requires_grad=True)
tensor([100, 200])
False