代码功能:使用RNNCell和RNN学习 hello ==> ohlol
- 使用RNNCell
- 注意RNNCell一次只能处理一个序列中的一个字符。
- labels 的 shape 是 (seqLen, 1)
- 注意在一个数据集中,各个数据的输入序列长度可能是不一样的。此时需要做填充。
- 使用RNN
- labels 的 shape 是 (seqLen*batchSize, 1),这里最好也 view 成 (-1, 1)
代码功能:实现一个增加了 embedding 层的RNN
- 这里一定要注意 x_data 和 y_data 的维数!
import torch
####################### Part1. Prepare Dataset #######################
dictionary = ['e', 'h', 'l', 'o']
# 注意这里并没有真的用one-hot向量来表示
x_data = [[1, 0, 2, 2, 3]] # hello
y_data = [3, 1, 2, 3, 2] # ohlol
inputs = torch.LongTensor(x_data)
labels = torch.LongTensor(y_data)
num_class = len(dictionary) # 字典的长度
inputs_size = num_class # 输入的维数,不是batch_size
hidden_size = 8 # 隐藏层的维数
embedding_size = 10 # embedding向量的维数,即将one-hot压缩(扩大)至几维
num_layers = 2 # RNN的层数
batch_size = 1 # batch_size,这里只有1组数据,所以取1
seq_len = len(x_data) # 输入序列的长度,如果各数据输入序列长度不同,则取最大值
print(inputs.size()) # torch.Size([1, 5]),即[batchSize, seqLen]
print(labels.size()) # torch.Size([5]),即[batchSize * seqLen]
####################### Part2. Design Model #######################
class MyModule(torch.nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.emb = torch.nn.Embedding(inputs_size, embedding_size)
self.rnn = torch.nn.RNN(input_size=embedding_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True)
self.fc = torch.nn.Linear(hidden_size, num_class)
def forward(self, x):
# hidden的形状为(num_layers * num_directions, batchSize, hidden_size)
# hidden其实就是每个元素对应的记忆细胞,所以是每组数据都要有自己的,不能共用别人的
hidden = torch.zeros(num_layers, x.size(0), hidden_size)
x = self.emb(x) # 输入值形状为(batchSize, seqLen), 输出值形状为(batchSize, seqLen, embeddingSize)
x, _ = self.rnn(x, hidden) # 输出值形状为(batchSize, seqLen, hiddenSize)
# 注意这里的返回值是(output, h_n),详情参考官方文档
x = self.fc(x) # 输出值形状为(batchSize, seqLen, numClass)
return x.view(-1, num_class) # reshape是为了维度和labels匹配,然后使用CrossEntropy损失函数
model = MyModule()
####################### Part3. Construct Loss and Optimizer #######################
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
####################### Part4. Train and Test #######################
for epoch in range(15):
y_pred = model(inputs)
loss = criterion(y_pred, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 返回输入张量给定维度上每行的最大值,并同时返回每个最大值的位置索引
_, index = y_pred.max(dim=1)
index = index.data.numpy()
print("Predicted:", "".join([dictionary[x] for x in index]), end="")
print(", Epoch [%d/15] loss = %.3f" % (epoch + 1, loss.item()))