基于CNN-LSTM优化模型的车辆路面类型识别实战:从数据修复到99.71%准确率
模型、GPURTX 5060、数据加载全部正常工作。让我用完整数据做一个小规模端到端测试确认整套流程 ● Bash(cd D:/huaweidata python -c import importlib.util, warnings, numpy as np…) ⎿ ✅ 运行设备: cuda ✅ 显卡: NVIDIA GeForce RTX 5060 总时序点数: 865605 … 13 lines (ctrlo to expand) ⎿ (timeout 2m) Thought for 2s (ctrlo to expand) ● 端到端测试完全通过RTX 5060 满载运行5 个 epoch 测试准确率已达 91.62%。 --- 优化总结 发现并修复的严重 Bug ┌──────────────────────┬─────────────────────────────────────────────────┬─────────────────────────────────────────┐ │ 问题 │ 原代码 │ 修复后 │ ├──────────────────────┼─────────────────────────────────────────────────┼─────────────────────────────────────────┤ │ 标签错误 │ 用 sheet 名作标签 → 20 类沥青-11、湿滑-11…… │ 提取路面类型 → 2 类沥青/湿滑 │ ├──────────────────────┼─────────────────────────────────────────────────┼─────────────────────────────────────────┤ │ 数据增强破坏物理意义 │ np.random.permutation(dim) 打乱 x/y/z 轴 │ 已移除保留幅值缩放噪声时间移位翻转 │ ├──────────────────────┼─────────────────────────────────────────────────┼─────────────────────────────────────────┤ │ 冗余标准化 │ 每 batch 再 StandardScaler但数据已标准化 │ 直接使用标准化后数据 │ └──────────────────────┴─────────────────────────────────────────────────┴─────────────────────────────────────────┘ 架构优化 ┌────────────┬───────────────────┬──────────────────────────────────────────┐ │ 模块 │ 原版 │ 优化版 v2 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ Conv 层 │ 2 层 Conv1D │ 3 层 Conv1D新增 k3 提取细粒度特征 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ BatchNorm │ ❌ 无 │ ✅ 每层 Conv 后 分类头加入 BatchNorm1d │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 通道注意力 │ 注释掉了 │ ✅ SENet 风格 ChannelAttention 可用 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ LSTM 方向 │ 单向 │ ✅ 第一层双向捕捉前后上下文 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 优化器 │ Adam │ ✅ AdamW 权重衰减防过拟合 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 学习率调度 │ ReduceLROnPlateau │ ✅ CosineAnnealingWarmRestarts │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 梯度裁剪 │ ❌ 无 │ ✅ clip_grad_norm_ 防 LSTM 梯度爆炸 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 模型保存 │ ❌ 无 │ ✅ best_model.pth 含权重标签映射 │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 评估指标 │ 准确率混淆矩阵 │ ✅ 新增 ROC-AUC、Precision/Recall/F1 │ └────────────┴───────────────────┴──────────────────────────────────────────┘ 运行结果5 epoch 快速测试 GPU: NVIDIA GeForce RTX 5060 (CUDA) 原始窗口分布: {湿滑: 792, 沥青: 2667} 数据集大小: 3459 个样本 (600×3 滑窗) Epoch 1: 测试准确率 79.34% Epoch 5: 测试准确率 91.62% ← 仅5轮已很高 新代码文件 路面训练4-CNN-LSTM优化v2.py 已生成可以直接运行 cd D:/huaweidata python 路面训练4-CNN-LSTM优化v2.py 完整训练 150 个 epoch 预计会达到 97% 的准确率训练完成后会自动 - 保存最佳模型到 best_model.pth - 生成训练曲线图 training_history.png - 生成混淆矩阵 confusion_matrix.png 要启动完整训练吗可以直接 python 路面训练4-CNN-LSTM优化v2.py。完整python代码 路面识别 — CNN-LSTM 优化版 v2 基于车轮传感器 3 轴加速度数据识别路面类型沥青 vs 湿滑 ⚠️ 发现并修复的严重问题 【标签错误】原代码用 sheet 名称如沥青-11,湿滑-11作标签 → 20 类 正确做法提取路面类型沥青/湿滑→ 二分类 【数据增强错误】原代码随机打乱 x/y/z 轴顺序破坏了物理意义已删除 【冗余标准化】数据已是按 sheet 标准化后的无需再 StandardScaler 【无模型保存】训练完不保存模型无法复用于推理 架构优化 新增 BatchNorm1d 加速收敛 提高泛化 新增第三层 Conv1D(k3) 提取更细粒度特征 启用通道注意力原 TF 版本注释掉的 ChannelAttention 第一层 LSTM 改为双向捕捉更完整上下文 CosineAnnealingWarmRestarts 学习率调度 文件说明 输入江淮试验场路面识别数据集_标准化后.xlsx已在每个 sheet 内做 z-score 输出best_model.pth最佳权重、训练曲线图、混淆矩阵 import os import warnings import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from collections import Counter from copy import deepcopy import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import Dataset, DataLoader from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts from sklearn.model_selection import train_test_split from sklearn.metrics import ( classification_report, accuracy_score, confusion_matrix, roc_auc_score, roc_curve, precision_recall_fscore_support ) from sklearn.utils.class_weight import compute_class_weight warnings.filterwarnings(ignore) plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False 全局配置 DEVICE torch.device(cuda if torch.cuda.is_available() else cpu) print(f✅ 运行设备: {DEVICE}) if torch.cuda.is_available(): print(f✅ 显卡: {torch.cuda.get_device_name(0)}) -------- 数据参数 -------- WINDOW_SIZE 600 # 窗口大小 ~0.33s 1800Hz STEP_SIZE 250 # 滑窗步长 AUGMENT_TIMES 3 # 少样本增强倍数 SAMPLE_THRESHOLD 80 # 低于此数量的类别才增强 NOISE_STD 0.03 # 高斯噪声标准差 SCALE_RANGE (0.9, 1.1) # 幅值缩放范围 -------- 训练参数 -------- BATCH_SIZE 96 EPOCHS 150 LEARNING_RATE 1e-3 WEIGHT_DECAY 1e-4 # L2 正则化防过拟合 PATIENCE_EARLY 25 # 早停耐心值 GRAD_CLIP_NORM 1.0 # 梯度裁剪防 LSTM 梯度爆炸 -------- 文件路径 -------- DATA_FILE 江淮试验场路面识别数据集_标准化后.xlsx MODEL_SAVE_PATH best_model.pth RESULT_FIG_PATH training_history.png CM_FIG_PATH confusion_matrix.png 1. 数据加载与标签提取 def parse_surface_label(sheet_name: str) - str: 从 sheet 名称中提取路面类型沥青 or 湿滑 name sheet_name.strip() if name.startswith(沥青): return 沥青 elif name.startswith(湿滑): return 湿滑 else: raise ValueError(fUnknown surface type in sheet: {sheet_name}) def load_and_merge_data(file_path: str): 读取所有 sheet合并为一个 DataFrame。 label 列只保留路面类型沥青/湿滑共 2 类。 xls pd.ExcelFile(file_path) all_data [] for sheet in xls.sheet_names: df pd.read_excel(xls, sheet_namesheet) # 确保列名统一 df.columns [c.lower().strip() for c in df.columns] # 提取路面类型标签大修复原代码直接用 sheet 名作标签 df[label] parse_surface_label(sheet) all_data.append(df) merged_df pd.concat(all_data, ignore_indexTrue) print(f 总时序点数: {len(merged_df)}) print(f 路面类型数: {merged_df[label].nunique()} (沥青/湿滑)) return merged_df 2. 数据增强保留物理意义 def augment_vibration_window(window_xyz: np.ndarray, noise_std0.03, scale_range(0.9, 1.1)): 对 IMU 振动窗口做数据增强。 ⚠️ 与原代码的关键区别不再打乱 x/y/z 轴会破坏物理方向含义 n_points window_xyz.shape[0] aug window_xyz.copy().astype(np.float64) # (1) 幅值缩放 scale np.random.uniform(*scale_range) aug * scale # (2) 加高斯噪声 noise np.random.normal(0, noise_std, sizewindow_xyz.shape) aug noise # (3) 时间循环移位模拟不同相位 shift np.random.randint(-int(n_points * 0.05), int(n_points * 0.05)) aug np.roll(aug, shift, axis0) # (4) 时间反转一半概率对振动信号合理 if np.random.random() gt; 0.5: aug np.flipud(aug) return aug def create_dataset(df: pd.DataFrame): 滑窗切分 → 数据增强 → 构建 (X, y) 标签用路面类型沥青/湿滑窗口内标签必须一致。 raw_windows [] raw_labels [] for i in range(0, len(df) - WINDOW_SIZE, STEP_SIZE): window df.iloc[i:i WINDOW_SIZE] # 跳过跨标签的窗口 if window[label].nunique() gt; 1: continue xyz_seq window[[x, y, z]].values.astype(np.float32) lab window[label].iloc[0] raw_windows.append(xyz_seq) raw_labels.append(lab) label_count Counter(raw_labels) print(f 原始窗口分布: {dict(label_count)}) # 识别少样本类别并增强 low_labs [lab for lab, cnt in label_count.items() if cnt lt; SAMPLE_THRESHOLD] if low_labs: print(f 增强类别: {low_labs}每类 ×{AUGMENT_TIMES}) aug_sequences [] aug_labels [] for seq, lab in zip(raw_windows, raw_labels): aug_sequences.append(seq) aug_labels.append(lab) if lab in low_labs: for _ in range(AUGMENT_TIMES): aug_sequences.append( augment_vibration_window(seq, NOISE_STD, SCALE_RANGE).astype(np.float32) ) aug_labels.append(lab) X np.array(aug_sequences, dtypenp.float32) y np.array(aug_labels) print(f 最终数据集: X{X.shape}, 分布{dict(Counter(y))}) return X, y 3. 数据集类 class IMUDataset(Dataset): def init(self, x_data: np.ndarray, y_label: np.ndarray): self.x torch.from_numpy(x_data).float() self.y torch.from_numpy(y_label).long() def __len__(self): return len(self.x) def __getitem__(self, idx): return self.x[idx], self.y[idx] 4. CNN-LSTM 模型优化版 class ChannelAttention(nn.Module): SENet 风格通道注意力——让模型关注哪些频率通道更重要 def init(self, channels, reduction8): super().init() self.fc nn.Sequential( nn.AdaptiveAvgPool1d(1), nn.Flatten(), nn.Linear(channels, max(channels // reduction, 4)), nn.ReLU(inplaceTrue), nn.Linear(max(channels // reduction, 4), channels), nn.Sigmoid(), ) def forward(self, x): # x: [B, C, T] weight self.fc(x).unsqueeze(-1) # [B, C, 1] return x * weight class CNNLSTM_IMU(nn.Module): 优化版 CNN-LSTM 路面识别模型 改进点 - 每层 Conv 后添加 BatchNorm → 加速收敛 减少过拟合 - 新增第三层 Conv1D(k3) → 提取细粒度局部振动模式 - 通道注意力SENet→ 自适应重标定特征通道 - 第一层 LSTM 改为双向 → 同时看前后上下文 - 分类头加 BatchNorm → 稳定训练 def __init__(self, input_dim3, num_classes2): super().__init__() # ----- Conv 特征提取模块 ----- self.conv_block1 nn.Sequential( nn.Conv1d(input_dim, 96, kernel_size15, paddingsame), nn.BatchNorm1d(96), nn.ReLU(inplaceTrue), nn.MaxPool1d(3), nn.Dropout(0.2), ) self.conv_block2 nn.Sequential( nn.Conv1d(96, 160, kernel_size7, paddingsame), nn.BatchNorm1d(160), nn.ReLU(inplaceTrue), nn.MaxPool1d(2), nn.Dropout(0.25), ) # 新增第三层小卷积核提取精细特征 self.conv_block3 nn.Sequential( nn.Conv1d(160, 160, kernel_size3, paddingsame), nn.BatchNorm1d(160), nn.ReLU(inplaceTrue), nn.MaxPool1d(2), nn.Dropout(0.3), ) # 通道注意力 self.channel_attn ChannelAttention(160, reduction8) # ----- LSTM 时序建模模块 ----- self.lstm1 nn.LSTM( input_size160, hidden_size128, batch_firstTrue, bidirectionalTrue, ) self.drop_lstm1 nn.Dropout(0.35) self.lstm2 nn.LSTM( input_size256, hidden_size96, # 双向 → 256 batch_firstTrue, bidirectionalFalse, ) self.drop_lstm2 nn.Dropout(0.35) # ----- 分类头 ----- self.classifier nn.Sequential( nn.Linear(96, 128), nn.BatchNorm1d(128), nn.ReLU(inplaceTrue), nn.Dropout(0.4), nn.Linear(128, num_classes), ) def forward(self, x): # x: [B, T, 3] → permute → [B, 3, T] for Conv1D x x.permute(0, 2, 1) # Conv 阶段 x self.conv_block1(x) # [B, 96, T/3] x self.conv_block2(x) # [B, 160, T/6] x self.conv_block3(x) # [B, 160, T/12] # 通道注意力 x self.channel_attn(x) # [B, 160, T/12] # 转回 LSTM 格式 [B, T, C] x x.permute(0, 2, 1) # LSTM 阶段 x, _ self.lstm1(x) x self.drop_lstm1(x) x, _ self.lstm2(x) x self.drop_lstm2(x) # 取最后时间步 x x[:, -1, :] # 分类 out self.classifier(x) return out 5. 早停机制 class EarlyStopping: 验证损失早停 最优权重保存 def init(self, patience20, min_delta1e-4): self.patience patience self.min_delta min_delta self.counter 0 self.best_loss float(inf) self.best_state None self.early_stop False def __call__(self, val_loss, model): if val_loss lt; self.best_loss - self.min_delta: self.best_loss val_loss self.best_state deepcopy(model.state_dict()) self.counter 0 else: self.counter 1 if self.counter gt; self.patience: self.early_stop True return self.early_stop 6. 绘图工具 def plot_training_history(train_loss, val_loss, train_acc, val_acc, save_path): plt.figure(figsize(14, 5)) plt.subplot(1, 2, 1) plt.plot(train_loss, label训练损失, linewidth1.5) plt.plot(val_loss, label验证损失, linewidth1.5) plt.title(损失曲线, fontsize13, fontweightbold) plt.xlabel(Epoch) plt.ylabel(Loss) plt.legend() plt.grid(True, alpha0.3) plt.subplot(1, 2, 2) plt.plot(train_acc, label训练准确率, linewidth1.5) plt.plot(val_acc, label验证准确率, linewidth1.5) plt.title(准确率曲线, fontsize13, fontweightbold) plt.xlabel(Epoch) plt.ylabel(Accuracy) plt.legend() plt.grid(True, alpha0.3) plt.tight_layout() plt.savefig(save_path, dpi150, bbox_inchestight) print(f 训练曲线已保存: {save_path}) plt.close() def plot_confusion_matrix(cm, class_names, save_path): plt.figure(figsize(8, 6)) sns.heatmap( cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names, annot_kws{size: 14}, ) plt.title(路面识别混淆矩阵 (CNN-LSTM), fontsize14, fontweightbold) plt.xlabel(预测标签, fontsize12) plt.ylabel(真实标签, fontsize12) plt.tight_layout() plt.savefig(save_path, dpi150, bbox_inchestight) print(f 混淆矩阵已保存: {save_path}) plt.close() 主训练流程 def main(): print( * 60) print( 路面识别 — CNN-LSTM 优化版 v2) print( * 60) # ---- 1. 加载数据 ---- print(\n[1/6] 加载数据...) raw_df load_and_merge_data(DATA_FILE) X, y create_dataset(raw_df) # ---- 2. 标签编码 ---- print(\n[2/6] 标签编码...) label_map {沥青: 0, 湿滑: 1} # 支持字典映射更快更清晰或 LabelEncoder 回退 try: y_encoded np.array([label_map[lab] for lab in y]) classes_ np.array([沥青, 湿滑]) except KeyError: from sklearn.preprocessing import LabelEncoder le LabelEncoder() y_encoded le.fit_transform(y) classes_ le.classes_ num_classes len(classes_) print(f路面类型: {classes_}, 编码: {dict(zip(classes_, range(num_classes)))}) print(f正样本(湿滑)占比: {(y_encoded 1).mean():.2%}) # ---- 3. 分层划分 ---- print(\n[3/6] 划分训练集/测试集...) X_train, X_test, y_train, y_test train_test_split( X, y_encoded, test_size0.2, random_state42, stratifyy_encoded, ) print(f训练集: {X_train.shape}, 测试集: {X_test.shape}) # ---- 4. 数据加载器 ---- train_set IMUDataset(X_train, y_train) test_set IMUDataset(X_test, y_test) train_loader DataLoader( train_set, batch_sizeBATCH_SIZE, shuffleTrue, drop_lastFalse, num_workers0, pin_memoryTrue, ) test_loader DataLoader( test_set, batch_sizeBATCH_SIZE * 2, shuffleFalse, num_workers0, pin_memoryTrue, ) # ---- 5. 模型初始化 ---- print(\n[4/6] 构建模型...) model CNNLSTM_IMU(input_dim3, num_classesnum_classes).to(DEVICE) # 计算模型参数量 total_params sum(p.numel() for p in model.parameters()) trainable_params sum(p.numel() for p in model.parameters() if p.requires_grad) print(f模型参数量: {total_params:,} (可训练: {trainable_params:,})) # ---- 6. 损失函数 amp; 优化器 ---- # 类别权重平衡沥青(多)与湿滑(少) class_weights compute_class_weight( balanced, classesnp.unique(y_encoded), yy_encoded, ) class_weights torch.tensor(class_weights, dtypetorch.float32).to(DEVICE) print(f类别权重: {class_weights}) criterion nn.CrossEntropyLoss(weightclass_weights) optimizer optim.AdamW( model.parameters(), lrLEARNING_RATE, weight_decayWEIGHT_DECAY, ) # CosineAnnealingWarmRestarts每个周期先升后降帮助跳出局部最优 scheduler CosineAnnealingWarmRestarts( optimizer, T_015, T_mult2, eta_min1e-6, ) early_stopper EarlyStopping(patiencePATIENCE_EARLY) # ---- 7. 训练循环 ---- print(\n[5/6] 开始训练...) train_losses, val_losses [], [] train_accs, val_accs [], [] for epoch in range(1, EPOCHS 1): # 训练阶段 model.train() total_loss 0.0 correct 0 total 0 for batch_x, batch_y in train_loader: batch_x batch_x.to(DEVICE, non_blockingTrue) batch_y batch_y.to(DEVICE, non_blockingTrue) optimizer.zero_grad() output model(batch_x) loss criterion(output, batch_y) loss.backward() # 【关键优化】梯度裁剪防止 LSTM 梯度爆炸 torch.nn.utils.clip_grad_norm_(model.parameters(), GRAD_CLIP_NORM) optimizer.step() total_loss loss.item() pred_class output.argmax(dim1) correct (pred_class batch_y).sum().item() total batch_y.size(0) avg_train_loss total_loss / len(train_loader) train_acc correct / total # 验证阶段 model.eval() val_loss 0.0 val_correct 0 val_total 0 with torch.no_grad(): for batch_x, batch_y in test_loader: batch_x batch_x.to(DEVICE, non_blockingTrue) batch_y batch_y.to(DEVICE, non_blockingTrue) output model(batch_x) loss criterion(output, batch_y) val_loss loss.item() pred_class output.argmax(dim1) val_correct (pred_class batch_y).sum().item() val_total batch_y.size(0) avg_val_loss val_loss / len(test_loader) val_acc val_correct / val_total # 学习率调整CosineAnnealingWarmRestarts 每个 epoch 一步 scheduler.step() current_lr optimizer.param_groups[0][lr] # 记录 train_losses.append(avg_train_loss) val_losses.append(avg_val_loss) train_accs.append(train_acc) val_accs.append(val_acc) # 打印 if epoch 1 or epoch % 5 0: print( fEpoch {epoch:3d}/{EPOCHS} | fTrain Loss: {avg_train_loss:.4f} | Val Loss: {avg_val_loss:.4f} | fTrain Acc: {train_acc:.4f} | Val Acc: {val_acc:.4f} | fLR: {current_lr:.2e} ) # 早停检查 if early_stopper(avg_val_loss, model): print(f\n⏹️ 早停触发! 最佳验证损失: {early_stopper.best_loss:.4f} (epoch {epoch - early_stopper.counter})) break # 恢复最佳权重 if early_stopper.best_state is not None: model.load_state_dict(early_stopper.best_state) print(✅ 已恢复最佳模型权重) # ---- 8. 保存模型 ---- torch.save({ model_state_dict: model.state_dict(), classes: classes_, window_size: WINDOW_SIZE, step_size: STEP_SIZE, input_dim: 3, }, MODEL_SAVE_PATH) print(f 模型已保存: {MODEL_SAVE_PATH}) # ---- 9. 评估 ---- print(\n[6/6] 评估模型...) model.eval() all_preds, all_probs, all_true [], [], [] with torch.no_grad(): for batch_x, batch_y in test_loader: batch_x batch_x.to(DEVICE) output model(batch_x) probs torch.softmax(output, dim1) preds output.argmax(dim1) all_probs.append(probs[:, 1].cpu().numpy()) # 湿滑的概率 all_preds.append(preds.cpu().numpy()) all_true.append(batch_y.numpy()) all_preds np.concatenate(all_preds) all_probs np.concatenate(all_probs) all_true np.concatenate(all_true) # ---- 10. 分类报告 ---- print(\n * 60) print( 评估结果) print( * 60) acc accuracy_score(all_true, all_preds) print(f\n 整体准确率: {acc:.4f} ({acc * 100:.2f}%)) print(\n 分类报告:) print(classification_report( all_true, all_preds, target_namesclasses_, digits4, zero_division0, )) # ROC-AUC if num_classes 2: auc roc_auc_score(all_true, all_probs) print(f ROC-AUC: {auc:.4f}) # 详细指标 precision, recall, f1, support precision_recall_fscore_support( all_true, all_preds, zero_division0, ) for i, cls in enumerate(classes_): print(f {cls}: Precision{precision[i]:.4f}, Recall{recall[i]:.4f}, F1{f1[i]:.4f}, Support{support[i]}) # ---- 11. 混淆矩阵 ---- cm confusion_matrix(all_true, all_preds) plot_confusion_matrix(cm, classes_, CM_FIG_PATH) # ---- 12. 训练曲线 ---- plot_training_history(train_losses, val_losses, train_accs, val_accs, RESULT_FIG_PATH) # 显示图表 plt.show() print(\n✅ 训练完成!) if name main: main()运行结果(torch-gpu) PS D:\huaweidata python 路面训练4-CNN-LSTM优化v2.py) python 路面训练4-CNN-LSTM优化v2.py ✅ 运行设备: cuda ✅ 显卡: NVIDIA GeForce RTX 5060 路面识别 — CNN-LSTM 优化版 v2 [1/6] 加载数据... 总时序点数: 865605 路面类型数: 2 (沥青/湿滑) 原始窗口分布: {湿滑: 792, 沥青: 2667} 最终数据集: X(3459, 600, 3), 分布{np.str_(湿滑): 792, np.str_(沥青): 2667} [2/6] 标签编码... 路面类型: [沥青 湿滑], 编码: {np.str_(沥青): 0, np.str_(湿滑): 1} 正样本(湿滑)占比: 22.90% [3/6] 划分训练集/测试集... 训练集: (2767, 600, 3), 测试集: (692, 600, 3) [4/6] 构建模型... 模型参数量: 642,294 (可训练: 642,294) 类别权重: tensor([0.6485, 2.1837], devicecuda:0) [5/6] 开始训练... Epoch 1/150 | Train Loss: 0.6766 | Val Loss: 0.6525 | Train Acc: 0.5916 | Val Acc: 0.4234 | LR: 9.89e-04 Epoch 5/150 | Train Loss: 0.1566 | Val Loss: 0.3763 | Train Acc: 0.9530 | Val Acc: 0.8555 | LR: 7.50e-04 Epoch 10/150 | Train Loss: 0.0838 | Val Loss: 0.0478 | Train Acc: 0.9761 | Val Acc: 0.9884 | LR: 2.51e-04 Epoch 15/150 | Train Loss: 0.0282 | Val Loss: 0.0601 | Train Acc: 0.9931 | Val Acc: 0.9884 | LR: 1.00e-03 Epoch 20/150 | Train Loss: 0.0694 | Val Loss: 0.1334 | Train Acc: 0.9819 | Val Acc: 0.9610 | LR: 9.33e-04 Epoch 25/150 | Train Loss: 0.0448 | Val Loss: 0.0242 | Train Acc: 0.9884 | Val Acc: 0.9957 | LR: 7.50e-04 Epoch 30/150 | Train Loss: 0.0198 | Val Loss: 0.0580 | Train Acc: 0.9953 | Val Acc: 0.9899 | LR: 5.01e-04 Epoch 35/150 | Train Loss: 0.0303 | Val Loss: 0.3765 | Train Acc: 0.9924 | Val Acc: 0.9610 | LR: 2.51e-04 Epoch 40/150 | Train Loss: 0.0055 | Val Loss: 0.0316 | Train Acc: 0.9989 | Val Acc: 0.9957 | LR: 6.79e-05 Epoch 45/150 | Train Loss: 0.0030 | Val Loss: 0.0384 | Train Acc: 0.9993 | Val Acc: 0.9957 | LR: 1.00e-03 Epoch 50/150 | Train Loss: 0.0375 | Val Loss: 0.0979 | Train Acc: 0.9899 | Val Acc: 0.9827 | LR: 9.83e-04 Epoch 55/150 | Train Loss: 0.0406 | Val Loss: 0.4275 | Train Acc: 0.9913 | Val Acc: 0.9436 | LR: 9.33e-04 Epoch 60/150 | Train Loss: 0.0212 | Val Loss: 0.2817 | Train Acc: 0.9978 | Val Acc: 0.9032 | LR: 8.54e-04 ⏹️ 早停触发! 最佳验证损失: 0.0098 (epoch 36) ✅ 已恢复最佳模型权重 模型已保存: best_model.pth [6/6] 评估模型... 评估结果 整体准确率: 0.9971 (99.71%) 分类报告: precision recall f1-score support 沥青 0.9981 0.9981 0.9981 534 湿滑 0.9937 0.9937 0.9937 158 accuracy 0.9971 692 macro avg 0.9959 0.9959 0.9959 692 weighted avg 0.9971 0.9971 0.9971 692 ROC-AUC: 0.9999 沥青: Precision0.9981, Recall0.9981, F10.9981, Support534 湿滑: Precision0.9937, Recall0.9937, F10.9937, Support158 混淆矩阵已保存: confusion_matrix.png 训练曲线已保存: training_history.png ✅ 训练完成!准确率99.71%

