新闻详情

新闻详情

首页 / 资讯中心 / 详情

交通流量预测毕设实战:LSTM模型调试与数据预处理避坑指南

发布时间:2026/9/28 14:08:56来源:尧图网络
交通流量预测毕设实战:LSTM模型调试与数据预处理避坑指南
这篇毕设日志写在2026年1月9日周五也是我进入寒假集中攻坚的第七天。学校要求的中期检查还有三周交初稿还有不到两个月而我手里这个交通流量预测项目还停在数据看着还行、模型完全没跑通的状态。写这篇日志不是做样子而是真的需要把自己这一天做过的事、走过的弯路、花掉的每一小时都摊开来看一遍不然我根本说不清楚时间到底去哪儿了。这篇日志不只是一篇流水账我还会把今天踩过的一个数据预处理坑、一个模型训练崩溃的排查过程、以及晚上复盘时意识到的时间管理问题全部记录下来。如果你也在寒假赶毕设或者正在面对差不多的看起来简单、跑起来全是事的项目这篇日志应该能帮你在同样的坑前面停下来。1. 为什么我把1月9日当成一个需要专门记录的时间节点1.1 这个日期在毕设时间线里的特殊位置1月9日既不是开题节点也不是中期截止表面上看只是寒假里普通的一天。但把时间倒推一下就明白了大多数学校会在3月上旬做中期检查4月底到5月初统一盲审和答辩。也就是说春节前这段时间是唯一一段没有课上、没有实习、没有老师随时催的相对完整时间块。一旦过了春节走亲戚、返校、补材料这类杂事会立刻把你的时间打碎。所以我在元旦之后就给自己定了死规矩春节前必须跑通核心模型、画出第一版有说服力的结果图假期结束前把毕业论文的前三章写出来。今天我做的所有任务都是围绕这个倒推结果展开的。这也是我建议所有正在做毕设的人先做的事不需要列什么宏大的甘特图你只需要问自己一句离下一个硬节点还有几周在这之前必须拿出什么结果。然后从那个结果往前倒推每天该做什么自然就清楚了。1.2 毕设日志到底该记什么很多人写的日志是今天做了什么明天要做什么两行字这种日志对推进项目没有任何帮助。我试了两周之后把日志模板改成了下面这套固定结构效果立刻不一样了今天的主目标是什么验收标准是什么实际完成了什么和主目标的偏差在哪里遇到的最大卡点是什么卡了多长时间这个卡点的技术细节、排查过程、最终解决方案明天最小可执行目标必须小到不可能完不成这套结构的核心逻辑是日志不只是记录更是帮助你识别时间黑洞的工具。如果你连自己卡在哪里、卡了多久都不清楚后面谈优化节奏就是空谈。1.3 今天的主目标与验收标准我给自己今天定的主目标是完成数据预处理、构造训练窗口跑通一个简单的历史均值基线模型。验收标准很简单能输出未来一小时流量的预测结果图算出MAE和RMSE数值。这个目标看起来不大但要在一天内扎实做完实际上包含了一长串子任务清洗原始数据、处理缺失值和异常值、构造小时和星期特征、划分训练验证测试集、确定窗口长度、写滑窗函数、跑基线模型、保存评估指标。任何一个环节出问题一天时间根本不够用。后来的事实也证明光是数据预处理这一环我就翻了一次车。2. 上午的预处理我不想再经历第二次的切窗翻车2.1 数据处理前的准备工作我的毕设题目是基于深度学习的城市交通流量预测系统用的是一份公开的城市路段流量监测数据字段不算复杂核心就是时间戳、路段编号、车流量外加上天气和温度这类辅助信息。原始数据长这样字段示例说明datetime2025-11-03 07:00:00每15分钟一条记录segment_idS-1024路段编号flow356车流量辆/15minweather1编码后的天气类型temp12.5摄氏温度第一步是检查数据字典和数据大小。这个数据大概有几十万行时间跨度三个月目标路段有十几条。我没有一上来就写模型代码而是先在Jupyter里做了几件看起来很基础的事看每个字段有没有空值、看时间戳是否连续、看flow的取值分布有没有明显异常。这一步千万别跳过去。很多项目做不下去不是模型不行是数据里藏着一堆脏东西等你把数据喂进神经网络时它就变成各种莫名其妙的错误炸给你看。2.2 缺失值处理里的细节流量数据有一个典型特点偶尔会有某一整段监测设备离线导致某个时段的数据整段缺失而不是零散的单个空值。我统计了一下大概有0.3%的缺失率听起来不多但分布很不均匀有一段连续缺了4个小时。处理方式我用了插值法而不是直接删除。# 对缺失的流量字段做时间插值 df[flow] df[flow].interpolate(methodtime) # 经过插值后再做一次后向填充兜底 df[flow] df[flow].fillna(methodbfill)interpolate(methodtime)会按时间间隔线性插值对于一段连续的小缺失比较合适。如果缺失段太长比如超过一天我觉得就不要插值了直接标记为缺失或者从训练集里排除更稳妥否则模型容易被一段人为制造的平滑数据带偏。2.3 真正的翻车点滑窗切分的索引问题白天的第一场翻车发生在一个看起来特别不起眼的小操作上。我要构造时间序列模型的训练样本也就是用过去24个时间点预测未来1个时间点所以我写了这样一个滑窗函数def make_window(df, inputs, label, window24): X, y [], [] for i in range(window, len(df)): # 错误示范直接拿loc标签切 x df.loc[i - window 1 : i, inputs] y df.loc[i, label] X.append(x.values) y_list.append(y) return np.array(X), np.array(y)如果你只看代码逻辑会觉得没问题啊就是从i-23到i取24行。问题出在df的索引上。我最初导入数据后把datetime设置成了索引这个索引是时间戳且原始数据里有重复时间、有缺失时间。此时df.loc[i - window 1 : i]去切的是标签而不是行位置。一旦中间的时间戳不连续这里切出来的窗口要么少了行要么多串了别的时段的记录。这个Bug不报错但会让模型的输入数据逐步错位表现为训练结果忽好忽坏、不可复现。排查它的过程特别恶心因为它不崩只是悄悄地错。正确的做法是先把索引重置成纯整数位置然后严格按照位置切# 正确示范重置索引后按位置切排除一切标签歧义 df df.reset_index(dropTrue) def make_window(df, inputs, label, window24): X, y [], [] for i in range(window, len(df)): x df.iloc[i - window 1 : i 1][inputs] X.append(x.values) y.append(df.iloc[i][label]) return np.array(X), np.array(y)注意这里同时改了两个地方一是切分范围变成i - window 1 : i 1包含当前时刻的前后关系才正确二是loc换成了iloc避免索引标签干扰。我现在回想如果最开始就把所有滑窗操作一律用iloc所有需要对齐时间戳的操作再用标签索引当成纪律这一步根本不会浪费我两个多小时。这也是日志的作用——让你下一次不再掉进同一个坑。2.4 归一化顺序一个容易导致数据泄漏的隐藏坑预处理里还有个隐藏很深的坑归一化到底应该在全量数据上做还是分开在训练、验证、测试集上做很多人图省事直接对整个DataFrame做MinMaxScaler我一开始也是。问题在于测试集的信息在训练时被偷看了这在时间序列预测里是严重的数据泄漏。虽然有论文说最后结果可能只是略微乐观但对于毕设来讲答辩老师只要一问你的归一化是fit在全量数据上的吗这个问题就足以让你背脊发凉。类比一下就是你先看了考试答案再去做题分数再高也不能说明你学会了。正确的做法是只对训练集做fit然后用同一个scaler去transform验证集和测试集from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() train_len len(train_df) scaler.fit(train_df[feature_cols]) # 只统计训练集的范围 train_scaled scaler.transform(train_df[feature_cols]) val_scaled scaler.transform(val_df[feature_cols]) test_scaled scaler.transform(test_df[feature_cols])我自己是先做了全量归一化后来重新看的时候才惊觉这个问题。这也是为什么我强调先想清楚预测目标和数据划分方式再写一行处理代码。不然回头修改工作量的成本远远超过开始前多花10分钟设计。3. 下午模型的loss变成NaN我的完整排查链路3.1 现象训练到第二个epoch直接崩溃下午两点半我把数据预处理完写了一个非常基础的三层LSTM模型准备先热热身。结果训练刚开始第一个epoch的loss已经从几千降到几百看起来一切正常第二个epoch开始后loss突然变成nan程序没有立即崩溃但随着epoch推进所有指标都变成了nan。到第三个epoch验证集loss直接爆出了一个巨大值。很多人看到NaN第一反应是学习率太大。我之前也这么觉得于是把学习率从0.001降到0.0001重新跑了一遍。结果是loss稳定了几个epoch然后再次爆掉。这说明问题不在单纯的学习率上。3.2 逐步排查的过程我决定不靠猜而是列了一个表格把每一个嫌疑点按顺序排查排查角度我当时做了什么结果结论学习率从0.001降到0.0001症状缓解但依然复现学习率不是根因数据中含有NaN检查全量DataFrame各列的isna情况没有发现NaN排除数据问题标签取值异常打印y的分布流量最大值在正常范围排除标签爆点梯度异常加入clip_grad_norm_依旧NaN说明梯度并非唯一元凶输入窗口数据错位打印第一个batch的实际张量发现窗口里混入大量0值找到根本原因真正的问题出现在最后一行。我打印了一个batch出来看发现有些窗口的数据几乎是空的也就是全0。为什么会出现全0因为之前我在做日周期特征时用shift(24)构造了一条前一天同一时刻的流量作为特征而这条特征在每天开头若干行必然为空。我用fillna(0)填充后那些0值就被当成正常数据送进了模型。本来这并不是致命问题因为0值是合理的填充策略。但问题在于我构造窗口时踩了上午那个错位索引的坑导致有些窗口里恰好包含了大量前一天的填充0却没有包含真正有效的近期流量。LSTM一看到这种输入自然算不出有效梯度loss就爆掉了。3.3 修复与最终结果找到根因后修复就快了。我把滑窗函数统一改成按位置的iloc切分并且把填充0的那一列特征在验证集和测试集上也做了同样的对齐填充保证训练和预测时的输入分布一致。同时顺手将学习率设为0.0005用Adam优化器重新跑。这次没有再出现NaN模型的loss在前10个epoch里平滑下降。等跑完20个epoch我在测试集上得到了历史均值基线外的第一份真实预测结果模型MAERMSE历史均值基线46.367.8三层LSTM31.248.5虽然优化空间还很大但至少证明整个流程是通的。这个阶段意义重大一旦有了能跑通的最小结果后面的所有改进都是增量优化而不需要再去担心整套代码能不能运行。3.4 一个后悔没早做的操作先跑简单基线今天这个下午的教训让我特别想对所有做毕设的人说一句不管你的题目听起来多高级第一步永远是跑最简单的基线模型。历史均值、线性回归、ARIMA都行哪个简单用哪个。为什么因为基线模型能帮你验证你的数据、切分、评估代码是不是对的。如果你的数据或窗口有问题线性回归早就炸了根本不需要等LSTM跑到NaN。我这次就是跳过了基线的校准步骤直接冲LSTM结果把大量时间花在了是模型问题还是数据问题的无差别排查上。4. 晚上复盘真正让我进度落后的三个坏习惯4.1 把时间轴摊开看才发现差距在哪晚上吃完饭我把今天的时间消耗整理成了一张表对比原定计划和实际情况。时间段原计划实际情况偏差原因8:00-9:00起床洗漱9:05才起熬夜看文献第二天起不来9:30-11:30数据预处理10:20才开始中间看手机3次拖延和任务切换13:30-15:30跑模型从14:30跑到16:30故障排查跳过基线直接上LSTM19:30-22:30调参与画图21:00才开始写日志对收尾工作严重低估说实话看到这张表的时候我很不好意思。有效工作时间比我以为的要少得多中间全是切换和重新进入状态的时间。比如每次从浏览器切回代码编辑器我都要花几分钟回忆刚才写到哪一行。一天下来这种切换浪费至少一小时。4.2 最致命的坏习惯一任务切换太频繁我今天干了这样几件事查邮件、看一篇新文献、改数据脚本、又切去写论文引言、再回来跑模型。每次切换看起来都很合理但代价是大脑需要重新加载上下文。写代码尤其明显如果中途切去查文献回来至少要花一刻钟才能重新进入数据流。我现在立了一个规矩把每天的工作块切成至少一个小时的完整时间片一个时间片只做一件事。文献就集中看代码就集中写论文就集中写禁止在代码时间片里开浏览器查文献。4.3 最致命的坏习惯二低估环境成本今天下午的一小时其实耗在了配置PyTorch的CUDA环境上。我之前以为装好了环境就不会有环境问题结果一跑就发现GPU显存不足又换CPU跑然后又遇到版本不一致导致的兼容报错。这就是典型的环境成本低估。在开始写模型之前应该先做一个空跑测试创建一个极小的虚拟数据比如100条从DataLoader到模型forward到loss.backward完整走一遍。走通了再放大数据量。这个习惯初期看起来是浪费时间实际上能省下成倍的时间。4.4 复盘模板晚上十分钟搞定为了方便每天坚持我把复盘模板固定成三个问题不超过十分钟就能写完今天的主线是推进了什么成果能否被验证哪个决策花了最久这个决策当初的证据是否充分明天最小的可执行目标是什么第一步打开电脑做什么这三个问题不要求你写长篇大论但必须写得具体。我举个例子今天我的最小可执行目标就是跑通一个带验证集的完整训练流程画出第一张预测曲线图。明天我一打开电脑就知道干什么不需要再花半小时思考接下来该干嘛。5. 从一天的日记里提炼出可复用的毕设推进方法5.1 数据预处理先想清楚预测目标再动手构造特征今天踩的所有坑归根结底是同一个问题我太着急处理数据而没想清楚这些数据到底要解决什么。做时间序列预测第一件事不是想着什么特征能提升精度而是明确预测目标、历史窗口、未来窗口、特征与标签的时间对齐方式。这四个东西没想清楚后面每一行代码都可能埋雷。具体到操作我建议动手前先写一段中文说明书用过去几天的流量、天气、时间属性预测未来哪个时刻的流量哪些字段在预测时是已知的哪些是未知的。这一步写清楚归一化、切窗、防泄漏都不会乱。5.2 实验管理固定随机种子和运行环境今天的NaN排查里有一个差点误导我的现象第一次跑出来结果还行第二次跑就崩了。我用的是PyTorch如果不固定随机种子每次结果都会有一点差异。如果环境还不稳定就很难判断崩溃是数据问题还是随机性导致的问题。建议从第一天开始就在代码里固定种子import random import numpy as np import torch def set_seed(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False另外强烈建议把Python包版本记录在一个requirements.txt里尤其是pandas、numpy、sklearn、torch这四件套。你会发现过两周你自己回来看代码如果环境变了跑出来的结果对不上你会无比崩溃。5.3 一天只定一个主目标今天的教训里最让我印象深刻的并不是技术问题而是一天定太多目标结果一个都没做完。我早上列了四件事预处理、跑基线、跑LSTM、写论文引言。结果到最后论文引言一个字的没写LSTM刚刚跑通基线结果还是顺带出的。如果让我重新计划今天我会砍掉写论文这一项把省下的时间用来认真记录实验参数和多跑几个对照实验。做毕设和写流水账不一样不是做了很多事就有价值而是关键事做不做才有意义。我的个人建议是给每天定唯一一个非完成不可的主目标其他任务都算加分项。主目标一定要小到可以在六小时内做完否则它就不是日目标而是一周目标。5.4 用文件夹和命名规则让日志变成论文素材库写日志这件事还有一个容易被忽略的价值它就是你写毕业论文时的第一手素材。如果只是把日志写在社交平台上、写在朋友圈里后面查找会很麻烦。我现在把日志存在项目目录下的notes/文件夹里用统一的命名规则2026-01-09-data-preprocessing-window-bug.md 2026-01-10-baseline-and-lstm-first-run.md文件名包含日期和当天的核心主题搜索起来非常方便。到了写论文实验与方法章节的时候直接把这些日志翻出来按日期排好就是最完整的时间线素材。我甚至不需要再去回忆当时是怎么做的日志里已经有完整排查路径了。另外我还会把重要实验的配置文件也放在每个日期目录下形成一个可追溯的实验文件。比如今天的滑窗修复我就单独存了一份make_window_correct.py上面注释写了为什么不能用loc切。下次如果有人问起这个问题我直接把这个文件翻出来讲就行。5.5 心态上的最后一点体会这篇日志写到最后我想多啰嗦一句。毕设过程中最磨人的往往不是技术难度而是看不到尽头的焦虑。1月9日这一天我的模型从崩溃到跑通总共花了六个小时而这六个小时里有将近一半是被自己制造的坑消耗掉的。但反过来想这些坑恰恰是毕设最值钱的地方。答辩时打动老师的往往不是你的模型有多先进而是你对问题边界的理解、对失败原因的分析、对方案取舍的解释——这些内容全部长在你自己踩过的坑里。日志就是帮你在三个月后还能翻出来这些细节的工具。今天写到这儿我已经完全清楚明天打开电脑的第一步是什么跑一次完整的训练-验证-测试流程把全量数据的结果图和误差指标画出来。就这一件事做完就算赢。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

