PyTorch 张量与自动微分操作

笔记

1 张量索引操作

python 复制代码
import torch
​
# 下标从左到右从0开始(0->第一个值), 从右到左从-1开始
# data[行下标, 列下标]
# data[0轴下标, 1轴下标, 2轴下标]
​
def dm01():
    # 创建张量
    torch.manual_seed(0)
    data = torch.randint(low=0, high=10, size=(4, 5))
    print('data->', data)
    # 根据下标值获取对应位置的元素
    # 行数据 第一行
    print('data[0] ->', data[0])
    # 列数据 第一列
    print('data[:, 0]->', data[:, 0])
    # 根据下标列表取值
    # 第二行第三列的值和第四行第五列值
    print('data[[1, 3], [2, 4]]->', data[[1, 3], [2, 4]])
    # [[1], [3]: 第二行第三列 第二行第五列值   第四行第三列 第四行第五列值
    print('data[[[1], [3]], [2, 4]]->', data[[[1], [3]], [2, 4]])
    # 根据布尔值取值
    # 第二列大于6的所有行数据
    print(data[:, 1] > 6)
    print('data[data[:, 1] > 6]->', data[data[:, 1] > 6])
    # 第三行大于6的所有列数据
    print('data[:, data[2]>6]->', data[:, data[2] > 6])
    # 根据范围取值  切片  [起始下标:结束下标:步长]
    # 第一行第三行以及第二列第四列张量
    print('data[::2, 1::2]->', data[::2, 1::2])
​
    # 创建三维张量
    data2 = torch.randint(0, 10, (3, 4, 5))
    print("data2->", data2)
    # 0轴第一个值
    print(data2[0, :, :])
    # 1轴第一个值
    print(data2[:, 0, :])
    # 2轴第一个值
    print(data2[:, :, 0])
​
​
if __name__ == '__main__':
    dm01()

2 张量形状操作

2.1 reshape

python 复制代码
import torch
​
​
# reshape(shape=(行,列)): 修改连续或非连续张量的形状, 不改数据
# -1: 表示自动计算行或列   例如:  (5, 6) -> (-1, 3) -1*3=5*6 -1=10  (10, 3)
def dm01():
    torch.manual_seed(0)
    t1 = torch.randint(0, 10, (5, 6))
    print('t1->', t1)
    print('t1的形状->', t1.shape)
    # 形状修改为 (2, 15)
    t2 = t1.reshape(shape=(2, 15))
    t3 = t1.reshape(shape=(2, -1))
    print('t2->', t2)
    print('t2的形状->', t2.shape)
    print('t3->', t3)
    print('t3的形状->', t3.shape)
​
​
​
if __name__ == '__main__':
    dm01()
复制代码

2.2 squeeze和unsqueeze

python 复制代码
# squeeze(dim=): 删除值为1的维度, dim->指定维度, 维度值不为1不生效  不设置dim,删除所有值为1的维度
# 例如: (3,1,2,1) -> squeeze()->(3,2)  squeeze(dim=1)->(3,2,1)
# unqueeze(dim=): 在指定维度上增加值为1的维度  dim=-1:最后维度
def dm02():
    torch.manual_seed(0)
    # 四维
    t1 = torch.randint(0, 10, (3, 1, 2, 1))
    print('t1->', t1)
    print('t1的形状->', t1.shape)
    # squeeze: 降维
    t2 = torch.squeeze(t1)
    print('t2->', t2)
    print('t2的形状->', t2.shape)
    # dim: 指定维度
    t3 = torch.squeeze(t1, dim=1)
    print('t3->', t3)
    print('t3的形状->', t3.shape)
    # unsqueeze: 升维
    # (3, 2)->(1, 3, 2)
    # t4 = t2.unsqueeze(dim=0)
    # 最后维度 (3, 2)->(3, 2, 1)
    t4 = t2.unsqueeze(dim=-1)
    print('t4->', t4)
    print('t4的形状->', t4.shape)
​
​
if __name__ == '__main__':
    dm02()

2.3 transpose和permute

python 复制代码
# 调换维度
# torch.permute(input=,dims=): 改变张量任意维度顺序
# input: 张量对象
# dims: 改变后的维度顺序, 传入轴下标值 (1,2,3)->(3,1,2)
# torch.transpose(input=,dim0=,dim1=): 改变张量两个维度顺序
# dim0: 轴下标值, 第一个维度
# dim1: 轴下标值, 第二个维度
# (1,2,3)->(2,1,3) 一次只能交换两个维度
def dm03():
    torch.manual_seed(0)
    t1 = torch.randint(low=0, high=10, size=(3, 4, 5))
    print('t1->', t1)
    print('t1形状->', t1.shape)
    # 交换0维和1维数据
    # t2 = t1.transpose(dim0=1, dim1=0)
    t2 = t1.permute(dims=(1, 0, 2))
    print('t2->', t2)
    print('t2形状->', t2.shape)
    # t1形状修改为 (5, 3, 4)
    t3 = t1.permute(dims=(2, 0, 1))
    print('t3->', t3)
    print('t3形状->', t3.shape)