相关新闻

半导体测试设备核心技术解析与选型指南

半导体测试设备核心技术解析与选型指南

1. 项目概述:半导体测试设备行业优质展商盘点 在半导体产业链中,测试环节是确保芯片质量和性能的关键步骤。本次我们将聚焦四家在该领域具有代表性的企业:爱德万测试(Advantest)、腾芯微电子、赤松城科技和长川科技。这…

2026/7/26 17:30:28 阅读更多 →
免费AI写歌软件推荐|AI写歌软件怎么选,哪些更适合做完整中文歌

免费AI写歌软件推荐|AI写歌软件怎么选,哪些更适合做完整中文歌

免费AI写歌软件推荐|AI写歌软件怎么选,哪些更适合做完整中文歌一、普通人用AI写歌最常卡在这些地方很多人想靠AI把脑子里的情绪做成完整歌曲,实际操作下来总会遇到各种不顺。有时候深夜冒出一句副歌歌词,输入工具生成旋律&#xf…

2026/7/26 9:11:27 阅读更多 →
AI作词工具与歌词生成器实测分享:写词卡壳时用来找灵感的实用工具

AI作词工具与歌词生成器实测分享:写词卡壳时用来找灵感的实用工具

写词最磨人的从来不是提笔,而是卡在中途进退两难。确定好了整首歌的情绪主题,主歌铺垫还算顺畅,写到副歌突然断思路,翻遍备忘录也找不到贴合心境的句子;或是写完一整版,通篇韵脚杂乱,意象零散&a…

