PyTorch
做 张量(Tensor) 处理的
它只有 数值 与 张量
张量的创建
torch.tensor() 基于指定数据创建张量 默认: int:64 float:32
torch.Tensor() 不仅可以基于指定数据创建,还可以基于 形状 创建
torch.IntTensor() DoubleTensor() FloatTensor() LongTensor() ShortTensor() 创建指定类型的张量
入门张量
#pytorch 2.7.0 -i 镜像地址
import torch
import numpy as np
t2 = torch.tensor([10])
print(t2)
t1 = torch.Tensor([10],)
print(t1)
t3 = torch.IntTensor(10)
print(t3)
t4 = torch.tensor(np.array(10))
print(t4)
随机张量
"""
案例:
通过Python代码演示如何创建 线性 和 随机张量.
涉及到的torch包中的函数如下:
torch.arange() 和 torch.linspace() 创建线性张量 与 正态分布
torch.random.initial_seed() 和 torch.random.manual_seed() 随机种子设置
torch.rand/randn() 创建随机浮点类型张量 +n 符合正态分布
torch.randint(low, high, size=()) 创建随机整数类型张量
掌握: torch.random.manual_seed() 手动设置随机种子, 如果种子一致, 则随机数也是"固定随机的" randint() 创建指定区间的随机整数张量"""
# 导包
import torch
import numpy as np
# todo 演示1: torch.arange() 和 torch.linspace() 创建线性张量
# 1. 创建1 ~ 10之间的线性张量, 步长为: 2
t1 = torch.arange(1, 11, 2) # 参1: 起始值, 参2: 结束值, 参3: 步长
print(f't1: {t1}')
# 2. 创建1 ~ 10之间的等差数列, 元素个数为: 5
t2 = torch.linspace(1, 10, 5) # 参1: 起始值, 参2: 结束值(包括), 参3: 元素个数
print(f't2: {t2}')
print('-' * 27)
# todo 演示2: torch.random.initial_seed() 和 torch.random.manual_seed() 随机种子设置
# torch.random.initial_seed() # 默认采用系统时间(每秒都在变化)作为种子.
torch.random.manual_seed(27) # 手动设置固定的随机种子
# todo 演示3: torch.rand/randn() 创建随机浮点类型张量
# 1. 创建2行3列的随机张量.
t1 = torch.rand(2, 3)
print(f't1: {t1}')
# 2. 创建2行3列的随机张量 -> 符合正态分布的随机张量.
t2 = torch.randn(2, 3)
print(f't2: {t2}')
print('-' * 27)
# todo 演示4: torch.randint(low, high, size=()) 创建随机整数类型张量
t1 = torch.randint(low=1, high=10, size=(2, 3)) # 2行3列 -> 随机生成1~10之间的随机数, 包左不包右.
print(f't1: {t1}')
# 扩展: Python的random模块下的randint()函数是包左包右的, 要记得和上述的作区分.
# import random
# print(random.randint(1, 1)) # 包左包右的
全0 全1 全指定
"""
案例:
演示如何创建全0, 全1, 全为指定值的张量.
涉及到的函数如下:
torch.ones 和 torch.ones_like 创建全1张量
torch.zeros 和 torch.zeros_like 创建全0张量
torch.full 和 torch.full_like 创建全为指定值张量
掌握:
zeros()
"""
# 导包
import torch
import numpy as np
# todo 演示1: torch.ones 和 torch.ones_like 创建全1张量
# 1. 创建指定形状的全1张量.
t1 = torch.ones(2, 3)
print(f't1: {t1}') # 默认是: float32
# 2. 基于指定(张量)的形状, 创建和其形状相同的全1张量.
my_tensor = torch.tensor([[1, 2], [3, 4], [5, 6]])
# print(my_tensor.shape) # torch.Size([3, 2])
t2 = torch.ones_like(my_tensor)
print(f't2: {t2}') # 3行2列的全1张量
print('-' * 27)
# todo 演示2: torch.zeros 和 torch.zeros_like 创建全0张量
t3 = torch.zeros(6, 2)
print(f't3: {t3}') # 默认是: float32
t4 = torch.zeros_like(my_tensor)
print(f't4: {t4}') # 3行2列的全0张量
print('-' * 27)
# todo 演示3: torch.full 和 torch.full_like 创建全为指定值张量
t5 = torch.full(size=(2, 3), fill_value=27)
print(f't5: {t5}')
t6 = torch.full_like(my_tensor, fill_value=27)
print(f't6: {t6}') # 3行2列的全27张量
改变类型
dtype 或者 直接点出来 .short .long .float .int .double .half-(一半)比如int64 -> int32
t1 = torch.tensor([1,2,3,4], dtype=torch.float32)
t2 = t1.type(torch.float64)
print(t2,t2.dtype)
张量的类型转换🪭
张量和numpy的ndarray之间的转换
张量 -> ndarray对象 :
t1.numpy().copy()
ndarray -> 张量:
torch.from_numpy()共享内存
torch.tensor() 不共享
提取0维张量:
0张量.item()
"""
案例:
演示PyTorch的张量 和 Numpy的ndarray类型相互转换.
涉及到的函数如下:
1. tensor#numpy() 可以变量张量 -> ndarray数组, 默认:共享内存.
2. torch.from_numpy() 把 ndarray -> 张量, 默认: 共享内存.
3. torch.tensor() 把 ndarray -> 张量, 默认: 不共享内存.
4. item()函数() 从张量中提取一个值.
"""
# 导包
import numpy as np
import torch
# 场景1: 张量 -> ndarray
# 1. 创建张量.
t1 = torch.tensor([1, 2, 3])
print(f't1: {t1}') # t1: tensor([1, 2, 3])
# 2. 把上述的张量 -> ndarray对象
n1 = t1.numpy() # 共享内存
n2 = t1.numpy().copy() # 不共享内存
print(f'n1: {n1}, n2: {n2}')
# 3. 修改张量的内容, 观察结果.
t1[0] = 100
# 4. 重新打印上述的张量信息.
print(f'张量的内容为: {t1}') # [10, 2, 3]
print(f'ndarray的内容为: {n1}, {n2}') # [100 2 3], [1 2 3]
print('-' * 27)
# todo 2. ndarray -> 张量
# 1. 创建ndarray对象.
n_obj = np.array([11, 22, 33])
# print(f'n_obj: {n_obj}, type: {type(n_obj)}') # 11 22 32], type: <class 'numpy.ndarray'>
# 2. 把上述的ndarray对象 -> 张量对象.
# 写法1: 共享内存
t3 = torch.from_numpy(n_obj)
print(f't3: {t3}, type: {type(t3)}') # <class 'torch.Tensor'>
# 写法2: 不共享内存
t4 = torch.from_numpy(n_obj.copy())
print(f't4: {t4}, type: {type(t4)}')
# 写法3: 不共享内存
t5 = torch.tensor(n_obj)
print(f't5: {t5}, type: {type(t5)}') # <class 'torch.Tensor'>
# 3. 修改ndarray对象, 观察结果.
n_obj[0] = 100
# 4. 打印修改后的内容.
print(f'ndarray的内容为: {n_obj}') # [100, 22, 33]
print(f't3: {t3}') # tensor([100, 22, 32], dtype=torch.int32)
print(f't4: {t4}') # tensor([11, 22, 32], dtype=torch.int32)
print(f't5: {t5}') # tensor([11, 22, 32], dtype=torch.int32)
print('-' * 27)
# todo 3: 演示 标量张量(1个值) 如何获取其中的 数值.
# 1. 创建一个标量张量.
t6 = torch.tensor(100)
print(f't6: {t6}, 类型: {type(t6)}') # tensor类型
# 2. 从上述的张量中, 提取数值.
a = t6.item() # item()函数: 只适用于 (标量)张量
print(f'a: {a}, 类型: {type(a)}') # int类型
张量运算函数
如add_() sub_() 加_表示 inplace=True
当然,我们 + - * / 用的多
加-add
t1 = torch.tensor([1,2,3,4,5],dtype=torch.int64)
print(t1)
t2 = t1.add(10)
print(t1)
print(t2)
t3 = t1.add_(10)
print(t3)
-------------------------------------------------------------
t1 = torch.tensor([1, -2, 3], dtype=torch.int64)
print(t1.add(10)) # tensor([11, 8, 13])
print(t1 + 10) # 效果同上
减-sub
print(t1.sub(10)) # tensor([ -9, -12, -7])
print(t1 - 10) # 效果同上
乘-mul
print(t1.mul(10)) # tensor([ 10, -20, 30])
print(t1 * 10) # 效果同上
除-div
print(t1.div(10)) # tensor([ 0.1000, -0.2000, 0.3000])
print(t1 / 10) # 效果同上
取反-neg
print(t1.neg()) # tensor([-1, 2, -3])
print(t1 * -1) # 效果同上
张量索引操作
"""
案例:
演示pytorch中的索引相关操作.
分类:
1. 简单的行列索引
2. 列表索引
3. 范围索引
4. 布尔索引
5. 多维索引
"""
# 导包
import torch
# todo 0.准备数据
# 1. 设置随机种子.
torch.manual_seed(27)
# 2. 随机生成4行5列的整数张量
t1 = torch.randint(0, 10, (4, 5))
print(f't1: {t1}')
print('-' * 27)
# todo 1. 演示简单的行列索引
print(t1[0]) # 获取第一行的数据
# todo 2. 演示列表索引
# 1. 获取(0, 1), (1, 2)两个位置的元素.
# 行 列
print(t1[[0, 1], [1, 2]])
# 2. 获取(0, 2), (3, 4)两个位置的元素.
print(t1[[0, 3], [2, 4]]) # 你: [9, 6], 我: [4, 2]
# 3. 返回0, 1行的 1,2列共4个元素.
print(t1[[[0], [1]], [1, 2]]) # 写法可以, 不报错, 但是不推荐, 会报警告.
print(t1[:2, [1, 2]]) # 推荐
print('-' * 27)
# todo 3. 演示范围索引
# 1. 获取前3行的前2列数据
print(t1[:3, :2])
# 2. 获取第2行到最后(一行)的 前2列数据
print(t1[1:, :2])
# 3. 获取所有行,所有列, 步长为2的数据
print(t1[::2, ::2])
print('-' * 27)
# todo 4. 演示布尔索引
# 1. 获取第4列大于8的行数据
print(t1[t1[:, 3] > 8])
# 2. 第2行大于5的列数据
print(t1[:, t1[1] > 5]) # : 表示所以行
print(t1[1, t1[1] > 5]) # 前边的1表示: 第2行(索引为1)
print('-' * 27)
# todo 5. 演示多维索引
# 1. 创建3个4行5列的, 随机整数张量.
t2 = torch.randint(0, 10, (3, 4, 5))
print(f't2: {t2}')
print('-' * 27)
# 2. 获取0轴上的第1个元素. # [3, 4, 5] -> [1, 4, 5]
print(t2[0, :, :]) # 即: 第1个4行5列的矩阵
# 3. 获取1轴上的第1个元素. # [3, 4, 5] -> [3, 1, 5]
print(t2[:, 0, :]) # 即: 获取3个(4行5列)矩阵的 第1行数据
# 4. 获取2轴上的第1个元素. # [3, 4, 5] -> [3, 4, 1]
print(t2[:, :, 0]) # 即: 获取3个(4行5列)矩阵的 第1列数据
张量形状操作
.shape[0/1]
size()[0/1]
张量的转换.reshape()
"""
案例:
演示pytorch中操作形状相关的函数.
涉及到的函数如下:
reshape() 改变张量的形状
squeeze() 删除张量中维度为1的维度(降维)
unsqueeze() 增加一个维度(升维)
"""
# 导包
import torch
# todo 1. 演示reshape()函数
def dm01_reshape():
# 1. 创建2行3列的矩阵(张量)
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 2. 打印上述张量的形状
print(f'形状为: {t1.shape}, 行数: {t1.shape[0]}, 列数: {t1.shape[1]}') # torch.Size([2, 3]), 2, 3
print(f'形状为: {t1.size()}, 行数: {t1.size(0)}, 列数: {t1.size(1)}') # 效果同上.
# 3. 改变张量的形状
# 3.1 从2行3列 -> 3行2列
t2 = t1.reshape(3, 2)
print(f't2: {t2}')
# todo 6. 测试代码
if __name__ == '__main__':
# 1. 测试: reshape()函数
dm01_reshape()
张量拼接操作
Cat() 只能在已有的维度上做拼接
stack() 可以在新的维度上做拼接
"""
案例:
演示Pytorch中的张量拼接动作
涉及到的函数如下:
cat() 只能在已有的维度上拼接, 不会改变维度数.
stack() 可以在新的维度上做拼接, 可以改变维度数.
细节:
1. 使用cat()函数拼接时, 拼接的那个维度值可以不同, 但是其它维度值必须相同.
例如:
按照0维拼接, 可以是: (3, 2) + (5, 2) = (8, 2)
按照1维拼接, 可以是: (2, 5) + (2, 3) = (2, 8)
"""
# 导包
import torch
# todo 1. 演示 cat()函数实现拼接
# 1. 创建2个随机的2维张量.
t1 = torch.randint(0, 10, (2, 3))
t2 = torch.randint(0, 10, (2, 3))
print(f't1: {t1}')
print(f't2: {t2}')
# 2. 再0维上做拼接, 即: (2, 3) + (2, 3) -> (4, 3)
t3 = torch.cat([t1, t2], dim=0)
print(f't3: {t3}')
# 3. 再1维上做拼接, 即: (2, 3) + (2, 3) -> (2, 8)
t4 = torch.cat([t1, t2], dim=1)
print(f't4: {t4}')
# 0维 1维 2维
# 4. 再2维上做拼接, 即: (2, 3) + (2, 3) -> (2, 3, 2)
# t5 = torch.cat([t1, t2], dim=2)
# print(f't5: {t5}') # 报错, cat()函数拼接的维度不能超过张量的维度数.
print('-' * 27)
# todo 2. 演示stack函数实现拼接.
# 1. 创建2个随机的2维张量.
t1 = torch.randint(0, 10, (2, 3))
t2 = torch.randint(0, 10, (2, 3))
print(f't1: {t1}')
print(f't2: {t2}')
# 2. 再0维上做拼接, 即: (2, 3) + (2, 3) -> (②, 2, 3)
t3 = torch.stack([t1, t2], dim=0)
print(f't3: {t3}, 形状: {t3.shape}')
# 3. 再1维上做拼接, 即: (2, 3) + (2, 3) -> (2, ②, 3)
t4 = torch.stack([t1, t2], dim=1)
print(f't4: {t4}, 形状: {t4.shape}')
# 4. 再2维上做拼接, 即: (2, 3) + (2, 3) -> (2, 3, ②)
t5 = torch.stack([t1, t2], dim=2)
print(f't5: {t5}, 形状: {t5.shape}') # 3维
# 5. 扩展: 再5维上做拼接.
# t6 = torch.stack([t1, t2], dim=5)
# print(f't6: {t6}, 形状: {t6.shape}') # 期望: (2, 3, 1, 1, ②), 结果是: 报错, 超出了维度数.
自动微分模块
自动求导
w = torch.tensor([10,20,30,40],requires_grad=True,dtype=torch.float32)
loss_fn = 2*w**2 #梯度公式 这里方便计算随便写的,如:准确率 召回率 F1 MAE MSE RMSE等
print(w.requires_grad)#查看梯度
print(w.data)#查看数据
loss_fn.sum().backward()#自动微分模块计算梯度
print(w.grad)#拿梯度
requires_grad 是否开启梯度跟踪
.grad:获取梯度
.data 查看数据
.backward 计算梯度
import torch
w = torch.tensor(10.0,requires_grad=True,dtype=torch.float32)
for i in range(1,100):
loss_fn = w**2
if w.grad is not None:
w.grad.zero_() #它的梯度会叠加 所以要清空-------梯度清零
loss_fn.backward()
w.data = w.data - w.grad * 0.01
print(f'第{i}次,{w.grad:.5f}|{w.data:.5f}'
梯度计算的注意点
如果一个张量 使用 自动微分动作 就不能ndarray转换
但 可以用 detach 进行备份 再 转ndarray
w = torch.tensor(10.0,requires_grad=True,dtype=torch.float32)
w1 = w.detach().numpy()
print(w,type(w))
print(w1,type(w1))
Comments NOTHING