【作业九】RNN-SRN-Seq2Seq

news2024/11/27 20:08:26

点击查看作业内容


目录

1 实现SRN

(1)使用numpy实现

(2)在(1)的基础上,增加激活函数tanh

(3)使用nn.RNNCell实现

(4)使用nn.RNN实现

 2 使用RNNCell实现“序列到序列”

3 实现“编码器-解码器”-Seq2Seq

4 简单总结nn.RNNCell、nn.RNN

(1)nn.RNNCell

(2)nn.RNN

5 谈一谈对“序列”、“序列到序列”的理解

6 总结本周理论课和作业,写心得体会


1 实现SRN

        先回顾一下什么是SRN。

        SRN全称Simple Recurrent Network,即简单循环网络。SRN在传统的前馈神经网络的基础上,增加了一个隐藏层,这个隐藏层的输出会反馈到自身,形成一个循环。这样,网络就能够在时间上保持状态,即“记忆”之前的输入信息。()

(1)使用numpy实现

'''
@Function: 使用numpy实现SRN
@Author: lxy
@Date: 2024/11/24
'''
import numpy as np
# 初始化输入序列
inputs = np.array([[1.,1.],[1.,1.],[2.,2.]])
print(f"inputs is:\n{inputs}")
# 初始化存储器
state_t = np.zeros(2)
print(f"states_t is:\n{state_t}")
# 初始化权重参数,这里所有权重都为1,bias = 0
w1, w2, w3, w4, w5, w6, w7, w8 = 1., 1., 1., 1., 1., 1., 1., 1.
U1, U2, U3, U4 = 1., 1., 1., 1.
print('============================================')
for t,input_t in enumerate(inputs):
    print(f"第{t+1}时刻:")
    print(f'input_t is: {input_t}')
    print(f'state_t is: {state_t}')
    # 隐藏层的输入=当前输入 + 前一时刻的状态
    input_h1 = np.dot([w1,w3],input_t) + np.dot([U2,U4],state_t)
    input_h2 = np.dot([w2,w4],input_t) + np.dot([U1,U3],state_t)
    state_t = input_h1, input_h2 # 更新状态(无激活 输入=输出):直接将计算得到的隐藏层输入赋值给state_t
    # 输入为隐藏层的输出,计算最终输出
    output_y1 = np.dot([w5, w7], state_t)
    output_y2 = np.dot([w6, w8], state_t)
    print(f"outputs is: {output_y1}、{output_y2}")
    print('============================================')

运行结果:

inputs is:
[[1. 1.]
 [1. 1.]
 [2. 2.]]
states_t is:
[0. 0.]
============================================
第1时刻:
input_t is: [1. 1.]
state_t is: [0. 0.]
outputs is: 4.0、4.0
============================================
第2时刻:
input_t is: [1. 1.]
state_t is: (2.0, 2.0)
outputs is: 12.0、12.0
============================================
第3时刻:
input_t is: [2. 2.]
state_t is: (6.0, 6.0)
outputs is: 32.0、32.0
============================================

可见与手动计算的结果一致 。

(图源) 

(2)在(1)的基础上,增加激活函数tanh

'''
@Function: 使用numpy实现SRN
@Author: lxy
@Date: 2024/11/24
'''
import numpy as np
# 初始化输入序列 3个对应三个时刻
inputs = np.array([[1.,1.],[1.,1.],[2.,2.]])
print(f"inputs is:\n{inputs}")
# 初始化存储器
state_t = np.zeros(2)
print(f"states_t is:\n{state_t}")
# 初始化权重参数,这里所有权重都为1,bias = 0
w1, w2, w3, w4, w5, w6, w7, w8 = 1., 1., 1., 1., 1., 1., 1., 1.
U1, U2, U3, U4 = 1., 1., 1., 1.
print('============================================')
for t,input_t in enumerate(inputs):
    print(f"第{t+1}时刻:")
    print(f'input_t is: {input_t}')
    print(f'state_t is: {state_t}')
    # 隐藏层的输入=当前输入 + 前一时刻的状态
    input_h1 = np.dot([w1,w3],input_t) + np.dot([U2,U4],state_t)
    input_h2 = np.dot([w2,w4],input_t) + np.dot([U1,U3],state_t)
    # state_t = input_h1, input_h2 # 更新状态(无激活 输出=输入):直接将计算得到的隐藏层输入赋值给state_t
    state_t = np.tanh(input_h1),np.tanh(input_h2) # 更新状态(有激活 输出=tanh(输入) )
    # 输入为隐藏层的输出,计算最终输出
    output_y1 = np.dot([w5, w7], state_t)
    output_y2 = np.dot([w6, w8], state_t)
    print(f"outputs is: {output_y1}、{output_y2}")
    print('============================================')

