基于pytorch的LSTM模型训练与预测(附源码)

news2025/6/28 17:01:31

1.LSTM模型

        关于这个模型的基本概念长短时记忆网络(LSTM)(超详细 |附训练代码)_lstm代码-CSDN博客可以查看这篇文章,写得很详细,我觉得能大概看明白反向传递各个部分的推导就行了。

2.pytorch的安装

        我使用的是conda环境,在参照网上的安装过程后,运行出现了报错OSError: [WinError 126] 找不到指定的模块。 Error loading "D:\WORK\anaconda\lib\site-packages\torch\lib\c10_cuda.dll" or one of its dependencies.

        重新创建了一个python3.9的conda环境后,再次安装torch就可以了。具体过程可以参考这篇文章安装PyTorch详细过程_pytorch安装-CSDN博客

3.LSTM训练

        本文只是简略的一个训练和预测过程,适合感兴趣的人初步学习。所有代码都已经写有详细的注释,希望对读者的阅读能有帮助。整个项目的流程包括爬虫,数据处理,还有数据集等等我已经放在GitHub上,感兴趣的小伙伴可以拿去学习或者修改出更好的训练代码,github链接。

3.1 LSTMModel.py

        编写一个简单的LSTM模块,pytroch已经内置了LSTM,我们只需要编写调用就行了,不用实现LSTM的内部功能。

import torch
import torch.nn as nn

# input_size输入特征的维度
# hidden_size隐藏层的维度,即每个LSTM单元的隐藏状态向量的维度。
# output_size:输出的维度。
# num_layers:LSTM层的数量,默认为1。


class LSTMModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers=1):
        super(LSTMModel, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers

        # 定义lsmt层
        # batch_first=True表示输入数据的形状是(batch_size, sequence_length, input_size)
        # 而不是默认的(sequence_length, batch_size, input_size)。
        # batch_size是指每个训练批次中包含的样本数量
        # sequence_length是指输入序列的长度
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)

        # 定义全连接层,将LSTM层的输出映射到最终的输出空间。
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        # 初始化了隐藏状态h0和细胞状态c0,并将其设为零向量。
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)

        # LSTM层前向传播
        # 将输入数据x以及初始化的隐藏状态和细胞状态传入LSTM层
        # 得到输出out和更新后的状态。
        # out的形状为(batch_size, sequence_length, hidden_size)。
        out, _ = self.lstm(x, (h0, c0))

        # 全连接层前向传播
        # 使用LSTM层的最后一个时间步的输出out[:, -1, :](形状为(batch_size, hidden_size))作为全连接层的输入,得到最终的输出。
        out = self.fc(out[:, -1, :])

        return out

3.2 load_data.py

        加载数据集模块,读取本地的CSV数据集,对数据集提取目标变量和特征变量。

# 加载数据集并划分数据集和测试集
import torch
from torch.utils.data import Dataset, DataLoader, random_split
import pandas as pd
from sklearn.preprocessing import StandardScaler


# 自定义一个数据集类
class CustomDataset(Dataset):
    def __init__(self, csv_file, transform=None):
        self.data = pd.read_csv(csv_file, encoding='GBK')
        self.transform = transform

        # 提取特征和目标变量
        self.X = self.data.drop(columns=['当日票房(万)'])  # 除了目标剩下的都是特征
        self.Y = self.data['当日票房(万)']  # 目标

        # 使用StandardScaler对数据进行标准化处理,以确保训练过程中的数值稳定性(可选)
        # pd.DataFrame()函数,可以将数据从不同的数据源(如列表、字典、NumPy数组等)转换成数据帧
        self.scaler = StandardScaler()
        self.X = pd.DataFrame(self.scaler.fit_transform(self.X), columns=self.X.columns)

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

    def __getitem__(self, idx):
        # 从self.X中选择索引为idx的行,并将其赋值给X_sample
        X_sample = self.X.iloc[idx]
        Y_sample = self.Y.iloc[idx]

        # 特征数据和标签数据都被转换为float32类型的PyTorch张量。
        sample = {'X': torch.tensor(X_sample.values, dtype=torch.float32),
                  'Y': torch.tensor(Y_sample, dtype=torch.float32)}

        # 在这里进行数据预处理,如果需要的话
        if self.transform:
            sample = self.transform(sample)

        return sample


