• 神经网络初始化实例化的维度与调用输入数据的维度


    神经网络初始化实例化的维度与调用输入数据的维度

    import numpy as np
    import torch
    import torch.nn as nn
    import torch.nn.functional as F

    #from agents.helpers import SinusoidalPosEmb
    class SinusoidalPosEmb(nn.Module):
    def init(self, dim=16): #dim为初始化需要设置的参数 比如默认为16 计算后会升维
    super().init()
    self.dim = dim

    def forward(self, x):
        device = x.device
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = torch.exp(torch.arange(half_dim, device=device) * -emb)
        emb = x[:, None] * emb[None, :]
        emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
        return emb
    

    class MLP(nn.Module):
    “”"
    MLP Model
    “”"
    def init(self, ##初始化以及参数
    state_dim=2, #####初始化实例化定义的维度这个对看懂代码很关键! 与后面调用函数的输入数据的维度一般需要一致
    action_dim=2,
    device=“cpu”,
    t_dim=16):

        super(MLP, self).__init__()
        self.device = "cpu"
    
        self.time_mlp = nn.Sequential(
            SinusoidalPosEmb(t_dim),  #  这个是初始化为16维度
            nn.Linear(t_dim, t_dim * 2),
            nn.Mish(),
            nn.Linear(t_dim * 2, t_dim),
        )
    
        input_dim = state_dim + action_dim + t_dim ## 2+2+16=20  维度数量
        self.mid_layer = nn.Sequential(nn.Linear(input_dim, 256),
                                       nn.Mish(),
                                       nn.Linear(256, 256),
                                       nn.Mish(),
                                       nn.Linear(256, 256),
                                       nn.Mish())
    
        self.final_layer = nn.Linear(256, action_dim)  ##输出2维度
    
    def forward(self, x, time, state):  ##定义个方法
    
        t = self.time_mlp(time)
        x = torch.cat([x, t, state], dim=1)  ###第二个维度以后要一致
        x = self.mid_layer(x)
    
        return self.final_layer(x)
    

    MLPinstance=MLP()#初始化一个实例
    MLPinstance

    ######################
    x = torch.rand(5, 1, 2) # [10, 1, 8] #bath_size,1,2维度
    time=5 #标量不对
    state=torch.rand(5, 1, 2)
    x.shape
    torch.tensor(range(5)).unsqueeze(1).unsqueeze(2).shape,torch.rand(5, 1, 2).shape #有什么区别?

    这两个 torch.tensor 的操作创建了不同形状和内容的张量。

    1. torch.tensor(range(5)).unsqueeze(1).unsqueeze(2)

    - 首先,torch.tensor(range(5)) 创建了一个一维张量,内容为 [0, 1, 2, 3, 4]

    - 然后,.unsqueeze(1) 在第1个维度(现在是一维张量的唯一维度,等同于插入一个新的列维度)添加一个维度,使得形状变为 (5, 1)

    - 接着,.unsqueeze(2) 再次在新维度的后面添加一个维度,最终形状变为 (5, 1, 1)。因此,这个操作的结果是一个形状为 (5, 1, 1) 的张量,每个元素都是从0到4的数字,每一行重复同一个数字,并且在最后两个维度上只有一个单位。

    2. torch.rand(5, 1, 2)

    - 这个操作直接创建了一个形状为 (5, 1, 2) 的三维张量,其中的所有元素都是从0到1之间的随机数(均匀分布)。这意味着你得到的是一个有5行,每行包含一个大小为1的子列表,每个子列表内有2个随机数的张量。

    总结:

    - 形状不同:前者形状为 (5, 1, 1),主要由连续的整数构成;后者形状为 (5, 1, 2),由随机浮点数构成。

    - 内容不同:前者的内容是确定的,是0到4的整数,每个数字沿最后一个维度重复;后者的内容是随机的,范围在0到1之间。

    - 数据类型不同:默认情况下,前者(基于 range)会是整数类型(除非显式转换),而后者明确是浮点数类型,因为使用了 torch.rand

    torch.tensor(range(5)).unsqueeze(1).unsqueeze(1).shape在那个维度后面升维度,torch.tensor(range(5)).unsqueeze(1).unsqueeze(2).shape

    ######################################

    x = torch.rand(2, 1) # [10, 1, 8]
    time=torch.tensor([5]) ##一维度的可以
    state=torch.rand(2, 1)
    x.shape

    实例化SinusoidalPosEmb类

    pos_emb = SinusoidalPosEmb(dim=16)

    创建一个示例输入张量x

    假设我们有一个序列长度为5,维度为16的输入

    #x = torch.tensor(range(5)).unsqueeze(1).unsqueeze(2) # 形状为 [5, 1] bath size,以及对应的timestep
    time = torch.tensor(time)
    print(time.shape)

    调用forward方法

    positional_embedding = pos_emb(time)

    ##########################################################################

    x = torch.rand(5, 1) # [10, 1, 8]
    time= torch.tensor(range(5)).unsqueeze(1)#没必要这样 经过embedding后会增加一个维度
    state=torch.rand(5, 1)
    x.shape

    #################################################################
    x = torch.rand(5, 1)
    time= torch.tensor([5])
    state=torch.rand(5, 1)
    x.shape,time.shape
    #############################################成功调用的####################
    x = torch.rand(5, 1) ####一般定义了2维度 所以一般输入的数据就是2个维度的多个元素 当然少于2维的运算后要能够升维度 或者运算后能够降低倒定义初始化中需要的的维度!!!!!!!!
    time= torch.tensor(range(5))
    state=torch.rand(5, 1)
    x.shape,time.shape

    torch.tensor([5]) 和torch.tensor(range(5))的维度有什么区别

    torch.tensor([5]) 创建的是一个形状为 torch.Size([1]) 的张量,表示它是一个包含单个元素的一维张量。

    torch.tensor(range(5)) 创建的是一个形状为 torch.Size([5]) 的张量,表示它是一个包含5个元素的一维张量。

    MLPinstance(x,time,state) #成功调用

    将位置索引 x 转换为形状 (5, 1),频率向量转换为形状 (1, 8) 是怎么理解请举例
    当我们谈论将位置索引 x 转换为形状 (5, 1) 和频率向量转换为形状 (1, 8),我们实际上是在讨论在进行矩阵运算之前对张量(在PyTorch中,张量是多维数组)的形状调整,以便它们能够进行有效的点乘操作。这个过程通常称为“广播”(broadcasting),它允许不同形状的张量进行数学运算,只要它们在没有明确指定的维度上大小为1或者完全匹配。

    例子说明:

    位置索引 x

    原始的位置索引 x 是一个一维张量,表示5个不同的位置:

    x = torch.tensor([0, 1, 2, 3, 4])
    

    形状是 (5,),表示有5个元素。

    为了使其能与频率向量正确点乘,我们需要将其扩展成一个二维张量,形状变为 (5, 1)。这意味着每个位置现在被视为一个单独的行,每一行只有一个元素:

    x_expanded = x.unsqueeze(1)
    # x_expanded 的形状现在是 (5, 1),内容为:
    # tensor([[0],
    #         [1],
    #         [2],
    #         [3],
    #         [4]])
    

    通过 unsqueeze(1) 操作,我们在索引1的位置增加了一个新的维度,使得每个位置值变成一个单独的列向量。

    频率向量

    频率向量是基于一半的维度数(如果 dim=16,则 half_dim=8)创建的,假定我们已经计算了对应的频率值并存储在一个一维张量中:

    freqs = torch.tensor([...])  # 假设这里填入了计算得到的频率值序列
    

    其原始形状可能是 (8,),代表了8个不同频率的值。

    为了点乘,我们需要将其调整为 (1, 8) 形状,意味着它变成了一个只有一行的矩阵:

    freqs_expanded = freqs.unsqueeze(0)
    # freqs_expanded 的形状现在是 (1, 8),内容保持原频率值不变,但结构上作为单行多列
    

    通过 unsqueeze(0),我们在索引0的位置增加了一个新的维度,使频率值构成了一行向量。

    结果

    完成上述操作后,x_expandedfreqs_expanded 可以直接相乘,因为它们在第二个维度(列)上是匹配的(一个是1,另一个是8,但因为是点乘,一维会自动复制以匹配另一方的维度)。这样,每个位置的索引值会与所有的频率值进行一一对应乘法运算,从而生成最终的编码向量的一部分。

    a为(5,3,1)的张量
    b为(5,16)的张量 能否把b变为(5,3,16)的维度?
    要将形状为 (5, 16) 的张量 b 转换成形状为 (5, 3, 16),以便它可以与形状为 (5, 3, 1) 的张量 a 在某些维度上进行运算,我们需要沿着一个新维度重复 b 中的每一行数据三次(因为 a 的第二个维度是 3)。这可以通过使用 torch.repeat_interleave 函数来完成,具体是沿着第1维度(在PyTorch中,维度索引从0开始计数,所以这是第二个维度)进行重复。

    下面是操作的示例代码:

    import torch
    
    # 假设 b 是形状为 (5, 16) 的张量
    b = torch.randn(5, 16)
    
    # 将 b 调整为形状为 (5, 3, 16)
    b_expanded = b.unsqueeze(1).repeat(1, 3, 1)
    
    print("Original shape of b:", b.shape)
    print("Expanded shape of b:", b_expanded.shape)
    

    这段代码首先使用 unsqueeze(1)b 添加一个新的维度(变成 (5, 1, 16)),然后使用 repeat(1, 3, 1) 沿着新添加的维度复制数据三次,最终得到形状为 (5, 3, 16) 的张量。

    这样调整后,b_expanded 就可以和形状为 (5, 3, 1) 的张量 a 在相应的维度上进行操作了,比如逐元素相乘等运算。

  • 相关阅读:
    AS400 大厂面试
    Vulnhub | DC: 8 |【实战】
    .NET分布式Orleans - 4 - 计时器和提醒
    640. 求解方程(JavaScript)
    一个简单的查询学生信息的接口测试
    makefile 杂项
    二十一、vite中的glob-import批量导入
    擎创技术流 | ClickHouse实用工具—ckman教程(1)部署安装
    漏洞复现--鸿运主动安全监控云平台任意文件下载
    C/C++程序的内存开辟
  • 原文地址:https://blog.csdn.net/qq_39306047/article/details/139449901