2026/7/26 16:57:55 阅读更多 →

最新新闻

华为OD机试C语言最短路径算法实战解析

华为OD机试C语言最短路径算法实战解析

1. 项目背景与题目解析 "直捣黄龙"是华为OD(Outstanding Developer)2026年最新机试系统中的一道C语言编程题,主要考察开发者对数据结构、算法设计和代码实现的综合能力。这道题目名称取材于成语"直捣黄龙",暗…

2026/7/27 7:40:30 阅读更多 →
Maven 学习框架:依赖管理 + 仓库配置 + IDEA 集成

Maven 学习框架:依赖管理 + 仓库配置 + IDEA 集成

1. Maven 的概念1.1. 什么是 MavenMaven 是一个基于 项目对象模型(POM) 的 Apache 开源项目管理工具。它不仅仅是一个构建工具,更是一个项目管理框架。核心机制:通过一个 pom.xml 文件管理项目的整个生命周期(编译、测…

2026/7/27 7:40:30 阅读更多 →
Java集合框架:Map与Set核心原理与性能优化实践

Java集合框架:Map与Set核心原理与性能优化实践

1. Map和Set基础概念解析Java集合框架中的Map和Set是日常开发中最常用的两种数据结构,它们虽然都属于集合类,但在设计理念和使用场景上有着本质区别。我刚开始接触Java时也经常混淆它们的特性,直到在真实项目中踩过几次坑后才真正理解它们的差…

2026/7/27 7:40:30 阅读更多 →
Python Tkinter Listbox实时搜索过滤实现与优化

Python Tkinter Listbox实时搜索过滤实现与优化

1. 项目概述:Tkinter实现Listbox实时搜索过滤在Python GUI开发中,Tkinter作为标准库提供了快速构建界面的能力。最近在开发一个员工管理系统时,我需要处理包含300条目的Listbox组件,用户需要快速定位特定条目。传统的滚动查找方式…

2026/7/27 7:40:30 阅读更多 →
Java SSL握手异常PKIX路径构建失败:原理、诊断与解决方案全解析

Java SSL握手异常PKIX路径构建失败:原理、诊断与解决方案全解析

1. 项目概述:当Java应用“握手”失败时 如果你是一名Java后端开发者,或者正在维护一个需要与外部服务(比如调用第三方API、连接数据库、访问HTTPS网站)通信的应用,那么“SSL握手异常”这个词组大概率会让你心头一紧。…

2026/7/27 7:40:30 阅读更多 →
Arch Linux + Wine + i3wm:搭建《重武器老鼠》复古游戏环境

Arch Linux + Wine + i3wm:搭建《重武器老鼠》复古游戏环境

概述《重武器老鼠》(Mighty Rodent,也有民间称为重装老鼠)是一款 2006 年发布的街机风格 2D 射击游戏,原为 Windows 平台 RAR 自解压包。本文记录在 Arch Linux i3wm AMD 双显卡笔记本 上通过 Wine 完整运行该游戏的实战流程&am…

2026/7/27 7:39:30 阅读更多 →

日新闻

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:54 阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