​
​
if __name__ == '__main__':
    dm03()

2.4 view和contiguous

python 复制代码
# tensor.view(shape=): 修改连续张量的形状, 操作等同于reshape()
# tensor.is_contiugous(): 判断张量是否连续, 返回True/False  张量经过transpose/permute处理变成不连续
# tensor.contiugous(): 将张量转为连续张量
def dm04():
    torch.manual_seed(0)
    t1 = torch.randint(low=0, high=10, size=(3, 4))
    print('t1->', t1)
    print('t1形状->', t1.shape)
    print('t1是否连续->', t1.is_contiguous())
    # 修改张量形状
    t2 = t1.view((4, 3))
    print('t2->', t2)
    print('t2形状->', t2.shape)
    print('t2是否连续->', t2.is_contiguous())
    # 张量经过transpose操作
    t3 = t1.transpose(dim0=1, dim1=0)
    print('t3->', t3)
    print('t3形状->', t3.shape)
    print('t3是否连续->', t3.is_contiguous())
    # 修改张量形状
    # view
    # contiugous(): 转换成连续张量
    t4 = t3.contiguous().view((3, 4))
    print('t4->', t4)
    t5 = t3.reshape(shape=(3, 4))
    print('t5->', t5)
    print('t5是否连续->', t5.is_contiguous())
​
​
if __name__ == '__main__':
    dm04()

3 张量拼接操作

3.1 cat/concat

python 复制代码
import torch
​
​
# torch.cat()/concat(tensors=, dim=): 在指定维度上进行拼接, 其他维度值必须相同, 不改变新张量的维度, 指定维度值相加
# tensors: 多个张量列表
# dim: 拼接维度
def dm01():
    torch.manual_seed(0)
    t1 = torch.randint(low=0, high=10, size=(2, 3))
    t2 = torch.randint(low=0, high=10, size=(2, 3))
    t3 = torch.cat(tensors=[t1, t2], dim=0)
    print('t3->', t3)
    print('t3形状->', t3.shape)
    t4 = torch.concat(tensors=[t1, t2], dim=1)
    print('t4->', t4)
    print('t4形状->', t4.shape)
    
​
if __name__ == '__main__':
    # dm01()

3.2 stack

python 复制代码
# torch.stack(tensors=, dim=): 根据指定维度进行堆叠, 在指定维度上新增一个维度(维度值张量个数), 新张量维度发生改变
# tensors: 多个张量列表
# dim: 拼接维度
def dm02():
    torch.manual_seed(0)
    t1 = torch.randint(low=0, high=10, size=(2, 3))
    t2 = torch.randint(low=0, high=10, size=(2, 3))
    t3 = torch.stack(tensors=[t1, t2], dim=0)
    # t3 = torch.stack(tensors=[t1, t2], dim=1)
    print('t3->', t3)
    print('t3形状->', t3.shape)
​
​
if __name__ == '__main__':
    dm02()

4 自动微分模块

4.1 梯度计算

python 复制代码
"""
梯度: 求导,求微分 上山下山最快的方向
梯度下降法: W1=W0-lr*梯度   lr是可调整已知参数  W0:初始模型的权重,已知  计算出W0的梯度后更新到W1权重
pytorch中如何自动计算梯度 自动微分模块
注意点: ①loss标量和w向量进行微分  ②梯度默认累加,计算当前的梯度, 梯度值是上次和当前次求和  ③梯度存储.grad属性中
"""
import torch
​
​
def dm01():
    # 创建标量张量 w权重
    # requires_grad: 是否自动微分,默认False
    # dtype: 自动微分的张量元素类型必须是浮点类型
    # w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
    # 创建向量张量 w权重
    w = torch.tensor(data=[10, 20], requires_grad=True, dtype=torch.float32)
    # 定义损失函数, 计算损失值
    loss = 2 * w ** 2
    print('loss->', loss)
    print('loss.sum()->', loss.sum())
    # 计算梯度 反向传播  loss必须是标量张量,否则无法计算梯度
    loss.sum().backward()
    # 获取w权重的梯度值
    print('w.grad->', w.grad)
    w.data = w.data - 0.01 * w.grad
    print('w->', w)
​
​
if __name__ == '__main__':
    dm01()

4.2 梯度下降法求最优解