def load_data():
    # 读取CSV文件
    csv_file = 'D:/WORK/all.movie.new.csv'

    # 创建数据集实例
    custom_dataset = CustomDataset(csv_file)

    # 划分训练集和测试集
    train_size = int(0.9 * len(custom_dataset))  # 训练集占比90%
    test_size = len(custom_dataset) - train_size  # 测试集占比10%
    train_dataset, test_dataset = random_split(custom_dataset, [train_size, test_size])  # 按照比例随机划分

    # 创建数据加载器
    # batch_size参数用于指定每个批次(batch)中包含的样本数量。
    # 通常情况下,较大的batch_size可以加快训练速度,但可能会占用更多的内存资源。
    train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
    test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

    # 检查数据加载器
    for batch in train_loader:
        print(batch['X'].shape, batch['Y'].shape)
        break

    return train_loader, test_loader, custom_dataset

 3.3 train.py

        训练模块,通过调用LSTMModel和load_data,来实例化模型和加载数据。然后进行前向传播和反向传递的无限循序训练。

import torch
from torch import nn
import load_data
import LSTMmodel as lstm
import torch.optim as optim


def evaluate_model(model, data_loader, criterion):
    # 评估模块
    model.eval()
    total_loss = 0
    with torch.no_grad():
        for batch in data_loader:
            X_batch = batch['X'].unsqueeze(1).to('cuda')
            Y_batch = batch['Y'].unsqueeze(1).to('cuda')

            outputs = model(X_batch)
            loss = criterion(outputs, Y_batch)
            total_loss += loss.item()
    return total_loss / len(data_loader)


def main():
    # 加载训练集和测试集和对应的数据加载器
    train_loader, test_loader, custom_dataset = load_data.load_data()

    # 设置超参数
    input_size = len(custom_dataset.X.columns)  # 特征数量
    hidden_size = 32  # 隐藏层大小
    # 隐藏层大小是指每个LSTM单元中的隐藏状态向量的维度,它在很大程度上影响了模型的表示能力和性能
    # 如果隐藏层太大,模型可能会过拟合训练数据,对测试数据表现不佳。
    # 如果隐藏层太小,模型可能无法捕捉到足够的信息,导致欠拟合。

    output_size = 1  # 输出大小(预测当日票房)

    num_layers = 4  # LSTM层数
    # 单层LSTM:适用于简单的序列建模任务,结构简单,计算效率高。
    # 多层LSTM:适用于复杂的序列建模任务,能够捕捉更复杂的模式和长距离依赖,但需要更多的计算资源。
    # 层数选择:需要通过实验来确定,考虑任务复杂度、数据量和计算资源。

    learning_rate = 0.01  # 学习率
    # 对于较小的网络或简单任务,较大的学习率(如 0.01)可能是合适的。
    # 对于较深的网络或复杂任务,较小的学习率(如 0.0001)可能是必要的。

    # 实例化模型、损失函数和优化器
    model = lstm.LSTMModel(input_size, hidden_size, output_size, num_layers).to('cuda')  # 在GPU上训练
    criterion = nn.SmoothL1Loss()  # 均方误差损失函数
    # 回归损失函数
    # torch.nn.MSELoss 用于回归任务,计算预测值与目标值之间的均方误差。
    # torch.nn.L1Loss 用于回归任务,计算预测值与目标值之间的平均绝对误差。
    # torch.nn.SmoothL1Loss 结合了 L1Loss 和 MSELoss 的优点,对于回归任务更为稳健。

    optimizer = optim.RMSprop(model.parameters(), lr=learning_rate)
    # model.parameters(),获取模型中所有需要训练的参数(权重和偏置)
    # SGD:适合大规模数据和需要较好泛化性能的任务,可以通过调节学习率和添加动量(Momentum)来改进。
    # RMSprop:适合处理非平稳目标,可以自动调整学习率。
    # Adam:适用于大多数情况,特别是有噪声的梯度和稀疏梯度的情形。

    # 训练模型
    try:
        epoch = 0
        model.train()
        while True:
            for batch in train_loader:
                X_batch = batch['X'].unsqueeze(1).to('cuda')  # 增加序列维度
                Y_batch = batch['Y'].unsqueeze(1).to('cuda')

                # 前向传播
                outputs = model(X_batch)  # 经过LSTM层,全连接层,生成输出
                loss = criterion(outputs, Y_batch)  # 计算模型输出与目标值之间的损失

                # 反向传播及优化
                optimizer.zero_grad()  # 梯度清零,防止堆积

                # 反向传播PyTorch会自动计算损失相对于模型参数的梯度
                # 在这一步中,PyTorch会执行以下操作:
                # 从损失开始,沿计算图的反向方向计算梯度。
                # 对于LSTM层,这意味着计算损失相对于LSTM权重和偏置的梯度。LSTM层的反向传播包括计算输入门、遗忘门、输出门和候选记忆细胞的梯度。
                # 对于全连接层(Linear layer),计算损失相对于线性层权重和偏置的梯度。
                loss.backward()

                torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)  # 添加梯度裁剪,防止梯度爆炸

                # 调用优化器的step函数,使用计算得到的梯度来更新模型参数
                # 优化器会使用学习率来缩放梯度。
                # 对于每个参数,优化器会减去相应的梯度乘以学习率,从而更新参数。
                optimizer.step()

            if (epoch + 1) % 20 == 0:
                # 每20epoch使用测试集计算一次损失,并保存模型
                test_loss = evaluate_model(model, test_loader, criterion)
                print(f'Epoch [{epoch + 1}], Train Loss: {loss.item():.4f}, Test Loss: {test_loss:.4f}')
                # 保存模型
                torch.save(model.state_dict(), f'D:/WORK/lstm_model_{epoch+1}.pth')
                print(f"训练完成并保存模型(lstm_model_{epoch+1}.pth)。")
                model.train()
            else:
                print(f'Epoch [{epoch + 1}], Train Loss: {loss.item():.4f}')

            epoch += 1

    except KeyboardInterrupt:
        # ctrl+c中止训练
        print("训练已中止。")


