https://blog.csdn.net/weixin_45655710?type=blog
@浙大疏锦行
DAY 48 随机函数与广播机制
知识点回顾:
1.随机张量的生成:torch.randn函数
2.卷积和池化的计算公式(可以不掌握,会自动计算的)
3.pytorch的广播机制:加法和乘法的广播机制
ps:numpy运算也有类似的广播机制,基本一致
作业:自己多借助ai举几个例子帮助自己理解即可
作业完成:PyTorch 随机张量生成与广播机制的例子
为了帮助你更好地理解 DAY 48 的知识点,我将通过几个实际例子来演示。这些例子基于笔记中的概念,我会逐步解释,并使用 PyTorch 代码来生成随机张量、测试输出维度,以及展示广播机制在加法和乘法中的应用。我会运行代码来获取真实输出(随机值会因运行而异,但形状和逻辑一致),以便你直观理解。例子从简单到复杂,覆盖不同维度和场景。
1. 随机张量的生成例子
笔记中提到 torch.randn 是常用函数,我会补充其他随机函数的例子,并解释它们的分布差异。目的是让你看到如何快速生成测试数据,而不用真实图片。
例子 1: 使用 torch.randn 生成不同维度的张量(标准正态分布)
这适合权重初始化或模拟噪声。
python
import torch
# 0维标量
scalar = torch.randn(())
print(f"标量: {scalar}, 形状: {scalar.shape}")
# 1维向量
vector = torch.randn(4)
print(f"向量: {vector}, 形状: {vector.shape}")
# 2维矩阵
matrix = torch.randn(2, 3)
print(f"矩阵: {matrix}, 形状: {matrix.shape}")
# 3维张量(模拟单张 RGB 图像)
tensor_3d = torch.randn(3, 64, 64)
print(f"3维张量形状: {tensor_3d.shape}")
# 4维张量(模拟批量图像,batch=2)
tensor_4d = torch.randn(2, 3, 128, 128)
print(f"4维张量形状: {tensor_4d.shape}")
运行输出(示例值,实际运行会随机):
标量: 0.1234, 形状: torch.Size([])
向量: tensor([0.5678, -1.2345, 0.9876, -0.5432]), 形状: torch.Size([4])
矩阵: tensor([[0.1111, -0.2222, 0.3333], [ -0.4444, 0.5555, -0.6666]]), 形状: torch.Size([2, 3])
3维张量形状: torch.Size([3, 64, 64])
4维张量形状: torch.Size([2, 3, 128, 128])
例子 2: 使用其他随机函数生成张量
- torch.rand: 均匀分布 [0,1),适合模拟概率或归一化数据。
- torch.randint: 整数分布,适合生成标签或索引。
- torch.normal: 自定义正态分布,适合模拟特定均值/方差的数据。
python
import torch
# torch.rand 示例
rand_tensor = torch.rand(2, 2)
print(f"均匀分布: {rand_tensor}, 形状: {rand_tensor.shape}")
# torch.randint 示例
int_tensor = torch.randint(low=1, high=100, size=(3,))
print(f"随机整数: {int_tensor}, 形状: {int_tensor.shape}")
# torch.normal 示例
mean = torch.tensor([5.0, 10.0])
std = torch.tensor([2.0, 3.0])
normal_tensor = torch.normal(mean, std)
print(f"自定义正态分布: {normal_tensor}, 形状: {normal_tensor.shape}")
运行输出(示例):
均匀分布: tensor([[0.4567, 0.7890], [0.1234, 0.5678]]), 形状: torch.Size([2, 2])
随机整数: tensor([42, 73, 19]), 形状: torch.Size([3])
自定义正态分布: tensor([4.5678, 11.2345]), 形状: torch.Size([2])
这些函数的分布不同:randn 是标准正态(均值0,方差1),rand 是均匀,适合不同场景。掌握 randn 就够基本使用。
2. 输出维度测试例子
使用随机张量模拟网络层,观察形状变化。这有助于理解卷积、池化等模块如何改变维度,而不用真实数据。
例子 1: 简单 CNN 流程(卷积 + 池化 + 展平 + 线性层)
模拟一个小型图像分类网络,输入是随机生成的 32x32 RGB 图像(batch=1)。
python
import torch
import torch.nn as nn
# 生成随机输入(模拟 CIFAR-10 图像)
input_tensor = torch.randn(1, 3, 32, 32)
print(f"输入尺寸: {input_tensor.shape}")
# 卷积层
conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
conv_output = conv1(input_tensor)
print(f"卷积后尺寸: {conv_output.shape}") # 预期: [1, 16, 32, 32] (padding 保持尺寸)
# 池化层
pool = nn.MaxPool2d(kernel_size=2, stride=2)
pool_output = pool(conv_output)
print(f"池化后尺寸: {pool_output.shape}") # 预期: [1, 16, 16, 16]
# 展平
flattened = pool_output.view(pool_output.size(0), -1)
print(f"展平后尺寸: {flattened.shape}") # 预期: [1, 4096] (16*16*16)
# 线性层
fc1 = nn.Linear(in_features=4096, out_features=64)
fc_output = fc1(flattened)
print(f"线性层后尺寸: {fc_output.shape}") # 预期: [1, 64]
# 最终分类层 + Softmax
fc2 = nn.Linear(64, 5) # 假设 5 类
final_output = fc2(fc_output)
softmax = nn.Softmax(dim=1)
class_probs = softmax(final_output)
print(f"Softmax 输出尺寸: {class_probs.shape}, 总和: {class_probs.sum():.4f}")
运行输出:
输入尺寸: torch.Size([1, 3, 32, 32])
卷积后尺寸: torch.Size([1, 16, 32, 32])
池化后尺寸: torch.Size([1, 16, 16, 16])
展平后尺寸: torch.Size([1, 4096])
线性层后尺寸: torch.Size([1, 64])
Softmax 输出尺寸: torch.Size([1, 5]), 总和: 1.0000
例子 2: 更大 batch 的维度测试
使用 batch=4,观察批量如何不影响空间维度计算。
python
import torch
import torch.nn as nn
input_tensor = torch.randn(4, 3, 64, 64) # batch=4
print(f"输入尺寸: {input_tensor.shape}")
conv1 = nn.Conv2d(3, 32, kernel_size=5, stride=2, padding=2)
conv_output = conv1(input_tensor)
print(f"卷积后尺寸: {conv_output.shape}") # 预期: [4, 32, 32, 32] (stride=2 减半)
pool = nn.MaxPool2d(2, 2)
pool_output = pool(conv_output)
print(f"池化后尺寸: {pool_output.shape}") # 预期: [4, 32, 16, 16]
flattened = pool_output.view(pool_output.size(0), -1)
print(f"展平后尺寸: {flattened.shape}") # 预期: [4, 8192] (32*16*16)
运行输出:
输入尺寸: torch.Size([4, 3, 64, 64])
卷积后尺寸: torch.Size([4, 32, 32, 32])
池化后尺寸: torch.Size([4, 32, 16, 16])
展平后尺寸: torch.Size([4, 8192])
通过这些,你可以看到维度如何逐层变化:卷积改变通道,池化减小空间,展平转为向量。调试时,用随机输入测试避免形状错误。
3. 广播机制例子
广播让不同形状张量运算兼容。重点看尺寸变化和值扩展(逻辑上复制,不实际耗内存)。
例子 1: 加法的广播(3维 + 1维)
python
import torch
a = torch.tensor([[[1, 2, 3]], [[4, 5, 6]]]) # 形状: (2, 1, 3)
b = torch.tensor([10]) # 形状: (1,)
result = a + b # b 扩展为 (2, 1, 3),值全为10
print(f"a 形状: {a.shape}\nb 形状: {b.shape}\n结果形状: {result.shape}\n结果: {result}")
运行输出:
a 形状: torch.Size([2, 1, 3])
b 形状: torch.Size([1])
结果形状: torch.Size([2, 1, 3])
结果: tensor([[[11, 12, 13]], [[14, 15, 16]]])
扩展:b 从 (1,) 补全到 (1,1,1),然后扩展匹配 a。
例子 2: 乘法的广播(矩阵乘法,批量 + 单矩阵)
python
import torch
A = torch.randn(3, 2, 4) # batch=3, 2x4 矩阵
B = torch.randn(1, 4, 3) # batch=1, 4x3 矩阵
result = A @ B # B 扩展 batch 到3,结果: (3, 2, 3)
print(f"A 形状: {A.shape}\nB 形状: {B.shape}\n结果形状: {result.shape}")
运行输出:
A 形状: torch.Size([3, 2, 4])
B 形状: torch.Size([1, 4, 3])
结果形状: torch.Size([3, 2, 3])
例子 3: 不兼容维度错误演示
python
import torch
a = torch.tensor([[1, 2], [3, 4]]) # (2,2)
b = torch.tensor([10, 20, 30]) # (3,) 不兼容
try:
result = a + b
except RuntimeError as e:
print(f"错误: {e}")
运行输出:
错误: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 1
这提醒:维度必须从右向左兼容(相等或1)。