深度学习_原理和进阶_PyTorch入门(2)后续语法3

后续语法3

1,**PyTorch-**广播机制

复制代码
import torch

"""
1,什么是广播机制
定义:广播机制是一种让 PyTorch (以及 NumPy 等其他科学
计算库)在进行元素级运算时,能够处理形状不完全相同的张量
的方法。它允许较小的张量“扩展”或者“广播”成较大的张量,以
便可以进行运算。
核心思想: 广播机制的目标是在不复制数据的情况下,使得不
同形状的张量能够进行运算。
优势:
代码简洁: 不需要显式地对张量进行复制或者重塑,代码更加简洁和易读。
内存高效: 避免不必要的数据复制,节约内存空间,提升计算效率。

2,PyTorch 中的广播遵循以下两个基本规则:
(1:维度对齐
(2:维度扩展
"""

# 1,相同形状的张量
scalar1 = torch.full((2, 2), 100)
scalar2 = torch.full((2, 2), 12)
scalar3 = scalar2 + scalar1
print(f"相同形状的张量相加,正常元素加法:{scalar3}")

# 2,维度拓展 维度大小不同,但是对应维度长度相同
scalar1 = torch.full((2, 2), 100)
scalar2 = torch.tensor([12, 12])
scalar3 = scalar2 + scalar1
# 逻辑等价(2) 被广播成了 (2,2)
print(f"对应维度长度相同加法:{scalar3}")

# 3,维度对齐 维度大小相同,其中一个维度长度为1
scalar1 = torch.full((2, 2), 100)
scalar2 = torch.full((1, 2), 12)
scalar3 = torch.full((2, 1), 12)
# 逻辑等价与 (2,1)和(1,2)都被广播成了(2,2)
scalar4 = scalar1 + scalar2 + scalar3
print(f"对应维度长度相同加法:{scalar4}")

#4,维度大小和对应维度长度都不相同情况,会报错
scalar1 = torch.full((2, 2), 100)
scalar2 = torch.tensor([12, 12,12])
scalar3 = scalar2 + scalar1