if __name__ == "__main__":
    main()

3.4 train_and_display.py

        通过调用windows的命令提示窗口来执行训练过程

import subprocess

# 在新的命令提示符窗口中启动另一个Python脚本执行训练,并将信息显示在窗口中
subprocess.Popen(["start", "cmd", "/k", "python", "train.py"], shell=True, creationflags=subprocess.CREATE_NEW_CONSOLE)

3.5 模型训练与调参

        训练

        运行train_and_display.py后开始训练,训练过中程序每20个epoch就会输出一次测试损失并保存模型。想要结束训练按ctrl+c。

        理论上,当训练达到一定的epoch后,loss损失会趋向于一个值,或者会在这个值附件浮动。如果想要继续降低损失,就需要进行调参。当训练过多以后,测试集的loss值可能会不降反而增加,这可能是模型过拟合导致的。

        调参

        在训练的过程中,通过Loss损失的反馈,我们需要对程序内的参数进行调整来训练出更好的模型好的模型(loss更小)。

        已下参数都我根据自己需求设置的。具体每一个参数的作用,代码中对应部分都有详细的注解。

  • hidden_size(隐藏层大小):32
  • output_size(输出大小):1
  • num_layers(LSTM层数):4
  • learning_rate(学习率):0.01
  • optimizer(优化器):RMSprop
  • criterion(损失函数):SmoothL1Loss
  • batch_size(指定每个批次中包含的样本数量):32

        在调参过程中,建议每次调整只对一个参数进行。

        经过不断调参后得到的训练损失:

4.模型预测 

        predict.py

        这是一个简单的预测模块,通过手动输入预测数据,然后调用模型对这些数据进行分析最后得出预测结果。

import torch
import LSTMmodel as lstm
import load_data


def predict(model, input_data):
    model.eval()  # 将模型设置为评估模式
    with torch.no_grad():  # 使用torch.no_grad()上下文管理器来关闭梯度计算,以便在推断过程中不计算梯度。
        # 将输入数据转换为torch张量(tensor),并进行一些维度调整,最后将其移动到GPU上
        input_tensor = torch.tensor(input_data, dtype=torch.float32).unsqueeze(0).unsqueeze(1).to('cuda')
        output = model(input_tensor)  # 将输入数据传递给模型,获取输出结果
        return output.item()


def main():
    # 加载数据
    _, _, custom_dataset = load_data.load_data()

    # 构建模型,参数需要与训练的时候相同
    input_size = len(custom_dataset.X.columns)
    hidden_size = 32
    output_size = 1
    num_layers = 4
    model = lstm.LSTMModel(input_size, hidden_size, output_size, num_layers).to('cuda')

    # 加载模型
    model.load_state_dict(torch.load('D:/WORK/lstm_model_560.pth'))

    # 输入预测数据
    # 上座率(%)	场均人次	    票房占比(%)	已上映天数
    # 排片场次	排片占比(%)   当日总出票   当日总场次
    # 出品国家	电影类别1	    电影类别2	    电影类别3
    # 电影评分	男性占比(%)	女性占比(%)	节假日
    input_data = [0.015, 2.0,   0.188, 6,
                  79039, 0.190, 74.0,  37.2,
                  1,     1,     22,    0,
                  9.4,   0.314, 0.686, 13]  # 示例输入数据

    # 进行预测
    prediction = predict(model, input_data)

    print(f'模型预测今日票房结果: {prediction:.1f}万')


