LSTM 科学实验评估 2024-3-12 公开

代码资料:
https://github.com/Whiffe/SCB-dataset/tree/main/EvaluationMethod/LSTM

上面的代码资料分两部分,代码与数据。

在这里插入图片描述
LSTM的三个文件只是参数和加载的训练测试文件不一样。

train test 是视频的行为序列与专注度分类。

在这里插入图片描述
图 6 学生科学实验评估流程

从下面的图可以看出train.csv,train2.csv的区别在于:train.csv中的ID 0,在train2.csv中变成了ID 5,这样做的目的是,在后续标准化的过程中,会进行补0操作,与train.csv中的发生冲突,所以在train2.csv中将0替换成了5.

在这里插入图片描述

下面是我在论文中描述的整个流程:

如图 6所示,是学生科学实验评估过程,输入的是学生录制的视频,然后抽帧,将抽帧的视频送入学生科学实验模型中检测,输出数据包括学生ID、时间ID和行为ID,其中0代表称重、1代表测高度、2代表丢球、3代表测大小、4代表记录。然后,我们重新组织这些行为数据,如图 6的步骤1所示,我们将整个视频中的每一位学生的行为集中在一个数组中,形成学生的原始行为序列,需要注意的是,由于行为的连续性,这些原始行为序列通常包含大量的连续重复行为ID,为了后续标准化与模型训练的方便,我们对原始行为序列进行重复删除的操作,然后对每个行为ID+1,这样做的目的是让行为ID不从0开始,如图 6的步骤2。

接下来,我们按照训练是设置的batch size大小来对行为序列进行标准化,找到每组中最大序列长度,然后按照这个最大的序列长度,对该组内的行为序列进行末尾空白补0,使得每一组内部的序列长度一致如图 6的步骤3。
我们选取了503个学生科学实验视频,然后将这些视频分成3类,高专注(286个,id=0)、中专注(100个,id=1)、低专注(117个,id=2),通过RE-DETR-ASF行为检测模型检测出原始行为序列,然后行为序列去重,行为ID+1,在进行对序列进行末尾补0标准化,这样就形成了一个学生行为序列专注度的数据集,如图 6的步骤4。
我们选择LSTM模型学生行为序列专注度数据集进行训练与测试,原因是LSTM模型能够有效地处理序列数据中的长期依赖关系,具有较强的记忆能力和灵活性,在很多序列建模任务中表现出色,并且有丰富的研究基础支持其应用。训练结束后的模型,我们就用于对学生视频专注度的预测,图 6的步骤5。

学生科学实验评估
我们选取了503个视频,将视频分成3类,286个高专注、100个中专注、117个低专注,然后通过RE-DETR-ASF行为检测模型检测出视频的原始行为序列,然后行为序列去重,行为ID+1,在进行对序列进行末尾补0标准化,然后按照4:1将行为序列划分为训练集与测试集,我们再将数据集送入LSTM模型中进行训练,最后在测试集上的准确度为:86.0%。

代码如下:

! pip install pandas
import torch
import torch.nn as nn
import pandas as pd
from torch.utils.data import Dataset, DataLoader
import torch.nn.functional as F

# 定义LSTM模型
class LSTMModel(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes):
        super(LSTMModel, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
        out, _ = self.lstm(x, (h0, c0))
        out = self.fc(out[:, -1, :])
        return out

# 自定义数据集类
class CustomDataset(Dataset):
    def __init__(self, csv_file):
        self.data = pd.read_csv(csv_file)

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        sequence = list(map(int, str(self.data.iloc[idx, 0]).split(', '))) # 将字符串序列转换为整数列表
        label = int(self.data.iloc[idx, 1]) # 获取标签
        return torch.tensor(sequence), torch.tensor(label)

# 超参数设置
input_size = 1 # 输入特征维度(每个行为序列中的元素个数)
hidden_size = 128 # LSTM隐藏单元数
num_layers = 2 # LSTM层数
num_classes = 3 # 分类类别数
batch_size = 4
num_epochs = 20
learning_rate = 0.0001

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

def collate_fn(batch):
    sequences, labels = zip(*batch)
    # 找到最长的序列长度
    max_length = max([len(seq) for seq in sequences])
    # 填充序列
    sequences_padded = [torch.cat([seq, torch.zeros(max_length - len(seq)).long()]) for seq in sequences]
    return torch.stack(sequences_padded, dim=0), torch.tensor(labels)


# 加载数据集
dataset = CustomDataset('/root/LSTM2/train.csv')  # 修改为Excel文件的路径



loader = DataLoader(dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)

# loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)


# 初始化模型、损失函数和优化器
model = LSTMModel(input_size, hidden_size, num_layers, num_classes).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# 训练模型
total_step = len(loader)
for epoch in range(num_epochs):
    for i, (sequences, labels) in enumerate(loader):
        # print(i, (sequences, labels))
        # input()
        sequences = sequences.view(-1, len(sequences[0]), input_size).float().to(device) # 将输入形状调整为(batch_size, sequence_length, input_size)
        labels = labels.to(device)

        # 正向传播
        outputs = model(sequences)
        loss = criterion(outputs, labels)

        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if (i+1) % 20 == 0:
            print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, i+1, total_step, loss.item()))

print('训练完成')

# 在测试集上评估模型
# ...
# 加载测试数据集
test_dataset = CustomDataset('/root/LSTM2/test.csv')  # 使用测试集的CSV文件路径
# test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, collate_fn=collate_fn)

# 将模型设置为评估模式
model.eval()

total_correct = 0
total_samples = 0
with torch.no_grad():
    for sequences, labels in test_loader:
        sequences = sequences.view(-1, len(sequences[0]), input_size).float().to(device) # 将输入形状调整为(batch_size, sequence_length, input_size)
        # sequences = sequences.unsqueeze(2).to(device)  # 添加一个维度,将序列变成三维张量
        labels = labels.to(device)

        # 正向传播
        outputs = model(sequences)
        # probabilities = F.softmax(outputs, dim=1)  # 应用softmax变换
        _, predicted = torch.max(outputs, 1)

        # 统计正确预测的样本数量
        total_correct += (predicted == labels).sum().item()
        total_samples += labels.size(0)

# 计算准确率
accuracy = total_correct / total_samples
print('在测试集上的准确率: {:.2f}%'.format(accuracy * 100))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CSPhD-winston-杨帆

给我饭钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值