运行结果:

inputs is:
[[1. 1.]
 [1. 1.]
 [2. 2.]]
states_t is:
[0. 0.]
============================================
第1时刻:
input_t is: [1. 1.]
state_t is: [0. 0.]
outputs is: 1.9280551601516338、1.9280551601516338
============================================
第2时刻:
input_t is: [1. 1.]
state_t is: (0.9640275800758169, 0.9640275800758169)
outputs is: 1.9984510891336251、1.9984510891336251
============================================
第3时刻:
input_t is: [2. 2.]
state_t is: (0.9992255445668126, 0.9992255445668126)
outputs is: 1.9999753470497836、1.9999753470497836
============================================

 对比(1)(2)输出 结果可以看到无激活函数时,输出值随着时间步的增加而线性增长,从4.0增加到32.0。有激活函数时,输出值在经过激活函数后,增长速度明显减缓。

(3)使用nn.RNNCell实现

'''
@Function: 使用nn.RNNCell实现SRN
@Author: lxy
@Date: 2024/11/24
'''
import torch
batch_size = 1
seq_len = 3  # 序列长度(多少时间步)
input_size = 2  # 输入序列维度
hidden_size = 2  # 隐藏层维度
output_size = 2  # 输出层维度

# # 创建RNNCell实例
cell = torch.nn.RNNCell(input_size=input_size,hidden_size=hidden_size)
# 初始化参数 https://zhuanlan.zhihu.com/p/342012463
'''
RNN的weight和bias封装在parameters中,且需要对weight和bias分开初始化
'''
for name,param in cell.named_parameters():
    if name.startswith('weight'): # 初始化weight
        torch.nn.init.ones_(param)
    else: # 初始化bias
        torch.nn.init.zeros_(param)

# 线性层-> 将隐藏状态映射到输出
linear = torch.nn.Linear(hidden_size,output_size)
# 初始化线性层的权重为1
linear.weight.data = torch.Tensor([[1,1],[1,1]])
# 初始化线性层的偏置为0
linear.bias.data = torch.Tensor([0.0])

# 定义输入序列
'''
三维,形状(3, 1, 2)
第一维:序列长度(seq_len),这里是3
第二维:批次大小(batch_size),这里是1
第三维:输入特征的维度(input_size),这里是2
'''
seq = torch.Tensor([[[1,1]],[[1,1]],[[2,2]]])
# 初始化隐藏状态和输出为0
hidden = torch.zeros(batch_size,hidden_size)
output = torch.zeros(batch_size,output_size)
# 遍历序列中的每一个时间步
for idx,input in enumerate(seq):
    print('===========================')
    print(f"第{idx+1}时刻:")
    print(f'Input :{input}')
    print(f'hidden :{hidden}')
    hidden = cell(input,hidden) # 使用RNNCell处理当前输入,并更新隐藏状态
    output = linear(hidden) # # 使用线性层将隐藏状态转换为输出
    print(f"output :{output}")

运行结果:

===========================
第1时刻:
Input :tensor([[1., 1.]])
hidden :tensor([[0., 0.]])
output :tensor([[1.9281, 1.9281]], grad_fn=<AddmmBackward0>)
===========================
第2时刻:
Input :tensor([[1., 1.]])
hidden :tensor([[0.9640, 0.9640]], grad_fn=<TanhBackward0>)
output :tensor([[1.9985, 1.9985]], grad_fn=<AddmmBackward0>)
===========================
第3时刻:
Input :tensor([[2., 2.]])
hidden :tensor([[0.9992, 0.9992]], grad_fn=<TanhBackward0>)
output :tensor([[2.0000, 2.0000]], grad_fn=<AddmmBackward0>)