DSP28377D启动流程全解析:从POR到main的七步硬件-固件链 2026/9/28 16:07:20

DSP28377D启动流程全解析:从POR到main的七步硬件-固件链

1. 这不是教科书里的启动流程,而是我在TI C2000产线踩了三个月坑后画出的真实路径图你手头那块DSP28377D开发板,上电后LED没亮、仿真器连不上、代码根本跑不起来——别急着换芯片或怀疑JTAG线接触不良。我去年在一家工业伺服驱动器厂商做固件支持时&…

阅读更多 →
Agent智能体开发实战:从LLM到ReAct架构的工程化指南 2026/9/28 16:07:13

Agent智能体开发实战:从LLM到ReAct架构的工程化指南

1. Agent智能体的本质与核心架构拆解1.1 从LLM到Agent:为什么需要智能体大语言模型本身是一个“输入文本、输出文本”的函数。你给它一段话,它给你一段回复,仅此而已。它没有记忆、没有工具、没有行动能力,更不会主动规划。但在实…

阅读更多 →
基于JSP+Servlet的宿舍管理系统开发实战:从数据库设计到部署避坑 2026/9/28 16:07:12

基于JSP+Servlet的宿舍管理系统开发实战:从数据库设计到部署避坑

简介:这是一个基于JSPServlet的JavaWeb宿舍管理系统完整项目,适用于毕业设计、课程设计及具有一定Java基础的学习者。项目围绕宿舍管理场景,实现了用户管理、宿舍分配、资源预订等常见功能,通过JSP页面展示界面、Servlet控制器处理…

