具体代码如下
import torch
# 准备数据
index_chart = ['e', 'h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [1, 0, 0, 3, 2]
one_hot_lookup = [[1, 0, 0, 0], # 设置一个索引表
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]]
x_one_hot = [one_hot_lookup[x] for x in x_data]
input_size = 4
batch_size = 1
inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size)
labels = torch.LongTensor(y_data).view(-1, 1) # 增加维度方便计算loss
# 设计网络模型
class LSTM(torch.nn.Module):
# 进行基础设置
def __init__(self):
super(LSTM, self).__init__()
self.lineari = torch.nn.Linear(4, 4)
self.linearf = torch.nn.Linear(4, 4)
self.linearc = torch.nn.Linear(4, 4)
self.linearo = torch.nn.Linear(4, 4)
self.sigmoid = torch.nn.Sigmoid()
self.tanh = torch.nn.Tanh()
# 设置前向传播函数
def forward(self, x, hidden, C):
i = self.sigmoid(self.lineari(x) + self.lineari(hidden))
f = self.sigmoid(self.linearf(x) + self.linearf(hidden))
c = self.sigmoid(self.linearc(x) + self.linearc(hidden))
o = self.sigmoid(self.linearo(x) + self.linearo(hidden))
C = f * C + i * c # 候选状态x输入状态+遗忘状态x上一个细胞状态,得到此次细胞状态
hidden = o * self.tanh(C) # 此次得到的细胞状态进行激活后,再乘以输出门,最后得到隐藏层输出
return hidden, C
net = LSTM()
# 计算损失和更新
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.03)
# 进行训练和更新
for epoch in range(100):
loss = 0
optimizer.zero_grad() # 梯度每一次迭代完之后都要归零
hidden = torch.zeros(batch_size, input_size) # 初始的隐藏层的值均设置为0,形状为(batch_size,input_size)
C = torch.zeros(batch_size, input_size) # 初始的细胞状态值均设置为0,形状为(batch_size,input_size)
print('Predicten string:', end='')
for input, label in zip(inputs, labels):
hidden, C = net(input, hidden, C)
loss += criterion(hidden, label) # hidden.shape=(1,4) label.shape=1
_, idx = hidden.max(dim=1) # 从第一个维度上取出预测概率最大的值和该值所在序号,_代表其最大概率对应的值,idx代表该值所对应的索引序号
print(index_chart[idx.item()], end='') # 按上面序号输出相应字母字符
loss.backward()
optimizer.step()
print(', Epoch [%d/100] loss=%.4f' % (epoch + 1, loss.item()))
LSTM结合embedding的方法代码如下
import torch
batch_size = 1
input_size = 4
index_chart = ['e', 'h', 'l', 'o'] # 预测的结果是设置的索引,这样方便对结果更快地进行取值
x_data = torch.LongTensor([[1, 0, 2, 2, 3]]).view(5, 1)
print(x_data.shape)
y_data = [3, 1, 2, 3, 2] # 标签
labels = torch.LongTensor(y_data).view(-1, 1) # 增加维度方便计算loss,view(-1,1)表示一定转换成1列,-1表示根据列数是1,自动计算其行
emb = torch.nn.Embedding(4, 10)
inputs = emb(x_data) # 将4维输入数据嵌入成10维,为后面的linear_ix等操作进行设置(5,1,10),嵌入值均是随机设定
print(inputs)
print(inputs.shape)
class emb_lstm(torch.nn.Module):
def __init__(self):
super(emb_lstm, self).__init__()
# 上一时刻的内部状态g(x),外部状态h(x)
self.linear_ix = torch.nn.Linear(10, 4) # 输入门,输入值和上一阶段的外部状态值通过激活函数激活后成为输入值it
self.linear_fx = torch.nn.Linear(10, 4) # 遗忘门,输入值和上一阶段的外部状态值通过激活函数激活后成为遗忘值ft
self.linear_gx = torch.nn.Linear(10, 4) # 候选变量,输入值和上一阶段的外部状态值通过tanh激活函数激活后成为候选变量值
self.linear_ox = torch.nn.Linear(10, 4) # 输出值,输入值和上一阶段的外部状态值通过激活函数激活后成为输出值ot
# 隐藏层的LSTM变换
self.linear_ih = torch.nn.Linear(4, 4)
self.linear_fh = torch.nn.Linear(4, 4)
self.linear_gh = torch.nn.Linear(4, 4)
self.linear_oh = torch.nn.Linear(4, 4)
self.sigmoid = torch.nn.Sigmoid()
self.tanh = torch.nn.Tanh()
def forward(self, x, hidden, c): # 输入x,外部状态hidden,以及候选状态c
# 输入值x和外部状态h(x)相结合,再通过激活函数激活得到内部状态的i,f,g(候选状态),o值;
i = self.sigmoid(self.linear_ix(x) + self.linear_ih(hidden))
f = self.sigmoid(self.linear_fx(x) + self.linear_fh(hidden))
g = self.tanh(self.linear_gx(x) + self.linear_gh(hidden))
o = self.sigmoid(self.linear_ox(x) + self.linear_oh(hidden))
# 候选状态g乘以输入值i,再加上上一时刻的内部状态c乘以遗忘值f,得到该时刻的更新的内部状态值c
# 输出元素 o 乘以经过激活函数激活后的该时刻的内部状态值,得到该时刻的外部状态值
c = f * c + i * g # 上一层的结果c通过遗忘门f得到最后的输出值,加上通过输入门的上一层的候选结果g;g是候选变量相比于c,是在激活函数上不同
hidden = o * self.tanh(c) # 上式得到的结果c通过输出门
return hidden, c
model = emb_lstm()
# 构建损失函数和优化器方法
criterion = torch.nn.CrossEntropyLoss() # 交叉熵
optimizer = torch.optim.Adam(model.parameters(), lr=0.06)
# 进行训练和更新
for epoch in range(100):
loss = 0
optimizer.zero_grad()
hidden = torch.zeros(batch_size, input_size) # 提供初始化隐藏层
c = torch.zeros(batch_size, input_size)
print('Predicten string:', end='')
for input, label in zip(inputs, labels): # 并行遍历数据集 一个一个训练
hidden, c = model(input, hidden, c)
loss += criterion(hidden, label)
_, idx = hidden.max(dim=1) # 从第一个维度(即行维度)上取出预测概率最大的值和该值所在序号,_表示
print(index_chart[idx.item()], end='') # 按上面序号输出相应字母字符
loss.backward(retain_graph=True)
optimizer.step()
print(', Epoch [%d/100] loss=%.4f' % (epoch + 1, loss.item()))