(4)使用nn.RNN实现

'''
@Function: 使用nn.RNN实现SRN
@Author: lxy
@Date: 2024/11/24
'''
import torch
# 设置批处理大小
batch_size = 1
# 设置序列长度
seq_len = 3
# 输入序列的维度
input_size = 2
# 隐藏层的维度
hidden_size = 2
# 输出层的维度
output_size = 2
# RNN层的数量
num_layers = 1

# 创建RNN实例
cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers)
# 初始化参数
for name, param in cell.named_parameters():
    if name.startswith('weight'):
        torch.nn.init.ones_(param)
    else:
        torch.nn.init.zeros_(param)

# 线性层 将隐藏状态映射到输出
linear = torch.nn.Linear(hidden_size, output_size)
# 初始化线性层的权重为1
linear.weight.data = torch.Tensor([[1,1],[1,1]])
# 初始化线性层的偏置为0
linear.bias.data = torch.Tensor([0.0])

# 创建输入序列
'''
三维,形状(3, 1, 2)
第一维:序列长度(seq_len),这里是3
第二维:批次大小(batch_size),这里是1
第三维:输入特征的维度(input_size),这里是2
'''
inputs = torch.Tensor([[[1,1]],[[1,1]],[[2,2]]])
# 初始化隐藏状态为0,这里需要考虑RNN层的数量
hidden = torch.zeros(num_layers, batch_size, hidden_size)
# 通过RNN处理输入序列,并更新隐藏状态
out, hidden = cell(inputs, hidden)

# 打印第一个时间步的输入、隐藏状态和输出
print("第1时刻:")
print(f'Input : {inputs[0]}')
print(f'hidden: {[0 , 0]}')
print(f'Output: {linear(out[0])}')
print('======================================')
# 打印第二个时间步的输入、隐藏状态和输出
print("第2时刻:")
print(f'Input : {inputs[1]}')
print(f'hidden: {out[0]}')
print(f'Output: {linear(out[1])}')
print('=======================================')
# 打印第三个时间步的输入、隐藏状态和输出
print("第3时刻:")
print(f'Input : {inputs[2]}')
print(f'hidden: {out[1]}')
print(f'Output: {linear(out[2])}')

【这里不使用循环来打印的原因是因为RNN是一个封装好的循环神经网络层,处理整个序列的前向传播,并返回每个时间步的输出和最后一个时间步的隐藏状态,而RNNCell 是一个基本的循环神经网络单元,只处理单个时间步的输入,所以在(3)中需要循环调用】 

运行结果:

第1时刻:
Input : tensor([[1., 1.]])
hidden: [0, 0]
Output: tensor([[1.9281, 1.9281]], grad_fn=<AddmmBackward0>)
======================================
第2时刻:
Input : tensor([[1., 1.]])
hidden: tensor([[0.9640, 0.9640]], grad_fn=<SelectBackward0>)
Output: tensor([[1.9985, 1.9985]], grad_fn=<AddmmBackward0>)
=======================================
第3时刻:
Input : tensor([[2., 2.]])
hidden: tensor([[0.9992, 0.9992]], grad_fn=<SelectBackward0>)
Output: tensor([[2.0000, 2.0000]], grad_fn=<AddmmBackward0>)

 2 使用RNNCell实现“序列到序列”

b站循环神经网络讲解--刘二大人  实现视频P12中的教学案例 hello--->ohlol

 

'''
@Function: 实现序列到序列:给出hello -->预测ohlol
@Author: lxy
@Date: 2024/11/24
'''
import torch
import torch.nn as nn
import torch.optim as optim

# 定义参数
input_size = 4 # 输入特征的维度:对应的是 one-hot 编码的大小(4个字符)
hidden_size = 4 # 隐藏层维度
batch_size = 1  # 批次大小(这里是1,表示一次只处理一个字符)

# 字符到索引的映射
idx2char = ['e', 'h', 'l', 'o']

# 输入和标签数据
x_data = [1, 0, 2, 2, 3] # 对应字符 ['h', 'e', 'l', 'l', 'o']
y_data = [3, 1, 2, 3, 2] # 对应目标字符 ['o', 'h', 'l', 'o', 'l']

