- x_t@w_(xh)+h_t@w_(hh)
-
- [batch,feature_len] @ [hidden_len,feature_len]^T+ [batch, hidden_len]@ [hidden_len , hidden_len]^T
- from torch import nn
- # 表示feature_len=100(如每个单词用100维向量表示), hidden_len=10(隐藏单元的尺寸)
- rnn = nn.RNN(100, 10)
- # 使用nn.RNN构造时传入的三个参数是feature_len、hidden_len、num_layers,默认空间层数=1。
- out, h_t=forward(x, h_0)
- """
- x是一次性将所有时刻特征喂入的,而不需要每次喂入当前时刻的x_t,所以其shape是[seq_len,batch,feature_len]。
- h_0是第一个时刻空间上所有层的记忆单元的Tensor,要考虑循环网络空间上的层数,所以这里输入的shape是[num_layer,batch,hidden_len]。
- 返回值有两部分:
- h_t是最后一个时刻空间上所有层的记忆单元,所以它和h_0的shape是一样的,即[num_layer,batch,hidden_len]。
- 返回的out是每一个时刻上空间上最后一层的输出,所以它的shape是[seq_len,batch,hidden_len]
- """
- # 表示feature_len=100, hidden_len=20, 层数=1
- rnn = nn.RNN(100, 20, 1)
- # 输入3个样本序列(batch=3), 序列长为10(seq_len=10), 每个特征100维度(feature_len=100)
- x = torch.randn(10, 3, 100)
- # 传入RNN处理, 另外传入h_0, shape是<层数, batch, hidden_len=20>
- out, h = rnn(x, torch.zeros(1, 3, 20))
- from torch import nn
-
- # 表示feature_len=100, hidden_len=20, 层数=2
- rnn = nn.RNN(100, 20, num_layers=2)
- """
- 从l1层开始接受的输入都是下面层的输出,也就是说接受的输入的特征数不再是feature_len而是hidden_len了,所以这里参数weight_ih_l1的shape应是[hidden_len,hidden_len]:
- nn.RNN的最底下一层l0将外部的feature_len转化为隐藏记忆单元的内部表示即hidden_len,而其它层都是输入hidden_len输出hidden_len的。
- """
- # RNN层
- self.rnn = nn.RNN(
- input_size=1, # 即feature_len=1
- hidden_size=hidden_len, # 隐藏记忆单元尺寸
- num_layers=1, # 层数,这里就用单层RNN
- batch_first=True # 在喂入数据时,按照[batch,seq_len,feature_len]的格式
- )
- # 对RNN层的参数做初始化
- for p in self.rnn.parameters():
- nn.init.normal_(p, mean=0.0, std=0.001)
- # 输出层,直接用一个线性变换把每个时刻记忆单元的hidden_len输出为所需的feature_len=1
- self.linear = nn.Linear(hidden_len, 1)
-
- """生成样本数据"""
- # 在0~3之间随机取开始的时刻点
- k = np.random.randint(3, size=1)[0]
- # 取点的区间是[k, k+10],均匀地取num_points个点
- time_steps = np.linspace(k, k + 10, num_points)
- # 在这num_points个时刻上生成函数值数据
- data = np.sin(time_steps)
-
- # 喂入模型得到输出
- out, h = model(x, h) # h是上次循环得到的h
- # 因为h在循环中被一次次嵌套,这里不要为上一个网络求梯度,而只求当前的,所以detach一下
- h = h.detach()
- h_t = forward(x_t, h_{t-1})
- """
- 当前时刻的输入x_t,所以其shape是[batch,feature_len]。
- h_{t-1}是这个时刻运行之前记忆单元的Tensor,也就是前一时刻的单元输出,所以这里输入的shape是[batch,hidden_len]。
- 返回值h_t是这个时刻运行之后记忆单元的Tensor,也就是下一时刻(如果有)的单元输入,所以它和h_{t-1}的shape是一样的,即[batch,hidden_len]。
- """
out = torch.stack([h1,h2,...,ht]) - # 表示feature_len=100, hidden_len=20
- cell = nn.RNNCell(100, 20)
- # 所有时刻的输入, 一共有10个时刻, 即seq_len=10
- xs = [torch.randn(3, 100) for i in range(10)]
- # 初始化隐藏记忆单元, batch=3, hidden_len=20
- h = torch.zeros(3, 20)
- # 对每个时刻的输入, 传入这个nn.RNNCell计算单元, 还要传入上一时h, 以进行前向计算
- for xt in xs:
- h = cell(xt, h)
- # 第0层和第1层的计算单元
- cell_l0 = nn.RNNCell(100, 30) # feature_len=100, hidden_len_l0=30
- cell_l1 = nn.RNNCell(30, 20) # hidden_len_l0=30, hidden_len_l1=20
-
- # 第0层和第1层使用的隐藏记忆单元(图中黄色和绿色)
- h_l0 = torch.zeros(3, 30) # batch=3, hidden_len_l0=30
- h_l1 = torch.zeros(3, 20) # batch=3, hidden_len_l1=20
-
- # 原始输入, batch=3, feature_len=100
- xs = [torch.randn(3, 100) for i in range(4)] # seq_len=4, 即共4个时刻
-
- for xt in xs:
- h_l0 = cell_l0(xt, h_l0)
- h_l1 = cell_l1(h_l0, h_l1)