原来求平均首先里面有Pad噪音(空白)、无主次,padding就相当于0位置的密集向量,pad平均到文章当中就相当于噪声,但是如果只用一个样本的话可能会有异常,效果不好并且时间长。即便没有padding,一些重要的表达情感的词语没有主次,一旦求平均,会认为每个人的权重是等价的,就比如这个例子:

我让你————> 你让我

没有先后位置信息,从而出现了神经循环网络

比如说输入一个词不断生成生成,也可能输入很多词然后分类得到一个,或者翻译。

工作的时候靠循环将每个词放进模型,黑框代表中间状态:

时间步从左往右加一,在每个时间步,RNN都会接收一个输入并输出一个结果,RNN在每个时间步都会保留一个隐藏状态也叫中间状态,这个隐藏状态包含了之前所有时间步的信息,并用于计算当前时间步的输出和下一个时间步的隐藏状态。

公式:

St-1叫Xt-1和Xt之间的中间状态,W就是一个全连接的线性层,U相当于一个参数

       

最简单的RNN也叫SIMPLERNN,在torch里面就叫RNN,SimpleRNN没做softmax和V的处理,前面的中间状态直接输出给下一个。

模型定义:

class RNN(nn.Module):
    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):
        super().__init__()
        self.embeding = nn.Embedding(vocab_size, embedding_dim)
        self.rnn = nn.RNN(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True, bidirectional=bidirectional) #bidirectional是双向的
        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)
        self.fc = nn.Linear(hidden_dim, 1)
        
    def forward(self, x):
        # [bs, seq length]
        x = self.embeding(x)
        # [bs, seq length, embedding_dim] -> shape [bs,seq length,hidden_dim]
        seq_output, final_hidden = self.rnn(x)
        # print(f'seq_output.shape={seq_output.shape}') # [bs, seq length, hidden_dim]
        # print(f'final_hidden.shape={final_hidden.shape}') #[1, bs, hidden_dim]
        x = seq_output[:, -1, :]
        # print(f'x.shape={x.shape}')
        #把final_hidden去除轴size为1的,和x进行比较,里边元素是否相等
        # assert torch.all(final_hidden.squeeze(0) == x)
        # 取最后一个时间步的输出 (这也是为什么要设置padding_first=True的原因)
        x = self.layer(x)
        x = self.fc(x)
        return x
    

    
print("{:=^80}".format(" 一层单向 RNN "))       
for key, value in RNN().named_parameters():
    print(f"{key:^40}paramerters num: {np.prod(value.shape)}")

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