# 将字符映射到one-hot编码
one_hot_lookup = [
    [1, 0, 0, 0],  # 'e' 对应 [1, 0, 0, 0]
    [0, 1, 0, 0],  # 'h' 对应 [0, 1, 0, 0]
    [0, 0, 1, 0],  # 'l' 对应 [0, 0, 1, 0]
    [0, 0, 0, 1]   # 'o' 对应 [0, 0, 0, 1]
]
# 将输入数据 x_data 转换为 one-hot 编码形式
x_one_hot = [one_hot_lookup[x] for x in x_data]

# 将输入和标签转换为PyTorch张量
inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size)  # (序列长度, 批次大小, 输入维度)
labels = torch.LongTensor(y_data).view(-1, 1)  # (序列长度, 1),每个标签对应一个字符的索引

# 定义RNN模型
class Model(nn.Module):
    def __init__(self, input_size, hidden_size, batch_size):
        super(Model, self).__init__()
        self.batch_size = batch_size
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.rnncell = nn.RNNCell(input_size=self.input_size, hidden_size=self.hidden_size)

    def forward(self, input, hidden):
        # RNNCell 处理每个输入,并返回新的隐藏状态
        hidden = self.rnncell(input, hidden)
        return hidden

    def init_hidden(self):
        return torch.zeros(self.batch_size, self.hidden_size)

# 初始化模型、损失函数和优化器
net = Model(input_size, hidden_size, batch_size)
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = optim.Adam(net.parameters(), lr=0.1)  # 使用 Adam 优化器

# 训练模型
for epoch in range(15):
    loss = 0
    optimizer.zero_grad()
    hidden = net.init_hidden() # 初始化隐藏状态
    print('Predicted string: ', end='')
    # 遍历输入序列和标签
    for input, label in zip(inputs, labels):
        hidden = net(input, hidden)  # 将输入传入网络并获取新的隐藏状态
        loss += criterion(hidden, label)  # 计算损失并累加
        _, idx = hidden.max(dim=1)   # 获取预测的字符索引(最大值)
        print(idx2char[idx.item()], end='')  # 输出对应的字符
    loss.backward()
    optimizer.step()
    print(', Epoch [%d/15] loss=%.4f' % (epoch + 1, loss.item()))

运行结果:

Predicted string: lllll, Epoch [1/15] loss=7.3776
Predicted string: lllll, Epoch [2/15] loss=6.0633
Predicted string: lhlll, Epoch [3/15] loss=4.9989
Predicted string: ohlol, Epoch [4/15] loss=4.0542
Predicted string: ohlol, Epoch [5/15] loss=3.3809
Predicted string: ohlol, Epoch [6/15] loss=3.0262
Predicted string: ohlol, Epoch [7/15] loss=2.7807
Predicted string: ohlol, Epoch [8/15] loss=2.5577
Predicted string: ohlol, Epoch [9/15] loss=2.3574
Predicted string: ohlol, Epoch [10/15] loss=2.2286
Predicted string: ohlol, Epoch [11/15] loss=2.1521
Predicted string: ohlol, Epoch [12/15] loss=2.0685
Predicted string: ohlol, Epoch [13/15] loss=1.9959
Predicted string: ohlol, Epoch [14/15] loss=1.9489
Predicted string: ohlol, Epoch [15/15] loss=1.9217

         可见模型的预测从初期的随机性lllll到 ohlol逐步改进,最终在第 4 个 epoch 开始预测正确的字符顺序。随着训练进行,损失逐渐下降,模型逐步学会了如何更准确地预测下一个字符。实现从hello到ohlol的转换。

3 实现“编码器-解码器”-Seq2Seq

Seq2Seq的Pytorch实现  ----b站配套讲解

seq2seq的PyTorch实现_哔哩哔哩_bilibili  ---代码实战

跟着问题学13——seq2seq详解及代码实战-CSDN博客

Seq2Seq原理详解 - 早起的小虫子 - 博客园

         Seq2seq模型通常用于将一个序列转换为另一个序列。这种模型由两部分组成:编码器(encoder)和解码器(decoder)。编码器将输入序列编码成一个固定长度的向量,解码器则从这个向量生成输出序列。