if __name__ == "__main__":
    main()

        预测结果

        预测6月13日《我才不要和你做朋友呢》电影的票房信息

       

        现在是6月14号,在猫眼专业版的网站上,我们可以查询到昨日的总票房

        准确率计算公式:   Accuracy=\left ( 1-\frac{|Predict-Actual|}{Actual} \right ) ,最后得出准确率大概有92%。

当然,因为只是对一个样例进行预测,所以这个结果也就是图一乐而已。

        因为精力有限,并没有对每一个样例进行详细预测。训练模型的时候训练集的特征数量也选得比较简单,所以大概能猜到最后的模型肯定还是不准的。要想提高模型的准确率,可以对训练集的特征进行特征工程,这又涉及到了很多其它知识,感兴趣的话大家可以去学习学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1822454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EndNote 专业的文献管理软件下载,强大的引用和参考文献生成功能

EndNote,它以其强大的功能和便捷的操作赢得了广大学术工作者的青睐,成为了他们不可或缺的研究助手。 EndNote软件的出现,极大地简化了学术文献的管理和组织工作。用户只需将收集到的文献导入软件,便可轻松实现对文献的分类、排序和…

【APP移动端自动化测试】第四节.元素操作的API

文章目录 前言一、点击&输入&清空操作 1.1 点击元素 1.2 输入&清空元素二、获取文本内容&位置&大小操作 2.1 获取文本内容 2.2 获取位置&大小三、根据属性名获取属性值操作四、滑动和拖拽操作 4.1 _swipe 4.2 _scroll …

20240613确认飞凌的OK3588-C的核心板的HDMI IN功能

20240613确认飞凌的OK3588-C的核心板的HDMI IN功能 2024/6/13 16:09 v4l2-ctl --list-devices v4l2-ctl --list-formats-ext -d /dev/video8 【这里必须拿到HDMI OUT机芯的分辨率。如果拿不到,肯定硬件异常/线没有接好】 v4l2-ctl -V -d /dev/video8 gst-launch-1.…

宏电“灌区哨兵”助力灌区信息化建设,开启灌区“智水”时代

灌区是保障国家粮食安全的重要水利设施。“十四五”提出,要推进大中型灌区节水改造和精细化管理。灌区信息化是建设智慧水利、深化行业监管、提升灌区科学管理水平的基础支撑,也是“十四五”期间灌区现代化改造的重点内容之一。 宏电智慧灌区信息化解决方…

探秘扩散模型:训练算法与采样算法的双重解读

很早之前就新建了一个专栏从0开始弃坑扩散模型,但发了一篇文章就没有继续这一系列,在这个AIGC的时代,于是我准备重启这个专栏。 整个专栏的学习顺序可以见这篇汇总文章 很多时候我们看到一篇文章很长,难免会心生胆怯,所以我将这些…

docker的教程长亭

把我的常用docker写在这里 之前用 vul - hub 靶场经常用 现在docker不知道为什么挂了 开启 docker-compose up -d 关闭 docker-compose down docker ps 只是运行 docker ps -a 所有 包括停止 docker ps -q 只看id docker stop <container_name_or_id> docker 的容器…

Pinia的简要概述

Pinia是专为 Vue 应用程序开发的状态管理库&#xff0c;Pinia 支持 Vue2和 Vue3。在 Vue3项目中,既可以使用传统的 Vuex实现状态管理&#xff0c;又可以使用 Pinia 实现状态管理。本章将对 Pinia的基本使用方法进行讲解。 一.Pinia 概述 Pinia 是新一代的轻量级状态管理库&…

Echarts图表实现X轴自动滚动加载数据

