简介面向计算机相关专业毕业设计场景这份基于深度学习LSTM的英雄联盟胜率预测项目包含完整源码与文档说明覆盖数据采集、存储、预处理、模型训练、预测到页面展示的端到端流程。资源共56个文件、8.6MB以16个Python脚本为主体涵盖爬虫抓取、MongoDB存储、JSON合并、BILSTM_Att模型实现与训练、预测消费者/生产者等环节另搭配前端页面、配置文件和说明文档便于理解项目的工程组织方式。项目经过严格调试并可直接运行适合作为毕业设计、课程设计或期末大作业也能为入门深度学习的读者提供从数据处理到模型部署的完整实战范例。压缩包目录结构清晰模型权重、依赖清单、日志和前端资源分区明确已有94人学习结合文档说明可快速跑通并在此基础上做扩展。1. 把英雄联盟胜率预测做成毕设LSTM能在对局数据里学到什么英雄联盟的对局过程是一条天然的时间序列经济差、人头数、小龙、大龙、防御塔都在随时间变化前后时刻高度关联。用深度学习里的 LSTM长短期记忆网络做胜率预测通常能达到 60% 到 70% 的验证集准确率比用全场比赛平均数值喂给 MLP 的“平均值流”高出不少。这个方向之所以适合做成 Python 毕业设计是因为它把时间序列预测、特征工程、深度学习训练、模型评估四块内容都串在了一个具体场景里工作量饱满且每块都有明确产出。如果你是计算机、数据科学、人工智能方向的毕设学生或者想自己完整跑一个 LSTM 项目练手顺着这个标题做下来得到的不只是“一个能用的预测模型”还有一套带源码、带数据说明、带文档的毕业设计交付物。2. 对局数据怎么喂给 LSTM从原始特征到滑动窗口样本2.1 拿到一张对局表先想清楚预测对象是什么做胜率预测第一步不是写模型而是把“预测什么”定义清楚。常见的做法是把一场比赛切成多个时间切片每两分钟记录一次当前的状态特征然后让模型根据前 N 个切片的状态预测这局游戏的最终胜负。以蓝色方视角为例一个典型的时间切片特征向量长这样# 单条对局记录示例单位分钟 [ 5.0, # 游戏进行到第 5 分钟 3, # 蓝色方总击杀数 1, # 蓝色方总死亡数 2, # 蓝色方总助攻数 850, # 蓝色方团队经济百为单位即 850*100 金币 1, # 蓝色方推掉的防御塔数 0, # 蓝色方拿到的峡谷先锋数 1, # 蓝色方拿到的元素龙数 0, # 蓝色方是否拿到大龙0/1 1 # 本局最终结果蓝色方胜利 1失败 0标签 ]特征未必需要太多核心是“团队视角 随时间变化”。如果拿的是选手个人数据还要按队伍聚合如果自定义特征建议起步阶段控制在 8 到 12 维方便后面做特征重要性分析。拿到数据之后先按game_id 时间切片的顺序排序然后检查时间点是否对齐。很多公开数据集的原始 CSV 里不同场次的时间戳是错开的有的从 1 分钟开始记录有的从 3 分钟开始。我一般会先用df.groupby(game_id)看一眼每局的行数和时间分布行数不齐的就先按时间重采样。2.2 滑动窗口切序列为什么单条样本进不了 LSTMLSTM 接收的是“一段序列”不是“一行记录”。如果用第 5 分钟的单个切片去预测整局胜负信息量明显不够但如果用整局从第 1 分钟到第 30 分钟的全部切片去预测模型偷看到了最后的态势实战意义又消失了。中间态的做法是滑动窗口切样本把最近 K 个时间切片拼成一条输入序列。import numpy as np def make_sequences(features, labels, window_size5, step2): 把 (N, n_features) 的对局记录切成长度为 window_size 的序列样本。 features形状 (N, n_features)要求已经按 game_id 和时间排序。 labels形状 (N,)每条时间切片对应的本局最终胜负标签。 step相邻两个样本之间的步长控制样本密度。 sequences, seq_labels [], [] i 0 while i window_size len(features): sequences.append(features[i:i window_size]) # 取窗口内最后一条切片的标签作为该窗口的胜负标签 seq_labels.append(labels[i window_size - 1]) i step return np.stack(sequences), np.array(seq_labels)这段代码的核心逻辑有三个。第一窗口window_size5意味着模型每次看最近 5 个时间切片通常对应 10 分钟游戏进程第二step2是为了让相邻窗口有重叠扩充样本量第三标签取窗口最后一条切片的标签也就是这场游戏最终的胜负。如果一条对局有 20 个时间切片window_size5、step2可以切出 8 个左右的窗口样本对于上千场对局来说样本量完全够 LSTM 训练。窗口大小是最值得调的参数之一。窗口太小模型只看到最近几分钟的态势容易把前期优势当结果窗口太大比如把整局都包进去又会出现“上帝视角”问题。毕设场景里我一般建议先定 5 或 6等模型跑通后再试 3 和 10 做对比分析。2.3 特征归一化与训练/验证集切分LSTM 最敏感的两件事LSTM 内部的激活函数是 tanh 和 sigmoid输入数值过大或过小梯度都会出问题。做归一化时不能只对每个特征列单独归一化还要考虑“时间切片之间”的先后关系。常见做法是先在全体训练数据上计算每个特征列的均值和标准差然后用这组统计量同时去归一化训练集、验证集和测试集。from sklearn.preprocessing import StandardScaler # 假设 train_seqs 是切好并展平后的训练窗口形状 (num_samples, window_size, n_features) num_samples, window_size, n_features train_seqs.shape train_flat train_seqs.reshape(-1, n_features) scaler StandardScaler() scaler.fit(train_flat) # 只 fit 训练集的统计量 def normalize_seq(seqs): flat seqs.reshape(-1, n_features) flat_scaled scaler.transform(flat) return flat_scaled.reshape(seqs.shape) train_seqs_norm normalize_seq(train_seqs) val_seqs_norm normalize_seq(val_seqs) test_seqs_norm normalize_seq(test_seqs)这段代码的关键点有两个。一是fit只放在训练集上防止验证集的信息泄漏到训练过程这一点很多初学者会漏二是 reshape 回原形状时窗口的先后顺序不能乱否则会出现“跨窗口混特征”的问题。训练/验证集的划分不能随机打乱后切分。同一局游戏切出来的多个窗口样本高度相关如果一部分窗口进了训练集、另一部分进了验证集验证准确率会虚高到 80% 以上。正确做法是按game_id分组切分比如前 80% 的场次作为训练集剩下 20% 的场次作为验证集。3. 用 PyTorch 搭一个能跑的 LSTM 二分类模型3.1 定义模型input_size、hidden_size、num_layers 怎么给模型定义是整个项目里最有“工作量感”的部分。用 PyTorch 实现一个单隐藏层 LSTM再在后接两层全连接代码量不大但每个参数都要对着数据形状来给。import torch import torch.nn as nn class MatchLSTM(nn.Module): def __init__(self, input_size, hidden_size64, num_layers1, dropout0.2): super(MatchLSTM, self).__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropoutdropout if num_layers 1 else 0.0 ) self.fc1 nn.Linear(hidden_size, 32) self.fc2 nn.Linear(32, 1) self.dropout nn.Dropout(dropout) self.relu nn.ReLU() def forward(self, x): # x: (batch_size, window_size, n_features) lstm_out, _ self.lstm(x) # 返回每个时间步的输出和隐层状态 # 取最后一个时间步的输出形状 (batch_size, hidden_size) last_out lstm_out[:, -1, :] out self.dropout(self.relu(self.fc1(last_out))) out self.fc2(out) return out.squeeze(-1) # 输出形状 (batch_size,)模型结构里需要注意三个点。第一batch_firstTrue让输入张量的第一维是 batchPyTorch 默认是第二维是 batch经常有人在这里翻车喂进去直接报形状错误第二lstm_out[:, -1, :]表示取最后一个时间步的输出作为整条序列的语义表示这是序列分类任务的标准做法比取隐层状态h_n更直观第三模型的最终输出是一个标量 logit不是 0/1 概率后面接BCEWithLogitsLoss时不需要手动加 sigmoid。hidden_size是 LSTM 记忆容量毕设项目 64 起步完全够调大不一定会带来明显提升num_layers层数超过 2 之后训练难度会明显上升数据量不够的时候更倾向于过拟合。所以这里默认值给的是 1 层、64 个隐藏单元。3.2 训练循环与 BCEWithLogitsLoss分类被当成回归就翻车胜率预测是二分类问题标签是 0 或 1但很多人会顺手用 MSELoss 当损失函数做出来之后预测值永远在 0.5 附近浮动。正确做法是用带 logits 的二元交叉熵损失import torch.optim as optim def train_one_epoch(model, dataloader, optimizer, criterion, device): model.train() total_loss, total_correct, total_samples 0.0, 0, 0 for batch_x, batch_y in dataloader: batch_x batch_x.to(device) batch_y batch_y.to(device).float() optimizer.zero_grad() logits model(batch_x) # (batch_size,) loss criterion(logits, batch_y) # BCEWithLogitsLoss loss.backward() optimizer.step() preds (torch.sigmoid(logits) 0.5).long() total_loss loss.item() * batch_x.size(0) total_correct (preds batch_y.long()).sum().item() total_samples batch_x.size(0) return total_loss / total_samples, total_correct / total_samples训练函数的几个细节值得展开。criterion用nn.BCEWithLogitsLoss()它把 sigmoid 和交叉熵合成一步计算数值上比“先 sigmoid 再 BCE”更稳定。batch_y需要转成 float因为 BCE loss 要求标签和 logits 同类型。torch.sigmoid(logits) 0.5是把 logit 转成预测类别0.5 这个阈值在正负样本不均衡时可能需要调整。数据加载部分用 PyTorch 的TensorDataset和DataLoader包一层from torch.utils.data import TensorDataset, DataLoader train_dataset TensorDataset( torch.tensor(train_seqs_norm, dtypetorch.float32), torch.tensor(train_labels, dtypetorch.float32) ) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue)batch_size64通常是个稳妥的起点显存占用不高收敛也平稳。如果训练集很大可以提高到 128过小比如 16会让 loss 曲线剧烈震荡。3.3 保存最佳权重毕设最常用的 Checkpoint 写法训练过程中验证集准确率不是单调上升的后面几个 epoch 往往会震荡甚至回退。所以最佳策略不是拿最后一轮模型而是每轮跑完验证集只要指标变好就把权重存下来。best_val_acc 0.0 best_epoch -1 for epoch in range(epochs): train_loss, train_acc train_one_epoch(model, train_loader, optimizer, criterion, device) val_loss, val_acc evaluate(model, val_loader, criterion, device) if val_acc best_val_acc: best_val_acc val_acc best_epoch epoch torch.save({ epoch: epoch, model_state_dict: model.state_dict(), optimizer_state_dict: optimizer.state_dict(), val_acc: val_acc }, best_model.pt) print(fEpoch {epoch1}/{epochs} | train loss {train_loss:.4f} | train acc {train_acc:.4f} | val acc {val_acc:.4f})把optimizer_state_dict也存进去是为了以后想从这个断点继续训练时不用重新构建优化器状态。毕设答辩或者写文档时这组 checkpoint 可以直接用来分析“模型在第几个 epoch 取得最佳结果”比只存权重更有说服力。4. 训练与调参让验证集准确率从 55% 到 68%4.1 八个关键超参数对照表与启动值LSTM 项目的调参最先盯住的不是学习率而是“窗口大小”和“隐藏单元数”。下表是我实际调这个方向时习惯的启动值和调整顺序参数启动值调整顺序调参说明window_size51太小丢上下文太大引入上帝视角按特征采样间隔定hidden_size642数据量小几千样本不建议直接上 128num_layers13数据量不够时2 层以上极易过拟合batch_size644训练不稳就降到 32训练太慢就加到 128learning_rate0.0015使用 Adam 时0.001 是通用起点dropout0.26过拟合时建议直接调到 0.4 观察epochs307每 5 轮看一次验证曲线不一定要跑到 30weight_decay1e-48验证集准确率上不去且训练集已经 90% 时再加调参顺序的核心逻辑是先改“数据形状相关”的参数窗口大小再改“模型容量”的参数隐藏单元和层数最后才动优化器相关参数。一上来就折腾学习率常常会掩盖结构问题。4.2 训练曲线怎么看过拟合和欠拟合在 loss 图上的长相LSTM 训练很容易出现过拟合因为数据本质上是“同局不同窗口”样本冗余度很高。判断过拟合不能只看训练集准确率要看训练损失和验证损失的差距是不是持续扩大。典型场景是前 5 个 epoch 两边都在下降第 8 个 epoch 之后训练损失继续降、验证损失开始回升。这时候当前权重已经不是最佳状态但仍能观察到模型在学习——学习的是训练局里的噪声。解决办法按优先级排第一把 dropout 从 0.2 调到 0.4第二加weight_decay1e-4第三把num_layers退回到 1 层第四检查验证集切分是不是混入了同一场对局的多个窗口。还有一种翻车情况是欠拟合验证集准确率长期低于 55%训练集也只有 60% 上下。这往往不是模型问题而是特征本身不够强。建议先回到数据层确认特征是不是真的随时间变化、窗口切片是不是有空值或者前 10 个时间切片的特征是否能区分胜负。特征工程补强比调模型参数有效得多。4.3 用 AUC 代替准确率当最终指标才不会被阈值骗到在正负样本刚好各占一半的数据集里准确率没什么大问题。但英雄联盟对局数据经过滑动窗口切分后优势方的样本天然更多最终标签分布可能偏向某一类。这时候 65% 的准确率到底是真的预测能力强还是模型在无脑输出优势类很难看出来。from sklearn.metrics import roc_auc_score def evaluate_auc(model, dataloader, device): model.eval() all_labels [] all_probs [] with torch.no_grad(): for batch_x, batch_y in dataloader: batch_x batch_x.to(device) logits model(batch_x) probs torch.sigmoid(logits).cpu().numpy() all_probs.extend(probs) all_labels.extend(batch_y.numpy()) return roc_auc_score(all_labels, all_probs)AUC 的含义是“随机抽一个正样本和一个负样本模型给正样本打更高分的概率”它不依赖阈值选择能更真实地反映模型排序能力。毕设里如果准确率 68%、AUC 0.74这个组合比准确率 72%、AUC 0.60 更有说服力。调参时优先盯 AUC最后再按 0.5 的阈值去报告准确率、精确率、召回率和 F1这样整套指标体系是完整的。5. 避坑记录把 LSTM 上手时踩过的坑按现象、原因、解决列清楚5.1 验证集准确率 95%一上真实场景就废数据泄漏是最常见的翻车现象训练完的模型在验证集上准确率高达 90% 以上兴奋地拿去预测新对局的前 10 分钟数据结果预测结果几乎等于随机。原因这是典型的“上帝视角”数据泄漏。常见泄漏源有两个。第一特征里混入了整场比赛结束后才能统计到的数据比如“整场总经济”“最终击杀数”这些信息在一个时间切片的特征里其实包含了全局信息第二验证集的切分没有按game_id分组同一局游戏切出来的窗口一部分在训练集一部分在验证集模型等于直接见过了答案。解决清洗特征时凡是涉及“整场”“最终”的字段全部去掉只保留“截至当前时刻的累计值”。验证集切分必须按game_id分层保证同一局的所有窗口只出现在同一侧。做完这两步验证集准确率会跌到 60% 上下这才是真实水平。5.2 训练到一半 loss 变成 NaN特征没归一化或梯度爆炸现象训练前几个 batch 正常随后loss突然变成nan准确率也跟着显示 0。原因LSTM 对输入尺度极其敏感。如果某个特征比如团队经济数值范围是 0 到几万而另一个特征是否拿大龙只有 0 和 1LSTM 的输入门和遗忘门会瞬间进入饱和区反向传播时梯度要么消失要么爆炸。另一个可能原因是学习率过大Adam 在初始阶段的二阶动量估计不够稳定也会放大梯度。解决先检查输入张量的数值范围确认每个特征都经过 StandardScaler 归一化而不是只做了 min-max 缩放。然后把学习率从 0.001 降到 0.0003并在clip_grad_norm_(model.parameters(), max_norm1.0)加一道梯度裁剪。两件事都做基本上能解决 NaN 问题。5.3 正负样本不均衡模型变成“无脑预测优势方”现象训练结束时准确率 65%看起来不错但打印分类报告发现负类劣势方获胜的召回率只有 0.1模型几乎把所有样本都判成正类。原因滑动窗口切分制造了大量“优势方视角”的样本。前二十分钟经济领先的队伍获胜概率超过 70%这样切出来的窗口正样本比例可能达到 75% 以上。模型学到的最优策略就是全部预测正类。解决一种办法是在DataLoader里做加权采样让正负样本在每个 batch 里大致平衡另一种更推荐的做法是调整决策阈值——在训练结束后遍历 0.3 到 0.7 之间的若干阈值选能在验证集上让 F1 最高的阈值作为最终分类边界。AUC 不需要重算因为 AUC 本身与阈值无关。5.4 同一场对局的窗口挤进同一个 batch验证指标一路虚高现象验证集准确率比测试集高出一大截而且每次运行结果波动极大。原因窗口重叠的样本之间不是独立的。相邻窗口共享了大量时间切片数据把它们同时放进训练集和验证集相当于考试前看了答案即使在验证集内部同局的几十个窗口也让评估结果严重偏向某些特定对局。解决切分数据时先用game_id.unique()把对局编号列表打乱再按比例切分切窗口的动作应在划分之后执行不能先切好窗口再随机划分。这样能确保验证集里出现的全是“没见过的对局”结果才接近真实预测场景。6. 把毕设做漂亮用对照实验证明“序列信息”真的有用很多毕设评审老师会问一个问题你用了 LSTM那么 LSTM 到底比普通模型强在哪要回答好这个问题得做一个“均值特征 MLP 对照实验”而不是只展示 LSTM 的准确率数字。具体做法是把每个窗口的 5 个时间切片取平均得到一条(batch_size, n_features)的普通特征向量然后用两层的全连接网络训练一个二分类模型最后把 MLP 的验证集 AUC 与 LSTM 的验证集 AUC 放到同一张表格里。# 对照模型用窗口均值特征替代序列输入 mean_features train_seqs_norm.mean(axis1) # (num_samples, n_features) val_mean_features val_seqs_norm.mean(axis1) # 训练一个简单 MLP2 层全连接 ReLU class BaselineMLP(nn.Module): def __init__(self, input_size): super().__init__() self.net nn.Sequential( nn.Linear(input_size, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): return self.net(x).squeeze(-1)对比结果如果显示 LSTM 的 AUC 比均值 MLP 高 0.05 到 0.1就说明“随时间变化的态势走向”确实比“一局的平均状态”更能预示胜负LSTM 的序列建模能力就有了直接证据。如果两者差不多说明你的预测信息主要藏在特征本身而不是时序变化里这时候可以换window_size或者挑一些连续变化特征重新做对比。最后一章落到这里是想说一个习惯我接手任何 LSTM 项目都会至少做一个非序列基线否则调出来的参数很难判断是“模型的功劳”还是“数据的功劳”。做毕业设计更该如此——对照组不复杂却能让整篇文档的论证站稳。希望这些步骤和踩坑记录能帮你在自己的数据上顺利跑通。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
本地部署 AI 小说生成器:3 步跑通多章节长篇小说自动写作 本地部署 AI 小说生成器:3 步跑通多章节长篇小说自动写作 【免费下载链接】AI_NovelGenerator 使用ai生成多章节的长篇小说,自动衔接上下文、伏笔 项目地址: https://gitcode.com/GitHub_Trending/ai/AI_NovelGenerator
AI_NovelGenerator 用大模型生成多章节… · 2026/9/26 2:15:15
Tutanota IPC 跨平台通信编译器 licc 详解:从 JSON Schema 到多语言代码自动生成 协同办公密码学 【免费下载链接】tutanota Tuta is an email service with a strong focus on security and privacy that lets you encrypt emails, contacts and calendar entries on all your devices. 项目地址: https://gitcode.com/gh_mirrors/tu/tutanota 点… · 2026/9/26 2:15:09
@ariakit/solid-store 完全指南:Ariakit 的 Solid 状态原语 API 与实现原理 UI组件前端 【免费下载链接】ariakit Toolkit with accessible components, styles, and examples for your next web app 项目地址: https://gitcode.com/gh_mirrors/ar/ariakit 点击查看 免费下载 导读
ariakit/solid-store 是 Ariakit 在 Solid 生态侧的"… · 2026/9/26 2:15:09
LabVIEW数据采集与趋势分析VI设计实战与避坑指南 做LabVIEW这几年,我见过太多人把“数据采集与变化趋势分析VI”想得太简单:以为拖一个波形图表控件、接上驱动跑起来,能看到曲线就算完事。结果一到现场就现原形——界面卡死、数据丢帧、曲线毛刺多得像心电图、程序打包到别的电脑直接打不开。… · 2026/9/26 3:25:12
NodeWarden 附件与 Send 文件分享指南:R2 与 KV 双模式、大小上限与一次性令牌安全 NodeWarden 附件与 Send 文件分享指南:R2 与 KV 双模式、大小上限与一次性令牌安全 【免费下载链接】nodewarden Bitwarden-compatible server running on Cloudflare Workers 项目地址: https://gitcode.com/gh_mirrors/no/nodewarden
NodeWarden 是一个运行… · 2026/9/26 3:25:12
AI Agent Harness故障演练方案:用TaoToken统一Key跑通混沌工程容错验证 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 3:25:12
2025亲测10款免费AI写小说工具:TaoToken统一Key接入DeepSeek/Kimi/豆包配置指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 3:25:12
大模型之Linux服务器部署大模型扒:TaoToken统一Key接入Cline的config.json骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 3:25:12
零碳工厂建设指南:从碳盘查到认证的全流程实操 最近有几个做制造业的朋友陆续来问我同一个问题:“零碳工厂要怎么建,指导意见里到底说了什么?”问的人多了,我发现大家其实卡在同一个地方——概念太多、文件太散、落地路径不清晰,很多人看完还是一头雾水。这篇我就用… · 2026/9/26 3:25:05
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46