阅读更多 →
宝峰1701刷OpenGD77固件全攻略:驱动安装、DFU模式与避坑指南 2026/9/28 16:07:12

宝峰1701刷OpenGD77固件全攻略:驱动安装、DFU模式与避坑指南

1. 宝峰1701刷OpenGD77的前期认知与方案选型宝峰1701这台机器在业余无线电圈子里算是入门级DMR手台里性价比很高的一款,原厂固件功能比较基础,菜单逻辑也偏简单。OpenGD77是一套开源固件,最早针对GD-77系列开发,后来逐步适配了包括…

阅读更多 →
ARTEMIS 框架实战:用视觉语言模型实现移动端 AI 自动化 2026/9/28 16:06:59

ARTEMIS 框架实战:用视觉语言模型实现移动端 AI 自动化

1. 为什么移动端自动化突然又火了移动端自动化这件事,其实不是新话题。从早期的按键精灵、Appium,到后来的无障碍服务脚本,再到近两年冒出来的各种 AI Agent 方案,本质上都在解决同一个问题:怎么让机器替人去点手机。但…

阅读更多 →
INT8 量化实战指南:从数值原理到 LLM 部署优化 2026/9/28 16:06:59

INT8 量化实战指南:从数值原理到 LLM 部署优化

这年头做模型部署,谁还没被显存和延迟逼疯过几次。模型在 fp16 下跑得动,一上生产环境就露馅:多路并发显存爆掉,首 token 延迟压不下来,单卡 QPS 提不上去。INT8 量化这时候往往是最立竿见影的一招——模型体积直接缩小…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