相同形状的张量相加,正常元素加法:tensor([[112, 112],

112, 112\]\]) 对应维度长度相同加法:tensor(\[\[112, 112\], \[112, 112\]\]) 对应维度长度相同加法:tensor(\[\[124, 124\], \[124, 124\]\]) Traceback (most recent call last): File "D:\\PycharmProjects\\AIStudy\\baizhanAI\\深度学习_原理进阶\\PyTorch\\9_PyTorch_广播机制.py", line 44, in \ scalar3 = scalar2 + scalar1 \~\~\~\~\~\~\~\~\^\~\~\~\~\~\~\~\~ RuntimeError: The size of tensor a (3) must match the size of tensor b (2) at non-singleton dimension 1 ### **2,PyTorch索引操作** ``` import torch """ 索引分类 1,行列索引 2,切片索引 3,列表u松阴 4,多维索引 5,布尔索引 6,省略号'...'使用 7,组合索引 8,通过索引赋值 在深度学习中经常用于: 数据预处理 批量处理 特征选择 注意力机制 """ scalar1 = torch.arange(1, 10, 1) # 左闭右开 # 转换为 3*3的矩阵 matrix1 = scalar1.reshape(3, 3) print(f"matrix1:{matrix1}") print("---------行列索引-------------") print(f"一行一列:{matrix1[0, 0]}") # 一行一列 print(f"1行三列:{matrix1[0, 2]}") # 1行三列 print(f"第二行:{matrix1[1]}") print(f"第1列:{matrix1[:, 0]}") print(f"前两行:{matrix1[0:2]}") print(f"前两列:{matrix1[:, 0:2]}") print("----------切片索引--------------") print(f"隔行隔列选择前两行列:{matrix1[::2, ::2]}") print("------------负数索引------------") print(f"最后一行:{matrix1[-1]}") print(f"最后一列:{matrix1[:, -1]}") print(f"最后一行的最后一列:{matrix1[-1, -1]}") print("----------使用列表或tensor作为索引-------------") indies = torch.tensor([1, -1]) print(f"第二行和最后一行:{matrix1[indies]}") print(f"选着一三列:{matrix1[:, [0, 2]]}") print(f"第二行和最后一行:{matrix1[indies]}") rows = torch.tensor([0, 1]) columns = torch.tensor([0, 1]) print(f"{matrix1[rows, columns]}") print("-------------布尔索引-------------------") mask = matrix1 > 6 print(f"选择>6的元素:{matrix1[mask]}") # 组合条件 mask = (matrix1 > 3) & (matrix1 < 8) print(f"选择3到8之间的所有元素:{matrix1[mask]}") # 行或列的布尔索引 row_mask = torch.tensor([True, False, True]) print(f"选择第1和第3行:{matrix1[row_mask]}") print("----------- ... 表示任意数量的:-------------") tensor_4d = torch.rand(3, 4, 5, 6) print(tensor_4d[0, ...]) # 等价于tensor_4d[0, :, :, :] print(tensor_4d[..., 0]) # 等价于tensor_4d[:, :, :, 0] # 混合使用多种索引方式 print('-------混合使用多种索引方式----------') print(f"前三行的1,2列:{matrix1[0:3, [0, 1]]}") mask = matrix1[:, 0] > 3 print(f"第一列大于3的行:{matrix1[mask]}") print(f"满足条件行的部分列:{matrix1[mask, 1:]}") print(f"所有维度前两列:{matrix1[..., 0:2]}") print(f"---------------使用索引修改tensor的值------------") matrix1[2][2] = 666 print(f"666:{matrix1}") matrix1[1] = torch.zeros(3) print(f"修改整行:{matrix1}") matrix1[matrix1 > 5] = 1 print(f"条件修改:{matrix1}") 运行结果太多了就不展示了 ``` ### **3,PyTorch张量形状操作** ``` import torch from numpy.array_api import reshape """ Tensor的形状描述了其在每个维度上的元素数量,例如torch.Tensor(2,3,4) 表示他又两个二维数组,每个数组有三个一维列表,每个列表有四个标量 常用方法 tensor.shape与tensor.size() 都返回一个元组,表示Tensor的形状 torch.reshape()与torch.view() 改变tensor的形状 可以处理非连续的tensor, tensor必须是连续的,如果tensor不连续会报错 """ print(torch.Tensor(2, 3, 4)) # 生成一个张量,形状为(2,3,4),元素从0到23 data_3d = torch.arange(24).reshape(2, 3, 4) # 两种方法都返回形状相同的元组 shape_1 = data_3d.shape size_1 = data_3d.size() print(f"shape_1:{shape_1},\n size_1:{size_1}") print("--------------reshape和view重定形状--------------") # reshape操作 reshaped = data_3d.reshape(3, 8) viewed = data_3d.view(3, 8) print(f"reshaped:{reshaped},\n viewed:{viewed}") # 注意 data_3d2 = data_3d.transpose(0, 1) #不是连续的内容,会报错 viewed1 = data_3d2.view(3, 8) print(f"不是连续内容:{viewed1}") ``` 运行结果: tensor(\[\[\[3.7653e-39, 7.6225e-39, 1.0102e-38, 9.3674e-39\], \[1.0469e-38, 7.6225e-39, 6.9796e-39, 6.1531e-39\], \[9.6429e-39, 1.0102e-38, 6.1531e-39, 1.0010e-38\]\], \[\[1.0194e-38, 9.2755e-39, 1.0653e-38, 4.5001e-39\], \[7.6225e-39, 1.0102e-38, 9.3674e-39, 1.0469e-38\], \[9.0918e-39, 8.0817e-39, 4.7755e-39, 9.1836e-39\]\]\]) shape_1:torch.Size(\[2, 3, 4\]), size_1:torch.Size(\[2, 3, 4\]) --------------reshape和view重定形状-------------- reshaped:tensor(\[\[ 0, 1, 2, 3, 4, 5, 6, 7\], \[ 8, 9, 10, 11, 12, 13, 14, 15\], \[16, 17, 18, 19, 20, 21, 22, 23\]\]), viewed:tensor(\[\[ 0, 1, 2, 3, 4, 5, 6, 7\], \[ 8, 9, 10, 11, 12, 13, 14, 15\], \[16, 17, 18, 19, 20, 21, 22, 23\]\]) Traceback (most recent call last): File "D:\\PycharmProjects\\AIStudy\\baizhanAI\\深度学习_原理进阶\\PyTorch\\12_PyTorch-张量形状操作.py", line 32, in \ viewed1 = data_3d2.view(3, 8) \^\^\^\^\^\^\^\^\^\^\^\^\^\^\^\^\^\^\^ RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead. ### **4,PyTorch张量升维与降维** ``` import torch """ 常用方法 torch.unsqueeze() 用在指定位置加一个维度,通常用于增加批次维度 torch.squeeze() 用于移除大小为1的维度,可简化Tensor形状 """ print("--------------------unsqueeze添加维度------------------") x1 = torch.randn(3,4) print(x1) x1_new = x1.unsqueeze(0) #最前面加一个维度 [1,3,4] print(x1_new) x1_new2 = x1.unsqueeze(1) #第二个位置添加一个维度 print(x1_new2) x1_new3 = x1.unsqueeze(-1) #最后1个位置添加一个维度[3,4,1] print(x1_new3) print("-------------------删除一个维度-------------------") x = torch.arange(6).reshape(1,2,3) x_new1 = x.squeeze() print(x_new1.shape) ``` 运行结果: --------------------unsqueeze添加维度------------------ tensor(\[\[-1.0873, -0.7961, -0.4153, 1.7513\], \[-0.8825, 0.1612, -0.6903, 1.0875\], \[ 0.1964, 0.6350, 0.0359, 1.1037\]\]) tensor(\[\[\[-1.0873, -0.7961, -0.4153, 1.7513\], \[-0.8825, 0.1612, -0.6903, 1.0875\], \[ 0.1964, 0.6350, 0.0359, 1.1037\]\]\]) tensor(\[\[\[-1.0873, -0.7961, -0.4153, 1.7513\]\], \[\[-0.8825, 0.1612, -0.6903, 1.0875\]\], \[\[ 0.1964, 0.6350, 0.0359, 1.1037\]\]\]) tensor(\[\[\[-1.0873\], \[-0.7961\], \[-0.4153\], \[ 1.7513\]\], \[\[-0.8825\], \[ 0.1612\], \[-0.6903\], \[ 1.0875\]\], \[\[ 0.1964\], \[ 0.6350\], \[ 0.0359\], \[ 1.1037\]\]\]) -------------------删除一个维度------------------- torch.Size(\[2, 3\]) ### **5,PyTorch张量维度交换** ``` import torch """ torch.transpose() 和torch.permute 用于修改维度顺序。通常用于图像格式转换,序列处理 transpose只能交换两个维度 permute可以任意重排所有维度 """ x = torch.arange(24).reshape(2,3,4) print("----torch.transpose() 和torch.permute 用于修改维度顺序----") print(f"x:{x.shape}") x_tran = x.transpose(0,1) print(f"x_tran:{x_tran.shape}") x_per= x.permute(1,2,0) #dim1,dim2,dim0 print(f"x_per:{x_per.shape}") 运行结果: ``` ----torch.transpose() 和torch.permute 用于修改维度顺序---- x:torch.Size(\[2, 3, 4\]) x_tran:torch.Size(\[3, 2, 4\]) x_per:torch.Size(\[3, 4, 2\]) ### **6,PyTorch 张量内存连续性** ``` import torch """ 张量在内存默认是按维度顺序连续存储 torch.is_contiguous() 判断张量是否连续存储 torch.contiguous() 返回内存连续的新张量(若已连续则返回自身) """ print("--------torch.is_contiguous()---------") x = torch.arange(32).reshape(2,4,4) x_tran = x.transpose(0,1) print(f"是否连续:{x.is_contiguous()}") print(f"交换维度后是否连续:{x_tran.is_contiguous()}") print("--------torch.contiguous()---------") x_con = x_tran.contiguous() print(f"处理后的连续性:{x_con.is_contiguous()}") ``` 运行结果: --------torch.is_contiguous()--------- 是否连续:True 交换维度后是否连续:False --------torch.contiguous()--------- 处理后的连续性:True ### **7,PyTorch 张量拼接** ``` import torch """ 张量拼接就是将多个张量按照特定维度组合成一个更大的张量 为什么需要拼接操作:数据合并、特征融合、批处理等 实际应用场景:图像处理、自然语言处理、多模态融合等 torch.cat(tensors, dim=0, out=None) 别名 torch.concatenate() tensors:要连接的张量序列(列表或元组) dim:沿着哪个维度连接 out:输出张量(可选) 注意: 拼接维度长度需要匹配 数据类型需要一致 设备一致(CPU / GPU) torch.stack(tensor,dim=0,out) 与cat的关键区别:创建新的维度进行堆叠 工作原理:沿着新维度堆叠张量 关键要求:所有张量的形状必须完全相同 """ # 设置随机种子 torch.manual_seed(100) # 创建张量 a1 = torch.ones(2, 3) b1 = torch.zeros(2, 3) print("--------cat------") print(f"a1:{a1} \n b1:{b1}") # 沿着0和1维拼接 c1_dim0 = torch.cat((a1, b1), dim=0) print(f"沿着0维拼接 c1_dim0: {c1_dim0}") c1_dim1 = torch.cat((a1, b1), dim=1) print(f"沿着1维拼接 c1_dim1: {c1_dim1}") print("--------stack------") c1_stack = torch.stack((a1, b1), dim=0) print(f"stack拼接 c1_stack: {c1_stack} \n 新形状:{c1_stack.shape}") #指定加到第三个维度 c2_stack = torch.stack((a1, b1), dim=2) print(f"stack拼接 c2_stack: {c2_stack} \n 新形状:{c2_stack.shape}") ``` 运行结果: --------cat------ a1:tensor(\[\[1., 1., 1.\], \[1., 1., 1.\]\]) b1:tensor(\[\[0., 0., 0.\], \[0., 0., 0.\]\]) 沿着0维拼接 c1_dim0: tensor(\[\[1., 1., 1.\], \[1., 1., 1.\], \[0., 0., 0.\], \[0., 0., 0.\]\]) 沿着1维拼接 c1_dim1: tensor(\[\[1., 1., 1., 0., 0., 0.\], \[1., 1., 1., 0., 0., 0.\]\]) --------stack------ stack拼接 c1_stack: tensor(\[\[\[1., 1., 1.\], \[1., 1., 1.\]\], \[\[0., 0., 0.\], \[0., 0., 0.\]\]\]) 新形状:torch.Size(\[2, 2, 3\]) stack拼接 c2_stack: tensor(\[\[\[1., 0.\], \[1., 0.\], \[1., 0.\]\], \[\[1., 0.\], \[1., 0.\], \[1., 0.\]\]\]) 新形状:torch.Size(\[2, 3, 2\]) ### **8,PyTorch自动微分** ``` import torch """ 自动微分模块可以自动梯度计算,不用手动推到和编码梯度,可以自动计算张量操作的导数 """ # # 简单的房价预测模型 # def predict_house_price(size, w, b): # w权重,b偏置 # return size * w + b # # # # 假设实际数据 # real_price = 100 # house_size = 50 # w = 1.5 # b = 10 # # # 预测价格 # predicted_price = predict_house_price(house_size, w, b) # # 计算误差 # error = predicted_price - real_price # # print(f"误差:{error}") """ 自动微分可以自动计算复杂函数的导数,而不需要手动推导和编写导数计算代码 """ # 手动计算梯度 def manual_gradient_calculation(): house_size = 50 real_price = 100 w = 1.5 b = 10 predicted_price = house_size * w + b error = predicted_price - real_price # 假设损失函数为平方误差 L = (predicted -real)^2 dl_dw = 2 * error * house_size # 梯度计算dl/dw dl_db = 2 * error # 梯度计算:dL/db = 2*(预测值-真实值) return dl_dw, dl_db # PyTorch自动微分部分 def pytorch_autograd(): house_size = torch.tensor([50.0]) real_price = torch.tensor([100.0]) w = torch.tensor([1.5], requires_grad=True) b = torch.tensor([10.0], requires_grad=True) predicted_price = house_size * w + b loss = torch.nn.MSELoss()(predicted_price, real_price) loss.backward() return w.grad.item(), b.grad.item() # 计算梯度 # 验证结果 if __name__ == "__main__": # 手动计算梯度 manual_dw, manual_db = manual_gradient_calculation() print(f"手动计算梯度: manual_dw:{manual_dw}, manual_db:{manual_db}") #自动计算梯度 auto_dw,auto_db = pytorch_autograd() print(f"自动微分: auto_dw:{auto_dw}, auto_db:{auto_db}") ``` 运行结果: 手动计算梯度: manual_dw:-1500.0, manual_db:-30.0 自动微分: auto_dw:-1500.0, auto_db:-30.0