'''
@功能: 使用PyTorch实现Seq2Seq编码器-解码器: 将输入的英语单词翻译成西班牙语
@作者: lxy
@日期: 2024/11/24
'''

import torch
import numpy as np
import torch.nn as nn
import torch.utils.data as Data

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# S: 表示解码输入的开始符号
# E: 表示解码输出的结束符号
# ?: 用于填充空白序列,当当前批次的数据长度不足n_step时使用

letter = [c for c in 'SE?abcdefghijklmnopqrstuvwxyz']
letter2idx = {n: i for i, n in enumerate(letter)}

# 示例数据: 英语单词与对应的西班牙语翻译
seq_data = [
    ['hello', 'hola'],  # 'hello' -> 'hola'(英语到西班牙语)
    ['cat', 'gato'],    # 'cat' -> 'gato'
    ['good', 'bueno'],  # 'good' -> 'bueno'
]

# Seq2Seq 参数
n_step = max([max(len(i), len(j)) for i, j in seq_data])  # 最大长度(=5)
n_hidden = 128  # 隐藏层维度
n_class = len(letter2idx)  # 类别数(即字符集大小)
batch_size = 3  # 批次大小

# 函数:构建训练数据
def make_data(seq_data):
    enc_input_all, dec_input_all, dec_output_all = [], [], []

    for seq in seq_data:
        for i in range(2):
            seq[i] = seq[i] + '?' * (n_step - len(seq[i]))  # 如 'man??', 'women'

        # 编码输入:将字符转为索引,并在末尾添加结束符'E'
        enc_input = [letter2idx[n] for n in (seq[0] + 'E')]  # ['m', 'a', 'n', '?', '?', 'E']
        # 解码输入:在开头添加起始符'S'
        dec_input = [letter2idx[n] for n in ('S' + seq[1])]  # ['S', 'w', 'o', 'm', 'e', 'n']
        # 解码输出:在末尾添加结束符'E'
        dec_output = [letter2idx[n] for n in (seq[1] + 'E')]  # ['w', 'o', 'm', 'e', 'n', 'E']

        # 将每个输入转为独热编码
        enc_input_all.append(np.eye(n_class)[enc_input])
        dec_input_all.append(np.eye(n_class)[dec_input])
        dec_output_all.append(dec_output)  # 解码输出不进行独热编码

    # 返回Tensor格式数据
    return torch.Tensor(enc_input_all), torch.Tensor(dec_input_all), torch.LongTensor(dec_output_all)

# 获取训练数据
enc_input_all, dec_input_all, dec_output_all = make_data(seq_data)

# 自定义数据集
class TranslateDataSet(Data.Dataset):
    def __init__(self, enc_input_all, dec_input_all, dec_output_all):
        self.enc_input_all = enc_input_all
        self.dec_input_all = dec_input_all
        self.dec_output_all = dec_output_all

    def __len__(self):  # 返回数据集的大小
        return len(self.enc_input_all)

    def __getitem__(self, idx):
        return self.enc_input_all[idx], self.dec_input_all[idx], self.dec_output_all[idx]

# 数据加载器
loader = Data.DataLoader(TranslateDataSet(enc_input_all, dec_input_all, dec_output_all), batch_size, True)

# Seq2Seq模型
class Seq2Seq(nn.Module):
    def __init__(self):
        super(Seq2Seq, self).__init__()
        # 编码器:RNN模型
        self.encoder = nn.RNN(input_size=n_class, hidden_size=n_hidden, dropout=0.5)
        # 解码器:RNN模型
        self.decoder = nn.RNN(input_size=n_class, hidden_size=n_hidden, dropout=0.5)
        # 全连接层,用于输出分类
        self.fc = nn.Linear(n_hidden, n_class)

    def forward(self, enc_input, enc_hidden, dec_input):
        # enc_input:输入的编码数据 [batch_size, n_step+1, n_class]
        # dec_input:输入的解码数据 [batch_size, n_step+1, n_class]
        enc_input = enc_input.transpose(0, 1)  # 转置为 [n_step+1, batch_size, n_class]
        dec_input = dec_input.transpose(0, 1)  # 转置为 [n_step+1, batch_size, n_class]

        # 编码器输出:h_t 是最后的隐藏状态
        _, h_t = self.encoder(enc_input, enc_hidden)
        # 解码器输出:outputs 是解码过程中的所有输出
        outputs, _ = self.decoder(dec_input, h_t)

        # 通过全连接层输出最终结果
        model = self.fc(outputs)  # [n_step+1, batch_size, n_class]
        return model

