人工智能(Pytorch)搭建GRU网络,构造数据实现训练过程与评估

大家好,我是微学AI,今天给大家介绍一下人工智能(Pytorch)搭建GRU网络的过程,通过构造数据,让大家了解整个训练的过程。

一、GRU模型

GRU(Gated Recurrent Unit,门控循环单元)是一种循环神经网络(RNN)的变体,用于处理序列数据。对于每个时刻,GRU模型都根据当前输入和之前的状态来推断出新状态,从而输出预测结果。与传统的RNN模型不同,在GRU模型中添加了两个门控机制,即「重置门」和「更新门」,来控制模型在推断时候保留多少历史信息。

举个例子:假设任务是让模型学习一段句子并预测它的下一个单词是什么。在传统的RNN模型中,模型在处理较长的序列时会出现梯度消失/爆炸的问题。而在GRU模型中,我们引入了两个门控机制。第一个是重置门,负责让模型忘记历史状态中的某些信息,以便有更好的记忆和推断。第二个是更新门,它决定了这时刻的门口该有多大程度打开,来控制历史信息的保留。因此,GRU模型不仅能够自动地提取各种长期依赖性,而且计算复杂度较低、训练效果也比传统的RNN模型更好。

二、GRU计算过程

在GRU的简化形式中,一个输入的序列被送入GRU网络,每一个时刻是一个单独的向量或一个含多个元素的序列。每一个时刻网络会读入一个输入向量,计算出当前的隐含状态,并把这个状态传递到下一个时刻。每一个时刻的计算包括三个部分:

1.通过重置门决定遗忘哪些过去的状态,从而缓解梯度消失的问题。

2.通过更新门决定当前时刻的输入信号量和历史信息量的权重,保持模型对序列中依赖性的更好的建模。

3.通过计算输入门和更新门的函数,计算出类似于LSTM中的记忆值。

三、GRU模型代码实现

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模型

扫描二维码关注公众号,回复: 14617784 查看本文章
# 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

以上用于分类问题,运行准确率较高。

欢迎大家关注与支持,也可以合作交流!

猜你喜欢

转载自blog.csdn.net/weixin_42878111/article/details/129992716