相关推荐
boonya2 小时前
ChatBox AI 中配置阿里云百炼模型实现聊天对话
人工智能·阿里云·云计算·chatboxai
8K超高清2 小时前
高校巡展:中国传媒大学+河北传媒学院
大数据·运维·网络·人工智能·传媒
老夫的码又出BUG了2 小时前
预测式AI与生成式AI
人工智能·科技·ai
AKAMAI2 小时前
AI 边缘计算:决胜未来
人工智能·云计算·边缘计算
flex88882 小时前
输入一个故事主题,使用大语言模型生成故事视频【视频中包含大模型生成的图片、故事内容,以及音频和字幕信息】
人工智能·语言模型·自然语言处理
TTGGGFF3 小时前
人工智能:大语言模型或为死胡同?拆解AI发展的底层逻辑、争议与未来方向
大数据·人工智能·语言模型
张艾拉 Fun AI Everyday3 小时前
从 ChatGPT 到 OpenEvidence:AI 医疗的正确打开方式
人工智能·chatgpt
哥布林学者3 小时前
吴恩达深度学习课程二: 改善深层神经网络 第二周:优化算法(二)指数加权平均和学习率衰减
深度学习·ai
mwq301233 小时前
位置编码的技术演进线路:从绝对到相对,再到几何一致性
人工智能