# 实例化模型
model = Seq2Seq().to(device)
criterion = nn.CrossEntropyLoss().to(device)  # 交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # Adam优化器

# 训练过程
for epoch in range(5000):
    for enc_input_batch, dec_input_batch, dec_output_batch in loader:
        # 初始化隐藏状态
        h_0 = torch.zeros(1, batch_size, n_hidden).to(device)

        # 将数据移至设备
        enc_input_batch, dec_input_batch, dec_output_batch = (
            enc_input_batch.to(device), dec_input_batch.to(device), dec_output_batch.to(device))

        # 训练模型,获取预测结果
        pred = model(enc_input_batch, h_0, dec_input_batch)

        # 计算损失
        pred = pred.transpose(0, 1)  # [batch_size, n_step+1, n_class]
        loss = 0
        for i in range(len(dec_output_batch)):
            loss += criterion(pred[i], dec_output_batch[i])  # 计算每一批次的损失

        # 每1000次迭代输出一次损失
        if (epoch + 1) % 1000 == 0:
            print('Epoch:', '%04d' % (epoch + 1), 'lost =', '{:.6f}'.format(loss))

        # 反向传播并优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

# 测试函数:翻译单词
def translate(word):
    enc_input, dec_input, _ = make_data([[word, '?' * n_step]])
    enc_input, dec_input = enc_input.to(device), dec_input.to(device)
    hidden = torch.zeros(1, 1, n_hidden).to(device)  # 初始化隐藏状态
    output = model(enc_input, hidden, dec_input)

    # 获取最大概率的预测值
    predict = output.data.max(2, keepdim=True)[1]
    decoded = [letter[i] for i in predict]
    translated = ''.join(decoded[:decoded.index('E')])  # 直到'E'为止

    return translated.replace('?', '')  # 去掉填充符号

# 测试翻译效果
print('测试')
for seq in seq_data:
    word = seq[0]  # 获取英语单词
    translated_word = translate(word)  # 获取翻译结果
    print(f'{word} -> {translated_word}')

运行结果;

Epoch: 1000 lost = 0.001182
Epoch: 2000 lost = 0.000338
Epoch: 3000 lost = 0.000147
Epoch: 4000 lost = 0.000075
Epoch: 5000 lost = 0.000041
测试
hello -> hola
cat?? -> gato
good? -> bueno

lost逐渐减小,这表明模型在不断优化,误差在不断减小 。

4 简单总结nn.RNNCell、nn.RNN

(1)nn.RNNCell

  • 单步处理RNNCell 是最基本的RNN单元,只处理单个时间步的数据。要处理整个序列,需要在外部循环中逐个时间步地调用RNNCell
  • 主要参数:input_size (int): 输入特征的维度。hidden_size (int): 隐藏状态的维度。

                        rnn_cell = nn.RNNCell(input_size, hidden_size)

  • 返回结果:当前时间步的输出 +更新后的隐藏状态

(2)nn.RNN

  • 批量处理RNN 是一个完整的RNN层,可以一次性处理整个序列。
  • 主要参数:

        input_size (int): 输入特征的维度。

        hidden_size (int): 隐藏状态的维度。

        num_layers (int, optional): RNN层的数量,默认为1。

        batch_first (bool, optional): 输入和输出张量的形状,默认为False。

        rnn = nn.RNN(input_size, hidden_size, num_layers=1, batch_first=True)

  • 返回结果: 整个序列的输出 +  最后一个时间步的隐藏状态
  •    🗣 batch_first,默认是 False,输入数据的格式为(seq_len, batch, input_size)。
         当batch_first=True时,输入序列的格式应该为( batch,seq_len, input_size)

当num_layers=1时: 

 当num_layers=3时:

 

5 谈一谈对“序列”、“序列到序列”的理解

