Day48打卡 @浙大疏锦行

知识点回顾:
  1. 随机张量的生成:torch.randn函数

在 PyTorch 中,torch.randn()是一个常用的随机张量生成函数,它可以创建一个由标准正态分布(均值为 0,标准差为 1)随机数填充的张量。这种随机张量在深度学习中非常实用,常用于初始化模型参数、生成测试数据或模拟输入特征。

torch.randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

  • size:必选参数,表示输出张量的形状(如(3, 4)表示 3 行 4 列的矩阵)。
  • dtype:可选参数,指定张量的数据类型(如torch.float32、torch.int64等)。
  • device:可选参数,指定张量存储的设备(如'cpu'或'cuda')。
  • requires_grad:可选参数,是否需要计算梯度(常用于训练模型时)。
import torch
# 生成标量(0维张量)
scalar = torch.randn(())
print(f"标量: {scalar}, 形状: {scalar.shape}")  
标量: -1.6167410612106323, 形状: torch.Size([])
# 生成向量(1维张量)
vector = torch.randn(5)  # 长度为5的向量
print(f"向量: {vector}, 形状: {vector.shape}")  
向量: tensor([-1.9524,  0.5900,  0.7467, -1.8307,  0.4263]), 形状: torch.Size([5])
# 生成矩阵(2维张量)
matrix = torch.randn(3, 4)  # 3行4列的矩阵
print(f"矩阵:{matrix},矩阵形状: {matrix.shape}")  
矩阵:tensor([[ 0.0283,  0.7692,  0.2744, -1.6120],
        [ 0.3726,  1.5382, -1.0128,  0.4129],
        [ 0.4898,  1.4782,  0.2019,  0.0863]]),矩阵形状: torch.Size([3, 4])
# 生成3维张量(常用于图像数据的通道、高度、宽度)
tensor_3d = torch.randn(3, 224, 224)  # 3通道,高224,宽224
print(f"3维张量形状: {tensor_3d.shape}")  # 输出: torch.Size([3, 224, 224])
3维张量形状: torch.Size([3, 224, 224])
# 生成4维张量(常用于批量图像数据:[batch, channel, height, width])
tensor_4d = torch.randn(2, 3, 224, 224)  # 批量大小为2,3通道,高224,宽224
print(f"4维张量形状: {tensor_4d.shape}")  # 输出: torch.Size([2, 3, 224, 224])
4维张量形状: torch.Size([2, 3, 224, 224])

2.卷积和池化的计算公式(可以不掌握,会自动计算的)

二维的卷积和池化计算公式是一致的

# 1. 卷积层操作
conv1 = nn.Conv2d(
    in_channels=3,        # 输入通道数
    out_channels=16,      # 输出通道数(卷积核数量)
    kernel_size=3,        # 卷积核大小
    stride=1,             # 步长
    padding=1             # 填充
)
conv_output = conv1(input_tensor) # 由于 padding=1 且 stride=1,空间尺寸保持不变
print(f"卷积后尺寸: {conv_output.shape}")  # 输出: [1, 16, 32, 32]
卷积后尺寸: torch.Size([1, 16, 32, 32])
# 2. 池化层操作 (减小空间尺寸)
pool = nn.MaxPool2d(kernel_size=2, stride=2) # 创建一个最大池化层
pool_output = pool(conv_output)
print(f"池化后尺寸: {pool_output.shape}")  # 输出: [1, 16, 16, 16]
池化后尺寸: torch.Size([1, 16, 16, 16])
# 3. 将多维张量展平为向量
flattened = pool_output.view(pool_output.size(0), -1)
print(f"展平后尺寸: {flattened.shape}")  # 输出: [1, 4096] (16*16*16=4096)

展平后尺寸: torch.Size([1, 4096])
# 4. 线性层操作
fc1 = nn.Linear(
    in_features=4096,     # 输入特征数
    out_features=128      # 输出特征数
)
fc_output = fc1(flattened)
print(f"线性层后尺寸: {fc_output.shape}")  # 输出: [1, 128]
线性层后尺寸: torch.Size([1, 128])
# 5. 再经过一个线性层(例如分类器)
fc2 = nn.Linear(128, 10)  # 假设是10分类问题
final_output = fc2(fc_output)
print(f"最终输出尺寸: {final_output.shape}")  # 输出: [1, 10]
print(final_output)
最终输出尺寸: torch.Size([1, 10])
tensor([[-0.3018, -0.4308,  0.3248,  0.2808,  0.5109, -0.0881, -0.0787, -0.0700,
         -0.1004, -0.0580]], grad_fn=)