1.用到了Echarts图表自带的dataZoom组件 2.使用定时器定时刷新数据 效果图 关键代码 dataZoom: [{xAxisData: 0,//这里是从X轴的0刻度开始show: false,//是否显示滑动条type: slider, // 这个 dataZoom 组件是 slider 型 dataZoom 组件startValue: 0, // 从头开始。endValue:…

小程序 UI 风格,构建美妙视觉

小程序 UI 风格&#xff0c;构建美妙视觉

数据结构——队列(Queue)详解

1.队列&#xff08;Queue&#xff09; 1.1概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out)的性质 入队列&#xff1a;进行插入操作的一端称为队尾(Tail/Rear) 出…

10054 远程主机强迫关闭了一个现有的连接

在连接数据库SQLserver&#xff0c;时可能会出现如下的故障&#xff0c;特别是当操作系统是Win11时&#xff0c;在连接比较旧的版本数据库时会出现这样的问题&#xff1a;10054 远程主机强迫关闭了一个现有的连接。报错如下图所示&#xff1a; 根据微软的官方网站&#xff0c;查…

U盘文件损坏且无法读取怎么修复?五个方法帮你搞定

在现代社会&#xff0c;U盘已经是我们日常生活和工作中不可缺少的工具之一。U盘的容量大、体积小、携带方便&#xff0c;很多人都喜欢使用U盘用于个人和工作数据的存储和传输。但是&#xff0c;U盘和其他的电子设备一样&#xff0c;在试用期间有时候会出现U盘打不开提示目录结构…

jadx+android studio+雷电模拟器 动态调试apk

# 环境准备 1.雷电模拟器&#xff0c;开启root 2.jadx&#xff1a; https://sourceforge.net/projects/jadx.mirror/files/v1.5.0/jadx-gui-1.5.0-with-jre-win.zip/download 3.java jdk 11 https://www.oracle.com/cn/java/technologies/javase/jdk11-archive-downloads.…

【CT】LeetCode手撕—21. 合并两个有序链表

目录 题目1-思路2- 实现⭐21. 合并两个有序链表——题解思路 3- ACM实现 题目 原题连接&#xff1a;21. 合并两个有序链表 1-思路 双指针&#xff1a;题目提供的 list1 和 list2 就是两个双指针 通过每次移动 list1 和 list2 并判断二者的值&#xff0c;判断完成后将其 插入…

【Text2SQL 论文】CodeS:Text2SQL 领域的开源语言模型

论文&#xff1a;CodeS: Towards Building Open-source Language Models for Text-to-SQL ⭐⭐⭐⭐ arXiv:2402.16347, SIGMOD 2024 人大 Code: CodeS | GitHub 一、论文速读 本文提出一个开源的专门用于 Text2SQL 任务的 LLM —— CodeS&#xff0c;有多个参数规模的版本&…

揭秘App广告监测黑科技!Xinstall助你洞察用户行为,提升转化率!

在移动互联网时代&#xff0c;App的推广与运营已成为企业获取用户、提升品牌知名度的重要手段。然而&#xff0c;面对激烈的市场竞争&#xff0c;如何确保广告投放的精准性、提高广告效果转化率&#xff0c;成为了摆在每一位推广者面前的难题。今天&#xff0c;我们就来聊聊如何…

盘点:支持国产化信创的项目管理软件有哪些?

对于个人或者预算充足的团队来说&#xff0c;找到一个靠谱、好用的项目管理软件是一件很有必要的事情&#xff0c;那么目前国内有哪些【国产化信创】的项目管理软件值得选择呢&#xff1f; 下面盘点10款&#xff0c;每一款都独具特色。 1、国产化项目管理软件&#xff0c;可灵活…

Go微服务框架Kratos中makefile命令的使用方法及报错处理

运用 kratos 微服务框架开发项目时&#xff0c;可以使用提供的 makefile 中的命令自动且快速生产相关代码&#xff0c;提高开发效率。 krotos中makefile文件内容如下&#xff1a; GOHOSTOS:$(shell go env GOHOSTOS) GOPATH:$(shell go env GOPATH) VERSION$(shell git descri…

【讯为Linux驱动开发】6.自旋锁spinlock

【自旋锁】 线程A获取自旋锁后&#xff0c;B假如想获取自旋锁则只能原地等待&#xff0c;仍占用CPU&#xff0c;不会休眠&#xff0c;直到获取自旋锁为止。 【函数】 DEFINE SINLOCK(spinlock t lock) 定义并初始化一个变量int spin lock init(spinlock t*lock) 初始化自…

工业4.0下的PLC进化论:ARMxy计算机如何重塑自动化

智能物流系统的高效与精准成为企业竞争力的关键。在这个背景下&#xff0c;传统的PLC系统因其固有的局限性&#xff0c;如扩展性差、系统封闭等&#xff0c;开始显得力不从心。ARMxy工业计算机作为新一代的PLC替代方案&#xff0c;凭借其低功耗、高性能以及高度的灵活性&#x…