python 复制代码
"""
① 创建自动微分w权重张量
② 自定义损失函数 loss=w**2+20  后续无需自定义,导入不同问题损失函数模块
③ 前向传播 -> 先根据上一版模型计算预测y值, 根据损失函数计算出损失值
④ 反向传播 -> 计算梯度
⑤ 梯度更新 -> 梯度下降法更新w权重
"""
import torch
​
​
def dm01():
    # ① 创建自动微分w权重张量
    w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
    print('w->', w)
    # ② 自定义损失函数 后续无需自定义, 导入不同问题损失函数模块
    loss = w ** 2 + 20
    print('loss->', loss)
    # 0.01 -> 学习率
    print('开始 权重x初始值:%.6f (0.01 * w.grad):无 loss:%.6f' % (w, loss))
    for i in range(1, 1001):
        # ③ 前向传播 -> 先根据上一版模型计算预测y值, 根据损失函数计算出损失值
        loss = w ** 2 + 20
        # 梯度清零 -> 梯度累加, 没有梯度默认None
        if w.grad is not None:
            w.grad.zero_()
        # ④ 反向传播 -> 计算梯度
        loss.sum().backward()
        # ⑤ 梯度更新 -> 梯度下降法更新w权重
        # W = W - lr * W.grad
        # w.data -> 更新w张量对象的数据, 不能直接使用w(将结果重新保存到一个新的变量中)
        w.data = w.data - 0.01 * w.grad
        print('w.grad->', w.grad)
        print('次数:%d 权重w: %.6f, (0.01 * w.grad):%.6f loss:%.6f' % (i, w, 0.01 * w.grad, loss))
​
    print('w->', w, w.grad, 'loss最小值', loss)
​
​
if __name__ == '__main__':
    dm01()

4.3 梯度计算注意点

python 复制代码
# 自动微分的张量不能转换成numpy数组, 可以借助detach()方法生成新的不自动微分张量
import torch
​
​
def dm01():
    x1 = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
    print('x1->', x1)
    # 判断张量是否自动微分 返回True/False
    print(x1.requires_grad)
    # 调用detach()方法对x1进行剥离, 得到新的张量,不能自动微分,数据和原张量共享
    x2 = x1.detach()
    print(x2.requires_grad)
    print(x1.data)
    print(x2.data)
    print(id(x1.data))
    print(id(x2.data))
    # 自动微分张量转换成numpy数组
    n1 = x2.numpy()
    print('n1->', n1)
​
​
if __name__ == '__main__':
    dm01()

4.4 自动微分模块应用

python 复制代码
import torch
import torch.nn as nn  # 损失函数,优化器函数,模型函数
​
​
def dm01():
    # todo:1-定义样本的x和y
    x = torch.ones(size=(2, 5))
    y = torch.zeros(size=(2, 3))
    print('x->', x)
    print('y->', y)
    # todo:2-初始模型权重 w b 自动微分张量
    w = torch.randn(size=(5, 3), requires_grad=True)
    b = torch.randn(size=(3,), requires_grad=True)
    print('w->', w)
    print('b->', b)
    # todo:3-初始模型,计算预测y值
    y_pred = torch.matmul(x, w) + b
    print('y_pred->', y_pred)
    # todo:4-根据MSE损失函数计算损失值
    # 创建MSE对象, 类创建对象
    criterion = nn.MSELoss()
    loss = criterion(y_pred, y)
    print('loss->', loss)
    # todo:5-反向传播,计算w和b梯度
    loss.sum().backward()
    print('w.grad->', w.grad)
    print('b.grad->', b.grad)
​
​
if __name__ == '__main__':
    dm01()
相关推荐
当当狸38 分钟前
当当狸智能天文望远镜 TW2 | 用科技触摸星辰,让探索触手可及
人工智能·科技·内容运营
LiLiYuan.39 分钟前
关于Stream
java·开发语言·windows·python
geneculture40 分钟前
金融的本质是智融、融资的实质是融智、投资的关键是投智,颠覆传统金融学的物质资本中心论,构建了以智力资本为核心的新范式
大数据·人工智能·算法·金融·系统工程融智学
Green1Leaves41 分钟前
从零开始学习人工智能(Python高级教程)Day6-Python3 正则表达式
python·学习·正则表达式
码有余悸41 分钟前
初学Python爬虫
python
极小狐42 分钟前
极狐Gitlab 如何创建并使用子群组?
数据库·人工智能·git·机器学习·gitlab
派阿喵搞电子2 小时前
YOLOv8的Python基础--函数篇
python·yolov8
MonkeyKing_sunyuhua6 小时前
6.5 行业特定应用:金融、医疗、制造等行业的定制化解决方案
人工智能·agent
god_Zeo7 小时前
从头训练小模型: 4 lora 微调
人工智能·机器学习
weixin_472339467 小时前
PyCharm 安装教程
ide·python·pycharm