3.pytorch的广播机制:加法和乘法的广播机制

加法的广播机制

二维张量与一维向量相加

import torch

# 创建原始张量
a = torch.tensor([[10], [20], [30]])  # 形状: (3, 1)
b = torch.tensor([1, 2, 3])          # 形状: (3,)

result = a + b
# 广播过程
# 1. b补全维度: (3,) → (1, 3)
# 2. a扩展列: (3, 1) → (3, 3)
# 3. b扩展行: (1, 3) → (3, 3)
# 最终形状: (3, 3)


print("原始张量a:")
print(a)


print("\n原始张量b:")
print(b)


print("\n广播后a的值扩展:")
print(torch.tensor([[10, 10, 10],
                    [20, 20, 20],
                    [30, 30, 30]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n广播后b的值扩展:")
print(torch.tensor([[1, 2, 3],
                    [1, 2, 3],
                    [1, 2, 3]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n加法结果:")
print(result)
原始张量a:
tensor([[10],
        [20],
        [30]])

原始张量b:
tensor([1, 2, 3])

广播后a的值扩展:
tensor([[10, 10, 10],
        [20, 20, 20],
        [30, 30, 30]])

广播后b的值扩展:
tensor([[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]])

加法结果:
tensor([[11, 12, 13],
        [21, 22, 23],
        [31, 32, 33]])

三维张量与二维张量相加

# 创建原始张量
a = torch.tensor([[[1], [2]], [[3], [4]]])  # 形状: (2, 2, 1)
b = torch.tensor([[10, 20]])               # 形状: (1, 2)

# 广播过程
# 1. b补全维度: (1, 2) → (1, 1, 2)
# 2. a扩展第三维: (2, 2, 1) → (2, 2, 2)
# 3. b扩展第一维: (1, 1, 2) → (2, 1, 2)
# 4. b扩展第二维: (2, 1, 2) → (2, 2, 2)
# 最终形状: (2, 2, 2)

result = a + b
print("原始张量a:")
print(a)


print("\n原始张量b:")
print(b)


print("\n广播后a的值扩展:")
print(torch.tensor([[[1, 1],
                     [2, 2]],
                    [[3, 3],
                     [4, 4]]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n广播后b的值扩展:")
print(torch.tensor([[[10, 20],
                     [10, 20]],
                    [[10, 20],
                     [10, 20]]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n加法结果:")
print(result)
原始张量a:
tensor([[[1],
         [2]],

        [[3],
         [4]]])

原始张量b:
tensor([[10, 20]])

广播后a的值扩展:
tensor([[[1, 1],
         [2, 2]],

        [[3, 3],
         [4, 4]]])

广播后b的值扩展:
tensor([[[10, 20],
         [10, 20]],

        [[10, 20],
         [10, 20]]])

加法结果:
tensor([[[11, 21],
         [12, 22]],

        [[13, 23],
         [14, 24]]])

二维张量与标量相加

# 创建原始张量
a = torch.tensor([[1, 2], [3, 4]])  # 形状: (2, 2)
b = 10                              # 标量,形状视为 ()

# 广播过程
# 1. b补全维度: () → (1, 1)
# 2. b扩展第一维: (1, 1) → (2, 1)
# 3. b扩展第二维: (2, 1) → (2, 2)
# 最终形状: (2, 2)

result = a + b
print("原始张量a:")
print(a)
# 输出:
# tensor([[1, 2],
#         [3, 4]])

print("\n标量b:")
print(b)
# 输出: 10

print("\n广播后b的值扩展:")
print(torch.tensor([[10, 10],
                    [10, 10]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n加法结果:")
print(result)
# 输出:
# tensor([[11, 12],
#         [13, 14]])
原始张量a:
tensor([[1, 2],
        [3, 4]])

标量b:
10

广播后b的值扩展:
tensor([[10, 10],
        [10, 10]])

加法结果:
tensor([[11, 12],
        [13, 14]])

高维张量与低维张量相加

# 创建原始张量
a = torch.tensor([[[1, 2], [3, 4]]])  # 形状: (1, 2, 2)
b = torch.tensor([[5, 6]])            # 形状: (1, 2)

# 广播过程
# 1. b补全维度: (1, 2) → (1, 1, 2)
# 2. b扩展第二维: (1, 1, 2) → (1, 2, 2)
# 最终形状: (1, 2, 2)

result = a + b
print("原始张量a:")
print(a)
# 输出:
# tensor([[[1, 2],
#          [3, 4]]])

print("\n原始张量b:")
print(b)
# 输出:
# tensor([[5, 6]])

print("\n广播后b的值扩展:")
print(torch.tensor([[[5, 6],
                     [5, 6]]]))  # 实际内存中未复制,仅逻辑上扩展

print("\n加法结果:")
print(result)
# 输出:
# tensor([[[6, 8],
#          [8, 10]]])
原始张量a:
tensor([[[1, 2],
         [3, 4]]])

原始张量b:
tensor([[5, 6]])

广播后b的值扩展:
tensor([[[5, 6],
         [5, 6]]])

加法结果:
tensor([[[ 6,  8],
         [ 8, 10]]])

关键总结

  1. 尺寸变化:广播后的形状由各维度的最大值决定(示例 2 中最终形状为 (2, 2, 2))。
  2. 值扩展:维度为 1 的张量通过复制扩展值(示例 1 中 b 从 [1, 2, 3] 扩展为三行相同的值)。
  3. 内存效率:扩展是逻辑上的,实际未复制数据,避免了内存浪费。

 乘法的广播机制

矩阵乘法(@)的特殊规则

矩阵乘法除了遵循通用广播规则外,还需要满足矩阵乘法的维度约束:

最后两个维度必须满足:A.shape[-1] == B.shape[-2](即 A 的列数等于 B 的行数)

其他维度(批量维度):遵循通用广播规则

批量矩阵与单个矩阵相乘

import torch

# A: 批量大小为2,每个是3×4的矩阵
A = torch.randn(2, 3, 4)  # 形状: (2, 3, 4)

# B: 单个4×5的矩阵
B = torch.randn(4, 5)     # 形状: (4, 5)

# 广播过程:
# 1. B补全维度: (4, 5) → (1, 4, 5)
# 2. B扩展第一维: (1, 4, 5) → (2, 4, 5)
# 矩阵乘法: (2, 3, 4) @ (2, 4, 5) → (2, 3, 5)
result = A @ B            # 结果形状: (2, 3, 5)

print("A形状:", A.shape)  # 输出: torch.Size([2, 3, 4])
print("B形状:", B.shape)  # 输出: torch.Size([4, 5])
print("结果形状:", result.shape)  # 输出: torch.Size([2, 3, 5])
A形状: torch.Size([2, 3, 4])
B形状: torch.Size([4, 5])
结果形状: torch.Size([2, 3, 5])

批量矩阵与批量矩阵相乘(部分广播)

# A: 批量大小为3,每个是2×4的矩阵
A = torch.randn(3, 2, 4)  # 形状: (3, 2, 4)

# B: 批量大小为1,每个是4×5的矩阵
B = torch.randn(1, 4, 5)  # 形状: (1, 4, 5)

# 广播过程:
# B扩展第一维: (1, 4, 5) → (3, 4, 5)
# 矩阵乘法: (3, 2, 4) @ (3, 4, 5) → (3, 2, 5)
result = A @ B            # 结果形状: (3, 2, 5)

print("A形状:", A.shape)  # 输出: torch.Size([3, 2, 4])
print("B形状:", B.shape)  # 输出: torch.Size([1, 4, 5])
print("结果形状:", result.shape)  # 输出: torch.Size([3, 2, 5])
A形状: torch.Size([3, 2, 4])
B形状: torch.Size([1, 4, 5])
结果形状: torch.Size([3, 2, 5])

三维张量与二维张量相乘(高维广播)

# A: 批量大小为2,通道数为3,每个是4×5的矩阵
A = torch.randn(2, 3, 4, 5)  # 形状: (2, 3, 4, 5)

# B: 单个5×6的矩阵
B = torch.randn(5, 6)        # 形状: (5, 6)

# 广播过程:
# 1. B补全维度: (5, 6) → (1, 1, 5, 6)
# 2. B扩展第一维: (1, 1, 5, 6) → (2, 1, 5, 6)
# 3. B扩展第二维: (2, 1, 5, 6) → (2, 3, 5, 6)
# 矩阵乘法: (2, 3, 4, 5) @ (2, 3, 5, 6) → (2, 3, 4, 6)
result = A @ B               # 结果形状: (2, 3, 4, 6)

print("A形状:", A.shape)     # 输出: torch.Size([2, 3, 4, 5])
print("B形状:", B.shape)     # 输出: torch.Size([5, 6])
print("结果形状:", result.shape)  # 输出: torch.Size([2, 3, 4, 6])
A形状: torch.Size([2, 3, 4, 5])
B形状: torch.Size([5, 6])
结果形状: torch.Size([2, 3, 4, 6])

ps:numpy运算也有类似的广播机制,基本一致

@浙大疏锦行

你可能感兴趣的:(python打卡shu,python)