序列:一组按照一定顺序排列的元素(数字、元素、字符等)。每个元素在序列中的位置是固定的,并且具有一定的顺序性。

序列到序列:一种深度学习模型,通过深度学习的方式,将一个序列转化为另一个序列。通过编码器提取输入序列的特征,再通过解码器生成输出序列。

6 总结本周理论课和作业,写心得体会

        

   通过实现作业的任务真正理解了RNN的原理,同时继卷积神经网络的Conv2d之后又认识到了循环神经网络中的nn.RNNCell和nn.RNN。另一个比较大的收获就是编码器和解码器的实现,第一次听说是在读“Attention is all you need”这篇论文中见到的(不过当时只是简单了解理论),这次作业中实现编码是用的one-hot编码(比较简单),还有更高级的词嵌入(Word Embeeding)方式。根据“编码器-解码器”架构的设计, 可以使用两个循环神经网络来设计一个序列到序列(Seq2Seq)学习的模型。

(部分笔记) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Emgu (OpenCV)

Emgu Github Emgu 环境&#xff1a; Emgu CV 4.9.0 netframework 4.8 1、下载 libemgucv-windesktop-4.9.0.5494.exe 安装后&#xff0c;找到安装路径下的runtime文件夹复制到c#项目Debug目录下 安装目录 c# Debug目录

YOLOv8模型pytorch格式转为onnx格式

