大家好,我是微学AI,今天给大家介绍一下人工智能(Pytorch)搭建GRU网络的过程,通过构造数据,让大家了解整个训练的过程。
GRU(Gated Recurrent Unit,门控循环单元)是一种循环神经网络(RNN)的变体,用于处理序列数据。对于每个时刻,GRU模型都根据当前输入和之前的状态来推断出新状态,从而输出预测结果。与传统的RNN模型不同,在GRU模型中添加了两个门控机制,即「重置门」和「更新门」,来控制模型在推断时候保留多少历史信息。
举个例子:假设任务是让模型学习一段句子并预测它的下一个单词是什么。在传统的RNN模型中,模型在处理较长的序列时会出现梯度消失/爆炸的问题。而在GRU模型中,我们引入了两个门控机制。第一个是重置门,负责让模型忘记历史状态中的某些信息,以便有更好的记忆和推断。第二个是更新门,它决定了这时刻的门口该有多大程度打开,来控制历史信息的保留。因此,GRU模型不仅能够自动地提取各种长期依赖性,而且计算复杂度较低、训练效果也比传统的RNN模型更好。
在GRU的简化形式中,一个输入的序列被送入GRU网络,每一个时刻是一个单独的向量或一个含多个元素的序列。每一个时刻网络会读入一个输入向量,计算出当前的隐含状态,并把这个状态传递到下一个时刻。每一个时刻的计算包括三个部分:
1.通过重置门决定遗忘哪些过去的状态,从而缓解梯度消失的问题。
2.通过更新门决定当前时刻的输入信号量和历史信息量的权重,保持模型对序列中依赖性的更好的建模。
3.通过计算输入门和更新门的函数,计算出类似于LSTM中的记忆值。
1. 导入所需库
# 1. 导入所需库
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from torch.utils.data import Dataset, DataLoader
2. 定义GRU模型
# 2. 定义GRU模型
class GRUModel(nn.Module):
def __init__(self, input_size, hidden_size, output_size, num_layers):
super(GRUModel, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
out, _ = self.gru(x, h0)
out = self.fc(out[:, -1, :])
return out
3. 准备数据集
我们构造一个数据集,目的是让大家跑通GRU模型,后续根据具体的项目进行更换数据集,这个是学习GRU的很好样例。
我们构造的数据集中每个样本包含一个大小为(10,5)的浮点数张量(即序列)和一个大小为(2,)的方向标签张量。在数据集初始化过程中,会生成1000个样本,其中序列随机生成,标签依赖于每个序列的元素总和是否大于0。我们首先定义了一个 SampleDataset
类,它继承自 PyTorch 内置的 Dataset
类。接着在 __init__
方法中,定义了两个空列表 self.sequences
和 self.labels
,用于存储序列和标签信息。我们生成1000个随机序列,并计算每个序列的元素总和,如果元素总和大于0,则对应的标签的第一个元素设为1,否则第二个元素设为1。这样得到每个序列对应的标签信息。然后将每个序列和其对应的标签信息存储到 self.sequences
和 self.labels
列表中。
构造 __len__
方法,返回数据集中样本的数量,即 self.sequences
列表的长度。
构造 __getitem__
方法中,接收一个索引 idx
,返回索引为 idx
的序列及其对应的标签。该函数用于从数据集中获取单个样本。
# 3. 准备数据集
class SampleDataset(Dataset):
def __init__(self):
self.sequences = []
self.labels = []
for _ in range(1000):
seq = torch.randn(10, 5)
label = torch.zeros(2)
if seq.sum() > 0:
label[0] = 1
else:
label[1] = 1
self.sequences.append(seq)
self.labels.append(label)
def __len__(self):
return len(self.sequences)
def __getitem__(self, idx):
return self.sequences[idx], self.labels[idx]
train_set_split = int(0.8 * len(SampleDataset()))
train_set, test_set = torch.utils.data.random_split(SampleDataset(), [train_set_split, len(SampleDataset()) - train_set_split])
train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
test_loader = DataLoader(test_set, batch_size=32, shuffle=False)
4. 定义训练过程
# 4. 定义训练过程
def train(model, loader, criterion, optimizer, device):
model.train()
running_loss = 0.0
correct = 0
total = 0
for batch_idx, (inputs, labels) in enumerate(loader):
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
_, predicted = torch.max(outputs, 1)
_, true_labels = torch.max(labels, 1)
total += true_labels.size(0)
correct += (predicted == true_labels).sum().item()
print("Train Loss: {:.4f}, Acc: {:.2f}%".format(running_loss / (batch_idx + 1), 100 * correct / total))
5. 定义评估过程
# 5. 定义评估过程
def evaluate(model, loader, criterion, device):
model.eval()
running_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
for batch_idx, (inputs, labels) in enumerate(loader):
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
running_loss += loss.item()
_, predicted = torch.max(outputs, 1)
_, true_labels = torch.max(labels, 1)
total += true_labels.size(0)
correct += (predicted == true_labels).sum().item()
print("Test Loss: {:.4f}, Acc: {:.2f}%".format(running_loss / (batch_idx + 1), 100 * correct / total))
6. 训练模型并评估
# 6. 训练模型并评估
device = "cuda" if torch.cuda.is_available() else "cpu"
model = GRUModel(input_size=5, hidden_size=10, output_size=2, num_layers=1).to(device)
criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
num_epochs = 100
for epoch in range(num_epochs):
print("Epoch {}/{}".format(epoch + 1, num_epochs))
train(model, train_loader, criterion, optimizer, device)
evaluate(model, test_loader, criterion, device)
运行结果:
.....
Epoch 93/100
Train Loss: 0.0409, Acc: 99.00%
Test Loss: 0.0655, Acc: 98.50%
Epoch 94/100
Train Loss: 0.0400, Acc: 99.50%
Test Loss: 0.0631, Acc: 98.50%
Epoch 95/100
Train Loss: 0.0412, Acc: 98.88%
Test Loss: 0.0609, Acc: 98.50%
Epoch 96/100
Train Loss: 0.0396, Acc: 99.38%
Test Loss: 0.0646, Acc: 98.00%
Epoch 97/100
Train Loss: 0.0369, Acc: 99.50%
Test Loss: 0.0562, Acc: 98.00%
Epoch 98/100
Train Loss: 0.0368, Acc: 99.38%
Test Loss: 0.0637, Acc: 98.00%
Epoch 99/100
Train Loss: 0.0364, Acc: 99.50%
Test Loss: 0.0581, Acc: 98.50%
Epoch 100/100
Train Loss: 0.0353, Acc: 99.75%
Test Loss: 0.0652, Acc: 98.00%
Process finished with exit code 0
以上用于分类问题,运行准确率较高。
欢迎大家关注与支持,也可以合作交流!