神经网络初始化实例化的维度与调用输入数据的维度
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
的操作创建了不同形状和内容的张量。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的数字,每一行重复同一个数字,并且在最后两个维度上只有一个单位。torch.rand(5, 1, 2)
(5, 1, 2)
的三维张量,其中的所有元素都是从0到1之间的随机数(均匀分布)。这意味着你得到的是一个有5行,每行包含一个大小为1的子列表,每个子列表内有2个随机数的张量。(5, 1, 1)
,主要由连续的整数构成;后者形状为 (5, 1, 2)
,由随机浮点数构成。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
pos_emb = SinusoidalPosEmb(dim=16)
#x = torch.tensor(range(5)).unsqueeze(1).unsqueeze(2) # 形状为 [5, 1] bath size,以及对应的timestep
time = torch.tensor(time)
print(time.shape)
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
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_expanded
和 freqs_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
在相应的维度上进行操作了,比如逐元素相乘等运算。