一、YOLOv8的Pytorch网络结构 model DetectionModel((model): Sequential((0): Conv((conv): Conv2d(3, 64, kernel_size(3, 3), stride(2, 2), padding(1, 1))(act): SiLU(inplaceTrue))(1): Conv((conv): Conv2d(64, 128, kernel_size(3, 3), stride(2, 2), padding(1, 1))(a…

澳洲房产市场数据清洗、聚类与可视化综合分析

本项目涉及数据清洗及分析时候的思路&#xff0c;如果仅在CSDN中看&#xff0c;可能会显得有些乱&#xff0c;建议去本人和鲸社区对应的项目中去查看&#xff0c;源代码和数据集都是免费下载的。 声明&#xff1a;本项目的成果可无偿分享&#xff0c;用于学习交流。但请勿用于…

IT服务团队建设与管理

在 IT 服务团队中&#xff0c;需要明确各种角色。例如系统管理员负责服务器和网络设备的维护与管理&#xff1b;软件工程师专注于软件的开发、测试和维护&#xff1b;运维工程师则保障系统的稳定运行&#xff0c;包括监控、故障排除等。通过清晰地定义每个角色的职责&#xff0…

go-zero(八) 中间件的使用

go-zero 中间件 一、中间件介绍 中间件&#xff08;Middleware&#xff09;是一个在请求和响应处理之间插入的程序或者函数&#xff0c;它可以用来处理、修改或者监控 HTTP 请求和响应的各个方面。 1.中间件的核心概念 请求拦截&#xff1a;中间件能够在请求到达目标处理器之…

Qt Graphics View 绘图架构

Qt Graphics View 绘图架构 "QWGraphicsView.h" 头文件代码如下&#xff1a; #pragma once#include <QGraphicsView>class QWGraphicsView : public QGraphicsView {Q_OBJECTpublic:QWGraphicsView(QWidget *parent);~QWGraphicsView();protected:void mouseM…

【eNSP】动态路由协议RIP和OSPF

动态路由RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;和OSPF&#xff08;Open Shortest Path First&#xff0c;开放式最短路径优先&#xff09;是两种常见的动态路由协议&#xff0c;它们各自具有不同的特点和使用场景。本篇会对这两种协…

差分 + 模拟,CF 815A - Karen and Game

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 815A - Karen and Game 二、解题报告 1、思路分析 一个经典的差分数组的…

vue3【实战】响应式的登录界面

效果预览 WEB 端效果 移动端效果 技术方案 vue3 vite Element Plus VueRouter UnoCSS TS vueUse AutoImport 技术要点 响应式设计 移动端&#xff1a;图片切换为绝对定位&#xff0c;下移一层&#xff0c;成为背景图片 <el-imageclass"w-screen h-screen lt-md…

加速科技精彩亮相中国国际半导体博览会IC China 2024

11月18日—20日&#xff0c;第二十一届中国国际半导体博览会&#xff08;IC China 2024&#xff09;在北京国家会议中心顺利举办&#xff0c;加速科技携重磅产品及全系测试解决方案精彩亮相&#xff0c;加速科技创始人兼董事长邬刚受邀在先进封装创新发展论坛与半导体产业前沿与…

php反序列化1_常见php序列化的CTF考题

声明&#xff1a; 以下多内容来自暗月师傅我是通过他的教程来学习记录的&#xff0c;如有侵权联系删除。 一道反序列化的CTF题分享_ctf反序列化题目_Mr.95的博客-CSDN博客 一些其他大佬的wp参考&#xff1a;php_反序列化_1 | dayu’s blog (killdayu.com) 序列化一个对象将…

RustDesk 搭建

RustDesk 服务端下载&#xff1a;https://github.com/rustdesk/rustdesk-server/releases RustDesk 客户端下载&#xff1a;https://github.com/rustdesk/rustdesk/releases RustDesk 官方部署教程&#xff1a;https://rustdesk.com/docs/zh-cn/ 1&#xff1a;RustDesk 概览# 1…

Qt读写Usb设备的数据

Qt读写Usb设备的数据 问题:要读取usb设备进行通讯&#xff0c;qt好像没有对应的库支持。解决&#xff1a;libusbwindow下载 :Linux下载: QtUsb 开源的第三方库库里面的函数说明&#xff1a;window版本&#xff1a;Linux中也提供的直接下载测试代码&#xff1a;库下载&#xff1…

模板初阶,STL简介(C++)

1.模板 1.1泛型编程 在之前的文章中讲过C支持函数重载&#xff0c;比如实现一个交换函数&#xff0c;可以是不同的数据类型&#xff0c;但是这样&#xff0c;需要增加大量函数&#xff0c;且可维护度比较低。 如&#xff1a; void Swap(int& left, int& right) {int …

Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64

yum install 报错: Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 CentOS7的SCL源在2024年6月30日停止维护了。 当scl源里面默认使用了centos官方的地址&#xff0c;无法连接&#xff0c;需要替换为阿里云。 cd /etc/yum.repos.d/ 找到 CentOS-SCLo-scl.repo 和…

蓝桥杯不知道叫什么题目

小蓝有一个整数&#xff0c;初始值为1&#xff0c;他可以花费一些代价对这个整数进行变换。 小蓝可以花贵1的代价将教数增加1。 小蓝可以花费3的代价将整数增加一个值,这个值是整数的数位中最大的那个(1到9) .小蓝可以花费10的代价将整数变为原来的2倍, 例如&#xff0c;如果整…

2024年11月HarmonyOS应用开发者高级认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同&#xff0c;作者已于2024年11月22日又更新了一波题库&#xff0c;题库正确率99%&#xff01; 新版…

技术文档的高质量翻译对俄罗斯汽车推广的影响

进入新市场需要的不仅仅是一个伟大的产品&#xff1b;它要求深入了解当地消费者的期望、法规和文化差异。对于希望在俄罗斯取得成功的国际汽车制造商来说&#xff0c;技术文件的质量是一个关键因素。手册、规范和服务指南在产品和用户之间形成了直接的桥梁&#xff0c;影响着客…

【组件】前端ElementUi 下拉Tree树形组件 带模糊搜索自动展开高亮功能 树结构 封装为组件使用

【组件】前端ElementUi 下拉Tree树形组件 带模糊搜索自动展开高亮功能 树结构 【组件】前端ElementUi 下拉Tree树形组件 带模糊 https://live.csdn.net/v/436057 单独使用 <template><div><el-popoverstyle"overflow-y: auto; "placement"bottom…

论文阅读:Dual-disentangled Deep Multiple Clustering

目录 摘要 引言 模型 实验 数据集 实验结果 结论 摘要 多重聚类近年来引起了广泛关注&#xff0c;因为它能够从不同的角度揭示数据的多种潜在结构。大多数多重聚类方法通常先通过控制特征之间的差异性来提取特征表示&#xff0c;然后使用传统的聚类方法&#xff08;如 …