机器学习实现盾构机滚刀状态识别:CNN、LSTM、GRU、SVM与随机森林全流程

📅 发布时间:2026/10/11 22:21:44
机器学习实现盾构机滚刀状态识别:CNN、LSTM、GRU、SVM与随机森林全流程
简介这份资源面向机械加工与智能制造方向的本科生、研究生及算法初学者提供一套基于机器学习的滚刀状态识别完整项目可用于毕业设计、期末大作业或课程设计。项目同时实现CNN、LSTM、GRU、SVM与随机森林等多种模型便于横向对比不同算法在刀具状态识别任务上的表现帮助读者理解特征提取、数据预处理与模型评估的完整流程。压缩包共15个文件约2.63MB包含8个Python源码文件、4个CSV数据集、1张结果图、1份README说明及gitignore配置源码与数据配套齐全部署后即可运行。目前已有233人学习下载。项目结构清晰涵盖数据合并、特征生成、各模型训练与测试脚本读者可据此掌握从原始信号到状态分类的建模思路并在此基础上替换数据或调整网络结构快速完成自己的实验与论文写作。1. 滚刀状态识别为什么值得用机器学习重做一遍盾构机在掘进时滚刀直接接触岩面磨损、崩刃、偏磨几乎每天都在发生。传统做法靠人工听刀盘异响、看推力扭矩曲线、定期开仓检查问题是开仓本身风险高、停机成本大而等到人能听出异常刀具往往已经严重损坏。我接触过的几个现场换刀时间占停机时间的三成以上其中相当一部分是「本来还能再挖几十环」的刀被提前换掉或者「再撑两环就崩」的刀没被识别出来。把滚刀状态识别交给机器学习核心逻辑是滚刀在不同健康状态下掘进参数推力、扭矩、贯入度、转速、刀盘振动等会呈现不同的统计特征和时序模式。CNN 擅长从多通道传感器数据里提取局部模式LSTM 和 GRU 擅长捕捉长时序依赖SVM 和随机森林则在特征工程到位时给出稳定、可解释的基线。这套组合不是炫技而是覆盖了「特征自动提取」和「小样本稳定分类」两条路线方便你在数据量、标注质量不同的阶段做取舍。这篇文章面向的是手里有掘进数据、想跑通滚刀状态识别全流程的工程师和研究生。我会从数据组织讲到模型训练、参数设置、结果验证再到实际部署时最容易翻车的地方。Python 是主线工具CNN、LSTM、GRU、SVM、随机森林都会给出可复现的代码骨架和参数说明。2. 数据准备与特征工程把掘进参数变成模型能吃的样本2.1 滚刀状态标签怎么定义才不坑自己滚刀状态识别第一个卡点不是模型是标签。现场能拿到的标签通常来自换刀记录某年某月某环某号刀更换更换原因写「磨损」「崩刃」「正常磨损」。但换刀记录的时间戳精度往往只到「班次」或「环号」而传感器数据是秒级或毫秒级。直接把换刀时刻前后一刀切会引入大量错标样本。我一般会做三层标签定义。第一层是「健康 / 异常」二分类异常包括崩刃、偏磨、严重磨损第二层是异常子类用于后续做多分类第三层是「退化程度」用剩余寿命或磨损量做回归。对于大多数团队建议先从二分类做起标签窗口取换刀前 N 环为异常换刀前 M 环到更早为健康中间留一段「灰区」不参与训练。灰区的作用是避免边界样本污染这个技巧在轴承故障诊断里也常用。具体操作上用环号对齐传感器数据。假设数据表里有ring_no、timestamp、thrust、torque、penetration、rpm、vibration_x等字段先按环号聚合出每环的统计量再按换刀记录打标签。下面这段代码是标签生成的核心逻辑import pandas as pd import numpy as np # df: 秒级传感器数据含 ring_no, timestamp, thrust, torque, penetration, rpm, vib_x, vib_y # change_log: 换刀记录含 ring_no, cutter_id, change_type def build_labels(df, change_log, abnormal_window5, healthy_gap10): abnormal_window: 换刀前多少环标为异常 healthy_gap: 异常窗口之后多少环内不参与训练灰区 df df.sort_values(ring_no).reset_index(dropTrue) df[label] -1 # -1 表示灰区/未标注 for _, row in change_log.iterrows(): r row[ring_no] # 异常窗口 df.loc[(df[ring_no] r - abnormal_window) (df[ring_no] r), label] 1 # 灰区 df.loc[(df[ring_no] r - abnormal_window - healthy_gap) (df[ring_no] r - abnormal_window), label] -1 # 健康窗口灰区之前到上一次换刀之后 df.loc[df[ring_no] r - abnormal_window - healthy_gap, label] 0 # 只保留有标签的样本 labeled df[df[label] ! -1].copy() return labeled这段代码的关键参数是abnormal_window和healthy_gap。abnormal_window太小异常样本不足太大会把健康退化早期也标成异常导致模型过于敏感。我的经验是先从 3 到 5 环试起看验证集上的召回率和误报率再调。healthy_gap一般取abnormal_window的 1.5 到 2 倍目的是让健康样本和异常样本在时间上不重叠。注意如果同一环有多把刀同时更换标签会混叠。建议先按单刀做或者把多刀更换的环直接剔除。2.2 时序窗口切分与多通道特征构造有了环级标签下一步是把秒级数据切成模型输入。CNN、LSTM、GRU 都需要固定长度的时序窗口。常见做法是滑窗切分窗口长度 L步长 S每个窗口继承其中心环号的标签。L 的选择和采样率有关如果传感器是 1 HzL 取 60 到 120 比较合理对应 1 到 2 分钟如果采样率更高可以先降采样到 1 Hz 再切。除了原始时序我还会构造一批统计特征给 SVM 和随机森林用。这些特征包括均值、标准差、均方根、峰值因子、峭度、偏度以及推力扭矩的比值、贯入度与转速的乘积等物理组合量。下面这个函数同时输出时序窗口和统计特征from scipy.stats import kurtosis, skew def extract_features(window_df): window_df: 一个窗口内的多通道数据列含 thrust, torque, penetration, rpm, vib_x, vib_y feats {} for col in [thrust, torque, penetration, rpm, vib_x, vib_y]: x window_df[col].values feats[f{col}_mean] np.mean(x) feats[f{col}_std] np.std(x) feats[f{col}_rms] np.sqrt(np.mean(x**2)) feats[f{col}_kurt] kurtosis(x) feats[f{col}_skew] skew(x) # 物理组合特征 feats[thrust_torque_ratio] feats[thrust_mean] / (feats[torque_mean] 1e-6) feats[penetration_rpm] feats[penetration_mean] * feats[rpm_mean] return feats def make_windows(df, window_len60, step30): 返回时序窗口数组和对应的统计特征DataFrame X_seq, X_stat, y [], [], [] for start in range(0, len(df) - window_len, step): win df.iloc[start:start window_len] label win[label].mode()[0] # 窗口内多数标签 X_seq.append(win[[thrust, torque, penetration, rpm, vib_x, vib_y]].values) X_stat.append(extract_features(win)) y.append(label) return np.array(X_seq), pd.DataFrame(X_stat), np.array(y)window_len和step是核心参数。window_len太短时序模型抓不到退化趋势太长样本数减少且实时性变差。step一般取window_len的 1/2 到 1/3做数据增强。如果类别不平衡可以在切窗时对少数类做重叠采样但要注意别让同一段数据同时出现在训练集和验证集。2.3 标准化、类别不平衡与数据集划分时序窗口和统计特征在送入模型前都要标准化。时序数据按通道做 z-score统计特征用StandardScaler或RobustScaler。这里有个容易翻车的地方标准化参数必须只在训练集上拟合再应用到验证集和测试集。我见过有人在全量数据上 fit结果验证集指标虚高上线后直接崩。类别不平衡在滚刀数据里很常见健康样本远多于异常样本。处理方式有三种类权重、过采样、欠采样。对于 SVM 和随机森林直接设class_weightbalanced最省事对于 CNN/LSTM/GRU可以在损失函数里加类权重或者用 focal loss。过采样建议用 SMOTE 的变体但只对统计特征做不要对时序窗口做 SMOTE否则会破坏时序结构。数据集划分按时间顺序切不要随机打乱。滚刀状态是随时间退化的随机划分会让未来数据泄露到训练集。常见比例是 70% 训练、15% 验证、15% 测试按环号排序后切分。如果数据量少可以用时间序列交叉验证比如TimeSeriesSplit。3. 五类模型怎么选、怎么训、参数怎么设3.1 CNN 做多通道时序特征提取的网络结构与训练参数CNN 在滚刀状态识别里的角色是自动提取局部模式。把多通道时序看成一张「通道数 × 时间步」的图用一维卷积沿时间轴滑动就能捕捉推力突变、扭矩振荡这类局部异常。我的常用结构是两层 Conv1D BatchNorm MaxPooling再接全局平均池化和全连接分类头。import tensorflow as tf from tensorflow.keras import layers, models def build_cnn(input_shape, n_classes2): inputs layers.Input(shapeinput_shape) # (window_len, n_channels) x layers.Conv1D(32, kernel_size5, paddingsame, activationrelu)(inputs) x layers.BatchNormalization()(x) x layers.MaxPooling1D(pool_size2)(x) x layers.Conv1D(64, kernel_size3, paddingsame, activationrelu)(x) x layers.BatchNormalization()(x) x layers.GlobalAveragePooling1D()(x) x layers.Dropout(0.3)(x) x layers.Dense(64, activationrelu)(x) outputs layers.Dense(n_classes, activationsoftmax)(x) model models.Model(inputs, outputs) model.compile(optimizertf.keras.optimizers.Adam(1e-3), losssparse_categorical_crossentropy, metrics[accuracy]) return modelkernel_size第一层取 5 到 7覆盖短时突变第二层取 3做组合特征。Dropout放在全局池化之后比例 0.3 到 0.5。学习率先用 1e-3如果验证 loss 震荡就降到 5e-4。Batch size 取 32 或 64数据量少时用 16。训练轮数不要固定用EarlyStopping监控验证 losspatience 设 10 到 15。注意如果输入窗口长度超过 500第一层卷积的kernel_size可以加大到 9 或 11否则感受野不够。3.2 LSTM 与 GRU 的时序建模差异和调参重点LSTM 和 GRU 都用来抓长时序依赖区别在门控结构。LSTM 有三个门参数多适合数据量较大的场景GRU 只有两个门参数少训练快在小样本上往往更稳。滚刀数据通常样本有限我一般先试 GRU如果欠拟合再换 LSTM。def build_gru(input_shape, n_classes2): inputs layers.Input(shapeinput_shape) x layers.GRU(64, return_sequencesTrue)(inputs) x layers.GRU(32)(x) x layers.Dropout(0.3)(x) x layers.Dense(32, activationrelu)(x) outputs layers.Dense(n_classes, activationsoftmax)(x) model models.Model(inputs, outputs) model.compile(optimizertf.keras.optimizers.Adam(5e-4), losssparse_categorical_crossentropy, metrics[accuracy]) return modelGRU 隐藏单元第一层 64、第二层 32 是常用起点。如果窗口长度超过 200建议加return_sequencesTrue堆叠或者用Bidirectional包一层。学习率比 CNN 低5e-4 到 1e-4。LSTM 的结构类似把GRU换成LSTM即可但隐藏单元可以适当减少比如 48 和 24避免过拟合。调参重点看验证集上的 loss 曲线。如果训练 loss 下降但验证 loss 上升先加 Dropout 或减隐藏单元如果两者都高先加层或加单元。梯度裁剪clipnorm1.0在 LSTM/GRU 上几乎必加能明显减少梯度爆炸。3.3 SVM 与随机森林小样本下的稳定基线怎么搭SVM 和随机森林用统计特征不直接吃时序窗口。SVM 适合特征维度不高、样本量几百到几千的场景核函数先用 RBFC和gamma用网格搜索。随机森林对特征尺度不敏感能给出特征重要性适合做特征筛选和可解释性分析。from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler # SVM 管道 svm_pipe Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf, class_weightbalanced, probabilityTrue)) ]) svm_params { svm__C: [0.1, 1, 10, 100], svm__gamma: [scale, 0.01, 0.001, 0.0001] } svm_grid GridSearchCV(svm_pipe, svm_params, cv5, scoringf1, n_jobs-1) # 随机森林 rf RandomForestClassifier( n_estimators300, max_depthNone, min_samples_leaf2, class_weightbalanced, random_state42, n_jobs-1 )SVM 的C越大对误分类容忍越低容易过拟合gamma越大决策边界越复杂。网格搜索用f1而不是accuracy因为类别不平衡时 accuracy 会骗人。随机森林的n_estimators300 起步min_samples_leaf设 2 到 5 能防过拟合。训练完后用feature_importances_看哪些统计特征贡献大通常thrust_mean、torque_std、vib_x_kurt会排前面。3.4 五类模型的对比与融合策略把五类模型放在一起对比不是为了选一个「最好」的而是看它们在验证集上的错误是否互补。CNN 和 GRU 擅长时序模式SVM 和随机森林擅长统计特征融合方式有两种投票法和堆叠法。投票法简单把五个模型的预测概率平均堆叠法用逻辑回归做元学习器效果通常更好但需要更多数据。模型输入优势主要参数适用场景CNN时序窗口局部模式提取kernel_size, filters数据量中等以上LSTM时序窗口长依赖建模units, dropout窗口长、退化趋势明显GRU时序窗口训练快、小样本稳units, dropout样本有限SVM统计特征小样本稳定C, gamma特征工程到位随机森林统计特征可解释、抗过拟合n_estimators, max_depth特征筛选、基线融合时注意五个模型的输出概率要先校准否则投票会被过度自信的模型带偏。sklearn的CalibratedClassifierCV可以对 SVM 和随机森林做概率校准神经网络本身输出 softmax一般不用再校准。4. 避坑与排查滚刀状态识别里最容易翻车的五件事4.1 标签泄漏验证集指标虚高上线就崩现象验证集准确率 95% 以上测试集掉到 70% 以下。原因通常是随机划分数据集或者标准化参数在全量数据上拟合导致未来信息泄露。解决严格按时间顺序切分标准化只在训练集 fit验证集和测试集 transform。检查方法是看训练集和验证集的环号范围是否有重叠。4.2 窗口重叠导致样本不独立现象交叉验证分数波动很小但换一批数据就失效。原因是滑窗步长太小相邻窗口高度重叠训练集和验证集里存在近似重复样本。解决按环号分组切分同一环的窗口只出现在一个集合里或者用GroupKFold按环号分组。4.3 类别不平衡被 accuracy 掩盖现象模型把所有样本预测为健康accuracy 仍有 80%。原因是异常样本占比低。解决用f1、recall、AUC替代 accuracy设class_weightbalanced在验证集上单独看异常类的召回率。如果异常召回低于 0.7优先调阈值或加过采样。4.4 时序模型过拟合训练 loss 降验证 loss 升现象CNN/LSTM/GRU 训练几轮后验证 loss 反弹。原因是模型容量过大或数据太少。解决减层、减隐藏单元、加 Dropout、加 L2 正则用EarlyStopping恢复最佳权重数据增强用加噪声、时间缩放但幅度别太大否则会破坏物理意义。4.5 特征量纲不一致导致 SVM 失效现象SVM 训练不收敛或预测全为同一类。原因是统计特征里有的量纲是千级有的是小数。解决SVM 前必须标准化用Pipeline把StandardScaler和SVC串起来随机森林虽然对量纲不敏感但标准化后特征重要性更可比。5. 从离线模型到现场可用验证方法与一个实用技巧模型训完不是终点现场能不能用要看三件事实时性、稳定性和可解释性。实时性方面CNN 和 GRU 的单窗口推理时间通常在毫秒级但如果你用滑动窗口每秒推理一次要注意别让特征提取成为瓶颈。我一般会把统计特征计算用numpy向量化时序窗口用固定长度缓冲避免每来一个点就重算整个窗口。稳定性验证用「跨环测试」拿连续 50 环数据逐环预测看异常概率是否在换刀前 3 到 5 环开始上升。如果概率曲线是平的说明模型没学到退化趋势如果概率在换刀前突然跳变说明模型可能过拟合了换刀记录的时间戳。理想曲线是缓慢上升在换刀前达到峰值。可解释性方面随机森林的特征重要性可以告诉你哪些参数最关键CNN 可以用 Grad-CAM 看时间轴上哪些片段被激活。我习惯把异常概率和推力、扭矩曲线画在一起现场人员更容易接受。一个实用技巧是「双阈值报警」设一个高阈值触发立即检查一个低阈值触发持续监控。高阈值取验证集上误报率 5% 对应的概率低阈值取召回率 90% 对应的概率。这样既能抓住严重异常又不会因为偶尔波动频繁报警。def dual_threshold_alarm(probs, high_th, low_th, patience3): probs: 按时间顺序的异常概率序列 high_th: 高阈值触发立即报警 low_th: 低阈值连续 patience 次超过才报警 alarms [] low_count 0 for p in probs: if p high_th: alarms.append(high) low_count 0 elif p low_th: low_count 1 if low_count patience: alarms.append(low) low_count 0 else: alarms.append(none) else: low_count 0 alarms.append(none) return alarmspatience取 3 到 5太小会误报太大会漏报。这个逻辑在现场跑的时候比单阈值稳得多。最后说个我自己的习惯每次换刀后把实际换刀原因和模型预测对齐记录误报和漏报的样本定期回训。滚刀状态识别不是一次训练就完事数据分布会随地质条件变化模型需要跟着更新。我一般每两周用新数据微调一次保持召回率不掉。希望帮到你。本文还有配套的精品资源点击获取