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

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

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 在相应的维度上进行操作了,比如逐元素相乘等运算。

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用反向传播算法的单隐藏层神经网络的多元回归预测代码实例分析,其中激活函数采用ReLU函数: ``` import numpy as np class NeuralNetwork: def __init__(self, num_inputs, num_hidden, num_outputs): self.input_size = num_inputs self.hidden_size = num_hidden self.output_size = num_outputs self.W1 = np.random.randn(self.input_size, self.hidden_size) * 0.01 self.b1 = np.zeros((1, self.hidden_size)) self.W2 = np.random.randn(self.hidden_size, self.output_size) * 0.01 self.b2 = np.zeros((1, self.output_size)) def relu(self, Z): return np.maximum(0, Z) def forward(self, X): Z1 = np.dot(X, self.W1) + self.b1 A1 = self.relu(Z1) Z2 = np.dot(A1, self.W2) + self.b2 y_hat = Z2 return y_hat def relu_derivative(self, Z): return np.where(Z > 0, 1, 0) def backward(self, X, y, learning_rate): y_hat = self.forward(X) dZ2 = y_hat - y dW2 = np.dot(self.relu(self.W1), dZ2) db2 = np.sum(dZ2, axis=0, keepdims=True) dZ1 = np.dot(dZ2, self.W2.T) * self.relu_derivative(self.W1) dW1 = np.dot(X.T, dZ1) db1 = np.sum(dZ1, axis=0) self.W2 -= learning_rate * dW2 self.b2 -= learning_rate * db2 self.W1 -= learning_rate * dW1 self.b1 -= learning_rate * db1 def train(self, X, y, num_epochs, learning_rate): for i in range(num_epochs): self.backward(X, y, learning_rate) if i % 100 == 0: loss = np.mean(np.square(y - self.forward(X))) print(f"Epoch {i} - Loss: {loss:.4f}") ``` 首先,在初始化函数中,我们指定了输入层、隐藏层和输出层的神经元数量,并随机初始化了两个权值矩阵`W1`和`W2`,以及两个偏置向量`b1`和`b2`。其中,`W1`的维度为`(num_inputs, num_hidden)`,`W2`的维度为`(num_hidden, num_outputs)`。 在`forward`函数中,我们首先计算隐藏层的输入`Z1`,即输入`X`与`W1`的乘积加上`b1`,然后通过ReLU函数计算出隐藏层的输出`A1`,即`relu(Z1)`。接着,我们计算输出层的输入`Z2`,即隐藏层的输出`A1`与`W2`的乘积加上`b2`,最后计算输出层的输出`y_hat`,即`Z2`。 在`relu`函数中,我们使用了ReLU函数,即`np.maximum(0, Z)`。ReLU函数在`Z > 0`时输出`Z`,在`Z <= 0`时输出0。 在`relu_derivative`函数中,我们计算了ReLU函数的导数,即`np.where(Z > 0, 1, 0)`。当`Z > 0`时,ReLU函数的导数为1,否则为0。 在`backward`函数中,我们首先计算输出层的误差`dZ2`,即预测值`y_hat`与真实值`y`之差。然后,我们计算输出层权值矩阵`W2`的梯度`dW2`,即隐藏层输出`A1`与误差`dZ2`的乘积。同时,我们也需要计算`b2`的梯度`db2`,即误差`dZ2`的和。接着,我们计算隐藏层的误差`dZ1`,即输出层误差`dZ2`与权值矩阵`W2`的转置的乘积乘以隐藏层输入`Z1`的导数。最后,我们计算隐藏层权值矩阵`W1`的梯度`dW1`,即输入`X`与误差`dZ1`的乘积,以及`b1`的梯度`db1`,即误差`dZ1`的和。最后,我们使用学习率`learning_rate`来更新权值和偏置。 在`train`函数中,我们使用反向传播算法来训练网络。对于每一个epoch,我们调用`backward`函数来计算梯度并更新权值和偏置。在每隔100个epoch时,我们打印当前的损失,即预测值与真实值之间的平方误差的均值。 需要注意的是,这段代码只是一个示例,实际使用中,我们需要根据具体的数据和任务进行相应的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值